обмен перенес на usart2

на новой плате изолированный 485 передатчик на uart2  .
на  type-c сидит uart1
This commit is contained in:
2025-11-18 19:35:22 +03:00
parent a37f13628d
commit 2e4b034670
828 changed files with 447501 additions and 229 deletions

View File

@@ -0,0 +1,1009 @@
/**
******************************************************************************
* @file stm32f1xx_hal_cec.c
* @author MCD Application Team
* @brief CEC HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of the High Definition Multimedia Interface
* Consumer Electronics Control Peripheral (CEC).
* + Initialization and de-initialization function
* + IO operation function
* + Peripheral Control function
*
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
===============================================================================
##### How to use this driver #####
===============================================================================
[..]
The CEC HAL driver can be used as follow:
(#) Declare a CEC_HandleTypeDef handle structure.
(#) Initialize the CEC low level resources by implementing the HAL_CEC_MspInit ()API:
(##) Enable the CEC interface clock.
(##) CEC pins configuration:
(+++) Enable the clock for the CEC GPIOs.
(+++) Configure these CEC pins as alternate function pull-up.
(##) NVIC configuration if you need to use interrupt process (HAL_CEC_Transmit_IT()
and HAL_CEC_Receive_IT() APIs):
(+++) Configure the CEC interrupt priority.
(+++) Enable the NVIC CEC IRQ handle.
(+++) The specific CEC interrupts (Transmission complete interrupt,
RXNE interrupt and Error Interrupts) will be managed using the macros
__HAL_CEC_ENABLE_IT() and __HAL_CEC_DISABLE_IT() inside the transmit
and receive process.
(#) Program the Bit Timing Error Mode and the Bit Period Error Mode in the hcec Init structure.
(#) Initialize the CEC registers by calling the HAL_CEC_Init() API.
[..]
(@) This API (HAL_CEC_Init()) configures also the low level Hardware (GPIO, CLOCK, CORTEX...etc)
by calling the customed HAL_CEC_MspInit() API.
*** Callback registration ***
=============================================
The compilation define USE_HAL_CEC_REGISTER_CALLBACKS when set to 1
allows the user to configure dynamically the driver callbacks.
Use Functions HAL_CEC_RegisterCallback() or HAL_CEC_RegisterXXXCallback()
to register an interrupt callback.
Function HAL_CEC_RegisterCallback() allows to register following callbacks:
(+) TxCpltCallback : Tx Transfer completed callback.
(+) ErrorCallback : callback for error detection.
(+) MspInitCallback : CEC MspInit.
(+) MspDeInitCallback : CEC MspDeInit.
This function takes as parameters the HAL peripheral handle, the Callback ID
and a pointer to the user callback function.
For specific callback HAL_CEC_RxCpltCallback use dedicated register callbacks
HAL_CEC_RegisterRxCpltCallback().
Use function HAL_CEC_UnRegisterCallback() to reset a callback to the default
weak function.
HAL_CEC_UnRegisterCallback() takes as parameters the HAL peripheral handle,
and the Callback ID.
This function allows to reset following callbacks:
(+) TxCpltCallback : Tx Transfer completed callback.
(+) ErrorCallback : callback for error detection.
(+) MspInitCallback : CEC MspInit.
(+) MspDeInitCallback : CEC MspDeInit.
For callback HAL_CEC_RxCpltCallback use dedicated unregister callback :
HAL_CEC_UnRegisterRxCpltCallback().
By default, after the HAL_CEC_Init() and when the state is HAL_CEC_STATE_RESET
all callbacks are set to the corresponding weak functions :
examples HAL_CEC_TxCpltCallback() , HAL_CEC_RxCpltCallback().
Exception done for MspInit and MspDeInit functions that are
reset to the legacy weak function in the HAL_CEC_Init()/ HAL_CEC_DeInit() only when
these callbacks are null (not registered beforehand).
if not, MspInit or MspDeInit are not null, the HAL_CEC_Init() / HAL_CEC_DeInit()
keep and use the user MspInit/MspDeInit functions (registered beforehand)
Callbacks can be registered/unregistered in HAL_CEC_STATE_READY state only.
Exception done MspInit/MspDeInit callbacks that can be registered/unregistered
in HAL_CEC_STATE_READY or HAL_CEC_STATE_RESET state,
thus registered (user) MspInit/DeInit callbacks can be used during the Init/DeInit.
In that case first register the MspInit/MspDeInit user callbacks
using HAL_CEC_RegisterCallback() before calling HAL_CEC_DeInit()
or HAL_CEC_Init() function.
When the compilation define USE_HAL_CEC_REGISTER_CALLBACKS is set to 0 or
not defined, the callback registration feature is not available and all callbacks
are set to the corresponding weak functions.
@endverbatim
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
#ifdef HAL_CEC_MODULE_ENABLED
#if defined (CEC)
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
/** @defgroup CEC CEC
* @brief HAL CEC module driver
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/** @defgroup CEC_Private_Constants CEC Private Constants
* @{
*/
#define CEC_CFGR_FIELDS (CEC_CFGR_BTEM | CEC_CFGR_BPEM )
#define CEC_FLAG_TRANSMIT_MASK (CEC_FLAG_TSOM|CEC_FLAG_TEOM|CEC_FLAG_TBTRF)
#define CEC_FLAG_RECEIVE_MASK (CEC_FLAG_RSOM|CEC_FLAG_REOM|CEC_FLAG_RBTF)
#define CEC_ESR_ALL_ERROR (CEC_ESR_BTE|CEC_ESR_BPE|CEC_ESR_RBTFE|CEC_ESR_SBE|CEC_ESR_ACKE|CEC_ESR_LINE|CEC_ESR_TBTFE)
#define CEC_RXXFERSIZE_INITIALIZE 0xFFFF /*!< Value used to initialise the RxXferSize of the handle */
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/** @defgroup CEC_Private_Functions CEC Private Functions
* @{
*/
static HAL_StatusTypeDef CEC_Transmit_IT(CEC_HandleTypeDef *hcec);
static HAL_StatusTypeDef CEC_Receive_IT(CEC_HandleTypeDef *hcec);
/**
* @}
*/
/* Exported functions ---------------------------------------------------------*/
/** @defgroup CEC_Exported_Functions CEC Exported Functions
* @{
*/
/** @defgroup CEC_Exported_Functions_Group1 Initialization and de-initialization functions
* @brief Initialization and Configuration functions
*
@verbatim
===============================================================================
##### Initialization and Configuration functions #####
===============================================================================
[..]
This subsection provides a set of functions allowing to initialize the CEC
(+) The following parameters need to be configured:
(++) TimingErrorFree
(++) PeriodErrorFree
(++) InitiatorAddress
@endverbatim
* @{
*/
/**
* @brief Initializes the CEC mode according to the specified
* parameters in the CEC_InitTypeDef and creates the associated handle .
* @param hcec CEC handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_CEC_Init(CEC_HandleTypeDef *hcec)
{
/* Check the CEC handle allocation */
if ((hcec == NULL) || (hcec->Init.RxBuffer == NULL))
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_CEC_ALL_INSTANCE(hcec->Instance));
assert_param(IS_CEC_BIT_TIMING_ERROR_MODE(hcec->Init.TimingErrorFree));
assert_param(IS_CEC_BIT_PERIOD_ERROR_MODE(hcec->Init.PeriodErrorFree));
assert_param(IS_CEC_ADDRESS(hcec->Init.OwnAddress));
#if (USE_HAL_CEC_REGISTER_CALLBACKS == 1)
if (hcec->gState == HAL_CEC_STATE_RESET)
{
/* Allocate lock resource and initialize it */
hcec->Lock = HAL_UNLOCKED;
hcec->TxCpltCallback = HAL_CEC_TxCpltCallback; /* Legacy weak TxCpltCallback */
hcec->RxCpltCallback = HAL_CEC_RxCpltCallback; /* Legacy weak RxCpltCallback */
hcec->ErrorCallback = HAL_CEC_ErrorCallback; /* Legacy weak ErrorCallback */
if (hcec->MspInitCallback == NULL)
{
hcec->MspInitCallback = HAL_CEC_MspInit; /* Legacy weak MspInit */
}
/* Init the low level hardware */
hcec->MspInitCallback(hcec);
}
#else
if (hcec->gState == HAL_CEC_STATE_RESET)
{
/* Allocate lock resource and initialize it */
hcec->Lock = HAL_UNLOCKED;
/* Init the low level hardware : GPIO, CLOCK */
HAL_CEC_MspInit(hcec);
}
#endif /* USE_HAL_CEC_REGISTER_CALLBACKS */
hcec->gState = HAL_CEC_STATE_BUSY;
/* Disable the Peripheral */
__HAL_CEC_DISABLE(hcec);
/* Write to CEC Control Register */
MODIFY_REG(hcec->Instance->CFGR, CEC_CFGR_FIELDS, hcec->Init.TimingErrorFree | hcec->Init.PeriodErrorFree);
/* Write to CEC Own Address Register */
MODIFY_REG(hcec->Instance->OAR, CEC_OAR_OA, hcec->Init.OwnAddress);
/* Configure the prescaler to generate the required 50 microseconds time base.*/
MODIFY_REG(hcec->Instance->PRES, CEC_PRES_PRES, 50U * (HAL_RCC_GetPCLK1Freq() / 1000000U) - 1U);
/* Enable the following CEC Interrupt */
__HAL_CEC_ENABLE_IT(hcec, CEC_IT_IE);
/* Enable the CEC Peripheral */
__HAL_CEC_ENABLE(hcec);
hcec->ErrorCode = HAL_CEC_ERROR_NONE;
hcec->gState = HAL_CEC_STATE_READY;
hcec->RxState = HAL_CEC_STATE_READY;
return HAL_OK;
}
/**
* @brief DeInitializes the CEC peripheral
* @param hcec CEC handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_CEC_DeInit(CEC_HandleTypeDef *hcec)
{
/* Check the CEC handle allocation */
if (hcec == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_CEC_ALL_INSTANCE(hcec->Instance));
hcec->gState = HAL_CEC_STATE_BUSY;
#if (USE_HAL_CEC_REGISTER_CALLBACKS == 1)
if (hcec->MspDeInitCallback == NULL)
{
hcec->MspDeInitCallback = HAL_CEC_MspDeInit; /* Legacy weak MspDeInit */
}
/* DeInit the low level hardware */
hcec->MspDeInitCallback(hcec);
#else
/* DeInit the low level hardware */
HAL_CEC_MspDeInit(hcec);
#endif /* USE_HAL_CEC_REGISTER_CALLBACKS */
__HAL_RCC_CEC_FORCE_RESET();
__HAL_RCC_CEC_RELEASE_RESET();
hcec->ErrorCode = HAL_CEC_ERROR_NONE;
hcec->gState = HAL_CEC_STATE_RESET;
hcec->RxState = HAL_CEC_STATE_RESET;
/* Process Unlock */
__HAL_UNLOCK(hcec);
return HAL_OK;
}
/**
* @brief Initializes the Own Address of the CEC device
* @param hcec CEC handle
* @param CEC_OwnAddress The CEC own address.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_CEC_SetDeviceAddress(CEC_HandleTypeDef *hcec, uint16_t CEC_OwnAddress)
{
/* Check the parameters */
assert_param(IS_CEC_OWN_ADDRESS(CEC_OwnAddress));
if ((hcec->gState == HAL_CEC_STATE_READY) && (hcec->RxState == HAL_CEC_STATE_READY))
{
/* Process Locked */
__HAL_LOCK(hcec);
hcec->gState = HAL_CEC_STATE_BUSY;
/* Disable the Peripheral */
__HAL_CEC_DISABLE(hcec);
if (CEC_OwnAddress != CEC_OWN_ADDRESS_NONE)
{
MODIFY_REG(hcec->Instance->OAR, CEC_OAR_OA, hcec->Init.OwnAddress);
}
else
{
CLEAR_BIT(hcec->Instance->OAR, CEC_OAR_OA);
}
hcec->gState = HAL_CEC_STATE_READY;
hcec->ErrorCode = HAL_CEC_ERROR_NONE;
/* Process Unlocked */
__HAL_UNLOCK(hcec);
/* Enable the Peripheral */
__HAL_CEC_ENABLE(hcec);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief CEC MSP Init
* @param hcec CEC handle
* @retval None
*/
__weak void HAL_CEC_MspInit(CEC_HandleTypeDef *hcec)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hcec);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_CEC_MspInit can be implemented in the user file
*/
}
/**
* @brief CEC MSP DeInit
* @param hcec CEC handle
* @retval None
*/
__weak void HAL_CEC_MspDeInit(CEC_HandleTypeDef *hcec)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hcec);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_CEC_MspDeInit can be implemented in the user file
*/
}
#if (USE_HAL_CEC_REGISTER_CALLBACKS == 1)
/**
* @brief Register a User CEC Callback
* To be used instead of the weak predefined callback
* @param hcec CEC handle
* @param CallbackID ID of the callback to be registered
* This parameter can be one of the following values:
* @arg @ref HAL_CEC_TX_CPLT_CB_ID Tx Complete callback ID
* @arg @ref HAL_CEC_ERROR_CB_ID Error callback ID
* @arg @ref HAL_CEC_MSPINIT_CB_ID MspInit callback ID
* @arg @ref HAL_CEC_MSPDEINIT_CB_ID MspDeInit callback ID
* @param pCallback pointer to the Callback function
* @retval HAL status
*/
HAL_StatusTypeDef HAL_CEC_RegisterCallback(CEC_HandleTypeDef *hcec, HAL_CEC_CallbackIDTypeDef CallbackID,
pCEC_CallbackTypeDef pCallback)
{
HAL_StatusTypeDef status = HAL_OK;
if (pCallback == NULL)
{
/* Update the error code */
hcec->ErrorCode |= HAL_CEC_ERROR_INVALID_CALLBACK;
return HAL_ERROR;
}
/* Process locked */
__HAL_LOCK(hcec);
if (hcec->gState == HAL_CEC_STATE_READY)
{
switch (CallbackID)
{
case HAL_CEC_TX_CPLT_CB_ID :
hcec->TxCpltCallback = pCallback;
break;
case HAL_CEC_ERROR_CB_ID :
hcec->ErrorCallback = pCallback;
break;
case HAL_CEC_MSPINIT_CB_ID :
hcec->MspInitCallback = pCallback;
break;
case HAL_CEC_MSPDEINIT_CB_ID :
hcec->MspDeInitCallback = pCallback;
break;
default :
/* Update the error code */
hcec->ErrorCode |= HAL_CEC_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else if (hcec->gState == HAL_CEC_STATE_RESET)
{
switch (CallbackID)
{
case HAL_CEC_MSPINIT_CB_ID :
hcec->MspInitCallback = pCallback;
break;
case HAL_CEC_MSPDEINIT_CB_ID :
hcec->MspDeInitCallback = pCallback;
break;
default :
/* Update the error code */
hcec->ErrorCode |= HAL_CEC_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else
{
/* Update the error code */
hcec->ErrorCode |= HAL_CEC_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(hcec);
return status;
}
/**
* @brief Unregister an CEC Callback
* CEC callback is redirected to the weak predefined callback
* @param hcec uart handle
* @param CallbackID ID of the callback to be unregistered
* This parameter can be one of the following values:
* @arg @ref HAL_CEC_TX_CPLT_CB_ID Tx Complete callback ID
* @arg @ref HAL_CEC_ERROR_CB_ID Error callback ID
* @arg @ref HAL_CEC_MSPINIT_CB_ID MspInit callback ID
* @arg @ref HAL_CEC_MSPDEINIT_CB_ID MspDeInit callback ID
* @retval status
*/
HAL_StatusTypeDef HAL_CEC_UnRegisterCallback(CEC_HandleTypeDef *hcec, HAL_CEC_CallbackIDTypeDef CallbackID)
{
HAL_StatusTypeDef status = HAL_OK;
/* Process locked */
__HAL_LOCK(hcec);
if (hcec->gState == HAL_CEC_STATE_READY)
{
switch (CallbackID)
{
case HAL_CEC_TX_CPLT_CB_ID :
hcec->TxCpltCallback = HAL_CEC_TxCpltCallback; /* Legacy weak TxCpltCallback */
break;
case HAL_CEC_ERROR_CB_ID :
hcec->ErrorCallback = HAL_CEC_ErrorCallback; /* Legacy weak ErrorCallback */
break;
case HAL_CEC_MSPINIT_CB_ID :
hcec->MspInitCallback = HAL_CEC_MspInit;
break;
case HAL_CEC_MSPDEINIT_CB_ID :
hcec->MspDeInitCallback = HAL_CEC_MspDeInit;
break;
default :
/* Update the error code */
hcec->ErrorCode |= HAL_CEC_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else if (hcec->gState == HAL_CEC_STATE_RESET)
{
switch (CallbackID)
{
case HAL_CEC_MSPINIT_CB_ID :
hcec->MspInitCallback = HAL_CEC_MspInit;
break;
case HAL_CEC_MSPDEINIT_CB_ID :
hcec->MspDeInitCallback = HAL_CEC_MspDeInit;
break;
default :
/* Update the error code */
hcec->ErrorCode |= HAL_CEC_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else
{
/* Update the error code */
hcec->ErrorCode |= HAL_CEC_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(hcec);
return status;
}
/**
* @brief Register CEC RX complete Callback
* To be used instead of the weak HAL_CEC_RxCpltCallback() predefined callback
* @param hcec CEC handle
* @param pCallback pointer to the Rx transfer compelete Callback function
* @retval HAL status
*/
HAL_StatusTypeDef HAL_CEC_RegisterRxCpltCallback(CEC_HandleTypeDef *hcec, pCEC_RxCallbackTypeDef pCallback)
{
HAL_StatusTypeDef status = HAL_OK;
if (pCallback == NULL)
{
/* Update the error code */
hcec->ErrorCode |= HAL_CEC_ERROR_INVALID_CALLBACK;
return HAL_ERROR;
}
/* Process locked */
__HAL_LOCK(hcec);
if (HAL_CEC_STATE_READY == hcec->RxState)
{
hcec->RxCpltCallback = pCallback;
}
else
{
/* Update the error code */
hcec->ErrorCode |= HAL_CEC_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(hcec);
return status;
}
/**
* @brief UnRegister CEC RX complete Callback
* CEC RX complete Callback is redirected to the weak HAL_CEC_RxCpltCallback() predefined callback
* @param hcec CEC handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_CEC_UnRegisterRxCpltCallback(CEC_HandleTypeDef *hcec)
{
HAL_StatusTypeDef status = HAL_OK;
/* Process locked */
__HAL_LOCK(hcec);
if (HAL_CEC_STATE_READY == hcec->RxState)
{
hcec->RxCpltCallback = HAL_CEC_RxCpltCallback; /* Legacy weak CEC RxCpltCallback */
}
else
{
/* Update the error code */
hcec->ErrorCode |= HAL_CEC_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(hcec);
return status;
}
#endif /* USE_HAL_CEC_REGISTER_CALLBACKS */
/**
* @}
*/
/** @defgroup CEC_Exported_Functions_Group2 Input and Output operation functions
* @brief CEC Transmit/Receive functions
*
@verbatim
===============================================================================
##### IO operation functions #####
===============================================================================
This subsection provides a set of functions allowing to manage the CEC data transfers.
(#) The CEC handle must contain the initiator (TX side) and the destination (RX side)
logical addresses (4-bit long addresses, 0xF for broadcast messages destination)
(#) The communication is performed using Interrupts.
These API's return the HAL status.
The end of the data processing will be indicated through the
dedicated CEC IRQ when using Interrupt mode.
The HAL_CEC_TxCpltCallback(), HAL_CEC_RxCpltCallback() user callbacks
will be executed respectively at the end of the transmit or Receive process
The HAL_CEC_ErrorCallback() user callback will be executed when a communication
error is detected
(#) API's with Interrupt are :
(+) HAL_CEC_Transmit_IT()
(+) HAL_CEC_IRQHandler()
(#) A set of User Callbacks are provided:
(+) HAL_CEC_TxCpltCallback()
(+) HAL_CEC_RxCpltCallback()
(+) HAL_CEC_ErrorCallback()
@endverbatim
* @{
*/
/**
* @brief Send data in interrupt mode
* @param hcec CEC handle
* @param InitiatorAddress Initiator address
* @param DestinationAddress destination logical address
* @param pData pointer to input byte data buffer
* @param Size amount of data to be sent in bytes (without counting the header).
* 0 means only the header is sent (ping operation).
* Maximum TX size is 15 bytes (1 opcode and up to 14 operands).
* @retval HAL status
*/
HAL_StatusTypeDef HAL_CEC_Transmit_IT(CEC_HandleTypeDef *hcec, uint8_t InitiatorAddress, uint8_t DestinationAddress,
const uint8_t *pData, uint32_t Size)
{
/* if the peripheral isn't already busy and if there is no previous transmission
already pending due to arbitration lost */
if (hcec->gState == HAL_CEC_STATE_READY)
{
if ((pData == NULL) && (Size > 0U))
{
return HAL_ERROR;
}
assert_param(IS_CEC_ADDRESS(DestinationAddress));
assert_param(IS_CEC_ADDRESS(InitiatorAddress));
assert_param(IS_CEC_MSGSIZE(Size));
/* Process Locked */
__HAL_LOCK(hcec);
hcec->pTxBuffPtr = pData;
hcec->gState = HAL_CEC_STATE_BUSY_TX;
hcec->ErrorCode = HAL_CEC_ERROR_NONE;
/* initialize the number of bytes to send,
* 0 means only one header is sent (ping operation) */
hcec->TxXferCount = Size;
/* send header block */
hcec->Instance->TXD = (uint8_t)((uint32_t)InitiatorAddress << CEC_INITIATOR_LSB_POS) | DestinationAddress;
/* Process Unlocked */
__HAL_UNLOCK(hcec);
/* case no data to be sent, sender is only pinging the system */
if (Size != 0)
{
/* Set TX Start of Message (TXSOM) bit */
MODIFY_REG(hcec->Instance->CSR, CEC_FLAG_TRANSMIT_MASK, CEC_FLAG_TSOM);
}
else
{
/* Send a ping command */
MODIFY_REG(hcec->Instance->CSR, CEC_FLAG_TRANSMIT_MASK, CEC_FLAG_TEOM | CEC_FLAG_TSOM);
}
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Get size of the received frame.
* @param hcec CEC handle
* @retval Frame size
*/
uint32_t HAL_CEC_GetLastReceivedFrameSize(const CEC_HandleTypeDef *hcec)
{
return hcec->RxXferSize;
}
/**
* @brief Change Rx Buffer.
* @param hcec CEC handle
* @param Rxbuffer Rx Buffer
* @note This function can be called only inside the HAL_CEC_RxCpltCallback()
* @retval Frame size
*/
void HAL_CEC_ChangeRxBuffer(CEC_HandleTypeDef *hcec, uint8_t *Rxbuffer)
{
hcec->Init.RxBuffer = Rxbuffer;
}
/**
* @brief This function handles CEC interrupt requests.
* @param hcec CEC handle
* @retval None
*/
void HAL_CEC_IRQHandler(CEC_HandleTypeDef *hcec)
{
/* save interrupts register for further error or interrupts handling purposes */
uint32_t itflag;
itflag = hcec->Instance->CSR;
/* Save error status register for further error handling purposes */
hcec->ErrorCode = READ_BIT(hcec->Instance->ESR, CEC_ESR_ALL_ERROR);
/* Transmit error */
if (HAL_IS_BIT_SET(itflag, CEC_FLAG_TERR))
{
/* Acknowledgement of the error */
__HAL_CEC_CLEAR_FLAG(hcec, CEC_FLAG_TERR);
hcec->gState = HAL_CEC_STATE_READY;
}
/* Receive error */
if (HAL_IS_BIT_SET(itflag, CEC_FLAG_RERR))
{
/* Acknowledgement of the error */
__HAL_CEC_CLEAR_FLAG(hcec, CEC_FLAG_RERR);
hcec->Init.RxBuffer -= hcec->RxXferSize;
hcec->RxXferSize = 0U;
hcec->RxState = HAL_CEC_STATE_READY;
}
if ((hcec->ErrorCode & CEC_ESR_ALL_ERROR) != 0U)
{
/* Error Call Back */
#if (USE_HAL_CEC_REGISTER_CALLBACKS == 1)
hcec->ErrorCallback(hcec);
#else
HAL_CEC_ErrorCallback(hcec);
#endif /* USE_HAL_CEC_REGISTER_CALLBACKS */
}
/* Transmit byte request or block transfer finished */
if (HAL_IS_BIT_SET(itflag, CEC_FLAG_TBTRF))
{
CEC_Transmit_IT(hcec);
}
/* Receive byte or block transfer finished */
if (HAL_IS_BIT_SET(itflag, CEC_FLAG_RBTF))
{
if (hcec->RxXferSize == 0U)
{
/* reception is starting */
hcec->RxState = HAL_CEC_STATE_BUSY_RX;
}
CEC_Receive_IT(hcec);
}
}
/**
* @brief Tx Transfer completed callback
* @param hcec CEC handle
* @retval None
*/
__weak void HAL_CEC_TxCpltCallback(CEC_HandleTypeDef *hcec)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hcec);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_CEC_TxCpltCallback can be implemented in the user file
*/
}
/**
* @brief Rx Transfer completed callback
* @param hcec CEC handle
* @param RxFrameSize Size of frame
* @retval None
*/
__weak void HAL_CEC_RxCpltCallback(CEC_HandleTypeDef *hcec, uint32_t RxFrameSize)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hcec);
UNUSED(RxFrameSize);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_CEC_RxCpltCallback can be implemented in the user file
*/
}
/**
* @brief CEC error callbacks
* @param hcec CEC handle
* @retval None
*/
__weak void HAL_CEC_ErrorCallback(CEC_HandleTypeDef *hcec)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hcec);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_CEC_ErrorCallback can be implemented in the user file
*/
}
/**
* @}
*/
/** @defgroup CEC_Exported_Functions_Group3 Peripheral Control functions
* @brief CEC control functions
*
@verbatim
===============================================================================
##### Peripheral Control function #####
===============================================================================
[..]
This subsection provides a set of functions allowing to control the CEC.
(+) HAL_CEC_GetState() API can be helpful to check in run-time the state of the CEC peripheral.
(+) HAL_CEC_GetError() API can be helpful to check in run-time the error of the CEC peripheral.
@endverbatim
* @{
*/
/**
* @brief return the CEC state
* @param hcec pointer to a CEC_HandleTypeDef structure that contains
* the configuration information for the specified CEC module.
* @retval HAL state
*/
HAL_CEC_StateTypeDef HAL_CEC_GetState(const CEC_HandleTypeDef *hcec)
{
uint32_t temp1;
uint32_t temp2;
temp1 = hcec->gState;
temp2 = hcec->RxState;
return (HAL_CEC_StateTypeDef)(temp1 | temp2);
}
/**
* @brief Return the CEC error code
* @param hcec pointer to a CEC_HandleTypeDef structure that contains
* the configuration information for the specified CEC.
* @retval CEC Error Code
*/
uint32_t HAL_CEC_GetError(const CEC_HandleTypeDef *hcec)
{
return hcec->ErrorCode;
}
/**
* @}
*/
/**
* @}
*/
/** @addtogroup CEC_Private_Functions
* @{
*/
/**
* @brief Send data in interrupt mode
* @param hcec CEC handle.
* Function called under interruption only, once
* interruptions have been enabled by HAL_CEC_Transmit_IT()
* @retval HAL status
*/
static HAL_StatusTypeDef CEC_Transmit_IT(CEC_HandleTypeDef *hcec)
{
/* if the peripheral is already busy or if there is a previous transmission
already pending due to arbitration loss */
if ((hcec->gState == HAL_CEC_STATE_BUSY_TX) || (__HAL_CEC_GET_TRANSMISSION_START_FLAG(hcec) != RESET))
{
/* if all data have been sent */
if (hcec->TxXferCount == 0U)
{
/* Acknowledge successful completion by writing 0x00 */
MODIFY_REG(hcec->Instance->CSR, CEC_FLAG_TRANSMIT_MASK, 0x00U);
hcec->gState = HAL_CEC_STATE_READY;
#if (USE_HAL_CEC_REGISTER_CALLBACKS == 1)
hcec->TxCpltCallback(hcec);
#else
HAL_CEC_TxCpltCallback(hcec);
#endif /* USE_HAL_CEC_REGISTER_CALLBACKS */
return HAL_OK;
}
else
{
/* Reduce the number of bytes to transfer by one */
hcec->TxXferCount--;
/* Write data to TX buffer*/
hcec->Instance->TXD = (uint8_t) * hcec->pTxBuffPtr++;
/* If this is the last byte of the ongoing transmission */
if (hcec->TxXferCount == 0U)
{
/* Acknowledge byte request and signal end of message */
MODIFY_REG(hcec->Instance->CSR, CEC_FLAG_TRANSMIT_MASK, CEC_FLAG_TEOM);
}
else
{
/* Acknowledge byte request by writing 0x00 */
MODIFY_REG(hcec->Instance->CSR, CEC_FLAG_TRANSMIT_MASK, 0x00U);
}
return HAL_OK;
}
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Receive data in interrupt mode.
* @param hcec CEC handle.
* Function called under interruption only, once
* interruptions have been enabled by HAL_CEC_Receive_IT()
* @retval HAL status
*/
static HAL_StatusTypeDef CEC_Receive_IT(CEC_HandleTypeDef *hcec)
{
static uint32_t temp;
if (hcec->RxState == HAL_CEC_STATE_BUSY_RX)
{
temp = hcec->Instance->CSR;
/* Store received data */
hcec->RxXferSize++;
*hcec->Init.RxBuffer++ = hcec->Instance->RXD;
/* Acknowledge received byte by writing 0x00 */
MODIFY_REG(hcec->Instance->CSR, CEC_FLAG_RECEIVE_MASK, 0x00U);
/* If the End Of Message is reached */
if (HAL_IS_BIT_SET(temp, CEC_FLAG_REOM))
{
/* Interrupts are not disabled due to transmission still ongoing */
hcec->RxState = HAL_CEC_STATE_READY;
#if (USE_HAL_CEC_REGISTER_CALLBACKS == 1)
hcec->RxCpltCallback(hcec, hcec->RxXferSize);
#else
HAL_CEC_RxCpltCallback(hcec, hcec->RxXferSize);
#endif /* USE_HAL_CEC_REGISTER_CALLBACKS */
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
else
{
return HAL_BUSY;
}
}
/**
* @}
*/
/**
* @}
*/
#endif /* CEC */
#endif /* HAL_CEC_MODULE_ENABLED */
/**
* @}
*/

View File

@@ -0,0 +1,328 @@
/**
******************************************************************************
* @file stm32f1xx_hal_crc.c
* @author MCD Application Team
* @brief CRC HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of the Cyclic Redundancy Check (CRC) peripheral:
* + Initialization and de-initialization functions
* + Peripheral Control functions
* + Peripheral State functions
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
===============================================================================
##### How to use this driver #####
===============================================================================
[..]
(+) Enable CRC AHB clock using __HAL_RCC_CRC_CLK_ENABLE();
(+) Initialize CRC calculator
(++) specify generating polynomial (peripheral default or non-default one)
(++) specify initialization value (peripheral default or non-default one)
(++) specify input data format
(++) specify input or output data inversion mode if any
(+) Use HAL_CRC_Accumulate() function to compute the CRC value of the
input data buffer starting with the previously computed CRC as
initialization value
(+) Use HAL_CRC_Calculate() function to compute the CRC value of the
input data buffer starting with the defined initialization value
(default or non-default) to initiate CRC calculation
@endverbatim
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
/** @defgroup CRC CRC
* @brief CRC HAL module driver.
* @{
*/
#ifdef HAL_CRC_MODULE_ENABLED
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @defgroup CRC_Exported_Functions CRC Exported Functions
* @{
*/
/** @defgroup CRC_Exported_Functions_Group1 Initialization and de-initialization functions
* @brief Initialization and Configuration functions.
*
@verbatim
===============================================================================
##### Initialization and de-initialization functions #####
===============================================================================
[..] This section provides functions allowing to:
(+) Initialize the CRC according to the specified parameters
in the CRC_InitTypeDef and create the associated handle
(+) DeInitialize the CRC peripheral
(+) Initialize the CRC MSP (MCU Specific Package)
(+) DeInitialize the CRC MSP
@endverbatim
* @{
*/
/**
* @brief Initialize the CRC according to the specified
* parameters in the CRC_InitTypeDef and create the associated handle.
* @param hcrc CRC handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_CRC_Init(CRC_HandleTypeDef *hcrc)
{
/* Check the CRC handle allocation */
if (hcrc == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_CRC_ALL_INSTANCE(hcrc->Instance));
if (hcrc->State == HAL_CRC_STATE_RESET)
{
/* Allocate lock resource and initialize it */
hcrc->Lock = HAL_UNLOCKED;
/* Init the low level hardware */
HAL_CRC_MspInit(hcrc);
}
/* Change CRC peripheral state */
hcrc->State = HAL_CRC_STATE_READY;
/* Return function status */
return HAL_OK;
}
/**
* @brief DeInitialize the CRC peripheral.
* @param hcrc CRC handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_CRC_DeInit(CRC_HandleTypeDef *hcrc)
{
/* Check the CRC handle allocation */
if (hcrc == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_CRC_ALL_INSTANCE(hcrc->Instance));
/* Check the CRC peripheral state */
if (hcrc->State == HAL_CRC_STATE_BUSY)
{
return HAL_BUSY;
}
/* Change CRC peripheral state */
hcrc->State = HAL_CRC_STATE_BUSY;
/* Reset CRC calculation unit */
__HAL_CRC_DR_RESET(hcrc);
/* Reset IDR register content */
__HAL_CRC_SET_IDR(hcrc, 0);
/* DeInit the low level hardware */
HAL_CRC_MspDeInit(hcrc);
/* Change CRC peripheral state */
hcrc->State = HAL_CRC_STATE_RESET;
/* Process unlocked */
__HAL_UNLOCK(hcrc);
/* Return function status */
return HAL_OK;
}
/**
* @brief Initializes the CRC MSP.
* @param hcrc CRC handle
* @retval None
*/
__weak void HAL_CRC_MspInit(CRC_HandleTypeDef *hcrc)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hcrc);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_CRC_MspInit can be implemented in the user file
*/
}
/**
* @brief DeInitialize the CRC MSP.
* @param hcrc CRC handle
* @retval None
*/
__weak void HAL_CRC_MspDeInit(CRC_HandleTypeDef *hcrc)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hcrc);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_CRC_MspDeInit can be implemented in the user file
*/
}
/**
* @}
*/
/** @defgroup CRC_Exported_Functions_Group2 Peripheral Control functions
* @brief management functions.
*
@verbatim
===============================================================================
##### Peripheral Control functions #####
===============================================================================
[..] This section provides functions allowing to:
(+) compute the 32-bit CRC value of a 32-bit data buffer
using combination of the previous CRC value and the new one.
[..] or
(+) compute the 32-bit CRC value of a 32-bit data buffer
independently of the previous CRC value.
@endverbatim
* @{
*/
/**
* @brief Compute the 32-bit CRC value of a 32-bit data buffer
* starting with the previously computed CRC as initialization value.
* @param hcrc CRC handle
* @param pBuffer pointer to the input data buffer.
* @param BufferLength input data buffer length (number of uint32_t words).
* @retval uint32_t CRC (returned value LSBs for CRC shorter than 32 bits)
*/
uint32_t HAL_CRC_Accumulate(CRC_HandleTypeDef *hcrc, uint32_t pBuffer[], uint32_t BufferLength)
{
uint32_t index; /* CRC input data buffer index */
uint32_t temp = 0U; /* CRC output (read from hcrc->Instance->DR register) */
/* Change CRC peripheral state */
hcrc->State = HAL_CRC_STATE_BUSY;
/* Enter Data to the CRC calculator */
for (index = 0U; index < BufferLength; index++)
{
hcrc->Instance->DR = pBuffer[index];
}
temp = hcrc->Instance->DR;
/* Change CRC peripheral state */
hcrc->State = HAL_CRC_STATE_READY;
/* Return the CRC computed value */
return temp;
}
/**
* @brief Compute the 32-bit CRC value of a 32-bit data buffer
* starting with hcrc->Instance->INIT as initialization value.
* @param hcrc CRC handle
* @param pBuffer pointer to the input data buffer.
* @param BufferLength input data buffer length (number of uint32_t words).
* @retval uint32_t CRC (returned value LSBs for CRC shorter than 32 bits)
*/
uint32_t HAL_CRC_Calculate(CRC_HandleTypeDef *hcrc, uint32_t pBuffer[], uint32_t BufferLength)
{
uint32_t index; /* CRC input data buffer index */
uint32_t temp = 0U; /* CRC output (read from hcrc->Instance->DR register) */
/* Change CRC peripheral state */
hcrc->State = HAL_CRC_STATE_BUSY;
/* Reset CRC Calculation Unit (hcrc->Instance->INIT is
* written in hcrc->Instance->DR) */
__HAL_CRC_DR_RESET(hcrc);
/* Enter 32-bit input data to the CRC calculator */
for (index = 0U; index < BufferLength; index++)
{
hcrc->Instance->DR = pBuffer[index];
}
temp = hcrc->Instance->DR;
/* Change CRC peripheral state */
hcrc->State = HAL_CRC_STATE_READY;
/* Return the CRC computed value */
return temp;
}
/**
* @}
*/
/** @defgroup CRC_Exported_Functions_Group3 Peripheral State functions
* @brief Peripheral State functions.
*
@verbatim
===============================================================================
##### Peripheral State functions #####
===============================================================================
[..]
This subsection permits to get in run-time the status of the peripheral.
@endverbatim
* @{
*/
/**
* @brief Return the CRC handle state.
* @param hcrc CRC handle
* @retval HAL state
*/
HAL_CRC_StateTypeDef HAL_CRC_GetState(const CRC_HandleTypeDef *hcrc)
{
/* Return CRC handle state */
return hcrc->State;
}
/**
* @}
*/
/**
* @}
*/
#endif /* HAL_CRC_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/

View File

@@ -0,0 +1,1418 @@
/**
******************************************************************************
* @file stm32f1xx_hal_dac.c
* @author MCD Application Team
* @brief DAC HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of the Digital to Analog Converter (DAC) peripheral:
* + Initialization and de-initialization functions
* + IO operation functions
* + Peripheral Control functions
* + Peripheral State and Errors functions
*
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
==============================================================================
##### DAC Peripheral features #####
==============================================================================
[..]
*** DAC Channels ***
====================
[..]
STM32F1 devices integrate two 12-bit Digital Analog Converters
The 2 converters (i.e. channel1 & channel2)
can be used independently or simultaneously (dual mode):
(#) DAC channel1 with DAC_OUT1 (PA4) as output or connected to on-chip
peripherals (ex. timers).
(#) DAC channel2 with DAC_OUT2 (PA5) as output or connected to on-chip
peripherals (ex. timers).
*** DAC Triggers ***
====================
[..]
Digital to Analog conversion can be non-triggered using DAC_TRIGGER_NONE
and DAC_OUT1/DAC_OUT2 is available once writing to DHRx register.
[..]
Digital to Analog conversion can be triggered by:
(#) External event: EXTI Line 9 (any GPIOx_PIN_9) using DAC_TRIGGER_EXT_IT9.
The used pin (GPIOx_PIN_9) must be configured in input mode.
(#) Timers TRGO: TIM2, TIM4, TIM6, TIM7
For STM32F10x connectivity line devices and STM32F100x devices: TIM3
For STM32F10x high-density and XL-density devices: TIM8
For STM32F100x high-density value line devices: TIM15 as
replacement of TIM5.
(DAC_TRIGGER_T2_TRGO, DAC_TRIGGER_T4_TRGO...)
(#) Software using DAC_TRIGGER_SOFTWARE
*** DAC Buffer mode feature ***
===============================
[..]
Each DAC channel integrates an output buffer that can be used to
reduce the output impedance, and to drive external loads directly
without having to add an external operational amplifier.
To enable, the output buffer use
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
[..]
(@) Refer to the device datasheet for more details about output
impedance value with and without output buffer.
*** GPIO configurations guidelines ***
=====================
[..]
When a DAC channel is used (ex channel1 on PA4) and the other is not
(ex channel2 on PA5 is configured in Analog and disabled).
Channel1 may disturb channel2 as coupling effect.
Note that there is no coupling on channel2 as soon as channel2 is turned on.
Coupling on adjacent channel could be avoided as follows:
when unused PA5 is configured as INPUT PULL-UP or DOWN.
PA5 is configured in ANALOG just before it is turned on.
*** DAC wave generation feature ***
===================================
[..]
Both DAC channels can be used to generate
(#) Noise wave
(#) Triangle wave
*** DAC data format ***
=======================
[..]
The DAC data format can be:
(#) 8-bit right alignment using DAC_ALIGN_8B_R
(#) 12-bit left alignment using DAC_ALIGN_12B_L
(#) 12-bit right alignment using DAC_ALIGN_12B_R
*** DAC data value to voltage correspondence ***
================================================
[..]
The analog output voltage on each DAC channel pin is determined
by the following equation:
[..]
DAC_OUTx = VREF+ * DOR / 4095
(+) with DOR is the Data Output Register
[..]
VREF+ is the input voltage reference (refer to the device datasheet)
[..]
e.g. To set DAC_OUT1 to 0.7V, use
(+) Assuming that VREF+ = 3.3V, DAC_OUT1 = (3.3 * 868) / 4095 = 0.7V
*** DMA requests ***
=====================
[..]
A DMA request can be generated when an external trigger (but not a software trigger)
occurs if DMA1 requests are enabled using HAL_DAC_Start_DMA().
DMA1 requests are mapped as following:
(#) DAC channel1 mapped on DMA1 channel3
for STM32F100x low-density, medium-density, high-density with DAC
DMA remap:
(#) DAC channel2 mapped on DMA2 channel3
for STM32F100x high-density without DAC DMA remap and other
STM32F1 devices
[..]
(@) For Dual mode and specific signal (Triangle and noise) generation please
refer to Extended Features Driver description
##### How to use this driver #####
==============================================================================
[..]
(+) DAC APB clock must be enabled to get write access to DAC
registers using HAL_DAC_Init()
(+) Configure DAC_OUTx (DAC_OUT1: PA4, DAC_OUT2: PA5) in analog mode.
(+) Configure the DAC channel using HAL_DAC_ConfigChannel() function.
(+) Enable the DAC channel using HAL_DAC_Start() or HAL_DAC_Start_DMA() functions.
*** Polling mode IO operation ***
=================================
[..]
(+) Start the DAC peripheral using HAL_DAC_Start()
(+) To read the DAC last data output value, use the HAL_DAC_GetValue() function.
(+) Stop the DAC peripheral using HAL_DAC_Stop()
*** DMA mode IO operation ***
==============================
[..]
(+) Start the DAC peripheral using HAL_DAC_Start_DMA(), at this stage the user specify the length
of data to be transferred at each end of conversion
First issued trigger will start the conversion of the value previously set by HAL_DAC_SetValue().
(+) At the middle of data transfer HAL_DAC_ConvHalfCpltCallbackCh1() or HAL_DACEx_ConvHalfCpltCallbackCh2()
function is executed and user can add his own code by customization of function pointer
HAL_DAC_ConvHalfCpltCallbackCh1() or HAL_DACEx_ConvHalfCpltCallbackCh2()
(+) At The end of data transfer HAL_DAC_ConvCpltCallbackCh1() or HAL_DACEx_ConvHalfCpltCallbackCh2()
function is executed and user can add his own code by customization of function pointer
HAL_DAC_ConvCpltCallbackCh1() or HAL_DACEx_ConvHalfCpltCallbackCh2()
(+) In case of transfer Error, HAL_DAC_ErrorCallbackCh1() function is executed and user can
add his own code by customization of function pointer HAL_DAC_ErrorCallbackCh1
(+) For STM32F100x devices with specific feature: DMA underrun.
In case of DMA underrun, DAC interruption triggers and execute internal function HAL_DAC_IRQHandler.
HAL_DAC_DMAUnderrunCallbackCh1() or HAL_DACEx_DMAUnderrunCallbackCh2()
function is executed and user can add his own code by customization of function pointer
HAL_DAC_DMAUnderrunCallbackCh1() or HAL_DACEx_DMAUnderrunCallbackCh2() and
add his own code by customization of function pointer HAL_DAC_ErrorCallbackCh1()
(+) Stop the DAC peripheral using HAL_DAC_Stop_DMA()
*** Callback registration ***
=============================================
[..]
The compilation define USE_HAL_DAC_REGISTER_CALLBACKS when set to 1
allows the user to configure dynamically the driver callbacks.
Use Functions HAL_DAC_RegisterCallback() to register a user callback,
it allows to register following callbacks:
(+) ConvCpltCallbackCh1 : callback when a half transfer is completed on Ch1.
(+) ConvHalfCpltCallbackCh1 : callback when a transfer is completed on Ch1.
(+) ErrorCallbackCh1 : callback when an error occurs on Ch1.
(+) DMAUnderrunCallbackCh1 : callback when an underrun error occurs on Ch1.
(+) ConvCpltCallbackCh2 : callback when a half transfer is completed on Ch2.
(+) ConvHalfCpltCallbackCh2 : callback when a transfer is completed on Ch2.
(+) ErrorCallbackCh2 : callback when an error occurs on Ch2.
(+) DMAUnderrunCallbackCh2 : callback when an underrun error occurs on Ch2.
(+) MspInitCallback : DAC MspInit.
(+) MspDeInitCallback : DAC MspdeInit.
This function takes as parameters the HAL peripheral handle, the Callback ID
and a pointer to the user callback function.
Use function HAL_DAC_UnRegisterCallback() to reset a callback to the default
weak (overridden) function. It allows to reset following callbacks:
(+) ConvCpltCallbackCh1 : callback when a half transfer is completed on Ch1.
(+) ConvHalfCpltCallbackCh1 : callback when a transfer is completed on Ch1.
(+) ErrorCallbackCh1 : callback when an error occurs on Ch1.
(+) DMAUnderrunCallbackCh1 : callback when an underrun error occurs on Ch1.
(+) ConvCpltCallbackCh2 : callback when a half transfer is completed on Ch2.
(+) ConvHalfCpltCallbackCh2 : callback when a transfer is completed on Ch2.
(+) ErrorCallbackCh2 : callback when an error occurs on Ch2.
(+) DMAUnderrunCallbackCh2 : callback when an underrun error occurs on Ch2.
(+) MspInitCallback : DAC MspInit.
(+) MspDeInitCallback : DAC MspdeInit.
(+) All Callbacks
This function) takes as parameters the HAL peripheral handle and the Callback ID.
By default, after the HAL_DAC_Init and if the state is HAL_DAC_STATE_RESET
all callbacks are reset to the corresponding legacy weak (overridden) functions.
Exception done for MspInit and MspDeInit callbacks that are respectively
reset to the legacy weak (overridden) functions in the HAL_DAC_Init
and HAL_DAC_DeInit only when these callbacks are null (not registered beforehand).
If not, MspInit or MspDeInit are not null, the HAL_DAC_Init and HAL_DAC_DeInit
keep and use the user MspInit/MspDeInit callbacks (registered beforehand)
Callbacks can be registered/unregistered in READY state only.
Exception done for MspInit/MspDeInit callbacks that can be registered/unregistered
in READY or RESET state, thus registered (user) MspInit/DeInit callbacks can be used
during the Init/DeInit.
In that case first register the MspInit/MspDeInit user callbacks
using HAL_DAC_RegisterCallback before calling HAL_DAC_DeInit
or HAL_DAC_Init function.
When The compilation define USE_HAL_DAC_REGISTER_CALLBACKS is set to 0 or
not defined, the callback registering feature is not available
and weak (overridden) callbacks are used.
*** DAC HAL driver macros list ***
=============================================
[..]
Below the list of most used macros in DAC HAL driver.
(+) __HAL_DAC_ENABLE : Enable the DAC peripheral (For STM32F100x devices with specific feature: DMA underrun)
(+) __HAL_DAC_DISABLE : Disable the DAC peripheral (For STM32F100x devices with specific feature: DMA underrun)
(+) __HAL_DAC_CLEAR_FLAG: Clear the DAC's pending flags (For STM32F100x devices with specific feature: DMA underrun)
(+) __HAL_DAC_GET_FLAG: Get the selected DAC's flag status (For STM32F100x devices with specific feature: DMA underrun)
[..]
(@) You can refer to the DAC HAL driver header file for more useful macros
@endverbatim
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
#ifdef HAL_DAC_MODULE_ENABLED
#if defined(DAC)
/** @defgroup DAC DAC
* @brief DAC driver modules
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions -------------------------------------------------------*/
/** @defgroup DAC_Exported_Functions DAC Exported Functions
* @{
*/
/** @defgroup DAC_Exported_Functions_Group1 Initialization and de-initialization functions
* @brief Initialization and Configuration functions
*
@verbatim
==============================================================================
##### Initialization and de-initialization functions #####
==============================================================================
[..] This section provides functions allowing to:
(+) Initialize and configure the DAC.
(+) De-initialize the DAC.
@endverbatim
* @{
*/
/**
* @brief Initialize the DAC peripheral according to the specified parameters
* in the DAC_InitStruct and initialize the associated handle.
* @param hdac pointer to a DAC_HandleTypeDef structure that contains
* the configuration information for the specified DAC.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DAC_Init(DAC_HandleTypeDef *hdac)
{
/* Check the DAC peripheral handle */
if (hdac == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_DAC_ALL_INSTANCE(hdac->Instance));
if (hdac->State == HAL_DAC_STATE_RESET)
{
#if (USE_HAL_DAC_REGISTER_CALLBACKS == 1)
/* Init the DAC Callback settings */
hdac->ConvCpltCallbackCh1 = HAL_DAC_ConvCpltCallbackCh1;
hdac->ConvHalfCpltCallbackCh1 = HAL_DAC_ConvHalfCpltCallbackCh1;
hdac->ErrorCallbackCh1 = HAL_DAC_ErrorCallbackCh1;
hdac->DMAUnderrunCallbackCh1 = HAL_DAC_DMAUnderrunCallbackCh1;
hdac->ConvCpltCallbackCh2 = HAL_DACEx_ConvCpltCallbackCh2;
hdac->ConvHalfCpltCallbackCh2 = HAL_DACEx_ConvHalfCpltCallbackCh2;
hdac->ErrorCallbackCh2 = HAL_DACEx_ErrorCallbackCh2;
hdac->DMAUnderrunCallbackCh2 = HAL_DACEx_DMAUnderrunCallbackCh2;
if (hdac->MspInitCallback == NULL)
{
hdac->MspInitCallback = HAL_DAC_MspInit;
}
#endif /* USE_HAL_DAC_REGISTER_CALLBACKS */
/* Allocate lock resource and initialize it */
hdac->Lock = HAL_UNLOCKED;
#if (USE_HAL_DAC_REGISTER_CALLBACKS == 1)
/* Init the low level hardware */
hdac->MspInitCallback(hdac);
#else
/* Init the low level hardware */
HAL_DAC_MspInit(hdac);
#endif /* USE_HAL_DAC_REGISTER_CALLBACKS */
}
/* Initialize the DAC state*/
hdac->State = HAL_DAC_STATE_BUSY;
/* Set DAC error code to none */
hdac->ErrorCode = HAL_DAC_ERROR_NONE;
/* Initialize the DAC state*/
hdac->State = HAL_DAC_STATE_READY;
/* Return function status */
return HAL_OK;
}
/**
* @brief Deinitialize the DAC peripheral registers to their default reset values.
* @param hdac pointer to a DAC_HandleTypeDef structure that contains
* the configuration information for the specified DAC.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DAC_DeInit(DAC_HandleTypeDef *hdac)
{
/* Check the DAC peripheral handle */
if (hdac == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_DAC_ALL_INSTANCE(hdac->Instance));
/* Change DAC state */
hdac->State = HAL_DAC_STATE_BUSY;
#if (USE_HAL_DAC_REGISTER_CALLBACKS == 1)
if (hdac->MspDeInitCallback == NULL)
{
hdac->MspDeInitCallback = HAL_DAC_MspDeInit;
}
/* DeInit the low level hardware */
hdac->MspDeInitCallback(hdac);
#else
/* DeInit the low level hardware */
HAL_DAC_MspDeInit(hdac);
#endif /* USE_HAL_DAC_REGISTER_CALLBACKS */
/* Set DAC error code to none */
hdac->ErrorCode = HAL_DAC_ERROR_NONE;
/* Change DAC state */
hdac->State = HAL_DAC_STATE_RESET;
/* Release Lock */
__HAL_UNLOCK(hdac);
/* Return function status */
return HAL_OK;
}
/**
* @brief Initialize the DAC MSP.
* @param hdac pointer to a DAC_HandleTypeDef structure that contains
* the configuration information for the specified DAC.
* @retval None
*/
__weak void HAL_DAC_MspInit(DAC_HandleTypeDef *hdac)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hdac);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_DAC_MspInit could be implemented in the user file
*/
}
/**
* @brief DeInitialize the DAC MSP.
* @param hdac pointer to a DAC_HandleTypeDef structure that contains
* the configuration information for the specified DAC.
* @retval None
*/
__weak void HAL_DAC_MspDeInit(DAC_HandleTypeDef *hdac)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hdac);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_DAC_MspDeInit could be implemented in the user file
*/
}
/**
* @}
*/
/** @defgroup DAC_Exported_Functions_Group2 IO operation functions
* @brief IO operation functions
*
@verbatim
==============================================================================
##### IO operation functions #####
==============================================================================
[..] This section provides functions allowing to:
(+) Start conversion.
(+) Stop conversion.
(+) Start conversion and enable DMA transfer.
(+) Stop conversion and disable DMA transfer.
(+) Get result of conversion.
@endverbatim
* @{
*/
/**
* @brief Enables DAC and starts conversion of channel.
* @param hdac pointer to a DAC_HandleTypeDef structure that contains
* the configuration information for the specified DAC.
* @param Channel The selected DAC channel.
* This parameter can be one of the following values:
* @arg DAC_CHANNEL_1: DAC Channel1 selected
* @arg DAC_CHANNEL_2: DAC Channel2 selected
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DAC_Start(DAC_HandleTypeDef *hdac, uint32_t Channel)
{
/* Check the DAC peripheral handle */
if (hdac == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_DAC_CHANNEL(Channel));
/* Process locked */
__HAL_LOCK(hdac);
/* Change DAC state */
hdac->State = HAL_DAC_STATE_BUSY;
/* Enable the Peripheral */
__HAL_DAC_ENABLE(hdac, Channel);
if (Channel == DAC_CHANNEL_1)
{
/* Check if software trigger enabled */
if ((hdac->Instance->CR & (DAC_CR_TEN1 | DAC_CR_TSEL1)) == DAC_TRIGGER_SOFTWARE)
{
/* Enable the selected DAC software conversion */
SET_BIT(hdac->Instance->SWTRIGR, DAC_SWTRIGR_SWTRIG1);
}
}
else
{
/* Check if software trigger enabled */
if ((hdac->Instance->CR & (DAC_CR_TEN2 | DAC_CR_TSEL2)) == (DAC_TRIGGER_SOFTWARE << (Channel & 0x10UL)))
{
/* Enable the selected DAC software conversion*/
SET_BIT(hdac->Instance->SWTRIGR, DAC_SWTRIGR_SWTRIG2);
}
}
/* Change DAC state */
hdac->State = HAL_DAC_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hdac);
/* Return function status */
return HAL_OK;
}
/**
* @brief Disables DAC and stop conversion of channel.
* @param hdac pointer to a DAC_HandleTypeDef structure that contains
* the configuration information for the specified DAC.
* @param Channel The selected DAC channel.
* This parameter can be one of the following values:
* @arg DAC_CHANNEL_1: DAC Channel1 selected
* @arg DAC_CHANNEL_2: DAC Channel2 selected
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DAC_Stop(DAC_HandleTypeDef *hdac, uint32_t Channel)
{
/* Check the DAC peripheral handle */
if (hdac == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_DAC_CHANNEL(Channel));
/* Disable the Peripheral */
__HAL_DAC_DISABLE(hdac, Channel);
/* Change DAC state */
hdac->State = HAL_DAC_STATE_READY;
/* Return function status */
return HAL_OK;
}
/**
* @brief Enables DAC and starts conversion of channel.
* @param hdac pointer to a DAC_HandleTypeDef structure that contains
* the configuration information for the specified DAC.
* @param Channel The selected DAC channel.
* This parameter can be one of the following values:
* @arg DAC_CHANNEL_1: DAC Channel1 selected
* @arg DAC_CHANNEL_2: DAC Channel2 selected
* @param pData The source Buffer address.
* @param Length The length of data to be transferred from memory to DAC peripheral
* @param Alignment Specifies the data alignment for DAC channel.
* This parameter can be one of the following values:
* @arg DAC_ALIGN_8B_R: 8bit right data alignment selected
* @arg DAC_ALIGN_12B_L: 12bit left data alignment selected
* @arg DAC_ALIGN_12B_R: 12bit right data alignment selected
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DAC_Start_DMA(DAC_HandleTypeDef *hdac, uint32_t Channel, const uint32_t *pData, uint32_t Length,
uint32_t Alignment)
{
HAL_StatusTypeDef status;
uint32_t tmpreg;
/* Check the DAC peripheral handle */
if (hdac == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_DAC_CHANNEL(Channel));
assert_param(IS_DAC_ALIGN(Alignment));
/* Process locked */
__HAL_LOCK(hdac);
/* Change DAC state */
hdac->State = HAL_DAC_STATE_BUSY;
if (Channel == DAC_CHANNEL_1)
{
/* Set the DMA transfer complete callback for channel1 */
hdac->DMA_Handle1->XferCpltCallback = DAC_DMAConvCpltCh1;
/* Set the DMA half transfer complete callback for channel1 */
hdac->DMA_Handle1->XferHalfCpltCallback = DAC_DMAHalfConvCpltCh1;
/* Set the DMA error callback for channel1 */
hdac->DMA_Handle1->XferErrorCallback = DAC_DMAErrorCh1;
/* Enable the selected DAC channel1 DMA request */
SET_BIT(hdac->Instance->CR, DAC_CR_DMAEN1);
/* Case of use of channel 1 */
switch (Alignment)
{
case DAC_ALIGN_12B_R:
/* Get DHR12R1 address */
tmpreg = (uint32_t)&hdac->Instance->DHR12R1;
break;
case DAC_ALIGN_12B_L:
/* Get DHR12L1 address */
tmpreg = (uint32_t)&hdac->Instance->DHR12L1;
break;
default: /* case DAC_ALIGN_8B_R */
/* Get DHR8R1 address */
tmpreg = (uint32_t)&hdac->Instance->DHR8R1;
break;
}
}
else
{
/* Set the DMA transfer complete callback for channel2 */
hdac->DMA_Handle2->XferCpltCallback = DAC_DMAConvCpltCh2;
/* Set the DMA half transfer complete callback for channel2 */
hdac->DMA_Handle2->XferHalfCpltCallback = DAC_DMAHalfConvCpltCh2;
/* Set the DMA error callback for channel2 */
hdac->DMA_Handle2->XferErrorCallback = DAC_DMAErrorCh2;
/* Enable the selected DAC channel2 DMA request */
SET_BIT(hdac->Instance->CR, DAC_CR_DMAEN2);
/* Case of use of channel 2 */
switch (Alignment)
{
case DAC_ALIGN_12B_R:
/* Get DHR12R2 address */
tmpreg = (uint32_t)&hdac->Instance->DHR12R2;
break;
case DAC_ALIGN_12B_L:
/* Get DHR12L2 address */
tmpreg = (uint32_t)&hdac->Instance->DHR12L2;
break;
default: /* case DAC_ALIGN_8B_R */
/* Get DHR8R2 address */
tmpreg = (uint32_t)&hdac->Instance->DHR8R2;
break;
}
}
if (Channel == DAC_CHANNEL_1)
{
#if defined(DAC_CR_DMAUDRIE1)
/* Enable the DAC DMA underrun interrupt */
__HAL_DAC_ENABLE_IT(hdac, DAC_IT_DMAUDR1);
#endif /* DAC_CR_DMAUDRIE1 */
/* Enable the DMA Stream */
status = HAL_DMA_Start_IT(hdac->DMA_Handle1, (uint32_t)pData, tmpreg, Length);
}
else
{
#if defined(DAC_CR_DMAUDRIE2)
/* Enable the DAC DMA underrun interrupt */
__HAL_DAC_ENABLE_IT(hdac, DAC_IT_DMAUDR2);
#endif /* DAC_CR_DMAUDRIE2 */
/* Enable the DMA Stream */
status = HAL_DMA_Start_IT(hdac->DMA_Handle2, (uint32_t)pData, tmpreg, Length);
}
/* Process Unlocked */
__HAL_UNLOCK(hdac);
if (status == HAL_OK)
{
/* Enable the Peripheral */
__HAL_DAC_ENABLE(hdac, Channel);
}
else
{
hdac->ErrorCode |= HAL_DAC_ERROR_DMA;
}
/* Return function status */
return status;
}
/**
* @brief Disables DAC and stop conversion of channel.
* @param hdac pointer to a DAC_HandleTypeDef structure that contains
* the configuration information for the specified DAC.
* @param Channel The selected DAC channel.
* This parameter can be one of the following values:
* @arg DAC_CHANNEL_1: DAC Channel1 selected
* @arg DAC_CHANNEL_2: DAC Channel2 selected
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DAC_Stop_DMA(DAC_HandleTypeDef *hdac, uint32_t Channel)
{
/* Check the DAC peripheral handle */
if (hdac == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_DAC_CHANNEL(Channel));
/* Disable the selected DAC channel DMA request */
hdac->Instance->CR &= ~(DAC_CR_DMAEN1 << (Channel & 0x10UL));
/* Disable the Peripheral */
__HAL_DAC_DISABLE(hdac, Channel);
/* Disable the DMA Stream */
/* Channel1 is used */
if (Channel == DAC_CHANNEL_1)
{
/* Disable the DMA Stream */
(void)HAL_DMA_Abort(hdac->DMA_Handle1);
#if defined(DAC_CR_DMAUDRIE1)
/* Disable the DAC DMA underrun interrupt */
__HAL_DAC_DISABLE_IT(hdac, DAC_IT_DMAUDR1);
#endif /* DAC_CR_DMAUDRIE1 */
}
else /* Channel2 is used for */
{
/* Disable the DMA Stream */
(void)HAL_DMA_Abort(hdac->DMA_Handle2);
#if defined(DAC_CR_DMAUDRIE2)
/* Disable the DAC DMA underrun interrupt */
__HAL_DAC_DISABLE_IT(hdac, DAC_IT_DMAUDR2);
#endif /* DAC_CR_DMAUDRIE2 */
}
/* Change DAC state */
hdac->State = HAL_DAC_STATE_READY;
/* Return function status */
return HAL_OK;
}
/**
* @brief Handles DAC interrupt request
* This function uses the interruption of DMA
* underrun.
* @param hdac pointer to a DAC_HandleTypeDef structure that contains
* the configuration information for the specified DAC.
* @retval None
*/
void HAL_DAC_IRQHandler(DAC_HandleTypeDef *hdac)
{
#if !defined(DAC_SR_DMAUDR1) && !defined(DAC_SR_DMAUDR2)
UNUSED(hdac);
#else
uint32_t itsource = hdac->Instance->CR;
uint32_t itflag = hdac->Instance->SR;
#endif /* !DAC_SR_DMAUDR1 && !DAC_SR_DMAUDR2 */
#if defined(DAC_SR_DMAUDR1)
if ((itsource & DAC_IT_DMAUDR1) == DAC_IT_DMAUDR1)
{
/* Check underrun flag of DAC channel 1 */
if ((itflag & DAC_FLAG_DMAUDR1) == DAC_FLAG_DMAUDR1)
{
/* Change DAC state to error state */
hdac->State = HAL_DAC_STATE_ERROR;
/* Set DAC error code to channel1 DMA underrun error */
SET_BIT(hdac->ErrorCode, HAL_DAC_ERROR_DMAUNDERRUNCH1);
/* Clear the underrun flag */
__HAL_DAC_CLEAR_FLAG(hdac, DAC_FLAG_DMAUDR1);
/* Disable the selected DAC channel1 DMA request */
__HAL_DAC_DISABLE_IT(hdac, DAC_CR_DMAEN1);
/* Error callback */
#if (USE_HAL_DAC_REGISTER_CALLBACKS == 1)
hdac->DMAUnderrunCallbackCh1(hdac);
#else
HAL_DAC_DMAUnderrunCallbackCh1(hdac);
#endif /* USE_HAL_DAC_REGISTER_CALLBACKS */
}
}
#endif /* DAC_SR_DMAUDR1 */
#if defined(DAC_SR_DMAUDR2)
if ((itsource & DAC_IT_DMAUDR2) == DAC_IT_DMAUDR2)
{
/* Check underrun flag of DAC channel 2 */
if ((itflag & DAC_FLAG_DMAUDR2) == DAC_FLAG_DMAUDR2)
{
/* Change DAC state to error state */
hdac->State = HAL_DAC_STATE_ERROR;
/* Set DAC error code to channel2 DMA underrun error */
SET_BIT(hdac->ErrorCode, HAL_DAC_ERROR_DMAUNDERRUNCH2);
/* Clear the underrun flag */
__HAL_DAC_CLEAR_FLAG(hdac, DAC_FLAG_DMAUDR2);
/* Disable the selected DAC channel2 DMA request */
__HAL_DAC_DISABLE_IT(hdac, DAC_CR_DMAEN2);
/* Error callback */
#if (USE_HAL_DAC_REGISTER_CALLBACKS == 1)
hdac->DMAUnderrunCallbackCh2(hdac);
#else
HAL_DACEx_DMAUnderrunCallbackCh2(hdac);
#endif /* USE_HAL_DAC_REGISTER_CALLBACKS */
}
}
#endif /* DAC_SR_DMAUDR2 */
}
/**
* @brief Set the specified data holding register value for DAC channel.
* @param hdac pointer to a DAC_HandleTypeDef structure that contains
* the configuration information for the specified DAC.
* @param Channel The selected DAC channel.
* This parameter can be one of the following values:
* @arg DAC_CHANNEL_1: DAC Channel1 selected
* @arg DAC_CHANNEL_2: DAC Channel2 selected
* @param Alignment Specifies the data alignment.
* This parameter can be one of the following values:
* @arg DAC_ALIGN_8B_R: 8bit right data alignment selected
* @arg DAC_ALIGN_12B_L: 12bit left data alignment selected
* @arg DAC_ALIGN_12B_R: 12bit right data alignment selected
* @param Data Data to be loaded in the selected data holding register.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DAC_SetValue(DAC_HandleTypeDef *hdac, uint32_t Channel, uint32_t Alignment, uint32_t Data)
{
__IO uint32_t tmp = 0UL;
/* Check the DAC peripheral handle */
if (hdac == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_DAC_CHANNEL(Channel));
assert_param(IS_DAC_ALIGN(Alignment));
assert_param(IS_DAC_DATA(Data));
tmp = (uint32_t)hdac->Instance;
if (Channel == DAC_CHANNEL_1)
{
tmp += DAC_DHR12R1_ALIGNMENT(Alignment);
}
else
{
tmp += DAC_DHR12R2_ALIGNMENT(Alignment);
}
/* Set the DAC channel selected data holding register */
*(__IO uint32_t *) tmp = Data;
/* Return function status */
return HAL_OK;
}
/**
* @brief Conversion complete callback in non-blocking mode for Channel1
* @param hdac pointer to a DAC_HandleTypeDef structure that contains
* the configuration information for the specified DAC.
* @retval None
*/
__weak void HAL_DAC_ConvCpltCallbackCh1(DAC_HandleTypeDef *hdac)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hdac);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_DAC_ConvCpltCallbackCh1 could be implemented in the user file
*/
}
/**
* @brief Conversion half DMA transfer callback in non-blocking mode for Channel1
* @param hdac pointer to a DAC_HandleTypeDef structure that contains
* the configuration information for the specified DAC.
* @retval None
*/
__weak void HAL_DAC_ConvHalfCpltCallbackCh1(DAC_HandleTypeDef *hdac)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hdac);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_DAC_ConvHalfCpltCallbackCh1 could be implemented in the user file
*/
}
/**
* @brief Error DAC callback for Channel1.
* @param hdac pointer to a DAC_HandleTypeDef structure that contains
* the configuration information for the specified DAC.
* @retval None
*/
__weak void HAL_DAC_ErrorCallbackCh1(DAC_HandleTypeDef *hdac)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hdac);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_DAC_ErrorCallbackCh1 could be implemented in the user file
*/
}
/**
* @brief DMA underrun DAC callback for channel1.
* @param hdac pointer to a DAC_HandleTypeDef structure that contains
* the configuration information for the specified DAC.
* @retval None
*/
__weak void HAL_DAC_DMAUnderrunCallbackCh1(DAC_HandleTypeDef *hdac)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hdac);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_DAC_DMAUnderrunCallbackCh1 could be implemented in the user file
*/
}
/**
* @}
*/
/** @defgroup DAC_Exported_Functions_Group3 Peripheral Control functions
* @brief Peripheral Control functions
*
@verbatim
==============================================================================
##### Peripheral Control functions #####
==============================================================================
[..] This section provides functions allowing to:
(+) Configure channels.
(+) Set the specified data holding register value for DAC channel.
@endverbatim
* @{
*/
/**
* @brief Returns the last data output value of the selected DAC channel.
* @param hdac pointer to a DAC_HandleTypeDef structure that contains
* the configuration information for the specified DAC.
* @param Channel The selected DAC channel.
* This parameter can be one of the following values:
* @arg DAC_CHANNEL_1: DAC Channel1 selected
* @arg DAC_CHANNEL_2: DAC Channel2 selected
* @retval The selected DAC channel data output value.
*/
uint32_t HAL_DAC_GetValue(const DAC_HandleTypeDef *hdac, uint32_t Channel)
{
uint32_t result;
/* Check the DAC peripheral handle */
assert_param(hdac != NULL);
/* Check the parameters */
assert_param(IS_DAC_CHANNEL(Channel));
if (Channel == DAC_CHANNEL_1)
{
result = hdac->Instance->DOR1;
}
else
{
result = hdac->Instance->DOR2;
}
/* Returns the DAC channel data output register value */
return result;
}
/**
* @brief Configures the selected DAC channel.
* @param hdac pointer to a DAC_HandleTypeDef structure that contains
* the configuration information for the specified DAC.
* @param sConfig DAC configuration structure.
* @param Channel The selected DAC channel.
* This parameter can be one of the following values:
* @arg DAC_CHANNEL_1: DAC Channel1 selected
* @arg DAC_CHANNEL_2: DAC Channel2 selected
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DAC_ConfigChannel(DAC_HandleTypeDef *hdac,
const DAC_ChannelConfTypeDef *sConfig, uint32_t Channel)
{
HAL_StatusTypeDef status = HAL_OK;
uint32_t tmpreg1;
uint32_t tmpreg2;
/* Check the DAC peripheral handle and channel configuration struct */
if ((hdac == NULL) || (sConfig == NULL))
{
return HAL_ERROR;
}
/* Check the DAC parameters */
assert_param(IS_DAC_TRIGGER(sConfig->DAC_Trigger));
assert_param(IS_DAC_OUTPUT_BUFFER_STATE(sConfig->DAC_OutputBuffer));
assert_param(IS_DAC_CHANNEL(Channel));
/* Process locked */
__HAL_LOCK(hdac);
/* Change DAC state */
hdac->State = HAL_DAC_STATE_BUSY;
/* Get the DAC CR value */
tmpreg1 = hdac->Instance->CR;
/* Clear BOFFx, TENx, TSELx, WAVEx and MAMPx bits */
tmpreg1 &= ~(((uint32_t)(DAC_CR_MAMP1 | DAC_CR_WAVE1 | DAC_CR_TSEL1 | DAC_CR_TEN1 | DAC_CR_BOFF1))
<< (Channel & 0x10UL));
/* Configure for the selected DAC channel: buffer output, trigger */
/* Set TSELx and TENx bits according to DAC_Trigger value */
/* Set BOFFx bit according to DAC_OutputBuffer value */
tmpreg2 = (sConfig->DAC_Trigger | sConfig->DAC_OutputBuffer);
/* Calculate CR register value depending on DAC_Channel */
tmpreg1 |= tmpreg2 << (Channel & 0x10UL);
/* Write to DAC CR */
hdac->Instance->CR = tmpreg1;
/* Disable wave generation */
CLEAR_BIT(hdac->Instance->CR, (DAC_CR_WAVE1 << (Channel & 0x10UL)));
/* Change DAC state */
hdac->State = HAL_DAC_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hdac);
/* Return function status */
return status;
}
/**
* @}
*/
/** @defgroup DAC_Exported_Functions_Group4 Peripheral State and Errors functions
* @brief Peripheral State and Errors functions
*
@verbatim
==============================================================================
##### Peripheral State and Errors functions #####
==============================================================================
[..]
This subsection provides functions allowing to
(+) Check the DAC state.
(+) Check the DAC Errors.
@endverbatim
* @{
*/
/**
* @brief return the DAC handle state
* @param hdac pointer to a DAC_HandleTypeDef structure that contains
* the configuration information for the specified DAC.
* @retval HAL state
*/
HAL_DAC_StateTypeDef HAL_DAC_GetState(const DAC_HandleTypeDef *hdac)
{
/* Return DAC handle state */
return hdac->State;
}
/**
* @brief Return the DAC error code
* @param hdac pointer to a DAC_HandleTypeDef structure that contains
* the configuration information for the specified DAC.
* @retval DAC Error Code
*/
uint32_t HAL_DAC_GetError(const DAC_HandleTypeDef *hdac)
{
return hdac->ErrorCode;
}
/**
* @}
*/
/**
* @}
*/
/** @addtogroup DAC_Exported_Functions
* @{
*/
/** @addtogroup DAC_Exported_Functions_Group1
* @{
*/
#if (USE_HAL_DAC_REGISTER_CALLBACKS == 1)
/**
* @brief Register a User DAC Callback
* To be used instead of the weak (overridden) predefined callback
* @note The HAL_DAC_RegisterCallback() may be called before HAL_DAC_Init() in HAL_DAC_STATE_RESET to register
* callbacks for HAL_DAC_MSPINIT_CB_ID and HAL_DAC_MSPDEINIT_CB_ID
* @param hdac DAC handle
* @param CallbackID ID of the callback to be registered
* This parameter can be one of the following values:
* @arg @ref HAL_DAC_ERROR_INVALID_CALLBACK DAC Error Callback ID
* @arg @ref HAL_DAC_CH1_COMPLETE_CB_ID DAC CH1 Complete Callback ID
* @arg @ref HAL_DAC_CH1_HALF_COMPLETE_CB_ID DAC CH1 Half Complete Callback ID
* @arg @ref HAL_DAC_CH1_ERROR_ID DAC CH1 Error Callback ID
* @arg @ref HAL_DAC_CH1_UNDERRUN_CB_ID DAC CH1 UnderRun Callback ID
* @arg @ref HAL_DAC_CH2_COMPLETE_CB_ID DAC CH2 Complete Callback ID
* @arg @ref HAL_DAC_CH2_HALF_COMPLETE_CB_ID DAC CH2 Half Complete Callback ID
* @arg @ref HAL_DAC_CH2_ERROR_ID DAC CH2 Error Callback ID
* @arg @ref HAL_DAC_CH2_UNDERRUN_CB_ID DAC CH2 UnderRun Callback ID
* @arg @ref HAL_DAC_MSPINIT_CB_ID DAC MSP Init Callback ID
* @arg @ref HAL_DAC_MSPDEINIT_CB_ID DAC MSP DeInit Callback ID
*
* @param pCallback pointer to the Callback function
* @retval status
*/
HAL_StatusTypeDef HAL_DAC_RegisterCallback(DAC_HandleTypeDef *hdac, HAL_DAC_CallbackIDTypeDef CallbackID,
pDAC_CallbackTypeDef pCallback)
{
HAL_StatusTypeDef status = HAL_OK;
/* Check the DAC peripheral handle */
if (hdac == NULL)
{
return HAL_ERROR;
}
if (pCallback == NULL)
{
/* Update the error code */
hdac->ErrorCode |= HAL_DAC_ERROR_INVALID_CALLBACK;
return HAL_ERROR;
}
if (hdac->State == HAL_DAC_STATE_READY)
{
switch (CallbackID)
{
case HAL_DAC_CH1_COMPLETE_CB_ID :
hdac->ConvCpltCallbackCh1 = pCallback;
break;
case HAL_DAC_CH1_HALF_COMPLETE_CB_ID :
hdac->ConvHalfCpltCallbackCh1 = pCallback;
break;
case HAL_DAC_CH1_ERROR_ID :
hdac->ErrorCallbackCh1 = pCallback;
break;
case HAL_DAC_CH1_UNDERRUN_CB_ID :
hdac->DMAUnderrunCallbackCh1 = pCallback;
break;
case HAL_DAC_CH2_COMPLETE_CB_ID :
hdac->ConvCpltCallbackCh2 = pCallback;
break;
case HAL_DAC_CH2_HALF_COMPLETE_CB_ID :
hdac->ConvHalfCpltCallbackCh2 = pCallback;
break;
case HAL_DAC_CH2_ERROR_ID :
hdac->ErrorCallbackCh2 = pCallback;
break;
case HAL_DAC_CH2_UNDERRUN_CB_ID :
hdac->DMAUnderrunCallbackCh2 = pCallback;
break;
case HAL_DAC_MSPINIT_CB_ID :
hdac->MspInitCallback = pCallback;
break;
case HAL_DAC_MSPDEINIT_CB_ID :
hdac->MspDeInitCallback = pCallback;
break;
default :
/* Update the error code */
hdac->ErrorCode |= HAL_DAC_ERROR_INVALID_CALLBACK;
/* update return status */
status = HAL_ERROR;
break;
}
}
else if (hdac->State == HAL_DAC_STATE_RESET)
{
switch (CallbackID)
{
case HAL_DAC_MSPINIT_CB_ID :
hdac->MspInitCallback = pCallback;
break;
case HAL_DAC_MSPDEINIT_CB_ID :
hdac->MspDeInitCallback = pCallback;
break;
default :
/* Update the error code */
hdac->ErrorCode |= HAL_DAC_ERROR_INVALID_CALLBACK;
/* update return status */
status = HAL_ERROR;
break;
}
}
else
{
/* Update the error code */
hdac->ErrorCode |= HAL_DAC_ERROR_INVALID_CALLBACK;
/* update return status */
status = HAL_ERROR;
}
return status;
}
/**
* @brief Unregister a User DAC Callback
* DAC Callback is redirected to the weak (overridden) predefined callback
* @note The HAL_DAC_UnRegisterCallback() may be called before HAL_DAC_Init() in HAL_DAC_STATE_RESET to un-register
* callbacks for HAL_DAC_MSPINIT_CB_ID and HAL_DAC_MSPDEINIT_CB_ID
* @param hdac DAC handle
* @param CallbackID ID of the callback to be unregistered
* This parameter can be one of the following values:
* @arg @ref HAL_DAC_CH1_COMPLETE_CB_ID DAC CH1 transfer Complete Callback ID
* @arg @ref HAL_DAC_CH1_HALF_COMPLETE_CB_ID DAC CH1 Half Complete Callback ID
* @arg @ref HAL_DAC_CH1_ERROR_ID DAC CH1 Error Callback ID
* @arg @ref HAL_DAC_CH1_UNDERRUN_CB_ID DAC CH1 UnderRun Callback ID
* @arg @ref HAL_DAC_CH2_COMPLETE_CB_ID DAC CH2 Complete Callback ID
* @arg @ref HAL_DAC_CH2_HALF_COMPLETE_CB_ID DAC CH2 Half Complete Callback ID
* @arg @ref HAL_DAC_CH2_ERROR_ID DAC CH2 Error Callback ID
* @arg @ref HAL_DAC_CH2_UNDERRUN_CB_ID DAC CH2 UnderRun Callback ID
* @arg @ref HAL_DAC_MSPINIT_CB_ID DAC MSP Init Callback ID
* @arg @ref HAL_DAC_MSPDEINIT_CB_ID DAC MSP DeInit Callback ID
* @arg @ref HAL_DAC_ALL_CB_ID DAC All callbacks
* @retval status
*/
HAL_StatusTypeDef HAL_DAC_UnRegisterCallback(DAC_HandleTypeDef *hdac, HAL_DAC_CallbackIDTypeDef CallbackID)
{
HAL_StatusTypeDef status = HAL_OK;
/* Check the DAC peripheral handle */
if (hdac == NULL)
{
return HAL_ERROR;
}
if (hdac->State == HAL_DAC_STATE_READY)
{
switch (CallbackID)
{
case HAL_DAC_CH1_COMPLETE_CB_ID :
hdac->ConvCpltCallbackCh1 = HAL_DAC_ConvCpltCallbackCh1;
break;
case HAL_DAC_CH1_HALF_COMPLETE_CB_ID :
hdac->ConvHalfCpltCallbackCh1 = HAL_DAC_ConvHalfCpltCallbackCh1;
break;
case HAL_DAC_CH1_ERROR_ID :
hdac->ErrorCallbackCh1 = HAL_DAC_ErrorCallbackCh1;
break;
case HAL_DAC_CH1_UNDERRUN_CB_ID :
hdac->DMAUnderrunCallbackCh1 = HAL_DAC_DMAUnderrunCallbackCh1;
break;
case HAL_DAC_CH2_COMPLETE_CB_ID :
hdac->ConvCpltCallbackCh2 = HAL_DACEx_ConvCpltCallbackCh2;
break;
case HAL_DAC_CH2_HALF_COMPLETE_CB_ID :
hdac->ConvHalfCpltCallbackCh2 = HAL_DACEx_ConvHalfCpltCallbackCh2;
break;
case HAL_DAC_CH2_ERROR_ID :
hdac->ErrorCallbackCh2 = HAL_DACEx_ErrorCallbackCh2;
break;
case HAL_DAC_CH2_UNDERRUN_CB_ID :
hdac->DMAUnderrunCallbackCh2 = HAL_DACEx_DMAUnderrunCallbackCh2;
break;
case HAL_DAC_MSPINIT_CB_ID :
hdac->MspInitCallback = HAL_DAC_MspInit;
break;
case HAL_DAC_MSPDEINIT_CB_ID :
hdac->MspDeInitCallback = HAL_DAC_MspDeInit;
break;
case HAL_DAC_ALL_CB_ID :
hdac->ConvCpltCallbackCh1 = HAL_DAC_ConvCpltCallbackCh1;
hdac->ConvHalfCpltCallbackCh1 = HAL_DAC_ConvHalfCpltCallbackCh1;
hdac->ErrorCallbackCh1 = HAL_DAC_ErrorCallbackCh1;
hdac->DMAUnderrunCallbackCh1 = HAL_DAC_DMAUnderrunCallbackCh1;
hdac->ConvCpltCallbackCh2 = HAL_DACEx_ConvCpltCallbackCh2;
hdac->ConvHalfCpltCallbackCh2 = HAL_DACEx_ConvHalfCpltCallbackCh2;
hdac->ErrorCallbackCh2 = HAL_DACEx_ErrorCallbackCh2;
hdac->DMAUnderrunCallbackCh2 = HAL_DACEx_DMAUnderrunCallbackCh2;
hdac->MspInitCallback = HAL_DAC_MspInit;
hdac->MspDeInitCallback = HAL_DAC_MspDeInit;
break;
default :
/* Update the error code */
hdac->ErrorCode |= HAL_DAC_ERROR_INVALID_CALLBACK;
/* update return status */
status = HAL_ERROR;
break;
}
}
else if (hdac->State == HAL_DAC_STATE_RESET)
{
switch (CallbackID)
{
case HAL_DAC_MSPINIT_CB_ID :
hdac->MspInitCallback = HAL_DAC_MspInit;
break;
case HAL_DAC_MSPDEINIT_CB_ID :
hdac->MspDeInitCallback = HAL_DAC_MspDeInit;
break;
default :
/* Update the error code */
hdac->ErrorCode |= HAL_DAC_ERROR_INVALID_CALLBACK;
/* update return status */
status = HAL_ERROR;
break;
}
}
else
{
/* Update the error code */
hdac->ErrorCode |= HAL_DAC_ERROR_INVALID_CALLBACK;
/* update return status */
status = HAL_ERROR;
}
return status;
}
#endif /* USE_HAL_DAC_REGISTER_CALLBACKS */
/**
* @}
*/
/**
* @}
*/
/** @addtogroup DAC_Private_Functions
* @{
*/
/**
* @brief DMA conversion complete callback.
* @param hdma pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
void DAC_DMAConvCpltCh1(DMA_HandleTypeDef *hdma)
{
DAC_HandleTypeDef *hdac = (DAC_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
#if (USE_HAL_DAC_REGISTER_CALLBACKS == 1)
hdac->ConvCpltCallbackCh1(hdac);
#else
HAL_DAC_ConvCpltCallbackCh1(hdac);
#endif /* USE_HAL_DAC_REGISTER_CALLBACKS */
hdac->State = HAL_DAC_STATE_READY;
}
/**
* @brief DMA half transfer complete callback.
* @param hdma pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
void DAC_DMAHalfConvCpltCh1(DMA_HandleTypeDef *hdma)
{
DAC_HandleTypeDef *hdac = (DAC_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
/* Conversion complete callback */
#if (USE_HAL_DAC_REGISTER_CALLBACKS == 1)
hdac->ConvHalfCpltCallbackCh1(hdac);
#else
HAL_DAC_ConvHalfCpltCallbackCh1(hdac);
#endif /* USE_HAL_DAC_REGISTER_CALLBACKS */
}
/**
* @brief DMA error callback
* @param hdma pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
void DAC_DMAErrorCh1(DMA_HandleTypeDef *hdma)
{
DAC_HandleTypeDef *hdac = (DAC_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
/* Set DAC error code to DMA error */
hdac->ErrorCode |= HAL_DAC_ERROR_DMA;
#if (USE_HAL_DAC_REGISTER_CALLBACKS == 1)
hdac->ErrorCallbackCh1(hdac);
#else
HAL_DAC_ErrorCallbackCh1(hdac);
#endif /* USE_HAL_DAC_REGISTER_CALLBACKS */
hdac->State = HAL_DAC_STATE_READY;
}
/**
* @}
*/
/**
* @}
*/
#endif /* DAC */
#endif /* HAL_DAC_MODULE_ENABLED */
/**
* @}
*/

View File

@@ -0,0 +1,515 @@
/**
******************************************************************************
* @file stm32f1xx_hal_dac_ex.c
* @author MCD Application Team
* @brief Extended DAC HAL module driver.
* This file provides firmware functions to manage the extended
* functionalities of the DAC peripheral.
*
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
==============================================================================
##### How to use this driver #####
==============================================================================
[..]
*** Signal generation operation ***
===================================
[..]
(+) Use HAL_DACEx_TriangleWaveGenerate() to generate Triangle signal.
(+) Use HAL_DACEx_NoiseWaveGenerate() to generate Noise signal.
@endverbatim
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
#ifdef HAL_DAC_MODULE_ENABLED
#if defined(DAC)
/** @defgroup DACEx DACEx
* @brief DAC Extended HAL module driver
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @defgroup DACEx_Exported_Functions DACEx Exported Functions
* @{
*/
/** @defgroup DACEx_Exported_Functions_Group2 IO operation functions
* @brief Extended IO operation functions
*
@verbatim
==============================================================================
##### Extended features functions #####
==============================================================================
[..] This section provides functions allowing to:
(+) Start conversion.
(+) Stop conversion.
(+) Start conversion and enable DMA transfer.
(+) Stop conversion and disable DMA transfer.
(+) Get result of conversion.
(+) Get result of dual mode conversion.
@endverbatim
* @{
*/
/**
* @brief Enables DAC and starts conversion of both channels.
* @param hdac pointer to a DAC_HandleTypeDef structure that contains
* the configuration information for the specified DAC.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DACEx_DualStart(DAC_HandleTypeDef *hdac)
{
uint32_t tmp_swtrig = 0UL;
/* Check the DAC peripheral handle */
if (hdac == NULL)
{
return HAL_ERROR;
}
/* Process locked */
__HAL_LOCK(hdac);
/* Change DAC state */
hdac->State = HAL_DAC_STATE_BUSY;
/* Enable the Peripheral */
__HAL_DAC_ENABLE(hdac, DAC_CHANNEL_1);
__HAL_DAC_ENABLE(hdac, DAC_CHANNEL_2);
/* Check if software trigger enabled */
if ((hdac->Instance->CR & (DAC_CR_TEN1 | DAC_CR_TSEL1)) == DAC_TRIGGER_SOFTWARE)
{
tmp_swtrig |= DAC_SWTRIGR_SWTRIG1;
}
if ((hdac->Instance->CR & (DAC_CR_TEN2 | DAC_CR_TSEL2)) == (DAC_TRIGGER_SOFTWARE << (DAC_CHANNEL_2 & 0x10UL)))
{
tmp_swtrig |= DAC_SWTRIGR_SWTRIG2;
}
/* Enable the selected DAC software conversion*/
SET_BIT(hdac->Instance->SWTRIGR, tmp_swtrig);
/* Change DAC state */
hdac->State = HAL_DAC_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hdac);
/* Return function status */
return HAL_OK;
}
/**
* @brief Disables DAC and stop conversion of both channels.
* @param hdac pointer to a DAC_HandleTypeDef structure that contains
* the configuration information for the specified DAC.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DACEx_DualStop(DAC_HandleTypeDef *hdac)
{
/* Check the DAC peripheral handle */
if (hdac == NULL)
{
return HAL_ERROR;
}
/* Disable the Peripheral */
__HAL_DAC_DISABLE(hdac, DAC_CHANNEL_1);
__HAL_DAC_DISABLE(hdac, DAC_CHANNEL_2);
/* Change DAC state */
hdac->State = HAL_DAC_STATE_READY;
/* Return function status */
return HAL_OK;
}
/**
* @brief Enable or disable the selected DAC channel wave generation.
* @param hdac pointer to a DAC_HandleTypeDef structure that contains
* the configuration information for the specified DAC.
* @param Channel The selected DAC channel.
* This parameter can be one of the following values:
* @arg DAC_CHANNEL_1: DAC Channel1 selected
* @arg DAC_CHANNEL_2: DAC Channel2 selected
* @param Amplitude Select max triangle amplitude.
* This parameter can be one of the following values:
* @arg DAC_TRIANGLEAMPLITUDE_1: Select max triangle amplitude of 1
* @arg DAC_TRIANGLEAMPLITUDE_3: Select max triangle amplitude of 3
* @arg DAC_TRIANGLEAMPLITUDE_7: Select max triangle amplitude of 7
* @arg DAC_TRIANGLEAMPLITUDE_15: Select max triangle amplitude of 15
* @arg DAC_TRIANGLEAMPLITUDE_31: Select max triangle amplitude of 31
* @arg DAC_TRIANGLEAMPLITUDE_63: Select max triangle amplitude of 63
* @arg DAC_TRIANGLEAMPLITUDE_127: Select max triangle amplitude of 127
* @arg DAC_TRIANGLEAMPLITUDE_255: Select max triangle amplitude of 255
* @arg DAC_TRIANGLEAMPLITUDE_511: Select max triangle amplitude of 511
* @arg DAC_TRIANGLEAMPLITUDE_1023: Select max triangle amplitude of 1023
* @arg DAC_TRIANGLEAMPLITUDE_2047: Select max triangle amplitude of 2047
* @arg DAC_TRIANGLEAMPLITUDE_4095: Select max triangle amplitude of 4095
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DACEx_TriangleWaveGenerate(DAC_HandleTypeDef *hdac, uint32_t Channel, uint32_t Amplitude)
{
/* Check the DAC peripheral handle */
if (hdac == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_DAC_CHANNEL(Channel));
assert_param(IS_DAC_LFSR_UNMASK_TRIANGLE_AMPLITUDE(Amplitude));
/* Process locked */
__HAL_LOCK(hdac);
/* Change DAC state */
hdac->State = HAL_DAC_STATE_BUSY;
/* Enable the triangle wave generation for the selected DAC channel */
MODIFY_REG(hdac->Instance->CR, ((DAC_CR_WAVE1) | (DAC_CR_MAMP1)) << (Channel & 0x10UL),
(DAC_CR_WAVE1_1 | Amplitude) << (Channel & 0x10UL));
/* Change DAC state */
hdac->State = HAL_DAC_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hdac);
/* Return function status */
return HAL_OK;
}
/**
* @brief Enable or disable the selected DAC channel wave generation.
* @param hdac pointer to a DAC_HandleTypeDef structure that contains
* the configuration information for the specified DAC.
* @param Channel The selected DAC channel.
* This parameter can be one of the following values:
* @arg DAC_CHANNEL_1: DAC Channel1 selected
* @arg DAC_CHANNEL_2: DAC Channel2 selected
* @param Amplitude Unmask DAC channel LFSR for noise wave generation.
* This parameter can be one of the following values:
* @arg DAC_LFSRUNMASK_BIT0: Unmask DAC channel LFSR bit0 for noise wave generation
* @arg DAC_LFSRUNMASK_BITS1_0: Unmask DAC channel LFSR bit[1:0] for noise wave generation
* @arg DAC_LFSRUNMASK_BITS2_0: Unmask DAC channel LFSR bit[2:0] for noise wave generation
* @arg DAC_LFSRUNMASK_BITS3_0: Unmask DAC channel LFSR bit[3:0] for noise wave generation
* @arg DAC_LFSRUNMASK_BITS4_0: Unmask DAC channel LFSR bit[4:0] for noise wave generation
* @arg DAC_LFSRUNMASK_BITS5_0: Unmask DAC channel LFSR bit[5:0] for noise wave generation
* @arg DAC_LFSRUNMASK_BITS6_0: Unmask DAC channel LFSR bit[6:0] for noise wave generation
* @arg DAC_LFSRUNMASK_BITS7_0: Unmask DAC channel LFSR bit[7:0] for noise wave generation
* @arg DAC_LFSRUNMASK_BITS8_0: Unmask DAC channel LFSR bit[8:0] for noise wave generation
* @arg DAC_LFSRUNMASK_BITS9_0: Unmask DAC channel LFSR bit[9:0] for noise wave generation
* @arg DAC_LFSRUNMASK_BITS10_0: Unmask DAC channel LFSR bit[10:0] for noise wave generation
* @arg DAC_LFSRUNMASK_BITS11_0: Unmask DAC channel LFSR bit[11:0] for noise wave generation
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DACEx_NoiseWaveGenerate(DAC_HandleTypeDef *hdac, uint32_t Channel, uint32_t Amplitude)
{
/* Check the DAC peripheral handle */
if (hdac == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_DAC_CHANNEL(Channel));
assert_param(IS_DAC_LFSR_UNMASK_TRIANGLE_AMPLITUDE(Amplitude));
/* Process locked */
__HAL_LOCK(hdac);
/* Change DAC state */
hdac->State = HAL_DAC_STATE_BUSY;
/* Enable the noise wave generation for the selected DAC channel */
MODIFY_REG(hdac->Instance->CR, ((DAC_CR_WAVE1) | (DAC_CR_MAMP1)) << (Channel & 0x10UL),
(DAC_CR_WAVE1_0 | Amplitude) << (Channel & 0x10UL));
/* Change DAC state */
hdac->State = HAL_DAC_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hdac);
/* Return function status */
return HAL_OK;
}
/**
* @brief Set the specified data holding register value for dual DAC channel.
* @param hdac pointer to a DAC_HandleTypeDef structure that contains
* the configuration information for the specified DAC.
* @param Alignment Specifies the data alignment for dual channel DAC.
* This parameter can be one of the following values:
* DAC_ALIGN_8B_R: 8bit right data alignment selected
* DAC_ALIGN_12B_L: 12bit left data alignment selected
* DAC_ALIGN_12B_R: 12bit right data alignment selected
* @param Data1 Data for DAC Channel1 to be loaded in the selected data holding register.
* @param Data2 Data for DAC Channel2 to be loaded in the selected data holding register.
* @note In dual mode, a unique register access is required to write in both
* DAC channels at the same time.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DACEx_DualSetValue(DAC_HandleTypeDef *hdac, uint32_t Alignment, uint32_t Data1, uint32_t Data2)
{
uint32_t data;
uint32_t tmp;
/* Check the DAC peripheral handle */
if (hdac == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_DAC_ALIGN(Alignment));
assert_param(IS_DAC_DATA(Data1));
assert_param(IS_DAC_DATA(Data2));
/* Calculate and set dual DAC data holding register value */
if (Alignment == DAC_ALIGN_8B_R)
{
data = ((uint32_t)Data2 << 8U) | Data1;
}
else
{
data = ((uint32_t)Data2 << 16U) | Data1;
}
tmp = (uint32_t)hdac->Instance;
tmp += DAC_DHR12RD_ALIGNMENT(Alignment);
/* Set the dual DAC selected data holding register */
*(__IO uint32_t *)tmp = data;
/* Return function status */
return HAL_OK;
}
/**
* @brief Conversion complete callback in non-blocking mode for Channel2.
* @param hdac pointer to a DAC_HandleTypeDef structure that contains
* the configuration information for the specified DAC.
* @retval None
*/
__weak void HAL_DACEx_ConvCpltCallbackCh2(DAC_HandleTypeDef *hdac)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hdac);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_DACEx_ConvCpltCallbackCh2 could be implemented in the user file
*/
}
/**
* @brief Conversion half DMA transfer callback in non-blocking mode for Channel2.
* @param hdac pointer to a DAC_HandleTypeDef structure that contains
* the configuration information for the specified DAC.
* @retval None
*/
__weak void HAL_DACEx_ConvHalfCpltCallbackCh2(DAC_HandleTypeDef *hdac)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hdac);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_DACEx_ConvHalfCpltCallbackCh2 could be implemented in the user file
*/
}
/**
* @brief Error DAC callback for Channel2.
* @param hdac pointer to a DAC_HandleTypeDef structure that contains
* the configuration information for the specified DAC.
* @retval None
*/
__weak void HAL_DACEx_ErrorCallbackCh2(DAC_HandleTypeDef *hdac)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hdac);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_DACEx_ErrorCallbackCh2 could be implemented in the user file
*/
}
/**
* @brief DMA underrun DAC callback for Channel2.
* @param hdac pointer to a DAC_HandleTypeDef structure that contains
* the configuration information for the specified DAC.
* @retval None
*/
__weak void HAL_DACEx_DMAUnderrunCallbackCh2(DAC_HandleTypeDef *hdac)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hdac);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_DACEx_DMAUnderrunCallbackCh2 could be implemented in the user file
*/
}
/**
* @}
*/
/** @defgroup DACEx_Exported_Functions_Group3 Peripheral Control functions
* @brief Extended Peripheral Control functions
*
@verbatim
==============================================================================
##### Peripheral Control functions #####
==============================================================================
[..] This section provides functions allowing to:
(+) Set the specified data holding register value for DAC channel.
@endverbatim
* @{
*/
/**
* @brief Return the last data output value of the selected DAC channel.
* @param hdac pointer to a DAC_HandleTypeDef structure that contains
* the configuration information for the specified DAC.
* @retval The selected DAC channel data output value.
*/
uint32_t HAL_DACEx_DualGetValue(const DAC_HandleTypeDef *hdac)
{
uint32_t tmp = 0UL;
tmp |= hdac->Instance->DOR1;
tmp |= hdac->Instance->DOR2 << 16UL;
/* Returns the DAC channel data output register value */
return tmp;
}
/**
* @}
*/
/**
* @}
*/
/* Private functions ---------------------------------------------------------*/
/** @defgroup DACEx_Private_Functions DACEx private functions
* @brief Extended private functions
* @{
*/
/**
* @brief DMA conversion complete callback.
* @param hdma pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
void DAC_DMAConvCpltCh2(DMA_HandleTypeDef *hdma)
{
DAC_HandleTypeDef *hdac = (DAC_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
#if (USE_HAL_DAC_REGISTER_CALLBACKS == 1)
hdac->ConvCpltCallbackCh2(hdac);
#else
HAL_DACEx_ConvCpltCallbackCh2(hdac);
#endif /* USE_HAL_DAC_REGISTER_CALLBACKS */
hdac->State = HAL_DAC_STATE_READY;
}
/**
* @brief DMA half transfer complete callback.
* @param hdma pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
void DAC_DMAHalfConvCpltCh2(DMA_HandleTypeDef *hdma)
{
DAC_HandleTypeDef *hdac = (DAC_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
/* Conversion complete callback */
#if (USE_HAL_DAC_REGISTER_CALLBACKS == 1)
hdac->ConvHalfCpltCallbackCh2(hdac);
#else
HAL_DACEx_ConvHalfCpltCallbackCh2(hdac);
#endif /* USE_HAL_DAC_REGISTER_CALLBACKS */
}
/**
* @brief DMA error callback.
* @param hdma pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
void DAC_DMAErrorCh2(DMA_HandleTypeDef *hdma)
{
DAC_HandleTypeDef *hdac = (DAC_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
/* Set DAC error code to DMA error */
hdac->ErrorCode |= HAL_DAC_ERROR_DMA;
#if (USE_HAL_DAC_REGISTER_CALLBACKS == 1)
hdac->ErrorCallbackCh2(hdac);
#else
HAL_DACEx_ErrorCallbackCh2(hdac);
#endif /* USE_HAL_DAC_REGISTER_CALLBACKS */
hdac->State = HAL_DAC_STATE_READY;
}
/**
* @}
*/
/**
* @}
*/
#endif /* DAC */
#endif /* HAL_DAC_MODULE_ENABLED */
/**
* @}
*/

View File

@@ -0,0 +1,2290 @@
/**
******************************************************************************
* @file stm32f1xx_hal_eth.c
* @author MCD Application Team
* @brief ETH HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of the Ethernet (ETH) peripheral:
* + Initialization and de-initialization functions
* + IO operation functions
* + Peripheral Control functions
* + Peripheral State and Errors functions
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
==============================================================================
##### How to use this driver #####
==============================================================================
[..]
(#)Declare a ETH_HandleTypeDef handle structure, for example:
ETH_HandleTypeDef heth;
(#)Fill parameters of Init structure in heth handle
(#)Call HAL_ETH_Init() API to initialize the Ethernet peripheral (MAC, DMA, ...)
(#)Initialize the ETH low level resources through the HAL_ETH_MspInit() API:
(##) Enable the Ethernet interface clock using
(+++) __HAL_RCC_ETHMAC_CLK_ENABLE();
(+++) __HAL_RCC_ETHMACTX_CLK_ENABLE();
(+++) __HAL_RCC_ETHMACRX_CLK_ENABLE();
(##) Initialize the related GPIO clocks
(##) Configure Ethernet pin-out
(##) Configure Ethernet NVIC interrupt (IT mode)
(#)Initialize Ethernet DMA Descriptors in chain mode and point to allocated buffers:
(##) HAL_ETH_DMATxDescListInit(); for Transmission process
(##) HAL_ETH_DMARxDescListInit(); for Reception process
(#)Enable MAC and DMA transmission and reception:
(##) HAL_ETH_Start();
(#)Prepare ETH DMA TX Descriptors and give the hand to ETH DMA to transfer
the frame to MAC TX FIFO:
(##) HAL_ETH_TransmitFrame();
(#)Poll for a received frame in ETH RX DMA Descriptors and get received
frame parameters
(##) HAL_ETH_GetReceivedFrame(); (should be called into an infinite loop)
(#) Get a received frame when an ETH RX interrupt occurs:
(##) HAL_ETH_GetReceivedFrame_IT(); (called in IT mode only)
(#) Communicate with external PHY device:
(##) Read a specific register from the PHY
HAL_ETH_ReadPHYRegister();
(##) Write data to a specific RHY register:
HAL_ETH_WritePHYRegister();
(#) Configure the Ethernet MAC after ETH peripheral initialization
HAL_ETH_ConfigMAC(); all MAC parameters should be filled.
(#) Configure the Ethernet DMA after ETH peripheral initialization
HAL_ETH_ConfigDMA(); all DMA parameters should be filled.
-@- The PTP protocol and the DMA descriptors ring mode are not supported
in this driver
*** Callback registration ***
=============================================
The compilation define USE_HAL_ETH_REGISTER_CALLBACKS when set to 1
allows the user to configure dynamically the driver callbacks.
Use Function @ref HAL_ETH_RegisterCallback() to register an interrupt callback.
Function @ref HAL_ETH_RegisterCallback() allows to register following callbacks:
(+) TxCpltCallback : Tx Complete Callback.
(+) RxCpltCallback : Rx Complete Callback.
(+) DMAErrorCallback : DMA Error Callback.
(+) MspInitCallback : MspInit Callback.
(+) MspDeInitCallback: MspDeInit Callback.
This function takes as parameters the HAL peripheral handle, the Callback ID
and a pointer to the user callback function.
Use function @ref HAL_ETH_UnRegisterCallback() to reset a callback to the default
weak function.
@ref HAL_ETH_UnRegisterCallback takes as parameters the HAL peripheral handle,
and the Callback ID.
This function allows to reset following callbacks:
(+) TxCpltCallback : Tx Complete Callback.
(+) RxCpltCallback : Rx Complete Callback.
(+) DMAErrorCallback : DMA Error Callback.
(+) MspInitCallback : MspInit Callback.
(+) MspDeInitCallback: MspDeInit Callback.
By default, after the HAL_ETH_Init and when the state is HAL_ETH_STATE_RESET
all callbacks are set to the corresponding weak functions:
examples @ref HAL_ETH_TxCpltCallback(), @ref HAL_ETH_RxCpltCallback().
Exception done for MspInit and MspDeInit functions that are
reset to the legacy weak function in the HAL_ETH_Init/ @ref HAL_ETH_DeInit only when
these callbacks are null (not registered beforehand).
if not, MspInit or MspDeInit are not null, the HAL_ETH_Init/ @ref HAL_ETH_DeInit
keep and use the user MspInit/MspDeInit callbacks (registered beforehand)
Callbacks can be registered/unregistered in HAL_ETH_STATE_READY state only.
Exception done MspInit/MspDeInit that can be registered/unregistered
in HAL_ETH_STATE_READY or HAL_ETH_STATE_RESET state,
thus registered (user) MspInit/DeInit callbacks can be used during the Init/DeInit.
In that case first register the MspInit/MspDeInit user callbacks
using @ref HAL_ETH_RegisterCallback() before calling @ref HAL_ETH_DeInit
or HAL_ETH_Init function.
When The compilation define USE_HAL_ETH_REGISTER_CALLBACKS is set to 0 or
not defined, the callback registration feature is not available and all callbacks
are set to the corresponding weak functions.
@endverbatim
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
/** @defgroup ETH ETH
* @brief ETH HAL module driver
* @{
*/
#ifdef HAL_ETH_MODULE_ENABLED
#if defined (ETH)
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/** @defgroup ETH_Private_Constants ETH Private Constants
* @{
*/
#define ETH_TIMEOUT_SWRESET 500U
#define ETH_TIMEOUT_LINKED_STATE 5000U
#define ETH_TIMEOUT_AUTONEGO_COMPLETED 5000U
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/** @defgroup ETH_Private_Functions ETH Private Functions
* @{
*/
static void ETH_MACDMAConfig(ETH_HandleTypeDef *heth, uint32_t err);
static void ETH_MACAddressConfig(ETH_HandleTypeDef *heth, uint32_t MacAddr, uint8_t *Addr);
static void ETH_MACReceptionEnable(ETH_HandleTypeDef *heth);
static void ETH_MACReceptionDisable(ETH_HandleTypeDef *heth);
static void ETH_MACTransmissionEnable(ETH_HandleTypeDef *heth);
static void ETH_MACTransmissionDisable(ETH_HandleTypeDef *heth);
static void ETH_DMATransmissionEnable(ETH_HandleTypeDef *heth);
static void ETH_DMATransmissionDisable(ETH_HandleTypeDef *heth);
static void ETH_DMAReceptionEnable(ETH_HandleTypeDef *heth);
static void ETH_DMAReceptionDisable(ETH_HandleTypeDef *heth);
static void ETH_FlushTransmitFIFO(ETH_HandleTypeDef *heth);
static void ETH_Delay(uint32_t mdelay);
#if (USE_HAL_ETH_REGISTER_CALLBACKS == 1)
static void ETH_InitCallbacksToDefault(ETH_HandleTypeDef *heth);
#endif /* USE_HAL_ETH_REGISTER_CALLBACKS */
/**
* @}
*/
/* Private functions ---------------------------------------------------------*/
/** @defgroup ETH_Exported_Functions ETH Exported Functions
* @{
*/
/** @defgroup ETH_Exported_Functions_Group1 Initialization and de-initialization functions
* @brief Initialization and Configuration functions
*
@verbatim
===============================================================================
##### Initialization and de-initialization functions #####
===============================================================================
[..] This section provides functions allowing to:
(+) Initialize and configure the Ethernet peripheral
(+) De-initialize the Ethernet peripheral
@endverbatim
* @{
*/
/**
* @brief Initializes the Ethernet MAC and DMA according to default
* parameters.
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @retval HAL status
*/
HAL_StatusTypeDef HAL_ETH_Init(ETH_HandleTypeDef *heth)
{
uint32_t tmpreg1 = 0U, phyreg = 0U;
uint32_t hclk = 60000000U;
uint32_t tickstart = 0U;
uint32_t err = ETH_SUCCESS;
/* Check the ETH peripheral state */
if (heth == NULL)
{
return HAL_ERROR;
}
/* Check parameters */
assert_param(IS_ETH_AUTONEGOTIATION(heth->Init.AutoNegotiation));
assert_param(IS_ETH_RX_MODE(heth->Init.RxMode));
assert_param(IS_ETH_CHECKSUM_MODE(heth->Init.ChecksumMode));
assert_param(IS_ETH_MEDIA_INTERFACE(heth->Init.MediaInterface));
if (heth->State == HAL_ETH_STATE_RESET)
{
/* Allocate lock resource and initialize it */
heth->Lock = HAL_UNLOCKED;
#if (USE_HAL_ETH_REGISTER_CALLBACKS == 1)
ETH_InitCallbacksToDefault(heth);
if (heth->MspInitCallback == NULL)
{
/* Init the low level hardware : GPIO, CLOCK, NVIC. */
heth->MspInitCallback = HAL_ETH_MspInit;
}
heth->MspInitCallback(heth);
#else
/* Init the low level hardware : GPIO, CLOCK, NVIC. */
HAL_ETH_MspInit(heth);
#endif /* USE_HAL_ETH_REGISTER_CALLBACKS */
}
/* Select MII or RMII Mode*/
AFIO->MAPR &= ~(AFIO_MAPR_MII_RMII_SEL);
AFIO->MAPR |= (uint32_t)heth->Init.MediaInterface;
/* Ethernet Software reset */
/* Set the SWR bit: resets all MAC subsystem internal registers and logic */
/* After reset all the registers holds their respective reset values */
(heth->Instance)->DMABMR |= ETH_DMABMR_SR;
/* Get tick */
tickstart = HAL_GetTick();
/* Wait for software reset */
while (((heth->Instance)->DMABMR & ETH_DMABMR_SR) != (uint32_t)RESET)
{
/* Check for the Timeout */
if ((HAL_GetTick() - tickstart) > ETH_TIMEOUT_SWRESET)
{
heth->State = HAL_ETH_STATE_TIMEOUT;
/* Process Unlocked */
__HAL_UNLOCK(heth);
/* Note: The SWR is not performed if the ETH_RX_CLK or the ETH_TX_CLK are
not available, please check your external PHY or the IO configuration */
return HAL_TIMEOUT;
}
}
/*-------------------------------- MAC Initialization ----------------------*/
/* Get the ETHERNET MACMIIAR value */
tmpreg1 = (heth->Instance)->MACMIIAR;
/* Clear CSR Clock Range CR[2:0] bits */
tmpreg1 &= ETH_MACMIIAR_CR_MASK;
/* Get hclk frequency value */
hclk = HAL_RCC_GetHCLKFreq();
/* Set CR bits depending on hclk value */
if ((hclk >= 20000000U) && (hclk < 35000000U))
{
/* CSR Clock Range between 20-35 MHz */
tmpreg1 |= (uint32_t)ETH_MACMIIAR_CR_DIV16;
}
else if ((hclk >= 35000000U) && (hclk < 60000000U))
{
/* CSR Clock Range between 35-60 MHz */
tmpreg1 |= (uint32_t)ETH_MACMIIAR_CR_DIV26;
}
else
{
/* CSR Clock Range between 60-72 MHz */
tmpreg1 |= (uint32_t)ETH_MACMIIAR_CR_DIV42;
}
/* Write to ETHERNET MAC MIIAR: Configure the ETHERNET CSR Clock Range */
(heth->Instance)->MACMIIAR = (uint32_t)tmpreg1;
/*-------------------- PHY initialization and configuration ----------------*/
/* Put the PHY in reset mode */
if ((HAL_ETH_WritePHYRegister(heth, PHY_BCR, PHY_RESET)) != HAL_OK)
{
/* In case of write timeout */
err = ETH_ERROR;
/* Config MAC and DMA */
ETH_MACDMAConfig(heth, err);
/* Set the ETH peripheral state to READY */
heth->State = HAL_ETH_STATE_READY;
/* Return HAL_ERROR */
return HAL_ERROR;
}
/* Delay to assure PHY reset */
HAL_Delay(PHY_RESET_DELAY);
if ((heth->Init).AutoNegotiation != ETH_AUTONEGOTIATION_DISABLE)
{
/* Get tick */
tickstart = HAL_GetTick();
/* We wait for linked status */
do
{
HAL_ETH_ReadPHYRegister(heth, PHY_BSR, &phyreg);
/* Check for the Timeout */
if ((HAL_GetTick() - tickstart) > ETH_TIMEOUT_LINKED_STATE)
{
/* In case of write timeout */
err = ETH_ERROR;
/* Config MAC and DMA */
ETH_MACDMAConfig(heth, err);
heth->State = HAL_ETH_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(heth);
return HAL_TIMEOUT;
}
}
while (((phyreg & PHY_LINKED_STATUS) != PHY_LINKED_STATUS));
/* Enable Auto-Negotiation */
if ((HAL_ETH_WritePHYRegister(heth, PHY_BCR, PHY_AUTONEGOTIATION)) != HAL_OK)
{
/* In case of write timeout */
err = ETH_ERROR;
/* Config MAC and DMA */
ETH_MACDMAConfig(heth, err);
/* Set the ETH peripheral state to READY */
heth->State = HAL_ETH_STATE_READY;
/* Return HAL_ERROR */
return HAL_ERROR;
}
/* Get tick */
tickstart = HAL_GetTick();
/* Wait until the auto-negotiation will be completed */
do
{
HAL_ETH_ReadPHYRegister(heth, PHY_BSR, &phyreg);
/* Check for the Timeout */
if ((HAL_GetTick() - tickstart) > ETH_TIMEOUT_AUTONEGO_COMPLETED)
{
/* In case of write timeout */
err = ETH_ERROR;
/* Config MAC and DMA */
ETH_MACDMAConfig(heth, err);
heth->State = HAL_ETH_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(heth);
return HAL_TIMEOUT;
}
}
while (((phyreg & PHY_AUTONEGO_COMPLETE) != PHY_AUTONEGO_COMPLETE));
/* Read the result of the auto-negotiation */
if ((HAL_ETH_ReadPHYRegister(heth, PHY_SR, &phyreg)) != HAL_OK)
{
/* In case of write timeout */
err = ETH_ERROR;
/* Config MAC and DMA */
ETH_MACDMAConfig(heth, err);
/* Set the ETH peripheral state to READY */
heth->State = HAL_ETH_STATE_READY;
/* Return HAL_ERROR */
return HAL_ERROR;
}
/* Configure the MAC with the Duplex Mode fixed by the auto-negotiation process */
if ((phyreg & PHY_DUPLEX_STATUS) != (uint32_t)RESET)
{
/* Set Ethernet duplex mode to Full-duplex following the auto-negotiation */
(heth->Init).DuplexMode = ETH_MODE_FULLDUPLEX;
}
else
{
/* Set Ethernet duplex mode to Half-duplex following the auto-negotiation */
(heth->Init).DuplexMode = ETH_MODE_HALFDUPLEX;
}
/* Configure the MAC with the speed fixed by the auto-negotiation process */
if ((phyreg & PHY_SPEED_STATUS) == PHY_SPEED_STATUS)
{
/* Set Ethernet speed to 10M following the auto-negotiation */
(heth->Init).Speed = ETH_SPEED_10M;
}
else
{
/* Set Ethernet speed to 100M following the auto-negotiation */
(heth->Init).Speed = ETH_SPEED_100M;
}
}
else /* AutoNegotiation Disable */
{
/* Check parameters */
assert_param(IS_ETH_SPEED(heth->Init.Speed));
assert_param(IS_ETH_DUPLEX_MODE(heth->Init.DuplexMode));
/* Set MAC Speed and Duplex Mode */
if (HAL_ETH_WritePHYRegister(heth, PHY_BCR, ((uint16_t)((heth->Init).DuplexMode >> 3U) |
(uint16_t)((heth->Init).Speed >> 1U))) != HAL_OK)
{
/* In case of write timeout */
err = ETH_ERROR;
/* Config MAC and DMA */
ETH_MACDMAConfig(heth, err);
/* Set the ETH peripheral state to READY */
heth->State = HAL_ETH_STATE_READY;
/* Return HAL_ERROR */
return HAL_ERROR;
}
/* Delay to assure PHY configuration */
HAL_Delay(PHY_CONFIG_DELAY);
}
/* Config MAC and DMA */
ETH_MACDMAConfig(heth, err);
/* Set ETH HAL State to Ready */
heth->State = HAL_ETH_STATE_READY;
/* Return function status */
return HAL_OK;
}
/**
* @brief De-Initializes the ETH peripheral.
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @retval HAL status
*/
HAL_StatusTypeDef HAL_ETH_DeInit(ETH_HandleTypeDef *heth)
{
/* Set the ETH peripheral state to BUSY */
heth->State = HAL_ETH_STATE_BUSY;
#if (USE_HAL_ETH_REGISTER_CALLBACKS == 1)
if (heth->MspDeInitCallback == NULL)
{
heth->MspDeInitCallback = HAL_ETH_MspDeInit;
}
/* De-Init the low level hardware : GPIO, CLOCK, NVIC. */
heth->MspDeInitCallback(heth);
#else
/* De-Init the low level hardware : GPIO, CLOCK, NVIC. */
HAL_ETH_MspDeInit(heth);
#endif
/* Set ETH HAL state to Disabled */
heth->State = HAL_ETH_STATE_RESET;
/* Release Lock */
__HAL_UNLOCK(heth);
/* Return function status */
return HAL_OK;
}
/**
* @brief Initializes the DMA Tx descriptors in chain mode.
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @param DMATxDescTab: Pointer to the first Tx desc list
* @param TxBuff: Pointer to the first TxBuffer list
* @param TxBuffCount: Number of the used Tx desc in the list
* @retval HAL status
*/
HAL_StatusTypeDef HAL_ETH_DMATxDescListInit(ETH_HandleTypeDef *heth, ETH_DMADescTypeDef *DMATxDescTab, uint8_t *TxBuff, uint32_t TxBuffCount)
{
uint32_t i = 0U;
ETH_DMADescTypeDef *dmatxdesc;
/* Process Locked */
__HAL_LOCK(heth);
/* Set the ETH peripheral state to BUSY */
heth->State = HAL_ETH_STATE_BUSY;
/* Set the DMATxDescToSet pointer with the first one of the DMATxDescTab list */
heth->TxDesc = DMATxDescTab;
/* Fill each DMATxDesc descriptor with the right values */
for (i = 0U; i < TxBuffCount; i++)
{
/* Get the pointer on the ith member of the Tx Desc list */
dmatxdesc = DMATxDescTab + i;
/* Set Second Address Chained bit */
dmatxdesc->Status = ETH_DMATXDESC_TCH;
/* Set Buffer1 address pointer */
dmatxdesc->Buffer1Addr = (uint32_t)(&TxBuff[i * ETH_TX_BUF_SIZE]);
if ((heth->Init).ChecksumMode == ETH_CHECKSUM_BY_HARDWARE)
{
/* Set the DMA Tx descriptors checksum insertion */
dmatxdesc->Status |= ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL;
}
/* Initialize the next descriptor with the Next Descriptor Polling Enable */
if (i < (TxBuffCount - 1U))
{
/* Set next descriptor address register with next descriptor base address */
dmatxdesc->Buffer2NextDescAddr = (uint32_t)(DMATxDescTab + i + 1U);
}
else
{
/* For last descriptor, set next descriptor address register equal to the first descriptor base address */
dmatxdesc->Buffer2NextDescAddr = (uint32_t) DMATxDescTab;
}
}
/* Set Transmit Descriptor List Address Register */
(heth->Instance)->DMATDLAR = (uint32_t) DMATxDescTab;
/* Set ETH HAL State to Ready */
heth->State = HAL_ETH_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(heth);
/* Return function status */
return HAL_OK;
}
/**
* @brief Initializes the DMA Rx descriptors in chain mode.
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @param DMARxDescTab: Pointer to the first Rx desc list
* @param RxBuff: Pointer to the first RxBuffer list
* @param RxBuffCount: Number of the used Rx desc in the list
* @retval HAL status
*/
HAL_StatusTypeDef HAL_ETH_DMARxDescListInit(ETH_HandleTypeDef *heth, ETH_DMADescTypeDef *DMARxDescTab, uint8_t *RxBuff, uint32_t RxBuffCount)
{
uint32_t i = 0U;
ETH_DMADescTypeDef *DMARxDesc;
/* Process Locked */
__HAL_LOCK(heth);
/* Set the ETH peripheral state to BUSY */
heth->State = HAL_ETH_STATE_BUSY;
/* Set the Ethernet RxDesc pointer with the first one of the DMARxDescTab list */
heth->RxDesc = DMARxDescTab;
/* Fill each DMARxDesc descriptor with the right values */
for (i = 0U; i < RxBuffCount; i++)
{
/* Get the pointer on the ith member of the Rx Desc list */
DMARxDesc = DMARxDescTab + i;
/* Set Own bit of the Rx descriptor Status */
DMARxDesc->Status = ETH_DMARXDESC_OWN;
/* Set Buffer1 size and Second Address Chained bit */
DMARxDesc->ControlBufferSize = ETH_DMARXDESC_RCH | ETH_RX_BUF_SIZE;
/* Set Buffer1 address pointer */
DMARxDesc->Buffer1Addr = (uint32_t)(&RxBuff[i * ETH_RX_BUF_SIZE]);
if ((heth->Init).RxMode == ETH_RXINTERRUPT_MODE)
{
/* Enable Ethernet DMA Rx Descriptor interrupt */
DMARxDesc->ControlBufferSize &= ~ETH_DMARXDESC_DIC;
}
/* Initialize the next descriptor with the Next Descriptor Polling Enable */
if (i < (RxBuffCount - 1U))
{
/* Set next descriptor address register with next descriptor base address */
DMARxDesc->Buffer2NextDescAddr = (uint32_t)(DMARxDescTab + i + 1U);
}
else
{
/* For last descriptor, set next descriptor address register equal to the first descriptor base address */
DMARxDesc->Buffer2NextDescAddr = (uint32_t)(DMARxDescTab);
}
}
/* Set Receive Descriptor List Address Register */
(heth->Instance)->DMARDLAR = (uint32_t) DMARxDescTab;
/* Set ETH HAL State to Ready */
heth->State = HAL_ETH_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(heth);
/* Return function status */
return HAL_OK;
}
/**
* @brief Initializes the ETH MSP.
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @retval None
*/
__weak void HAL_ETH_MspInit(ETH_HandleTypeDef *heth)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(heth);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_ETH_MspInit could be implemented in the user file
*/
}
/**
* @brief DeInitializes ETH MSP.
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @retval None
*/
__weak void HAL_ETH_MspDeInit(ETH_HandleTypeDef *heth)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(heth);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_ETH_MspDeInit could be implemented in the user file
*/
}
#if (USE_HAL_ETH_REGISTER_CALLBACKS == 1)
/**
* @brief Register a User ETH Callback
* To be used instead of the weak predefined callback
* @param heth eth handle
* @param CallbackID ID of the callback to be registered
* This parameter can be one of the following values:
* @arg @ref HAL_ETH_TX_COMPLETE_CB_ID Tx Complete Callback ID
* @arg @ref HAL_ETH_RX_COMPLETE_CB_ID Rx Complete Callback ID
* @arg @ref HAL_ETH_DMA_ERROR_CB_ID DMA Error Callback ID
* @arg @ref HAL_ETH_MSPINIT_CB_ID MspInit callback ID
* @arg @ref HAL_ETH_MSPDEINIT_CB_ID MspDeInit callback ID
* @param pCallback pointer to the Callback function
* @retval status
*/
HAL_StatusTypeDef HAL_ETH_RegisterCallback(ETH_HandleTypeDef *heth, HAL_ETH_CallbackIDTypeDef CallbackID, pETH_CallbackTypeDef pCallback)
{
HAL_StatusTypeDef status = HAL_OK;
if (pCallback == NULL)
{
return HAL_ERROR;
}
/* Process locked */
__HAL_LOCK(heth);
if (heth->State == HAL_ETH_STATE_READY)
{
switch (CallbackID)
{
case HAL_ETH_TX_COMPLETE_CB_ID :
heth->TxCpltCallback = pCallback;
break;
case HAL_ETH_RX_COMPLETE_CB_ID :
heth->RxCpltCallback = pCallback;
break;
case HAL_ETH_DMA_ERROR_CB_ID :
heth->DMAErrorCallback = pCallback;
break;
case HAL_ETH_MSPINIT_CB_ID :
heth->MspInitCallback = pCallback;
break;
case HAL_ETH_MSPDEINIT_CB_ID :
heth->MspDeInitCallback = pCallback;
break;
default :
/* Return error status */
status = HAL_ERROR;
break;
}
}
else if (heth->State == HAL_ETH_STATE_RESET)
{
switch (CallbackID)
{
case HAL_ETH_MSPINIT_CB_ID :
heth->MspInitCallback = pCallback;
break;
case HAL_ETH_MSPDEINIT_CB_ID :
heth->MspDeInitCallback = pCallback;
break;
default :
/* Return error status */
status = HAL_ERROR;
break;
}
}
else
{
/* Return error status */
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(heth);
return status;
}
/**
* @brief Unregister an ETH Callback
* ETH callback is redirected to the weak predefined callback
* @param heth eth handle
* @param CallbackID ID of the callback to be unregistered
* This parameter can be one of the following values:
* @arg @ref HAL_ETH_TX_COMPLETE_CB_ID Tx Complete Callback ID
* @arg @ref HAL_ETH_RX_COMPLETE_CB_ID Rx Complete Callback ID
* @arg @ref HAL_ETH_DMA_ERROR_CB_ID DMA Error Callback ID
* @arg @ref HAL_ETH_MSPINIT_CB_ID MspInit callback ID
* @arg @ref HAL_ETH_MSPDEINIT_CB_ID MspDeInit callback ID
* @retval status
*/
HAL_StatusTypeDef HAL_ETH_UnRegisterCallback(ETH_HandleTypeDef *heth, HAL_ETH_CallbackIDTypeDef CallbackID)
{
HAL_StatusTypeDef status = HAL_OK;
/* Process locked */
__HAL_LOCK(heth);
if (heth->State == HAL_ETH_STATE_READY)
{
switch (CallbackID)
{
case HAL_ETH_TX_COMPLETE_CB_ID :
heth->TxCpltCallback = HAL_ETH_TxCpltCallback;
break;
case HAL_ETH_RX_COMPLETE_CB_ID :
heth->RxCpltCallback = HAL_ETH_RxCpltCallback;
break;
case HAL_ETH_DMA_ERROR_CB_ID :
heth->DMAErrorCallback = HAL_ETH_ErrorCallback;
break;
case HAL_ETH_MSPINIT_CB_ID :
heth->MspInitCallback = HAL_ETH_MspInit;
break;
case HAL_ETH_MSPDEINIT_CB_ID :
heth->MspDeInitCallback = HAL_ETH_MspDeInit;
break;
default :
/* Return error status */
status = HAL_ERROR;
break;
}
}
else if (heth->State == HAL_ETH_STATE_RESET)
{
switch (CallbackID)
{
case HAL_ETH_MSPINIT_CB_ID :
heth->MspInitCallback = HAL_ETH_MspInit;
break;
case HAL_ETH_MSPDEINIT_CB_ID :
heth->MspDeInitCallback = HAL_ETH_MspDeInit;
break;
default :
/* Return error status */
status = HAL_ERROR;
break;
}
}
else
{
/* Return error status */
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(heth);
return status;
}
#endif /* USE_HAL_ETH_REGISTER_CALLBACKS */
/**
* @}
*/
/** @defgroup ETH_Exported_Functions_Group2 IO operation functions
* @brief Data transfers functions
*
@verbatim
==============================================================================
##### IO operation functions #####
==============================================================================
[..] This section provides functions allowing to:
(+) Transmit a frame
HAL_ETH_TransmitFrame();
(+) Receive a frame
HAL_ETH_GetReceivedFrame();
HAL_ETH_GetReceivedFrame_IT();
(+) Read from an External PHY register
HAL_ETH_ReadPHYRegister();
(+) Write to an External PHY register
HAL_ETH_WritePHYRegister();
@endverbatim
* @{
*/
/**
* @brief Sends an Ethernet frame.
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @param FrameLength: Amount of data to be sent
* @retval HAL status
*/
HAL_StatusTypeDef HAL_ETH_TransmitFrame(ETH_HandleTypeDef *heth, uint32_t FrameLength)
{
uint32_t bufcount = 0U, size = 0U, i = 0U;
/* Process Locked */
__HAL_LOCK(heth);
/* Set the ETH peripheral state to BUSY */
heth->State = HAL_ETH_STATE_BUSY;
if (FrameLength == 0U)
{
/* Set ETH HAL state to READY */
heth->State = HAL_ETH_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(heth);
return HAL_ERROR;
}
/* Check if the descriptor is owned by the ETHERNET DMA (when set) or CPU (when reset) */
if (((heth->TxDesc)->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET)
{
/* OWN bit set */
heth->State = HAL_ETH_STATE_BUSY_TX;
/* Process Unlocked */
__HAL_UNLOCK(heth);
return HAL_ERROR;
}
/* Get the number of needed Tx buffers for the current frame */
if (FrameLength > ETH_TX_BUF_SIZE)
{
bufcount = FrameLength / ETH_TX_BUF_SIZE;
if (FrameLength % ETH_TX_BUF_SIZE)
{
bufcount++;
}
}
else
{
bufcount = 1U;
}
if (bufcount == 1U)
{
/* Set LAST and FIRST segment */
heth->TxDesc->Status |= ETH_DMATXDESC_FS | ETH_DMATXDESC_LS;
/* Set frame size */
heth->TxDesc->ControlBufferSize = (FrameLength & ETH_DMATXDESC_TBS1);
/* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */
heth->TxDesc->Status |= ETH_DMATXDESC_OWN;
/* Point to next descriptor */
heth->TxDesc = (ETH_DMADescTypeDef *)(heth->TxDesc->Buffer2NextDescAddr);
}
else
{
for (i = 0U; i < bufcount; i++)
{
/* Clear FIRST and LAST segment bits */
heth->TxDesc->Status &= ~(ETH_DMATXDESC_FS | ETH_DMATXDESC_LS);
if (i == 0U)
{
/* Setting the first segment bit */
heth->TxDesc->Status |= ETH_DMATXDESC_FS;
}
/* Program size */
heth->TxDesc->ControlBufferSize = (ETH_TX_BUF_SIZE & ETH_DMATXDESC_TBS1);
if (i == (bufcount - 1U))
{
/* Setting the last segment bit */
heth->TxDesc->Status |= ETH_DMATXDESC_LS;
size = FrameLength - (bufcount - 1U) * ETH_TX_BUF_SIZE;
heth->TxDesc->ControlBufferSize = (size & ETH_DMATXDESC_TBS1);
}
/* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */
heth->TxDesc->Status |= ETH_DMATXDESC_OWN;
/* point to next descriptor */
heth->TxDesc = (ETH_DMADescTypeDef *)(heth->TxDesc->Buffer2NextDescAddr);
}
}
/* When Tx Buffer unavailable flag is set: clear it and resume transmission */
if (((heth->Instance)->DMASR & ETH_DMASR_TBUS) != (uint32_t)RESET)
{
/* Clear TBUS ETHERNET DMA flag */
(heth->Instance)->DMASR = ETH_DMASR_TBUS;
/* Resume DMA transmission*/
(heth->Instance)->DMATPDR = 0U;
}
/* Set ETH HAL State to Ready */
heth->State = HAL_ETH_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(heth);
/* Return function status */
return HAL_OK;
}
/**
* @brief Checks for received frames.
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @retval HAL status
*/
HAL_StatusTypeDef HAL_ETH_GetReceivedFrame(ETH_HandleTypeDef *heth)
{
uint32_t framelength = 0U;
/* Process Locked */
__HAL_LOCK(heth);
/* Check the ETH state to BUSY */
heth->State = HAL_ETH_STATE_BUSY;
/* Check if segment is not owned by DMA */
/* (((heth->RxDesc->Status & ETH_DMARXDESC_OWN) == (uint32_t)RESET) && ((heth->RxDesc->Status & ETH_DMARXDESC_LS) != (uint32_t)RESET)) */
if (((heth->RxDesc->Status & ETH_DMARXDESC_OWN) == (uint32_t)RESET))
{
/* Check if last segment */
if (((heth->RxDesc->Status & ETH_DMARXDESC_LS) != (uint32_t)RESET))
{
/* increment segment count */
(heth->RxFrameInfos).SegCount++;
/* Check if last segment is first segment: one segment contains the frame */
if ((heth->RxFrameInfos).SegCount == 1U)
{
(heth->RxFrameInfos).FSRxDesc = heth->RxDesc;
}
heth->RxFrameInfos.LSRxDesc = heth->RxDesc;
/* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */
framelength = (((heth->RxDesc)->Status & ETH_DMARXDESC_FL) >> ETH_DMARXDESC_FRAMELENGTHSHIFT) - 4U;
heth->RxFrameInfos.length = framelength;
/* Get the address of the buffer start address */
heth->RxFrameInfos.buffer = ((heth->RxFrameInfos).FSRxDesc)->Buffer1Addr;
/* point to next descriptor */
heth->RxDesc = (ETH_DMADescTypeDef *)((heth->RxDesc)->Buffer2NextDescAddr);
/* Set HAL State to Ready */
heth->State = HAL_ETH_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(heth);
/* Return function status */
return HAL_OK;
}
/* Check if first segment */
else if ((heth->RxDesc->Status & ETH_DMARXDESC_FS) != (uint32_t)RESET)
{
(heth->RxFrameInfos).FSRxDesc = heth->RxDesc;
(heth->RxFrameInfos).LSRxDesc = NULL;
(heth->RxFrameInfos).SegCount = 1U;
/* Point to next descriptor */
heth->RxDesc = (ETH_DMADescTypeDef *)(heth->RxDesc->Buffer2NextDescAddr);
}
/* Check if intermediate segment */
else
{
(heth->RxFrameInfos).SegCount++;
/* Point to next descriptor */
heth->RxDesc = (ETH_DMADescTypeDef *)(heth->RxDesc->Buffer2NextDescAddr);
}
}
/* Set ETH HAL State to Ready */
heth->State = HAL_ETH_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(heth);
/* Return function status */
return HAL_ERROR;
}
/**
* @brief Gets the Received frame in interrupt mode.
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @retval HAL status
*/
HAL_StatusTypeDef HAL_ETH_GetReceivedFrame_IT(ETH_HandleTypeDef *heth)
{
uint32_t descriptorscancounter = 0U;
/* Process Locked */
__HAL_LOCK(heth);
/* Set ETH HAL State to BUSY */
heth->State = HAL_ETH_STATE_BUSY;
/* Scan descriptors owned by CPU */
while (((heth->RxDesc->Status & ETH_DMARXDESC_OWN) == (uint32_t)RESET) && (descriptorscancounter < ETH_RXBUFNB))
{
/* Just for security */
descriptorscancounter++;
/* Check if first segment in frame */
/* ((heth->RxDesc->Status & ETH_DMARXDESC_FS) != (uint32_t)RESET) && ((heth->RxDesc->Status & ETH_DMARXDESC_LS) == (uint32_t)RESET)) */
if ((heth->RxDesc->Status & (ETH_DMARXDESC_FS | ETH_DMARXDESC_LS)) == (uint32_t)ETH_DMARXDESC_FS)
{
heth->RxFrameInfos.FSRxDesc = heth->RxDesc;
heth->RxFrameInfos.SegCount = 1U;
/* Point to next descriptor */
heth->RxDesc = (ETH_DMADescTypeDef *)(heth->RxDesc->Buffer2NextDescAddr);
}
/* Check if intermediate segment */
/* ((heth->RxDesc->Status & ETH_DMARXDESC_LS) == (uint32_t)RESET)&& ((heth->RxDesc->Status & ETH_DMARXDESC_FS) == (uint32_t)RESET)) */
else if ((heth->RxDesc->Status & (ETH_DMARXDESC_LS | ETH_DMARXDESC_FS)) == (uint32_t)RESET)
{
/* Increment segment count */
(heth->RxFrameInfos.SegCount)++;
/* Point to next descriptor */
heth->RxDesc = (ETH_DMADescTypeDef *)(heth->RxDesc->Buffer2NextDescAddr);
}
/* Should be last segment */
else
{
/* Last segment */
heth->RxFrameInfos.LSRxDesc = heth->RxDesc;
/* Increment segment count */
(heth->RxFrameInfos.SegCount)++;
/* Check if last segment is first segment: one segment contains the frame */
if ((heth->RxFrameInfos.SegCount) == 1U)
{
heth->RxFrameInfos.FSRxDesc = heth->RxDesc;
}
/* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */
heth->RxFrameInfos.length = (((heth->RxDesc)->Status & ETH_DMARXDESC_FL) >> ETH_DMARXDESC_FRAMELENGTHSHIFT) - 4U;
/* Get the address of the buffer start address */
heth->RxFrameInfos.buffer = ((heth->RxFrameInfos).FSRxDesc)->Buffer1Addr;
/* Point to next descriptor */
heth->RxDesc = (ETH_DMADescTypeDef *)(heth->RxDesc->Buffer2NextDescAddr);
/* Set HAL State to Ready */
heth->State = HAL_ETH_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(heth);
/* Return function status */
return HAL_OK;
}
}
/* Set HAL State to Ready */
heth->State = HAL_ETH_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(heth);
/* Return function status */
return HAL_ERROR;
}
/**
* @brief This function handles ETH interrupt request.
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @retval HAL status
*/
void HAL_ETH_IRQHandler(ETH_HandleTypeDef *heth)
{
/* Frame received */
if (__HAL_ETH_DMA_GET_FLAG(heth, ETH_DMA_FLAG_R))
{
#if (USE_HAL_ETH_REGISTER_CALLBACKS == 1)
/*Call registered Receive complete callback*/
heth->RxCpltCallback(heth);
#else
/* Receive complete callback */
HAL_ETH_RxCpltCallback(heth);
#endif /* USE_HAL_ETH_REGISTER_CALLBACKS */
/* Clear the Eth DMA Rx IT pending bits */
__HAL_ETH_DMA_CLEAR_IT(heth, ETH_DMA_IT_R);
/* Set HAL State to Ready */
heth->State = HAL_ETH_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(heth);
}
/* Frame transmitted */
else if (__HAL_ETH_DMA_GET_FLAG(heth, ETH_DMA_FLAG_T))
{
#if (USE_HAL_ETH_REGISTER_CALLBACKS == 1)
/* Call resgistered Transfer complete callback*/
heth->TxCpltCallback(heth);
#else
/* Transfer complete callback */
HAL_ETH_TxCpltCallback(heth);
#endif /* USE_HAL_ETH_REGISTER_CALLBACKS */
/* Clear the Eth DMA Tx IT pending bits */
__HAL_ETH_DMA_CLEAR_IT(heth, ETH_DMA_IT_T);
/* Set HAL State to Ready */
heth->State = HAL_ETH_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(heth);
}
/* Clear the interrupt flags */
__HAL_ETH_DMA_CLEAR_IT(heth, ETH_DMA_IT_NIS);
/* ETH DMA Error */
if (__HAL_ETH_DMA_GET_FLAG(heth, ETH_DMA_FLAG_AIS))
{
#if (USE_HAL_ETH_REGISTER_CALLBACKS == 1)
heth->DMAErrorCallback(heth);
#else
/* Ethernet Error callback */
HAL_ETH_ErrorCallback(heth);
#endif /* USE_HAL_ETH_REGISTER_CALLBACKS */
/* Clear the interrupt flags */
__HAL_ETH_DMA_CLEAR_IT(heth, ETH_DMA_FLAG_AIS);
/* Set HAL State to Ready */
heth->State = HAL_ETH_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(heth);
}
}
/**
* @brief Tx Transfer completed callbacks.
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @retval None
*/
__weak void HAL_ETH_TxCpltCallback(ETH_HandleTypeDef *heth)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(heth);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_ETH_TxCpltCallback could be implemented in the user file
*/
}
/**
* @brief Rx Transfer completed callbacks.
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @retval None
*/
__weak void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(heth);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_ETH_TxCpltCallback could be implemented in the user file
*/
}
/**
* @brief Ethernet transfer error callbacks
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @retval None
*/
__weak void HAL_ETH_ErrorCallback(ETH_HandleTypeDef *heth)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(heth);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_ETH_TxCpltCallback could be implemented in the user file
*/
}
/**
* @brief Reads a PHY register
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @param PHYReg: PHY register address, is the index of one of the 32 PHY register.
* This parameter can be one of the following values:
* PHY_BCR: Transceiver Basic Control Register,
* PHY_BSR: Transceiver Basic Status Register.
* More PHY register could be read depending on the used PHY
* @param RegValue: PHY register value
* @retval HAL status
*/
HAL_StatusTypeDef HAL_ETH_ReadPHYRegister(ETH_HandleTypeDef *heth, uint16_t PHYReg, uint32_t *RegValue)
{
uint32_t tmpreg1 = 0U;
uint32_t tickstart = 0U;
/* Check parameters */
assert_param(IS_ETH_PHY_ADDRESS(heth->Init.PhyAddress));
/* Check the ETH peripheral state */
if (heth->State == HAL_ETH_STATE_BUSY_RD)
{
return HAL_BUSY;
}
/* Set ETH HAL State to BUSY_RD */
heth->State = HAL_ETH_STATE_BUSY_RD;
/* Get the ETHERNET MACMIIAR value */
tmpreg1 = heth->Instance->MACMIIAR;
/* Keep only the CSR Clock Range CR[2:0] bits value */
tmpreg1 &= ~ETH_MACMIIAR_CR_MASK;
/* Prepare the MII address register value */
tmpreg1 |= (((uint32_t)heth->Init.PhyAddress << 11U) & ETH_MACMIIAR_PA); /* Set the PHY device address */
tmpreg1 |= (((uint32_t)PHYReg << 6U) & ETH_MACMIIAR_MR); /* Set the PHY register address */
tmpreg1 &= ~ETH_MACMIIAR_MW; /* Set the read mode */
tmpreg1 |= ETH_MACMIIAR_MB; /* Set the MII Busy bit */
/* Write the result value into the MII Address register */
heth->Instance->MACMIIAR = tmpreg1;
/* Get tick */
tickstart = HAL_GetTick();
/* Check for the Busy flag */
while ((tmpreg1 & ETH_MACMIIAR_MB) == ETH_MACMIIAR_MB)
{
/* Check for the Timeout */
if ((HAL_GetTick() - tickstart) > PHY_READ_TO)
{
heth->State = HAL_ETH_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(heth);
return HAL_TIMEOUT;
}
tmpreg1 = heth->Instance->MACMIIAR;
}
/* Get MACMIIDR value */
*RegValue = (uint16_t)(heth->Instance->MACMIIDR);
/* Set ETH HAL State to READY */
heth->State = HAL_ETH_STATE_READY;
/* Return function status */
return HAL_OK;
}
/**
* @brief Writes to a PHY register.
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @param PHYReg: PHY register address, is the index of one of the 32 PHY register.
* This parameter can be one of the following values:
* PHY_BCR: Transceiver Control Register.
* More PHY register could be written depending on the used PHY
* @param RegValue: the value to write
* @retval HAL status
*/
HAL_StatusTypeDef HAL_ETH_WritePHYRegister(ETH_HandleTypeDef *heth, uint16_t PHYReg, uint32_t RegValue)
{
uint32_t tmpreg1 = 0U;
uint32_t tickstart = 0U;
/* Check parameters */
assert_param(IS_ETH_PHY_ADDRESS(heth->Init.PhyAddress));
/* Check the ETH peripheral state */
if (heth->State == HAL_ETH_STATE_BUSY_WR)
{
return HAL_BUSY;
}
/* Set ETH HAL State to BUSY_WR */
heth->State = HAL_ETH_STATE_BUSY_WR;
/* Get the ETHERNET MACMIIAR value */
tmpreg1 = heth->Instance->MACMIIAR;
/* Keep only the CSR Clock Range CR[2:0] bits value */
tmpreg1 &= ~ETH_MACMIIAR_CR_MASK;
/* Prepare the MII register address value */
tmpreg1 |= (((uint32_t)heth->Init.PhyAddress << 11U) & ETH_MACMIIAR_PA); /* Set the PHY device address */
tmpreg1 |= (((uint32_t)PHYReg << 6U) & ETH_MACMIIAR_MR); /* Set the PHY register address */
tmpreg1 |= ETH_MACMIIAR_MW; /* Set the write mode */
tmpreg1 |= ETH_MACMIIAR_MB; /* Set the MII Busy bit */
/* Give the value to the MII data register */
heth->Instance->MACMIIDR = (uint16_t)RegValue;
/* Write the result value into the MII Address register */
heth->Instance->MACMIIAR = tmpreg1;
/* Get tick */
tickstart = HAL_GetTick();
/* Check for the Busy flag */
while ((tmpreg1 & ETH_MACMIIAR_MB) == ETH_MACMIIAR_MB)
{
/* Check for the Timeout */
if ((HAL_GetTick() - tickstart) > PHY_WRITE_TO)
{
heth->State = HAL_ETH_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(heth);
return HAL_TIMEOUT;
}
tmpreg1 = heth->Instance->MACMIIAR;
}
/* Set ETH HAL State to READY */
heth->State = HAL_ETH_STATE_READY;
/* Return function status */
return HAL_OK;
}
/**
* @}
*/
/** @defgroup ETH_Exported_Functions_Group3 Peripheral Control functions
* @brief Peripheral Control functions
*
@verbatim
===============================================================================
##### Peripheral Control functions #####
===============================================================================
[..] This section provides functions allowing to:
(+) Enable MAC and DMA transmission and reception.
HAL_ETH_Start();
(+) Disable MAC and DMA transmission and reception.
HAL_ETH_Stop();
(+) Set the MAC configuration in runtime mode
HAL_ETH_ConfigMAC();
(+) Set the DMA configuration in runtime mode
HAL_ETH_ConfigDMA();
@endverbatim
* @{
*/
/**
* @brief Enables Ethernet MAC and DMA reception/transmission
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @retval HAL status
*/
HAL_StatusTypeDef HAL_ETH_Start(ETH_HandleTypeDef *heth)
{
/* Process Locked */
__HAL_LOCK(heth);
/* Set the ETH peripheral state to BUSY */
heth->State = HAL_ETH_STATE_BUSY;
/* Enable transmit state machine of the MAC for transmission on the MII */
ETH_MACTransmissionEnable(heth);
/* Enable receive state machine of the MAC for reception from the MII */
ETH_MACReceptionEnable(heth);
/* Flush Transmit FIFO */
ETH_FlushTransmitFIFO(heth);
/* Start DMA transmission */
ETH_DMATransmissionEnable(heth);
/* Start DMA reception */
ETH_DMAReceptionEnable(heth);
/* Set the ETH state to READY*/
heth->State = HAL_ETH_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(heth);
/* Return function status */
return HAL_OK;
}
/**
* @brief Stop Ethernet MAC and DMA reception/transmission
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @retval HAL status
*/
HAL_StatusTypeDef HAL_ETH_Stop(ETH_HandleTypeDef *heth)
{
/* Process Locked */
__HAL_LOCK(heth);
/* Set the ETH peripheral state to BUSY */
heth->State = HAL_ETH_STATE_BUSY;
/* Stop DMA transmission */
ETH_DMATransmissionDisable(heth);
/* Stop DMA reception */
ETH_DMAReceptionDisable(heth);
/* Disable receive state machine of the MAC for reception from the MII */
ETH_MACReceptionDisable(heth);
/* Flush Transmit FIFO */
ETH_FlushTransmitFIFO(heth);
/* Disable transmit state machine of the MAC for transmission on the MII */
ETH_MACTransmissionDisable(heth);
/* Set the ETH state*/
heth->State = HAL_ETH_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(heth);
/* Return function status */
return HAL_OK;
}
/**
* @brief Set ETH MAC Configuration.
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @param macconf: MAC Configuration structure
* @retval HAL status
*/
HAL_StatusTypeDef HAL_ETH_ConfigMAC(ETH_HandleTypeDef *heth, ETH_MACInitTypeDef *macconf)
{
uint32_t tmpreg1 = 0U;
/* Process Locked */
__HAL_LOCK(heth);
/* Set the ETH peripheral state to BUSY */
heth->State = HAL_ETH_STATE_BUSY;
assert_param(IS_ETH_SPEED(heth->Init.Speed));
assert_param(IS_ETH_DUPLEX_MODE(heth->Init.DuplexMode));
if (macconf != NULL)
{
/* Check the parameters */
assert_param(IS_ETH_WATCHDOG(macconf->Watchdog));
assert_param(IS_ETH_JABBER(macconf->Jabber));
assert_param(IS_ETH_INTER_FRAME_GAP(macconf->InterFrameGap));
assert_param(IS_ETH_CARRIER_SENSE(macconf->CarrierSense));
assert_param(IS_ETH_RECEIVE_OWN(macconf->ReceiveOwn));
assert_param(IS_ETH_LOOPBACK_MODE(macconf->LoopbackMode));
assert_param(IS_ETH_CHECKSUM_OFFLOAD(macconf->ChecksumOffload));
assert_param(IS_ETH_RETRY_TRANSMISSION(macconf->RetryTransmission));
assert_param(IS_ETH_AUTOMATIC_PADCRC_STRIP(macconf->AutomaticPadCRCStrip));
assert_param(IS_ETH_BACKOFF_LIMIT(macconf->BackOffLimit));
assert_param(IS_ETH_DEFERRAL_CHECK(macconf->DeferralCheck));
assert_param(IS_ETH_RECEIVE_ALL(macconf->ReceiveAll));
assert_param(IS_ETH_SOURCE_ADDR_FILTER(macconf->SourceAddrFilter));
assert_param(IS_ETH_CONTROL_FRAMES(macconf->PassControlFrames));
assert_param(IS_ETH_BROADCAST_FRAMES_RECEPTION(macconf->BroadcastFramesReception));
assert_param(IS_ETH_DESTINATION_ADDR_FILTER(macconf->DestinationAddrFilter));
assert_param(IS_ETH_PROMISCUOUS_MODE(macconf->PromiscuousMode));
assert_param(IS_ETH_MULTICAST_FRAMES_FILTER(macconf->MulticastFramesFilter));
assert_param(IS_ETH_UNICAST_FRAMES_FILTER(macconf->UnicastFramesFilter));
assert_param(IS_ETH_PAUSE_TIME(macconf->PauseTime));
assert_param(IS_ETH_ZEROQUANTA_PAUSE(macconf->ZeroQuantaPause));
assert_param(IS_ETH_PAUSE_LOW_THRESHOLD(macconf->PauseLowThreshold));
assert_param(IS_ETH_UNICAST_PAUSE_FRAME_DETECT(macconf->UnicastPauseFrameDetect));
assert_param(IS_ETH_RECEIVE_FLOWCONTROL(macconf->ReceiveFlowControl));
assert_param(IS_ETH_TRANSMIT_FLOWCONTROL(macconf->TransmitFlowControl));
assert_param(IS_ETH_VLAN_TAG_COMPARISON(macconf->VLANTagComparison));
assert_param(IS_ETH_VLAN_TAG_IDENTIFIER(macconf->VLANTagIdentifier));
/*------------------------ ETHERNET MACCR Configuration --------------------*/
/* Get the ETHERNET MACCR value */
tmpreg1 = (heth->Instance)->MACCR;
/* Clear WD, PCE, PS, TE and RE bits */
tmpreg1 &= ETH_MACCR_CLEAR_MASK;
tmpreg1 |= (uint32_t)(macconf->Watchdog |
macconf->Jabber |
macconf->InterFrameGap |
macconf->CarrierSense |
(heth->Init).Speed |
macconf->ReceiveOwn |
macconf->LoopbackMode |
(heth->Init).DuplexMode |
macconf->ChecksumOffload |
macconf->RetryTransmission |
macconf->AutomaticPadCRCStrip |
macconf->BackOffLimit |
macconf->DeferralCheck);
/* Write to ETHERNET MACCR */
(heth->Instance)->MACCR = (uint32_t)tmpreg1;
/* Wait until the write operation will be taken into account :
at least four TX_CLK/RX_CLK clock cycles */
tmpreg1 = (heth->Instance)->MACCR;
HAL_Delay(ETH_REG_WRITE_DELAY);
(heth->Instance)->MACCR = tmpreg1;
/*----------------------- ETHERNET MACFFR Configuration --------------------*/
/* Write to ETHERNET MACFFR */
(heth->Instance)->MACFFR = (uint32_t)(macconf->ReceiveAll |
macconf->SourceAddrFilter |
macconf->PassControlFrames |
macconf->BroadcastFramesReception |
macconf->DestinationAddrFilter |
macconf->PromiscuousMode |
macconf->MulticastFramesFilter |
macconf->UnicastFramesFilter);
/* Wait until the write operation will be taken into account :
at least four TX_CLK/RX_CLK clock cycles */
tmpreg1 = (heth->Instance)->MACFFR;
HAL_Delay(ETH_REG_WRITE_DELAY);
(heth->Instance)->MACFFR = tmpreg1;
/*--------------- ETHERNET MACHTHR and MACHTLR Configuration ---------------*/
/* Write to ETHERNET MACHTHR */
(heth->Instance)->MACHTHR = (uint32_t)macconf->HashTableHigh;
/* Write to ETHERNET MACHTLR */
(heth->Instance)->MACHTLR = (uint32_t)macconf->HashTableLow;
/*----------------------- ETHERNET MACFCR Configuration --------------------*/
/* Get the ETHERNET MACFCR value */
tmpreg1 = (heth->Instance)->MACFCR;
/* Clear xx bits */
tmpreg1 &= ETH_MACFCR_CLEAR_MASK;
tmpreg1 |= (uint32_t)((macconf->PauseTime << 16U) |
macconf->ZeroQuantaPause |
macconf->PauseLowThreshold |
macconf->UnicastPauseFrameDetect |
macconf->ReceiveFlowControl |
macconf->TransmitFlowControl);
/* Write to ETHERNET MACFCR */
(heth->Instance)->MACFCR = (uint32_t)tmpreg1;
/* Wait until the write operation will be taken into account :
at least four TX_CLK/RX_CLK clock cycles */
tmpreg1 = (heth->Instance)->MACFCR;
HAL_Delay(ETH_REG_WRITE_DELAY);
(heth->Instance)->MACFCR = tmpreg1;
/*----------------------- ETHERNET MACVLANTR Configuration -----------------*/
(heth->Instance)->MACVLANTR = (uint32_t)(macconf->VLANTagComparison |
macconf->VLANTagIdentifier);
/* Wait until the write operation will be taken into account :
at least four TX_CLK/RX_CLK clock cycles */
tmpreg1 = (heth->Instance)->MACVLANTR;
HAL_Delay(ETH_REG_WRITE_DELAY);
(heth->Instance)->MACVLANTR = tmpreg1;
}
else /* macconf == NULL : here we just configure Speed and Duplex mode */
{
/*------------------------ ETHERNET MACCR Configuration --------------------*/
/* Get the ETHERNET MACCR value */
tmpreg1 = (heth->Instance)->MACCR;
/* Clear FES and DM bits */
tmpreg1 &= ~(0x00004800U);
tmpreg1 |= (uint32_t)(heth->Init.Speed | heth->Init.DuplexMode);
/* Write to ETHERNET MACCR */
(heth->Instance)->MACCR = (uint32_t)tmpreg1;
/* Wait until the write operation will be taken into account:
at least four TX_CLK/RX_CLK clock cycles */
tmpreg1 = (heth->Instance)->MACCR;
HAL_Delay(ETH_REG_WRITE_DELAY);
(heth->Instance)->MACCR = tmpreg1;
}
/* Set the ETH state to Ready */
heth->State = HAL_ETH_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(heth);
/* Return function status */
return HAL_OK;
}
/**
* @brief Sets ETH DMA Configuration.
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @param dmaconf: DMA Configuration structure
* @retval HAL status
*/
HAL_StatusTypeDef HAL_ETH_ConfigDMA(ETH_HandleTypeDef *heth, ETH_DMAInitTypeDef *dmaconf)
{
uint32_t tmpreg1 = 0U;
/* Process Locked */
__HAL_LOCK(heth);
/* Set the ETH peripheral state to BUSY */
heth->State = HAL_ETH_STATE_BUSY;
/* Check parameters */
assert_param(IS_ETH_DROP_TCPIP_CHECKSUM_FRAME(dmaconf->DropTCPIPChecksumErrorFrame));
assert_param(IS_ETH_RECEIVE_STORE_FORWARD(dmaconf->ReceiveStoreForward));
assert_param(IS_ETH_FLUSH_RECEIVE_FRAME(dmaconf->FlushReceivedFrame));
assert_param(IS_ETH_TRANSMIT_STORE_FORWARD(dmaconf->TransmitStoreForward));
assert_param(IS_ETH_TRANSMIT_THRESHOLD_CONTROL(dmaconf->TransmitThresholdControl));
assert_param(IS_ETH_FORWARD_ERROR_FRAMES(dmaconf->ForwardErrorFrames));
assert_param(IS_ETH_FORWARD_UNDERSIZED_GOOD_FRAMES(dmaconf->ForwardUndersizedGoodFrames));
assert_param(IS_ETH_RECEIVE_THRESHOLD_CONTROL(dmaconf->ReceiveThresholdControl));
assert_param(IS_ETH_SECOND_FRAME_OPERATE(dmaconf->SecondFrameOperate));
assert_param(IS_ETH_ADDRESS_ALIGNED_BEATS(dmaconf->AddressAlignedBeats));
assert_param(IS_ETH_FIXED_BURST(dmaconf->FixedBurst));
assert_param(IS_ETH_RXDMA_BURST_LENGTH(dmaconf->RxDMABurstLength));
assert_param(IS_ETH_TXDMA_BURST_LENGTH(dmaconf->TxDMABurstLength));
assert_param(IS_ETH_DMA_DESC_SKIP_LENGTH(dmaconf->DescriptorSkipLength));
assert_param(IS_ETH_DMA_ARBITRATION_ROUNDROBIN_RXTX(dmaconf->DMAArbitration));
/*----------------------- ETHERNET DMAOMR Configuration --------------------*/
/* Get the ETHERNET DMAOMR value */
tmpreg1 = (heth->Instance)->DMAOMR;
/* Clear xx bits */
tmpreg1 &= ETH_DMAOMR_CLEAR_MASK;
tmpreg1 |= (uint32_t)(dmaconf->DropTCPIPChecksumErrorFrame |
dmaconf->ReceiveStoreForward |
dmaconf->FlushReceivedFrame |
dmaconf->TransmitStoreForward |
dmaconf->TransmitThresholdControl |
dmaconf->ForwardErrorFrames |
dmaconf->ForwardUndersizedGoodFrames |
dmaconf->ReceiveThresholdControl |
dmaconf->SecondFrameOperate);
/* Write to ETHERNET DMAOMR */
(heth->Instance)->DMAOMR = (uint32_t)tmpreg1;
/* Wait until the write operation will be taken into account:
at least four TX_CLK/RX_CLK clock cycles */
tmpreg1 = (heth->Instance)->DMAOMR;
HAL_Delay(ETH_REG_WRITE_DELAY);
(heth->Instance)->DMAOMR = tmpreg1;
/*----------------------- ETHERNET DMABMR Configuration --------------------*/
(heth->Instance)->DMABMR = (uint32_t)(dmaconf->AddressAlignedBeats |
dmaconf->FixedBurst |
dmaconf->RxDMABurstLength | /* !! if 4xPBL is selected for Tx or Rx it is applied for the other */
dmaconf->TxDMABurstLength |
(dmaconf->DescriptorSkipLength << 2U) |
dmaconf->DMAArbitration |
ETH_DMABMR_USP); /* Enable use of separate PBL for Rx and Tx */
/* Wait until the write operation will be taken into account:
at least four TX_CLK/RX_CLK clock cycles */
tmpreg1 = (heth->Instance)->DMABMR;
HAL_Delay(ETH_REG_WRITE_DELAY);
(heth->Instance)->DMABMR = tmpreg1;
/* Set the ETH state to Ready */
heth->State = HAL_ETH_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(heth);
/* Return function status */
return HAL_OK;
}
/**
* @}
*/
/** @defgroup ETH_Exported_Functions_Group4 Peripheral State functions
* @brief Peripheral State functions
*
@verbatim
===============================================================================
##### Peripheral State functions #####
===============================================================================
[..]
This subsection permits to get in run-time the status of the peripheral
and the data flow.
(+) Get the ETH handle state:
HAL_ETH_GetState();
@endverbatim
* @{
*/
/**
* @brief Return the ETH HAL state
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @retval HAL state
*/
HAL_ETH_StateTypeDef HAL_ETH_GetState(ETH_HandleTypeDef *heth)
{
/* Return ETH state */
return heth->State;
}
/**
* @}
*/
/**
* @}
*/
/** @addtogroup ETH_Private_Functions
* @{
*/
/**
* @brief Configures Ethernet MAC and DMA with default parameters.
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @param err: Ethernet Init error
* @retval HAL status
*/
static void ETH_MACDMAConfig(ETH_HandleTypeDef *heth, uint32_t err)
{
ETH_MACInitTypeDef macinit;
ETH_DMAInitTypeDef dmainit;
uint32_t tmpreg1 = 0U;
if (err != ETH_SUCCESS) /* Auto-negotiation failed */
{
/* Set Ethernet duplex mode to Full-duplex */
(heth->Init).DuplexMode = ETH_MODE_FULLDUPLEX;
/* Set Ethernet speed to 100M */
(heth->Init).Speed = ETH_SPEED_100M;
}
/* Ethernet MAC default initialization **************************************/
macinit.Watchdog = ETH_WATCHDOG_ENABLE;
macinit.Jabber = ETH_JABBER_ENABLE;
macinit.InterFrameGap = ETH_INTERFRAMEGAP_96BIT;
macinit.CarrierSense = ETH_CARRIERSENCE_ENABLE;
macinit.ReceiveOwn = ETH_RECEIVEOWN_ENABLE;
macinit.LoopbackMode = ETH_LOOPBACKMODE_DISABLE;
if (heth->Init.ChecksumMode == ETH_CHECKSUM_BY_HARDWARE)
{
macinit.ChecksumOffload = ETH_CHECKSUMOFFLAOD_ENABLE;
}
else
{
macinit.ChecksumOffload = ETH_CHECKSUMOFFLAOD_DISABLE;
}
macinit.RetryTransmission = ETH_RETRYTRANSMISSION_DISABLE;
macinit.AutomaticPadCRCStrip = ETH_AUTOMATICPADCRCSTRIP_DISABLE;
macinit.BackOffLimit = ETH_BACKOFFLIMIT_10;
macinit.DeferralCheck = ETH_DEFFERRALCHECK_DISABLE;
macinit.ReceiveAll = ETH_RECEIVEAll_DISABLE;
macinit.SourceAddrFilter = ETH_SOURCEADDRFILTER_DISABLE;
macinit.PassControlFrames = ETH_PASSCONTROLFRAMES_BLOCKALL;
macinit.BroadcastFramesReception = ETH_BROADCASTFRAMESRECEPTION_ENABLE;
macinit.DestinationAddrFilter = ETH_DESTINATIONADDRFILTER_NORMAL;
macinit.PromiscuousMode = ETH_PROMISCUOUS_MODE_DISABLE;
macinit.MulticastFramesFilter = ETH_MULTICASTFRAMESFILTER_PERFECT;
macinit.UnicastFramesFilter = ETH_UNICASTFRAMESFILTER_PERFECT;
macinit.HashTableHigh = 0x0U;
macinit.HashTableLow = 0x0U;
macinit.PauseTime = 0x0U;
macinit.ZeroQuantaPause = ETH_ZEROQUANTAPAUSE_DISABLE;
macinit.PauseLowThreshold = ETH_PAUSELOWTHRESHOLD_MINUS4;
macinit.UnicastPauseFrameDetect = ETH_UNICASTPAUSEFRAMEDETECT_DISABLE;
macinit.ReceiveFlowControl = ETH_RECEIVEFLOWCONTROL_DISABLE;
macinit.TransmitFlowControl = ETH_TRANSMITFLOWCONTROL_DISABLE;
macinit.VLANTagComparison = ETH_VLANTAGCOMPARISON_16BIT;
macinit.VLANTagIdentifier = 0x0U;
/*------------------------ ETHERNET MACCR Configuration --------------------*/
/* Get the ETHERNET MACCR value */
tmpreg1 = (heth->Instance)->MACCR;
/* Clear WD, PCE, PS, TE and RE bits */
tmpreg1 &= ETH_MACCR_CLEAR_MASK;
/* Set the WD bit according to ETH Watchdog value */
/* Set the JD: bit according to ETH Jabber value */
/* Set the IFG bit according to ETH InterFrameGap value */
/* Set the DCRS bit according to ETH CarrierSense value */
/* Set the FES bit according to ETH Speed value */
/* Set the DO bit according to ETH ReceiveOwn value */
/* Set the LM bit according to ETH LoopbackMode value */
/* Set the DM bit according to ETH Mode value */
/* Set the IPCO bit according to ETH ChecksumOffload value */
/* Set the DR bit according to ETH RetryTransmission value */
/* Set the ACS bit according to ETH AutomaticPadCRCStrip value */
/* Set the BL bit according to ETH BackOffLimit value */
/* Set the DC bit according to ETH DeferralCheck value */
tmpreg1 |= (uint32_t)(macinit.Watchdog |
macinit.Jabber |
macinit.InterFrameGap |
macinit.CarrierSense |
(heth->Init).Speed |
macinit.ReceiveOwn |
macinit.LoopbackMode |
(heth->Init).DuplexMode |
macinit.ChecksumOffload |
macinit.RetryTransmission |
macinit.AutomaticPadCRCStrip |
macinit.BackOffLimit |
macinit.DeferralCheck);
/* Write to ETHERNET MACCR */
(heth->Instance)->MACCR = (uint32_t)tmpreg1;
/* Wait until the write operation will be taken into account:
at least four TX_CLK/RX_CLK clock cycles */
tmpreg1 = (heth->Instance)->MACCR;
HAL_Delay(ETH_REG_WRITE_DELAY);
(heth->Instance)->MACCR = tmpreg1;
/*----------------------- ETHERNET MACFFR Configuration --------------------*/
/* Set the RA bit according to ETH ReceiveAll value */
/* Set the SAF and SAIF bits according to ETH SourceAddrFilter value */
/* Set the PCF bit according to ETH PassControlFrames value */
/* Set the DBF bit according to ETH BroadcastFramesReception value */
/* Set the DAIF bit according to ETH DestinationAddrFilter value */
/* Set the PR bit according to ETH PromiscuousMode value */
/* Set the PM, HMC and HPF bits according to ETH MulticastFramesFilter value */
/* Set the HUC and HPF bits according to ETH UnicastFramesFilter value */
/* Write to ETHERNET MACFFR */
(heth->Instance)->MACFFR = (uint32_t)(macinit.ReceiveAll |
macinit.SourceAddrFilter |
macinit.PassControlFrames |
macinit.BroadcastFramesReception |
macinit.DestinationAddrFilter |
macinit.PromiscuousMode |
macinit.MulticastFramesFilter |
macinit.UnicastFramesFilter);
/* Wait until the write operation will be taken into account:
at least four TX_CLK/RX_CLK clock cycles */
tmpreg1 = (heth->Instance)->MACFFR;
HAL_Delay(ETH_REG_WRITE_DELAY);
(heth->Instance)->MACFFR = tmpreg1;
/*--------------- ETHERNET MACHTHR and MACHTLR Configuration --------------*/
/* Write to ETHERNET MACHTHR */
(heth->Instance)->MACHTHR = (uint32_t)macinit.HashTableHigh;
/* Write to ETHERNET MACHTLR */
(heth->Instance)->MACHTLR = (uint32_t)macinit.HashTableLow;
/*----------------------- ETHERNET MACFCR Configuration -------------------*/
/* Get the ETHERNET MACFCR value */
tmpreg1 = (heth->Instance)->MACFCR;
/* Clear xx bits */
tmpreg1 &= ETH_MACFCR_CLEAR_MASK;
/* Set the PT bit according to ETH PauseTime value */
/* Set the DZPQ bit according to ETH ZeroQuantaPause value */
/* Set the PLT bit according to ETH PauseLowThreshold value */
/* Set the UP bit according to ETH UnicastPauseFrameDetect value */
/* Set the RFE bit according to ETH ReceiveFlowControl value */
/* Set the TFE bit according to ETH TransmitFlowControl value */
tmpreg1 |= (uint32_t)((macinit.PauseTime << 16U) |
macinit.ZeroQuantaPause |
macinit.PauseLowThreshold |
macinit.UnicastPauseFrameDetect |
macinit.ReceiveFlowControl |
macinit.TransmitFlowControl);
/* Write to ETHERNET MACFCR */
(heth->Instance)->MACFCR = (uint32_t)tmpreg1;
/* Wait until the write operation will be taken into account:
at least four TX_CLK/RX_CLK clock cycles */
tmpreg1 = (heth->Instance)->MACFCR;
HAL_Delay(ETH_REG_WRITE_DELAY);
(heth->Instance)->MACFCR = tmpreg1;
/*----------------------- ETHERNET MACVLANTR Configuration ----------------*/
/* Set the ETV bit according to ETH VLANTagComparison value */
/* Set the VL bit according to ETH VLANTagIdentifier value */
(heth->Instance)->MACVLANTR = (uint32_t)(macinit.VLANTagComparison |
macinit.VLANTagIdentifier);
/* Wait until the write operation will be taken into account:
at least four TX_CLK/RX_CLK clock cycles */
tmpreg1 = (heth->Instance)->MACVLANTR;
HAL_Delay(ETH_REG_WRITE_DELAY);
(heth->Instance)->MACVLANTR = tmpreg1;
/* Ethernet DMA default initialization ************************************/
dmainit.DropTCPIPChecksumErrorFrame = ETH_DROPTCPIPCHECKSUMERRORFRAME_ENABLE;
dmainit.ReceiveStoreForward = ETH_RECEIVESTOREFORWARD_ENABLE;
dmainit.FlushReceivedFrame = ETH_FLUSHRECEIVEDFRAME_ENABLE;
dmainit.TransmitStoreForward = ETH_TRANSMITSTOREFORWARD_ENABLE;
dmainit.TransmitThresholdControl = ETH_TRANSMITTHRESHOLDCONTROL_64BYTES;
dmainit.ForwardErrorFrames = ETH_FORWARDERRORFRAMES_DISABLE;
dmainit.ForwardUndersizedGoodFrames = ETH_FORWARDUNDERSIZEDGOODFRAMES_DISABLE;
dmainit.ReceiveThresholdControl = ETH_RECEIVEDTHRESHOLDCONTROL_64BYTES;
dmainit.SecondFrameOperate = ETH_SECONDFRAMEOPERARTE_ENABLE;
dmainit.AddressAlignedBeats = ETH_ADDRESSALIGNEDBEATS_ENABLE;
dmainit.FixedBurst = ETH_FIXEDBURST_ENABLE;
dmainit.RxDMABurstLength = ETH_RXDMABURSTLENGTH_32BEAT;
dmainit.TxDMABurstLength = ETH_TXDMABURSTLENGTH_32BEAT;
dmainit.DescriptorSkipLength = 0x0U;
dmainit.DMAArbitration = ETH_DMAARBITRATION_ROUNDROBIN_RXTX_1_1;
/* Get the ETHERNET DMAOMR value */
tmpreg1 = (heth->Instance)->DMAOMR;
/* Clear xx bits */
tmpreg1 &= ETH_DMAOMR_CLEAR_MASK;
/* Set the DT bit according to ETH DropTCPIPChecksumErrorFrame value */
/* Set the RSF bit according to ETH ReceiveStoreForward value */
/* Set the DFF bit according to ETH FlushReceivedFrame value */
/* Set the TSF bit according to ETH TransmitStoreForward value */
/* Set the TTC bit according to ETH TransmitThresholdControl value */
/* Set the FEF bit according to ETH ForwardErrorFrames value */
/* Set the FUF bit according to ETH ForwardUndersizedGoodFrames value */
/* Set the RTC bit according to ETH ReceiveThresholdControl value */
/* Set the OSF bit according to ETH SecondFrameOperate value */
tmpreg1 |= (uint32_t)(dmainit.DropTCPIPChecksumErrorFrame |
dmainit.ReceiveStoreForward |
dmainit.FlushReceivedFrame |
dmainit.TransmitStoreForward |
dmainit.TransmitThresholdControl |
dmainit.ForwardErrorFrames |
dmainit.ForwardUndersizedGoodFrames |
dmainit.ReceiveThresholdControl |
dmainit.SecondFrameOperate);
/* Write to ETHERNET DMAOMR */
(heth->Instance)->DMAOMR = (uint32_t)tmpreg1;
/* Wait until the write operation will be taken into account:
at least four TX_CLK/RX_CLK clock cycles */
tmpreg1 = (heth->Instance)->DMAOMR;
HAL_Delay(ETH_REG_WRITE_DELAY);
(heth->Instance)->DMAOMR = tmpreg1;
/*----------------------- ETHERNET DMABMR Configuration ------------------*/
/* Set the AAL bit according to ETH AddressAlignedBeats value */
/* Set the FB bit according to ETH FixedBurst value */
/* Set the RPBL and 4*PBL bits according to ETH RxDMABurstLength value */
/* Set the PBL and 4*PBL bits according to ETH TxDMABurstLength value */
/* Set the DSL bit according to ETH DesciptorSkipLength value */
/* Set the PR and DA bits according to ETH DMAArbitration value */
(heth->Instance)->DMABMR = (uint32_t)(dmainit.AddressAlignedBeats |
dmainit.FixedBurst |
dmainit.RxDMABurstLength | /* !! if 4xPBL is selected for Tx or Rx it is applied for the other */
dmainit.TxDMABurstLength |
(dmainit.DescriptorSkipLength << 2U) |
dmainit.DMAArbitration |
ETH_DMABMR_USP); /* Enable use of separate PBL for Rx and Tx */
/* Wait until the write operation will be taken into account:
at least four TX_CLK/RX_CLK clock cycles */
tmpreg1 = (heth->Instance)->DMABMR;
HAL_Delay(ETH_REG_WRITE_DELAY);
(heth->Instance)->DMABMR = tmpreg1;
if ((heth->Init).RxMode == ETH_RXINTERRUPT_MODE)
{
/* Enable the Ethernet Rx Interrupt */
__HAL_ETH_DMA_ENABLE_IT((heth), ETH_DMA_IT_NIS | ETH_DMA_IT_R);
}
/* Initialize MAC address in ethernet MAC */
ETH_MACAddressConfig(heth, ETH_MAC_ADDRESS0, heth->Init.MACAddr);
}
/**
* @brief Configures the selected MAC address.
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @param MacAddr: The MAC address to configure
* This parameter can be one of the following values:
* @arg ETH_MAC_Address0: MAC Address0
* @arg ETH_MAC_Address1: MAC Address1
* @arg ETH_MAC_Address2: MAC Address2
* @arg ETH_MAC_Address3: MAC Address3
* @param Addr: Pointer to MAC address buffer data (6 bytes)
* @retval HAL status
*/
static void ETH_MACAddressConfig(ETH_HandleTypeDef *heth, uint32_t MacAddr, uint8_t *Addr)
{
uint32_t tmpreg1;
/* Prevent unused argument(s) compilation warning */
UNUSED(heth);
/* Check the parameters */
assert_param(IS_ETH_MAC_ADDRESS0123(MacAddr));
/* Calculate the selected MAC address high register */
tmpreg1 = ((uint32_t)Addr[5U] << 8U) | (uint32_t)Addr[4U];
/* Load the selected MAC address high register */
(*(__IO uint32_t *)((uint32_t)(ETH_MAC_ADDR_HBASE + MacAddr))) = tmpreg1;
/* Calculate the selected MAC address low register */
tmpreg1 = ((uint32_t)Addr[3U] << 24U) | ((uint32_t)Addr[2U] << 16U) | ((uint32_t)Addr[1U] << 8U) | Addr[0U];
/* Load the selected MAC address low register */
(*(__IO uint32_t *)((uint32_t)(ETH_MAC_ADDR_LBASE + MacAddr))) = tmpreg1;
}
/**
* @brief Enables the MAC transmission.
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @retval None
*/
static void ETH_MACTransmissionEnable(ETH_HandleTypeDef *heth)
{
__IO uint32_t tmpreg1 = 0U;
/* Enable the MAC transmission */
(heth->Instance)->MACCR |= ETH_MACCR_TE;
/* Wait until the write operation will be taken into account:
at least four TX_CLK/RX_CLK clock cycles */
tmpreg1 = (heth->Instance)->MACCR;
ETH_Delay(ETH_REG_WRITE_DELAY);
(heth->Instance)->MACCR = tmpreg1;
}
/**
* @brief Disables the MAC transmission.
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @retval None
*/
static void ETH_MACTransmissionDisable(ETH_HandleTypeDef *heth)
{
__IO uint32_t tmpreg1 = 0U;
/* Disable the MAC transmission */
(heth->Instance)->MACCR &= ~ETH_MACCR_TE;
/* Wait until the write operation will be taken into account:
at least four TX_CLK/RX_CLK clock cycles */
tmpreg1 = (heth->Instance)->MACCR;
ETH_Delay(ETH_REG_WRITE_DELAY);
(heth->Instance)->MACCR = tmpreg1;
}
/**
* @brief Enables the MAC reception.
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @retval None
*/
static void ETH_MACReceptionEnable(ETH_HandleTypeDef *heth)
{
__IO uint32_t tmpreg1 = 0U;
/* Enable the MAC reception */
(heth->Instance)->MACCR |= ETH_MACCR_RE;
/* Wait until the write operation will be taken into account:
at least four TX_CLK/RX_CLK clock cycles */
tmpreg1 = (heth->Instance)->MACCR;
ETH_Delay(ETH_REG_WRITE_DELAY);
(heth->Instance)->MACCR = tmpreg1;
}
/**
* @brief Disables the MAC reception.
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @retval None
*/
static void ETH_MACReceptionDisable(ETH_HandleTypeDef *heth)
{
__IO uint32_t tmpreg1 = 0U;
/* Disable the MAC reception */
(heth->Instance)->MACCR &= ~ETH_MACCR_RE;
/* Wait until the write operation will be taken into account:
at least four TX_CLK/RX_CLK clock cycles */
tmpreg1 = (heth->Instance)->MACCR;
ETH_Delay(ETH_REG_WRITE_DELAY);
(heth->Instance)->MACCR = tmpreg1;
}
/**
* @brief Enables the DMA transmission.
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @retval None
*/
static void ETH_DMATransmissionEnable(ETH_HandleTypeDef *heth)
{
/* Enable the DMA transmission */
(heth->Instance)->DMAOMR |= ETH_DMAOMR_ST;
}
/**
* @brief Disables the DMA transmission.
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @retval None
*/
static void ETH_DMATransmissionDisable(ETH_HandleTypeDef *heth)
{
/* Disable the DMA transmission */
(heth->Instance)->DMAOMR &= ~ETH_DMAOMR_ST;
}
/**
* @brief Enables the DMA reception.
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @retval None
*/
static void ETH_DMAReceptionEnable(ETH_HandleTypeDef *heth)
{
/* Enable the DMA reception */
(heth->Instance)->DMAOMR |= ETH_DMAOMR_SR;
}
/**
* @brief Disables the DMA reception.
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @retval None
*/
static void ETH_DMAReceptionDisable(ETH_HandleTypeDef *heth)
{
/* Disable the DMA reception */
(heth->Instance)->DMAOMR &= ~ETH_DMAOMR_SR;
}
/**
* @brief Clears the ETHERNET transmit FIFO.
* @param heth: pointer to a ETH_HandleTypeDef structure that contains
* the configuration information for ETHERNET module
* @retval None
*/
static void ETH_FlushTransmitFIFO(ETH_HandleTypeDef *heth)
{
__IO uint32_t tmpreg1 = 0U;
/* Set the Flush Transmit FIFO bit */
(heth->Instance)->DMAOMR |= ETH_DMAOMR_FTF;
/* Wait until the write operation will be taken into account:
at least four TX_CLK/RX_CLK clock cycles */
tmpreg1 = (heth->Instance)->DMAOMR;
ETH_Delay(ETH_REG_WRITE_DELAY);
(heth->Instance)->DMAOMR = tmpreg1;
}
/**
* @brief This function provides delay (in milliseconds) based on CPU cycles method.
* @param mdelay: specifies the delay time length, in milliseconds.
* @retval None
*/
static void ETH_Delay(uint32_t mdelay)
{
__IO uint32_t Delay = mdelay * (SystemCoreClock / 8U / 1000U);
do
{
__NOP();
}
while (Delay --);
}
#if (USE_HAL_ETH_REGISTER_CALLBACKS == 1)
static void ETH_InitCallbacksToDefault(ETH_HandleTypeDef *heth)
{
/* Init the ETH Callback settings */
heth->TxCpltCallback = HAL_ETH_TxCpltCallback; /* Legacy weak TxCpltCallback */
heth->RxCpltCallback = HAL_ETH_RxCpltCallback; /* Legacy weak RxCpltCallback */
heth->DMAErrorCallback = HAL_ETH_ErrorCallback; /* Legacy weak DMAErrorCallback */
}
#endif /* USE_HAL_ETH_REGISTER_CALLBACKS */
/**
* @}
*/
#endif /* ETH */
#endif /* HAL_ETH_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/

View File

@@ -0,0 +1,1738 @@
/**
******************************************************************************
* @file stm32f1xx_hal_hcd.c
* @author MCD Application Team
* @brief HCD HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of the USB Peripheral Controller:
* + Initialization and de-initialization functions
* + IO operation functions
* + Peripheral Control functions
* + Peripheral State functions
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
==============================================================================
##### How to use this driver #####
==============================================================================
[..]
(#)Declare a HCD_HandleTypeDef handle structure, for example:
HCD_HandleTypeDef hhcd;
(#)Fill parameters of Init structure in HCD handle
(#)Call HAL_HCD_Init() API to initialize the HCD peripheral (Core, Host core, ...)
(#)Initialize the HCD low level resources through the HAL_HCD_MspInit() API:
(##) Enable the HCD/USB Low Level interface clock using the following macros
(+++) __HAL_RCC_USB_OTG_FS_CLK_ENABLE();
(##) Initialize the related GPIO clocks
(##) Configure HCD pin-out
(##) Configure HCD NVIC interrupt
(#)Associate the Upper USB Host stack to the HAL HCD Driver:
(##) hhcd.pData = phost;
(#)Enable HCD transmission and reception:
(##) HAL_HCD_Start();
@endverbatim
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
#ifdef HAL_HCD_MODULE_ENABLED
#if defined (USB_OTG_FS)
/** @defgroup HCD HCD
* @brief HCD HAL module driver
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/** @defgroup HCD_Private_Functions HCD Private Functions
* @{
*/
static void HCD_HC_IN_IRQHandler(HCD_HandleTypeDef *hhcd, uint8_t chnum);
static void HCD_HC_OUT_IRQHandler(HCD_HandleTypeDef *hhcd, uint8_t chnum);
static void HCD_RXQLVL_IRQHandler(HCD_HandleTypeDef *hhcd);
static void HCD_Port_IRQHandler(HCD_HandleTypeDef *hhcd);
/**
* @}
*/
/* Exported functions --------------------------------------------------------*/
/** @defgroup HCD_Exported_Functions HCD Exported Functions
* @{
*/
/** @defgroup HCD_Exported_Functions_Group1 Initialization and de-initialization functions
* @brief Initialization and Configuration functions
*
@verbatim
===============================================================================
##### Initialization and de-initialization functions #####
===============================================================================
[..] This section provides functions allowing to:
@endverbatim
* @{
*/
/**
* @brief Initialize the host driver.
* @param hhcd HCD handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_HCD_Init(HCD_HandleTypeDef *hhcd)
{
/* Check the HCD handle allocation */
if (hhcd == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_HCD_ALL_INSTANCE(hhcd->Instance));
if (hhcd->State == HAL_HCD_STATE_RESET)
{
/* Allocate lock resource and initialize it */
hhcd->Lock = HAL_UNLOCKED;
#if (USE_HAL_HCD_REGISTER_CALLBACKS == 1U)
hhcd->SOFCallback = HAL_HCD_SOF_Callback;
hhcd->ConnectCallback = HAL_HCD_Connect_Callback;
hhcd->DisconnectCallback = HAL_HCD_Disconnect_Callback;
hhcd->PortEnabledCallback = HAL_HCD_PortEnabled_Callback;
hhcd->PortDisabledCallback = HAL_HCD_PortDisabled_Callback;
hhcd->HC_NotifyURBChangeCallback = HAL_HCD_HC_NotifyURBChange_Callback;
if (hhcd->MspInitCallback == NULL)
{
hhcd->MspInitCallback = HAL_HCD_MspInit;
}
/* Init the low level hardware */
hhcd->MspInitCallback(hhcd);
#else
/* Init the low level hardware : GPIO, CLOCK, NVIC... */
HAL_HCD_MspInit(hhcd);
#endif /* (USE_HAL_HCD_REGISTER_CALLBACKS) */
}
hhcd->State = HAL_HCD_STATE_BUSY;
/* Disable DMA mode for FS instance */
hhcd->Init.dma_enable = 0U;
/* Disable the Interrupts */
__HAL_HCD_DISABLE(hhcd);
/* Init the Core (common init.) */
if (USB_CoreInit(hhcd->Instance, hhcd->Init) != HAL_OK)
{
hhcd->State = HAL_HCD_STATE_ERROR;
return HAL_ERROR;
}
/* Force Host Mode */
if (USB_SetCurrentMode(hhcd->Instance, USB_HOST_MODE) != HAL_OK)
{
hhcd->State = HAL_HCD_STATE_ERROR;
return HAL_ERROR;
}
/* Init Host */
if (USB_HostInit(hhcd->Instance, hhcd->Init) != HAL_OK)
{
hhcd->State = HAL_HCD_STATE_ERROR;
return HAL_ERROR;
}
hhcd->State = HAL_HCD_STATE_READY;
return HAL_OK;
}
/**
* @brief Initialize a host channel.
* @param hhcd HCD handle
* @param ch_num Channel number.
* This parameter can be a value from 1 to 15
* @param epnum Endpoint number.
* This parameter can be a value from 1 to 15
* @param dev_address Current device address
* This parameter can be a value from 0 to 255
* @param speed Current device speed.
* This parameter can be one of these values:
* HCD_DEVICE_SPEED_FULL: Full speed mode,
* HCD_DEVICE_SPEED_LOW: Low speed mode
* @param ep_type Endpoint Type.
* This parameter can be one of these values:
* EP_TYPE_CTRL: Control type,
* EP_TYPE_ISOC: Isochronous type,
* EP_TYPE_BULK: Bulk type,
* EP_TYPE_INTR: Interrupt type
* @param mps Max Packet Size.
* This parameter can be a value from 0 to32K
* @retval HAL status
*/
HAL_StatusTypeDef HAL_HCD_HC_Init(HCD_HandleTypeDef *hhcd, uint8_t ch_num, uint8_t epnum,
uint8_t dev_address, uint8_t speed, uint8_t ep_type, uint16_t mps)
{
HAL_StatusTypeDef status;
uint32_t HCcharMps = mps;
__HAL_LOCK(hhcd);
hhcd->hc[ch_num].do_ping = 0U;
hhcd->hc[ch_num].dev_addr = dev_address;
hhcd->hc[ch_num].ch_num = ch_num;
hhcd->hc[ch_num].ep_type = ep_type;
hhcd->hc[ch_num].ep_num = epnum & 0x7FU;
(void)HAL_HCD_HC_ClearHubInfo(hhcd, ch_num);
if ((epnum & 0x80U) == 0x80U)
{
hhcd->hc[ch_num].ep_is_in = 1U;
}
else
{
hhcd->hc[ch_num].ep_is_in = 0U;
}
hhcd->hc[ch_num].speed = speed;
hhcd->hc[ch_num].max_packet = (uint16_t)HCcharMps;
status = USB_HC_Init(hhcd->Instance, ch_num, epnum,
dev_address, speed, ep_type, (uint16_t)HCcharMps);
__HAL_UNLOCK(hhcd);
return status;
}
/**
* @brief Halt a host channel.
* @param hhcd HCD handle
* @param ch_num Channel number.
* This parameter can be a value from 1 to 15
* @retval HAL status
*/
HAL_StatusTypeDef HAL_HCD_HC_Halt(HCD_HandleTypeDef *hhcd, uint8_t ch_num)
{
HAL_StatusTypeDef status = HAL_OK;
__HAL_LOCK(hhcd);
(void)USB_HC_Halt(hhcd->Instance, ch_num);
__HAL_UNLOCK(hhcd);
return status;
}
/**
* @brief DeInitialize the host driver.
* @param hhcd HCD handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_HCD_DeInit(HCD_HandleTypeDef *hhcd)
{
/* Check the HCD handle allocation */
if (hhcd == NULL)
{
return HAL_ERROR;
}
hhcd->State = HAL_HCD_STATE_BUSY;
#if (USE_HAL_HCD_REGISTER_CALLBACKS == 1U)
if (hhcd->MspDeInitCallback == NULL)
{
hhcd->MspDeInitCallback = HAL_HCD_MspDeInit; /* Legacy weak MspDeInit */
}
/* DeInit the low level hardware */
hhcd->MspDeInitCallback(hhcd);
#else
/* DeInit the low level hardware: CLOCK, NVIC.*/
HAL_HCD_MspDeInit(hhcd);
#endif /* USE_HAL_HCD_REGISTER_CALLBACKS */
__HAL_HCD_DISABLE(hhcd);
hhcd->State = HAL_HCD_STATE_RESET;
return HAL_OK;
}
/**
* @brief Initialize the HCD MSP.
* @param hhcd HCD handle
* @retval None
*/
__weak void HAL_HCD_MspInit(HCD_HandleTypeDef *hhcd)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hhcd);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_HCD_MspInit could be implemented in the user file
*/
}
/**
* @brief DeInitialize the HCD MSP.
* @param hhcd HCD handle
* @retval None
*/
__weak void HAL_HCD_MspDeInit(HCD_HandleTypeDef *hhcd)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hhcd);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_HCD_MspDeInit could be implemented in the user file
*/
}
/**
* @}
*/
/** @defgroup HCD_Exported_Functions_Group2 Input and Output operation functions
* @brief HCD IO operation functions
*
@verbatim
===============================================================================
##### IO operation functions #####
===============================================================================
[..] This subsection provides a set of functions allowing to manage the USB Host Data
Transfer
@endverbatim
* @{
*/
/**
* @brief Submit a new URB for processing.
* @param hhcd HCD handle
* @param ch_num Channel number.
* This parameter can be a value from 1 to 15
* @param direction Channel number.
* This parameter can be one of these values:
* 0 : Output / 1 : Input
* @param ep_type Endpoint Type.
* This parameter can be one of these values:
* EP_TYPE_CTRL: Control type/
* EP_TYPE_ISOC: Isochronous type/
* EP_TYPE_BULK: Bulk type/
* EP_TYPE_INTR: Interrupt type/
* @param token Endpoint Type.
* This parameter can be one of these values:
* 0: HC_PID_SETUP / 1: HC_PID_DATA1
* @param pbuff pointer to URB data
* @param length Length of URB data
* @param do_ping activate do ping protocol (for high speed only).
* This parameter can be one of these values:
* 0 : do ping inactive / 1 : do ping active
* @retval HAL status
*/
HAL_StatusTypeDef HAL_HCD_HC_SubmitRequest(HCD_HandleTypeDef *hhcd,
uint8_t ch_num,
uint8_t direction,
uint8_t ep_type,
uint8_t token,
uint8_t *pbuff,
uint16_t length,
uint8_t do_ping)
{
hhcd->hc[ch_num].ep_is_in = direction;
hhcd->hc[ch_num].ep_type = ep_type;
if (token == 0U)
{
hhcd->hc[ch_num].data_pid = HC_PID_SETUP;
hhcd->hc[ch_num].do_ping = do_ping;
}
else
{
hhcd->hc[ch_num].data_pid = HC_PID_DATA1;
}
/* Manage Data Toggle */
switch (ep_type)
{
case EP_TYPE_CTRL:
if (token == 1U) /* send data */
{
if (direction == 0U)
{
if (length == 0U)
{
/* For Status OUT stage, Length == 0U, Status Out PID = 1 */
hhcd->hc[ch_num].toggle_out = 1U;
}
/* Set the Data Toggle bit as per the Flag */
if (hhcd->hc[ch_num].toggle_out == 0U)
{
/* Put the PID 0 */
hhcd->hc[ch_num].data_pid = HC_PID_DATA0;
}
else
{
/* Put the PID 1 */
hhcd->hc[ch_num].data_pid = HC_PID_DATA1;
}
}
}
break;
case EP_TYPE_BULK:
if (direction == 0U)
{
/* Set the Data Toggle bit as per the Flag */
if (hhcd->hc[ch_num].toggle_out == 0U)
{
/* Put the PID 0 */
hhcd->hc[ch_num].data_pid = HC_PID_DATA0;
}
else
{
/* Put the PID 1 */
hhcd->hc[ch_num].data_pid = HC_PID_DATA1;
}
}
else
{
if (hhcd->hc[ch_num].toggle_in == 0U)
{
hhcd->hc[ch_num].data_pid = HC_PID_DATA0;
}
else
{
hhcd->hc[ch_num].data_pid = HC_PID_DATA1;
}
}
break;
case EP_TYPE_INTR:
if (direction == 0U)
{
/* Set the Data Toggle bit as per the Flag */
if (hhcd->hc[ch_num].toggle_out == 0U)
{
/* Put the PID 0 */
hhcd->hc[ch_num].data_pid = HC_PID_DATA0;
}
else
{
/* Put the PID 1 */
hhcd->hc[ch_num].data_pid = HC_PID_DATA1;
}
}
else
{
if (hhcd->hc[ch_num].toggle_in == 0U)
{
hhcd->hc[ch_num].data_pid = HC_PID_DATA0;
}
else
{
hhcd->hc[ch_num].data_pid = HC_PID_DATA1;
}
}
break;
case EP_TYPE_ISOC:
hhcd->hc[ch_num].data_pid = HC_PID_DATA0;
break;
default:
break;
}
hhcd->hc[ch_num].xfer_buff = pbuff;
hhcd->hc[ch_num].xfer_len = length;
hhcd->hc[ch_num].urb_state = URB_IDLE;
hhcd->hc[ch_num].xfer_count = 0U;
hhcd->hc[ch_num].ch_num = ch_num;
hhcd->hc[ch_num].state = HC_IDLE;
return USB_HC_StartXfer(hhcd->Instance, &hhcd->hc[ch_num]);
}
/**
* @brief Handle HCD interrupt request.
* @param hhcd HCD handle
* @retval None
*/
void HAL_HCD_IRQHandler(HCD_HandleTypeDef *hhcd)
{
USB_OTG_GlobalTypeDef *USBx = hhcd->Instance;
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t i;
uint32_t interrupt;
/* Ensure that we are in device mode */
if (USB_GetMode(hhcd->Instance) == USB_OTG_MODE_HOST)
{
/* Avoid spurious interrupt */
if (__HAL_HCD_IS_INVALID_INTERRUPT(hhcd))
{
return;
}
if (__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_PXFR_INCOMPISOOUT))
{
/* Incorrect mode, acknowledge the interrupt */
__HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_PXFR_INCOMPISOOUT);
}
if (__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_IISOIXFR))
{
/* Incorrect mode, acknowledge the interrupt */
__HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_IISOIXFR);
}
if (__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_PTXFE))
{
/* Incorrect mode, acknowledge the interrupt */
__HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_PTXFE);
}
if (__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_MMIS))
{
/* Incorrect mode, acknowledge the interrupt */
__HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_MMIS);
}
/* Handle Host Disconnect Interrupts */
if (__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_DISCINT))
{
__HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_DISCINT);
if ((USBx_HPRT0 & USB_OTG_HPRT_PCSTS) == 0U)
{
/* Flush USB Fifo */
(void)USB_FlushTxFifo(USBx, 0x10U);
(void)USB_FlushRxFifo(USBx);
if (hhcd->Init.phy_itface == USB_OTG_EMBEDDED_PHY)
{
/* Restore FS Clock */
(void)USB_InitFSLSPClkSel(hhcd->Instance, HCFG_48_MHZ);
}
/* Handle Host Port Disconnect Interrupt */
#if (USE_HAL_HCD_REGISTER_CALLBACKS == 1U)
hhcd->DisconnectCallback(hhcd);
#else
HAL_HCD_Disconnect_Callback(hhcd);
#endif /* USE_HAL_HCD_REGISTER_CALLBACKS */
}
}
/* Handle Host Port Interrupts */
if (__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_HPRTINT))
{
HCD_Port_IRQHandler(hhcd);
}
/* Handle Host SOF Interrupt */
if (__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_SOF))
{
#if (USE_HAL_HCD_REGISTER_CALLBACKS == 1U)
hhcd->SOFCallback(hhcd);
#else
HAL_HCD_SOF_Callback(hhcd);
#endif /* USE_HAL_HCD_REGISTER_CALLBACKS */
__HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_SOF);
}
/* Handle Host channel Interrupt */
if (__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_HCINT))
{
interrupt = USB_HC_ReadInterrupt(hhcd->Instance);
for (i = 0U; i < hhcd->Init.Host_channels; i++)
{
if ((interrupt & (1UL << (i & 0xFU))) != 0U)
{
if ((USBx_HC(i)->HCCHAR & USB_OTG_HCCHAR_EPDIR) == USB_OTG_HCCHAR_EPDIR)
{
HCD_HC_IN_IRQHandler(hhcd, (uint8_t)i);
}
else
{
HCD_HC_OUT_IRQHandler(hhcd, (uint8_t)i);
}
}
}
__HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_HCINT);
}
/* Handle Rx Queue Level Interrupts */
if ((__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_RXFLVL)) != 0U)
{
USB_MASK_INTERRUPT(hhcd->Instance, USB_OTG_GINTSTS_RXFLVL);
HCD_RXQLVL_IRQHandler(hhcd);
USB_UNMASK_INTERRUPT(hhcd->Instance, USB_OTG_GINTSTS_RXFLVL);
}
}
}
/**
* @brief Handles HCD Wakeup interrupt request.
* @param hhcd HCD handle
* @retval HAL status
*/
void HAL_HCD_WKUP_IRQHandler(HCD_HandleTypeDef *hhcd)
{
UNUSED(hhcd);
}
/**
* @brief SOF callback.
* @param hhcd HCD handle
* @retval None
*/
__weak void HAL_HCD_SOF_Callback(HCD_HandleTypeDef *hhcd)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hhcd);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_HCD_SOF_Callback could be implemented in the user file
*/
}
/**
* @brief Connection Event callback.
* @param hhcd HCD handle
* @retval None
*/
__weak void HAL_HCD_Connect_Callback(HCD_HandleTypeDef *hhcd)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hhcd);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_HCD_Connect_Callback could be implemented in the user file
*/
}
/**
* @brief Disconnection Event callback.
* @param hhcd HCD handle
* @retval None
*/
__weak void HAL_HCD_Disconnect_Callback(HCD_HandleTypeDef *hhcd)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hhcd);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_HCD_Disconnect_Callback could be implemented in the user file
*/
}
/**
* @brief Port Enabled Event callback.
* @param hhcd HCD handle
* @retval None
*/
__weak void HAL_HCD_PortEnabled_Callback(HCD_HandleTypeDef *hhcd)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hhcd);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_HCD_Disconnect_Callback could be implemented in the user file
*/
}
/**
* @brief Port Disabled Event callback.
* @param hhcd HCD handle
* @retval None
*/
__weak void HAL_HCD_PortDisabled_Callback(HCD_HandleTypeDef *hhcd)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hhcd);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_HCD_Disconnect_Callback could be implemented in the user file
*/
}
/**
* @brief Notify URB state change callback.
* @param hhcd HCD handle
* @param chnum Channel number.
* This parameter can be a value from 1 to 15
* @param urb_state:
* This parameter can be one of these values:
* URB_IDLE/
* URB_DONE/
* URB_NOTREADY/
* URB_NYET/
* URB_ERROR/
* URB_STALL/
* @retval None
*/
__weak void HAL_HCD_HC_NotifyURBChange_Callback(HCD_HandleTypeDef *hhcd, uint8_t chnum, HCD_URBStateTypeDef urb_state)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hhcd);
UNUSED(chnum);
UNUSED(urb_state);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_HCD_HC_NotifyURBChange_Callback could be implemented in the user file
*/
}
#if (USE_HAL_HCD_REGISTER_CALLBACKS == 1U)
/**
* @brief Register a User USB HCD Callback
* To be used instead of the weak predefined callback
* @param hhcd USB HCD handle
* @param CallbackID ID of the callback to be registered
* This parameter can be one of the following values:
* @arg @ref HAL_HCD_SOF_CB_ID USB HCD SOF callback ID
* @arg @ref HAL_HCD_CONNECT_CB_ID USB HCD Connect callback ID
* @arg @ref HAL_HCD_DISCONNECT_CB_ID OTG HCD Disconnect callback ID
* @arg @ref HAL_HCD_PORT_ENABLED_CB_ID USB HCD Port Enable callback ID
* @arg @ref HAL_HCD_PORT_DISABLED_CB_ID USB HCD Port Disable callback ID
* @arg @ref HAL_HCD_MSPINIT_CB_ID MspDeInit callback ID
* @arg @ref HAL_HCD_MSPDEINIT_CB_ID MspDeInit callback ID
* @param pCallback pointer to the Callback function
* @retval HAL status
*/
HAL_StatusTypeDef HAL_HCD_RegisterCallback(HCD_HandleTypeDef *hhcd,
HAL_HCD_CallbackIDTypeDef CallbackID,
pHCD_CallbackTypeDef pCallback)
{
HAL_StatusTypeDef status = HAL_OK;
if (pCallback == NULL)
{
/* Update the error code */
hhcd->ErrorCode |= HAL_HCD_ERROR_INVALID_CALLBACK;
return HAL_ERROR;
}
/* Process locked */
__HAL_LOCK(hhcd);
if (hhcd->State == HAL_HCD_STATE_READY)
{
switch (CallbackID)
{
case HAL_HCD_SOF_CB_ID :
hhcd->SOFCallback = pCallback;
break;
case HAL_HCD_CONNECT_CB_ID :
hhcd->ConnectCallback = pCallback;
break;
case HAL_HCD_DISCONNECT_CB_ID :
hhcd->DisconnectCallback = pCallback;
break;
case HAL_HCD_PORT_ENABLED_CB_ID :
hhcd->PortEnabledCallback = pCallback;
break;
case HAL_HCD_PORT_DISABLED_CB_ID :
hhcd->PortDisabledCallback = pCallback;
break;
case HAL_HCD_MSPINIT_CB_ID :
hhcd->MspInitCallback = pCallback;
break;
case HAL_HCD_MSPDEINIT_CB_ID :
hhcd->MspDeInitCallback = pCallback;
break;
default :
/* Update the error code */
hhcd->ErrorCode |= HAL_HCD_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else if (hhcd->State == HAL_HCD_STATE_RESET)
{
switch (CallbackID)
{
case HAL_HCD_MSPINIT_CB_ID :
hhcd->MspInitCallback = pCallback;
break;
case HAL_HCD_MSPDEINIT_CB_ID :
hhcd->MspDeInitCallback = pCallback;
break;
default :
/* Update the error code */
hhcd->ErrorCode |= HAL_HCD_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else
{
/* Update the error code */
hhcd->ErrorCode |= HAL_HCD_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(hhcd);
return status;
}
/**
* @brief Unregister an USB HCD Callback
* USB HCD callback is redirected to the weak predefined callback
* @param hhcd USB HCD handle
* @param CallbackID ID of the callback to be unregistered
* This parameter can be one of the following values:
* @arg @ref HAL_HCD_SOF_CB_ID USB HCD SOF callback ID
* @arg @ref HAL_HCD_CONNECT_CB_ID USB HCD Connect callback ID
* @arg @ref HAL_HCD_DISCONNECT_CB_ID OTG HCD Disconnect callback ID
* @arg @ref HAL_HCD_PORT_ENABLED_CB_ID USB HCD Port Enabled callback ID
* @arg @ref HAL_HCD_PORT_DISABLED_CB_ID USB HCD Port Disabled callback ID
* @arg @ref HAL_HCD_MSPINIT_CB_ID MspDeInit callback ID
* @arg @ref HAL_HCD_MSPDEINIT_CB_ID MspDeInit callback ID
* @retval HAL status
*/
HAL_StatusTypeDef HAL_HCD_UnRegisterCallback(HCD_HandleTypeDef *hhcd, HAL_HCD_CallbackIDTypeDef CallbackID)
{
HAL_StatusTypeDef status = HAL_OK;
/* Process locked */
__HAL_LOCK(hhcd);
/* Setup Legacy weak Callbacks */
if (hhcd->State == HAL_HCD_STATE_READY)
{
switch (CallbackID)
{
case HAL_HCD_SOF_CB_ID :
hhcd->SOFCallback = HAL_HCD_SOF_Callback;
break;
case HAL_HCD_CONNECT_CB_ID :
hhcd->ConnectCallback = HAL_HCD_Connect_Callback;
break;
case HAL_HCD_DISCONNECT_CB_ID :
hhcd->DisconnectCallback = HAL_HCD_Disconnect_Callback;
break;
case HAL_HCD_PORT_ENABLED_CB_ID :
hhcd->PortEnabledCallback = HAL_HCD_PortEnabled_Callback;
break;
case HAL_HCD_PORT_DISABLED_CB_ID :
hhcd->PortDisabledCallback = HAL_HCD_PortDisabled_Callback;
break;
case HAL_HCD_MSPINIT_CB_ID :
hhcd->MspInitCallback = HAL_HCD_MspInit;
break;
case HAL_HCD_MSPDEINIT_CB_ID :
hhcd->MspDeInitCallback = HAL_HCD_MspDeInit;
break;
default :
/* Update the error code */
hhcd->ErrorCode |= HAL_HCD_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else if (hhcd->State == HAL_HCD_STATE_RESET)
{
switch (CallbackID)
{
case HAL_HCD_MSPINIT_CB_ID :
hhcd->MspInitCallback = HAL_HCD_MspInit;
break;
case HAL_HCD_MSPDEINIT_CB_ID :
hhcd->MspDeInitCallback = HAL_HCD_MspDeInit;
break;
default :
/* Update the error code */
hhcd->ErrorCode |= HAL_HCD_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else
{
/* Update the error code */
hhcd->ErrorCode |= HAL_HCD_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(hhcd);
return status;
}
/**
* @brief Register USB HCD Host Channel Notify URB Change Callback
* To be used instead of the weak HAL_HCD_HC_NotifyURBChange_Callback() predefined callback
* @param hhcd HCD handle
* @param pCallback pointer to the USB HCD Host Channel Notify URB Change Callback function
* @retval HAL status
*/
HAL_StatusTypeDef HAL_HCD_RegisterHC_NotifyURBChangeCallback(HCD_HandleTypeDef *hhcd,
pHCD_HC_NotifyURBChangeCallbackTypeDef pCallback)
{
HAL_StatusTypeDef status = HAL_OK;
if (pCallback == NULL)
{
/* Update the error code */
hhcd->ErrorCode |= HAL_HCD_ERROR_INVALID_CALLBACK;
return HAL_ERROR;
}
/* Process locked */
__HAL_LOCK(hhcd);
if (hhcd->State == HAL_HCD_STATE_READY)
{
hhcd->HC_NotifyURBChangeCallback = pCallback;
}
else
{
/* Update the error code */
hhcd->ErrorCode |= HAL_HCD_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(hhcd);
return status;
}
/**
* @brief Unregister the USB HCD Host Channel Notify URB Change Callback
* USB HCD Host Channel Notify URB Change Callback is redirected
* to the weak HAL_HCD_HC_NotifyURBChange_Callback() predefined callback
* @param hhcd HCD handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_HCD_UnRegisterHC_NotifyURBChangeCallback(HCD_HandleTypeDef *hhcd)
{
HAL_StatusTypeDef status = HAL_OK;
/* Process locked */
__HAL_LOCK(hhcd);
if (hhcd->State == HAL_HCD_STATE_READY)
{
hhcd->HC_NotifyURBChangeCallback = HAL_HCD_HC_NotifyURBChange_Callback; /* Legacy weak DataOutStageCallback */
}
else
{
/* Update the error code */
hhcd->ErrorCode |= HAL_HCD_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(hhcd);
return status;
}
#endif /* USE_HAL_HCD_REGISTER_CALLBACKS */
/**
* @}
*/
/** @defgroup HCD_Exported_Functions_Group3 Peripheral Control functions
* @brief Management functions
*
@verbatim
===============================================================================
##### Peripheral Control functions #####
===============================================================================
[..]
This subsection provides a set of functions allowing to control the HCD data
transfers.
@endverbatim
* @{
*/
/**
* @brief Start the host driver.
* @param hhcd HCD handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_HCD_Start(HCD_HandleTypeDef *hhcd)
{
__HAL_LOCK(hhcd);
/* Enable port power */
(void)USB_DriveVbus(hhcd->Instance, 1U);
/* Enable global interrupt */
__HAL_HCD_ENABLE(hhcd);
__HAL_UNLOCK(hhcd);
return HAL_OK;
}
/**
* @brief Stop the host driver.
* @param hhcd HCD handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_HCD_Stop(HCD_HandleTypeDef *hhcd)
{
__HAL_LOCK(hhcd);
(void)USB_StopHost(hhcd->Instance);
__HAL_UNLOCK(hhcd);
return HAL_OK;
}
/**
* @brief Reset the host port.
* @param hhcd HCD handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_HCD_ResetPort(HCD_HandleTypeDef *hhcd)
{
return (USB_ResetPort(hhcd->Instance));
}
/**
* @}
*/
/** @defgroup HCD_Exported_Functions_Group4 Peripheral State functions
* @brief Peripheral State functions
*
@verbatim
===============================================================================
##### Peripheral State functions #####
===============================================================================
[..]
This subsection permits to get in run-time the status of the peripheral
and the data flow.
@endverbatim
* @{
*/
/**
* @brief Return the HCD handle state.
* @param hhcd HCD handle
* @retval HAL state
*/
HCD_StateTypeDef HAL_HCD_GetState(HCD_HandleTypeDef const *hhcd)
{
return hhcd->State;
}
/**
* @brief Return URB state for a channel.
* @param hhcd HCD handle
* @param chnum Channel number.
* This parameter can be a value from 1 to 15
* @retval URB state.
* This parameter can be one of these values:
* URB_IDLE/
* URB_DONE/
* URB_NOTREADY/
* URB_NYET/
* URB_ERROR/
* URB_STALL
*/
HCD_URBStateTypeDef HAL_HCD_HC_GetURBState(HCD_HandleTypeDef const *hhcd, uint8_t chnum)
{
return hhcd->hc[chnum].urb_state;
}
/**
* @brief Return the last host transfer size.
* @param hhcd HCD handle
* @param chnum Channel number.
* This parameter can be a value from 1 to 15
* @retval last transfer size in byte
*/
uint32_t HAL_HCD_HC_GetXferCount(HCD_HandleTypeDef const *hhcd, uint8_t chnum)
{
return hhcd->hc[chnum].xfer_count;
}
/**
* @brief Return the Host Channel state.
* @param hhcd HCD handle
* @param chnum Channel number.
* This parameter can be a value from 1 to 15
* @retval Host channel state
* This parameter can be one of these values:
* HC_IDLE/
* HC_XFRC/
* HC_HALTED/
* HC_NYET/
* HC_NAK/
* HC_STALL/
* HC_XACTERR/
* HC_BBLERR/
* HC_DATATGLERR
*/
HCD_HCStateTypeDef HAL_HCD_HC_GetState(HCD_HandleTypeDef const *hhcd, uint8_t chnum)
{
return hhcd->hc[chnum].state;
}
/**
* @brief Return the current Host frame number.
* @param hhcd HCD handle
* @retval Current Host frame number
*/
uint32_t HAL_HCD_GetCurrentFrame(HCD_HandleTypeDef *hhcd)
{
return (USB_GetCurrentFrame(hhcd->Instance));
}
/**
* @brief Return the Host enumeration speed.
* @param hhcd HCD handle
* @retval Enumeration speed
*/
uint32_t HAL_HCD_GetCurrentSpeed(HCD_HandleTypeDef *hhcd)
{
return (USB_GetHostSpeed(hhcd->Instance));
}
/**
* @brief Set host channel Hub information.
* @param hhcd HCD handle
* @param ch_num Channel number.
* This parameter can be a value from 1 to 15
* @param addr Hub address
* @param PortNbr Hub port number
* @retval HAL status
*/
HAL_StatusTypeDef HAL_HCD_HC_SetHubInfo(HCD_HandleTypeDef *hhcd, uint8_t ch_num,
uint8_t addr, uint8_t PortNbr)
{
hhcd->hc[ch_num].hub_addr = addr;
hhcd->hc[ch_num].hub_port_nbr = PortNbr;
return HAL_OK;
}
/**
* @brief Clear host channel hub information.
* @param hhcd HCD handle
* @param ch_num Channel number.
* This parameter can be a value from 1 to 15
* @retval HAL status
*/
HAL_StatusTypeDef HAL_HCD_HC_ClearHubInfo(HCD_HandleTypeDef *hhcd, uint8_t ch_num)
{
hhcd->hc[ch_num].hub_addr = 0U;
hhcd->hc[ch_num].hub_port_nbr = 0U;
return HAL_OK;
}
/**
* @}
*/
/**
* @}
*/
/** @addtogroup HCD_Private_Functions
* @{
*/
/**
* @brief Handle Host Channel IN interrupt requests.
* @param hhcd HCD handle
* @param chnum Channel number.
* This parameter can be a value from 1 to 15
* @retval none
*/
static void HCD_HC_IN_IRQHandler(HCD_HandleTypeDef *hhcd, uint8_t chnum)
{
const USB_OTG_GlobalTypeDef *USBx = hhcd->Instance;
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t tmpreg;
if (__HAL_HCD_GET_CH_FLAG(hhcd, chnum, USB_OTG_HCINT_AHBERR))
{
__HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_AHBERR);
hhcd->hc[chnum].state = HC_XACTERR;
(void)USB_HC_Halt(hhcd->Instance, chnum);
}
else if (__HAL_HCD_GET_CH_FLAG(hhcd, chnum, USB_OTG_HCINT_BBERR))
{
__HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_BBERR);
hhcd->hc[chnum].state = HC_BBLERR;
(void)USB_HC_Halt(hhcd->Instance, chnum);
}
else if (__HAL_HCD_GET_CH_FLAG(hhcd, chnum, USB_OTG_HCINT_STALL))
{
__HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_STALL);
hhcd->hc[chnum].state = HC_STALL;
(void)USB_HC_Halt(hhcd->Instance, chnum);
}
else if (__HAL_HCD_GET_CH_FLAG(hhcd, chnum, USB_OTG_HCINT_DTERR))
{
__HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_DTERR);
hhcd->hc[chnum].state = HC_DATATGLERR;
(void)USB_HC_Halt(hhcd->Instance, chnum);
}
else if (__HAL_HCD_GET_CH_FLAG(hhcd, chnum, USB_OTG_HCINT_TXERR))
{
__HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_TXERR);
hhcd->hc[chnum].state = HC_XACTERR;
(void)USB_HC_Halt(hhcd->Instance, chnum);
}
else
{
/* ... */
}
if (__HAL_HCD_GET_CH_FLAG(hhcd, chnum, USB_OTG_HCINT_FRMOR))
{
(void)USB_HC_Halt(hhcd->Instance, chnum);
__HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_FRMOR);
}
else if (__HAL_HCD_GET_CH_FLAG(hhcd, chnum, USB_OTG_HCINT_XFRC))
{
hhcd->hc[chnum].state = HC_XFRC;
hhcd->hc[chnum].ErrCnt = 0U;
__HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_XFRC);
if ((hhcd->hc[chnum].ep_type == EP_TYPE_CTRL) ||
(hhcd->hc[chnum].ep_type == EP_TYPE_BULK))
{
(void)USB_HC_Halt(hhcd->Instance, chnum);
__HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NAK);
}
else if ((hhcd->hc[chnum].ep_type == EP_TYPE_INTR) ||
(hhcd->hc[chnum].ep_type == EP_TYPE_ISOC))
{
USBx_HC(chnum)->HCCHAR |= USB_OTG_HCCHAR_ODDFRM;
hhcd->hc[chnum].urb_state = URB_DONE;
#if (USE_HAL_HCD_REGISTER_CALLBACKS == 1U)
hhcd->HC_NotifyURBChangeCallback(hhcd, chnum, hhcd->hc[chnum].urb_state);
#else
HAL_HCD_HC_NotifyURBChange_Callback(hhcd, chnum, hhcd->hc[chnum].urb_state);
#endif /* USE_HAL_HCD_REGISTER_CALLBACKS */
}
else
{
/* ... */
}
if (hhcd->Init.dma_enable == 1U)
{
if ((((hhcd->hc[chnum].xfer_count + hhcd->hc[chnum].max_packet - 1U) / hhcd->hc[chnum].max_packet) & 1U) != 0U)
{
hhcd->hc[chnum].toggle_in ^= 1U;
}
}
else
{
hhcd->hc[chnum].toggle_in ^= 1U;
}
}
else if (__HAL_HCD_GET_CH_FLAG(hhcd, chnum, USB_OTG_HCINT_ACK))
{
__HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_ACK);
}
else if (__HAL_HCD_GET_CH_FLAG(hhcd, chnum, USB_OTG_HCINT_CHH))
{
__HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_CHH);
if (hhcd->hc[chnum].state == HC_XFRC)
{
hhcd->hc[chnum].state = HC_HALTED;
hhcd->hc[chnum].urb_state = URB_DONE;
}
else if (hhcd->hc[chnum].state == HC_STALL)
{
hhcd->hc[chnum].state = HC_HALTED;
hhcd->hc[chnum].urb_state = URB_STALL;
}
else if ((hhcd->hc[chnum].state == HC_XACTERR) ||
(hhcd->hc[chnum].state == HC_DATATGLERR))
{
hhcd->hc[chnum].state = HC_HALTED;
hhcd->hc[chnum].ErrCnt++;
if (hhcd->hc[chnum].ErrCnt > 2U)
{
hhcd->hc[chnum].ErrCnt = 0U;
hhcd->hc[chnum].urb_state = URB_ERROR;
}
else
{
hhcd->hc[chnum].urb_state = URB_NOTREADY;
if ((hhcd->hc[chnum].ep_type == EP_TYPE_CTRL) ||
(hhcd->hc[chnum].ep_type == EP_TYPE_BULK))
{
/* re-activate the channel */
tmpreg = USBx_HC(chnum)->HCCHAR;
tmpreg &= ~USB_OTG_HCCHAR_CHDIS;
tmpreg |= USB_OTG_HCCHAR_CHENA;
USBx_HC(chnum)->HCCHAR = tmpreg;
}
}
}
else if (hhcd->hc[chnum].state == HC_NYET)
{
hhcd->hc[chnum].state = HC_HALTED;
}
else if (hhcd->hc[chnum].state == HC_ACK)
{
hhcd->hc[chnum].state = HC_HALTED;
}
else if (hhcd->hc[chnum].state == HC_NAK)
{
hhcd->hc[chnum].state = HC_HALTED;
hhcd->hc[chnum].urb_state = URB_NOTREADY;
if ((hhcd->hc[chnum].ep_type == EP_TYPE_CTRL) ||
(hhcd->hc[chnum].ep_type == EP_TYPE_BULK))
{
/* re-activate the channel */
tmpreg = USBx_HC(chnum)->HCCHAR;
tmpreg &= ~USB_OTG_HCCHAR_CHDIS;
tmpreg |= USB_OTG_HCCHAR_CHENA;
USBx_HC(chnum)->HCCHAR = tmpreg;
}
}
else if (hhcd->hc[chnum].state == HC_BBLERR)
{
hhcd->hc[chnum].state = HC_HALTED;
hhcd->hc[chnum].ErrCnt++;
hhcd->hc[chnum].urb_state = URB_ERROR;
}
else
{
if (hhcd->hc[chnum].state == HC_HALTED)
{
return;
}
}
#if (USE_HAL_HCD_REGISTER_CALLBACKS == 1U)
hhcd->HC_NotifyURBChangeCallback(hhcd, chnum, hhcd->hc[chnum].urb_state);
#else
HAL_HCD_HC_NotifyURBChange_Callback(hhcd, chnum, hhcd->hc[chnum].urb_state);
#endif /* USE_HAL_HCD_REGISTER_CALLBACKS */
}
else if (__HAL_HCD_GET_CH_FLAG(hhcd, chnum, USB_OTG_HCINT_NYET))
{
__HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NYET);
hhcd->hc[chnum].state = HC_NYET;
hhcd->hc[chnum].ErrCnt = 0U;
(void)USB_HC_Halt(hhcd->Instance, chnum);
}
else if (__HAL_HCD_GET_CH_FLAG(hhcd, chnum, USB_OTG_HCINT_NAK))
{
if (hhcd->hc[chnum].ep_type == EP_TYPE_INTR)
{
hhcd->hc[chnum].ErrCnt = 0U;
hhcd->hc[chnum].state = HC_NAK;
(void)USB_HC_Halt(hhcd->Instance, chnum);
}
else if ((hhcd->hc[chnum].ep_type == EP_TYPE_CTRL) ||
(hhcd->hc[chnum].ep_type == EP_TYPE_BULK))
{
hhcd->hc[chnum].ErrCnt = 0U;
hhcd->hc[chnum].state = HC_NAK;
(void)USB_HC_Halt(hhcd->Instance, chnum);
}
else
{
/* ... */
}
__HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NAK);
}
else
{
/* ... */
}
}
/**
* @brief Handle Host Channel OUT interrupt requests.
* @param hhcd HCD handle
* @param chnum Channel number.
* This parameter can be a value from 1 to 15
* @retval none
*/
static void HCD_HC_OUT_IRQHandler(HCD_HandleTypeDef *hhcd, uint8_t chnum)
{
const USB_OTG_GlobalTypeDef *USBx = hhcd->Instance;
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t tmpreg;
uint32_t num_packets;
if (__HAL_HCD_GET_CH_FLAG(hhcd, chnum, USB_OTG_HCINT_AHBERR))
{
__HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_AHBERR);
hhcd->hc[chnum].state = HC_XACTERR;
(void)USB_HC_Halt(hhcd->Instance, chnum);
}
else if (__HAL_HCD_GET_CH_FLAG(hhcd, chnum, USB_OTG_HCINT_ACK))
{
__HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_ACK);
}
else if (__HAL_HCD_GET_CH_FLAG(hhcd, chnum, USB_OTG_HCINT_FRMOR))
{
__HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_FRMOR);
(void)USB_HC_Halt(hhcd->Instance, chnum);
}
else if (__HAL_HCD_GET_CH_FLAG(hhcd, chnum, USB_OTG_HCINT_XFRC))
{
hhcd->hc[chnum].ErrCnt = 0U;
__HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_XFRC);
hhcd->hc[chnum].state = HC_XFRC;
(void)USB_HC_Halt(hhcd->Instance, chnum);
}
else if (__HAL_HCD_GET_CH_FLAG(hhcd, chnum, USB_OTG_HCINT_STALL))
{
__HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_STALL);
hhcd->hc[chnum].state = HC_STALL;
(void)USB_HC_Halt(hhcd->Instance, chnum);
}
else if (__HAL_HCD_GET_CH_FLAG(hhcd, chnum, USB_OTG_HCINT_NAK))
{
hhcd->hc[chnum].ErrCnt = 0U;
hhcd->hc[chnum].state = HC_NAK;
(void)USB_HC_Halt(hhcd->Instance, chnum);
__HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NAK);
}
else if (__HAL_HCD_GET_CH_FLAG(hhcd, chnum, USB_OTG_HCINT_TXERR))
{
hhcd->hc[chnum].state = HC_XACTERR;
(void)USB_HC_Halt(hhcd->Instance, chnum);
__HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_TXERR);
}
else if (__HAL_HCD_GET_CH_FLAG(hhcd, chnum, USB_OTG_HCINT_DTERR))
{
hhcd->hc[chnum].state = HC_DATATGLERR;
(void)USB_HC_Halt(hhcd->Instance, chnum);
__HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_DTERR);
}
else if (__HAL_HCD_GET_CH_FLAG(hhcd, chnum, USB_OTG_HCINT_CHH))
{
__HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_CHH);
if (hhcd->hc[chnum].state == HC_XFRC)
{
hhcd->hc[chnum].state = HC_HALTED;
hhcd->hc[chnum].urb_state = URB_DONE;
if ((hhcd->hc[chnum].ep_type == EP_TYPE_BULK) ||
(hhcd->hc[chnum].ep_type == EP_TYPE_INTR))
{
if (hhcd->Init.dma_enable == 0U)
{
hhcd->hc[chnum].toggle_out ^= 1U;
}
if ((hhcd->Init.dma_enable == 1U) && (hhcd->hc[chnum].xfer_len > 0U))
{
num_packets = (hhcd->hc[chnum].xfer_len + hhcd->hc[chnum].max_packet - 1U) / hhcd->hc[chnum].max_packet;
if ((num_packets & 1U) != 0U)
{
hhcd->hc[chnum].toggle_out ^= 1U;
}
}
}
}
else if (hhcd->hc[chnum].state == HC_ACK)
{
hhcd->hc[chnum].state = HC_HALTED;
}
else if (hhcd->hc[chnum].state == HC_NAK)
{
hhcd->hc[chnum].state = HC_HALTED;
hhcd->hc[chnum].urb_state = URB_NOTREADY;
}
else if (hhcd->hc[chnum].state == HC_STALL)
{
hhcd->hc[chnum].state = HC_HALTED;
hhcd->hc[chnum].urb_state = URB_STALL;
}
else if ((hhcd->hc[chnum].state == HC_XACTERR) ||
(hhcd->hc[chnum].state == HC_DATATGLERR))
{
hhcd->hc[chnum].state = HC_HALTED;
hhcd->hc[chnum].ErrCnt++;
if (hhcd->hc[chnum].ErrCnt > 2U)
{
hhcd->hc[chnum].ErrCnt = 0U;
hhcd->hc[chnum].urb_state = URB_ERROR;
}
else
{
hhcd->hc[chnum].urb_state = URB_NOTREADY;
/* re-activate the channel */
tmpreg = USBx_HC(chnum)->HCCHAR;
tmpreg &= ~USB_OTG_HCCHAR_CHDIS;
tmpreg |= USB_OTG_HCCHAR_CHENA;
USBx_HC(chnum)->HCCHAR = tmpreg;
}
}
else
{
return;
}
#if (USE_HAL_HCD_REGISTER_CALLBACKS == 1U)
hhcd->HC_NotifyURBChangeCallback(hhcd, chnum, hhcd->hc[chnum].urb_state);
#else
HAL_HCD_HC_NotifyURBChange_Callback(hhcd, chnum, hhcd->hc[chnum].urb_state);
#endif /* USE_HAL_HCD_REGISTER_CALLBACKS */
}
else
{
return;
}
}
/**
* @brief Handle Rx Queue Level interrupt requests.
* @param hhcd HCD handle
* @retval none
*/
static void HCD_RXQLVL_IRQHandler(HCD_HandleTypeDef *hhcd)
{
const USB_OTG_GlobalTypeDef *USBx = hhcd->Instance;
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t pktsts;
uint32_t pktcnt;
uint32_t GrxstspReg;
uint32_t xferSizePktCnt;
uint32_t tmpreg;
uint32_t chnum;
GrxstspReg = hhcd->Instance->GRXSTSP;
chnum = GrxstspReg & USB_OTG_GRXSTSP_EPNUM;
pktsts = (GrxstspReg & USB_OTG_GRXSTSP_PKTSTS) >> 17;
pktcnt = (GrxstspReg & USB_OTG_GRXSTSP_BCNT) >> 4;
switch (pktsts)
{
case GRXSTS_PKTSTS_IN:
/* Read the data into the host buffer. */
if ((pktcnt > 0U) && (hhcd->hc[chnum].xfer_buff != (void *)0))
{
if ((hhcd->hc[chnum].xfer_count + pktcnt) <= hhcd->hc[chnum].xfer_len)
{
(void)USB_ReadPacket(hhcd->Instance,
hhcd->hc[chnum].xfer_buff, (uint16_t)pktcnt);
/* manage multiple Xfer */
hhcd->hc[chnum].xfer_buff += pktcnt;
hhcd->hc[chnum].xfer_count += pktcnt;
/* get transfer size packet count */
xferSizePktCnt = (USBx_HC(chnum)->HCTSIZ & USB_OTG_HCTSIZ_PKTCNT) >> 19;
if ((hhcd->hc[chnum].max_packet == pktcnt) && (xferSizePktCnt > 0U))
{
/* re-activate the channel when more packets are expected */
tmpreg = USBx_HC(chnum)->HCCHAR;
tmpreg &= ~USB_OTG_HCCHAR_CHDIS;
tmpreg |= USB_OTG_HCCHAR_CHENA;
USBx_HC(chnum)->HCCHAR = tmpreg;
hhcd->hc[chnum].toggle_in ^= 1U;
}
}
else
{
hhcd->hc[chnum].urb_state = URB_ERROR;
}
}
break;
case GRXSTS_PKTSTS_DATA_TOGGLE_ERR:
break;
case GRXSTS_PKTSTS_IN_XFER_COMP:
case GRXSTS_PKTSTS_CH_HALTED:
default:
break;
}
}
/**
* @brief Handle Host Port interrupt requests.
* @param hhcd HCD handle
* @retval None
*/
static void HCD_Port_IRQHandler(HCD_HandleTypeDef *hhcd)
{
const USB_OTG_GlobalTypeDef *USBx = hhcd->Instance;
uint32_t USBx_BASE = (uint32_t)USBx;
__IO uint32_t hprt0;
__IO uint32_t hprt0_dup;
/* Handle Host Port Interrupts */
hprt0 = USBx_HPRT0;
hprt0_dup = USBx_HPRT0;
hprt0_dup &= ~(USB_OTG_HPRT_PENA | USB_OTG_HPRT_PCDET | \
USB_OTG_HPRT_PENCHNG | USB_OTG_HPRT_POCCHNG);
/* Check whether Port Connect detected */
if ((hprt0 & USB_OTG_HPRT_PCDET) == USB_OTG_HPRT_PCDET)
{
if ((hprt0 & USB_OTG_HPRT_PCSTS) == USB_OTG_HPRT_PCSTS)
{
#if (USE_HAL_HCD_REGISTER_CALLBACKS == 1U)
hhcd->ConnectCallback(hhcd);
#else
HAL_HCD_Connect_Callback(hhcd);
#endif /* USE_HAL_HCD_REGISTER_CALLBACKS */
}
hprt0_dup |= USB_OTG_HPRT_PCDET;
}
/* Check whether Port Enable Changed */
if ((hprt0 & USB_OTG_HPRT_PENCHNG) == USB_OTG_HPRT_PENCHNG)
{
hprt0_dup |= USB_OTG_HPRT_PENCHNG;
if ((hprt0 & USB_OTG_HPRT_PENA) == USB_OTG_HPRT_PENA)
{
if (hhcd->Init.phy_itface == USB_OTG_EMBEDDED_PHY)
{
if ((hprt0 & USB_OTG_HPRT_PSPD) == (HPRT0_PRTSPD_LOW_SPEED << 17))
{
(void)USB_InitFSLSPClkSel(hhcd->Instance, HCFG_6_MHZ);
}
else
{
(void)USB_InitFSLSPClkSel(hhcd->Instance, HCFG_48_MHZ);
}
}
else
{
if (hhcd->Init.speed == HCD_SPEED_FULL)
{
USBx_HOST->HFIR = HFIR_60_MHZ;
}
}
#if (USE_HAL_HCD_REGISTER_CALLBACKS == 1U)
hhcd->PortEnabledCallback(hhcd);
#else
HAL_HCD_PortEnabled_Callback(hhcd);
#endif /* USE_HAL_HCD_REGISTER_CALLBACKS */
}
else
{
#if (USE_HAL_HCD_REGISTER_CALLBACKS == 1U)
hhcd->PortDisabledCallback(hhcd);
#else
HAL_HCD_PortDisabled_Callback(hhcd);
#endif /* USE_HAL_HCD_REGISTER_CALLBACKS */
}
}
/* Check for an overcurrent */
if ((hprt0 & USB_OTG_HPRT_POCCHNG) == USB_OTG_HPRT_POCCHNG)
{
hprt0_dup |= USB_OTG_HPRT_POCCHNG;
}
/* Clear Port Interrupts */
USBx_HPRT0 = hprt0_dup;
}
/**
* @}
*/
/**
* @}
*/
#endif /* defined (USB_OTG_FS) */
#endif /* HAL_HCD_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/

View File

@@ -0,0 +1,1876 @@
/**
******************************************************************************
* @file stm32f1xx_hal_i2s.c
* @author MCD Application Team
* @brief I2S HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of the Integrated Interchip Sound (I2S) peripheral:
* + Initialization and de-initialization functions
* + IO operation functions
* + Peripheral State and Errors functions
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
===============================================================================
##### How to use this driver #####
===============================================================================
[..]
The I2S HAL driver can be used as follow:
(#) Declare a I2S_HandleTypeDef handle structure.
(#) Initialize the I2S low level resources by implement the HAL_I2S_MspInit() API:
(##) Enable the SPIx interface clock.
(##) I2S pins configuration:
(+++) Enable the clock for the I2S GPIOs.
(+++) Configure these I2S pins as alternate function pull-up.
(##) NVIC configuration if you need to use interrupt process (HAL_I2S_Transmit_IT()
and HAL_I2S_Receive_IT() APIs).
(+++) Configure the I2Sx interrupt priority.
(+++) Enable the NVIC I2S IRQ handle.
(##) DMA Configuration if you need to use DMA process (HAL_I2S_Transmit_DMA()
and HAL_I2S_Receive_DMA() APIs:
(+++) Declare a DMA handle structure for the Tx/Rx Stream/Channel.
(+++) Enable the DMAx interface clock.
(+++) Configure the declared DMA handle structure with the required Tx/Rx parameters.
(+++) Configure the DMA Tx/Rx Stream/Channel.
(+++) Associate the initialized DMA handle to the I2S DMA Tx/Rx handle.
(+++) Configure the priority and enable the NVIC for the transfer complete interrupt on the
DMA Tx/Rx Stream/Channel.
(#) Program the Mode, Standard, Data Format, MCLK Output, Audio frequency and Polarity
using HAL_I2S_Init() function.
-@- The specific I2S interrupts (Transmission complete interrupt,
RXNE interrupt and Error Interrupts) will be managed using the macros
__HAL_I2S_ENABLE_IT() and __HAL_I2S_DISABLE_IT() inside the transmit and receive process.
-@- The I2SxCLK source is the system clock (provided by the HSI, the HSE or the PLL, and sourcing the AHB clock).
For connectivity line devices, the I2SxCLK source can be either SYSCLK or the PLL3 VCO (2 x PLL3CLK) clock
in order to achieve the maximum accuracy.
-@- Make sure that either:
(+@) External clock source is configured after setting correctly
the define constant HSE_VALUE in the stm32f1xx_hal_conf.h file.
(#) Three mode of operations are available within this driver :
*** Polling mode IO operation ***
=================================
[..]
(+) Send an amount of data in blocking mode using HAL_I2S_Transmit()
(+) Receive an amount of data in blocking mode using HAL_I2S_Receive()
*** Interrupt mode IO operation ***
===================================
[..]
(+) Send an amount of data in non blocking mode using HAL_I2S_Transmit_IT()
(+) At transmission end of half transfer HAL_I2S_TxHalfCpltCallback is executed and user can
add his own code by customization of function pointer HAL_I2S_TxHalfCpltCallback
(+) At transmission end of transfer HAL_I2S_TxCpltCallback is executed and user can
add his own code by customization of function pointer HAL_I2S_TxCpltCallback
(+) Receive an amount of data in non blocking mode using HAL_I2S_Receive_IT()
(+) At reception end of half transfer HAL_I2S_RxHalfCpltCallback is executed and user can
add his own code by customization of function pointer HAL_I2S_RxHalfCpltCallback
(+) At reception end of transfer HAL_I2S_RxCpltCallback is executed and user can
add his own code by customization of function pointer HAL_I2S_RxCpltCallback
(+) In case of transfer Error, HAL_I2S_ErrorCallback() function is executed and user can
add his own code by customization of function pointer HAL_I2S_ErrorCallback
*** DMA mode IO operation ***
==============================
[..]
(+) Send an amount of data in non blocking mode (DMA) using HAL_I2S_Transmit_DMA()
(+) At transmission end of half transfer HAL_I2S_TxHalfCpltCallback is executed and user can
add his own code by customization of function pointer HAL_I2S_TxHalfCpltCallback
(+) At transmission end of transfer HAL_I2S_TxCpltCallback is executed and user can
add his own code by customization of function pointer HAL_I2S_TxCpltCallback
(+) Receive an amount of data in non blocking mode (DMA) using HAL_I2S_Receive_DMA()
(+) At reception end of half transfer HAL_I2S_RxHalfCpltCallback is executed and user can
add his own code by customization of function pointer HAL_I2S_RxHalfCpltCallback
(+) At reception end of transfer HAL_I2S_RxCpltCallback is executed and user can
add his own code by customization of function pointer HAL_I2S_RxCpltCallback
(+) In case of transfer Error, HAL_I2S_ErrorCallback() function is executed and user can
add his own code by customization of function pointer HAL_I2S_ErrorCallback
(+) Pause the DMA Transfer using HAL_I2S_DMAPause()
(+) Resume the DMA Transfer using HAL_I2S_DMAResume()
(+) Stop the DMA Transfer using HAL_I2S_DMAStop()
In Slave mode, if HAL_I2S_DMAStop is used to stop the communication, an error
HAL_I2S_ERROR_BUSY_LINE_RX is raised as the master continue to transmit data.
In this case __HAL_I2S_FLUSH_RX_DR macro must be used to flush the remaining data
inside DR register and avoid using DeInit/Init process for the next transfer.
*** I2S HAL driver macros list ***
===================================
[..]
Below the list of most used macros in I2S HAL driver.
(+) __HAL_I2S_ENABLE: Enable the specified SPI peripheral (in I2S mode)
(+) __HAL_I2S_DISABLE: Disable the specified SPI peripheral (in I2S mode)
(+) __HAL_I2S_ENABLE_IT : Enable the specified I2S interrupts
(+) __HAL_I2S_DISABLE_IT : Disable the specified I2S interrupts
(+) __HAL_I2S_GET_FLAG: Check whether the specified I2S flag is set or not
(+) __HAL_I2S_FLUSH_RX_DR: Read DR Register to Flush RX Data
[..]
(@) You can refer to the I2S HAL driver header file for more useful macros
*** I2S HAL driver macros list ***
===================================
[..]
Callback registration:
(#) The compilation flag USE_HAL_I2S_REGISTER_CALLBACKS when set to 1U
allows the user to configure dynamically the driver callbacks.
Use Functions HAL_I2S_RegisterCallback() to register an interrupt callback.
Function HAL_I2S_RegisterCallback() allows to register following callbacks:
(++) TxCpltCallback : I2S Tx Completed callback
(++) RxCpltCallback : I2S Rx Completed callback
(++) TxHalfCpltCallback : I2S Tx Half Completed callback
(++) RxHalfCpltCallback : I2S Rx Half Completed callback
(++) ErrorCallback : I2S Error callback
(++) MspInitCallback : I2S Msp Init callback
(++) MspDeInitCallback : I2S Msp DeInit callback
This function takes as parameters the HAL peripheral handle, the Callback ID
and a pointer to the user callback function.
(#) Use function HAL_I2S_UnRegisterCallback to reset a callback to the default
weak function.
HAL_I2S_UnRegisterCallback takes as parameters the HAL peripheral handle,
and the Callback ID.
This function allows to reset following callbacks:
(++) TxCpltCallback : I2S Tx Completed callback
(++) RxCpltCallback : I2S Rx Completed callback
(++) TxHalfCpltCallback : I2S Tx Half Completed callback
(++) RxHalfCpltCallback : I2S Rx Half Completed callback
(++) ErrorCallback : I2S Error callback
(++) MspInitCallback : I2S Msp Init callback
(++) MspDeInitCallback : I2S Msp DeInit callback
[..]
By default, after the HAL_I2S_Init() and when the state is HAL_I2S_STATE_RESET
all callbacks are set to the corresponding weak functions:
examples HAL_I2S_MasterTxCpltCallback(), HAL_I2S_MasterRxCpltCallback().
Exception done for MspInit and MspDeInit functions that are
reset to the legacy weak functions in the HAL_I2S_Init()/ HAL_I2S_DeInit() only when
these callbacks are null (not registered beforehand).
If MspInit or MspDeInit are not null, the HAL_I2S_Init()/ HAL_I2S_DeInit()
keep and use the user MspInit/MspDeInit callbacks (registered beforehand) whatever the state.
[..]
Callbacks can be registered/unregistered in HAL_I2S_STATE_READY state only.
Exception done MspInit/MspDeInit functions that can be registered/unregistered
in HAL_I2S_STATE_READY or HAL_I2S_STATE_RESET state,
thus registered (user) MspInit/DeInit callbacks can be used during the Init/DeInit.
Then, the user first registers the MspInit/MspDeInit user callbacks
using HAL_I2S_RegisterCallback() before calling HAL_I2S_DeInit()
or HAL_I2S_Init() function.
[..]
When the compilation define USE_HAL_I2S_REGISTER_CALLBACKS is set to 0 or
not defined, the callback registering feature is not available
and weak (surcharged) callbacks are used.
*** I2S Workarounds linked to Silicon Limitation ***
====================================================
[..]
(@) Only the 16-bit mode with no data extension can be used when the I2S
is in Master and used the PCM long synchronization mode.
@endverbatim
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
#ifdef HAL_I2S_MODULE_ENABLED
#if defined(SPI_I2S_SUPPORT)
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
/** @defgroup I2S I2S
* @brief I2S HAL module driver
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define I2S_TIMEOUT_FLAG 100U /*!< Timeout 100 ms */
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/** @defgroup I2S_Private_Functions I2S Private Functions
* @{
*/
static void I2S_DMATxCplt(DMA_HandleTypeDef *hdma);
static void I2S_DMATxHalfCplt(DMA_HandleTypeDef *hdma);
static void I2S_DMARxCplt(DMA_HandleTypeDef *hdma);
static void I2S_DMARxHalfCplt(DMA_HandleTypeDef *hdma);
static void I2S_DMAError(DMA_HandleTypeDef *hdma);
static void I2S_Transmit_IT(I2S_HandleTypeDef *hi2s);
static void I2S_Receive_IT(I2S_HandleTypeDef *hi2s);
static HAL_StatusTypeDef I2S_WaitFlagStateUntilTimeout(I2S_HandleTypeDef *hi2s, uint32_t Flag, FlagStatus State,
uint32_t Timeout);
/**
* @}
*/
/* Exported functions ---------------------------------------------------------*/
/** @defgroup I2S_Exported_Functions I2S Exported Functions
* @{
*/
/** @defgroup I2S_Exported_Functions_Group1 Initialization and de-initialization functions
* @brief Initialization and Configuration functions
*
@verbatim
===============================================================================
##### Initialization and de-initialization functions #####
===============================================================================
[..] This subsection provides a set of functions allowing to initialize and
de-initialize the I2Sx peripheral in simplex mode:
(+) User must Implement HAL_I2S_MspInit() function in which he configures
all related peripherals resources (CLOCK, GPIO, DMA, IT and NVIC ).
(+) Call the function HAL_I2S_Init() to configure the selected device with
the selected configuration:
(++) Mode
(++) Standard
(++) Data Format
(++) MCLK Output
(++) Audio frequency
(++) Polarity
(+) Call the function HAL_I2S_DeInit() to restore the default configuration
of the selected I2Sx peripheral.
@endverbatim
* @{
*/
/**
* @brief Initializes the I2S according to the specified parameters
* in the I2S_InitTypeDef and create the associated handle.
* @param hi2s pointer to a I2S_HandleTypeDef structure that contains
* the configuration information for I2S module
* @retval HAL status
*/
HAL_StatusTypeDef HAL_I2S_Init(I2S_HandleTypeDef *hi2s)
{
uint32_t i2sdiv;
uint32_t i2sodd;
uint32_t packetlength;
uint32_t tmp;
uint32_t i2sclk;
/* Check the I2S handle allocation */
if (hi2s == NULL)
{
return HAL_ERROR;
}
/* Check the I2S parameters */
assert_param(IS_I2S_ALL_INSTANCE(hi2s->Instance));
assert_param(IS_I2S_MODE(hi2s->Init.Mode));
assert_param(IS_I2S_STANDARD(hi2s->Init.Standard));
assert_param(IS_I2S_DATA_FORMAT(hi2s->Init.DataFormat));
assert_param(IS_I2S_MCLK_OUTPUT(hi2s->Init.MCLKOutput));
assert_param(IS_I2S_AUDIO_FREQ(hi2s->Init.AudioFreq));
assert_param(IS_I2S_CPOL(hi2s->Init.CPOL));
if (hi2s->State == HAL_I2S_STATE_RESET)
{
/* Allocate lock resource and initialize it */
hi2s->Lock = HAL_UNLOCKED;
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 1U)
/* Init the I2S Callback settings */
hi2s->TxCpltCallback = HAL_I2S_TxCpltCallback; /* Legacy weak TxCpltCallback */
hi2s->RxCpltCallback = HAL_I2S_RxCpltCallback; /* Legacy weak RxCpltCallback */
hi2s->TxHalfCpltCallback = HAL_I2S_TxHalfCpltCallback; /* Legacy weak TxHalfCpltCallback */
hi2s->RxHalfCpltCallback = HAL_I2S_RxHalfCpltCallback; /* Legacy weak RxHalfCpltCallback */
hi2s->ErrorCallback = HAL_I2S_ErrorCallback; /* Legacy weak ErrorCallback */
if (hi2s->MspInitCallback == NULL)
{
hi2s->MspInitCallback = HAL_I2S_MspInit; /* Legacy weak MspInit */
}
/* Init the low level hardware : GPIO, CLOCK, NVIC... */
hi2s->MspInitCallback(hi2s);
#else
/* Init the low level hardware : GPIO, CLOCK, CORTEX...etc */
HAL_I2S_MspInit(hi2s);
#endif /* USE_HAL_I2S_REGISTER_CALLBACKS */
}
hi2s->State = HAL_I2S_STATE_BUSY;
/*----------------------- SPIx I2SCFGR & I2SPR Configuration ----------------*/
/* Clear I2SMOD, I2SE, I2SCFG, PCMSYNC, I2SSTD, CKPOL, DATLEN and CHLEN bits */
CLEAR_BIT(hi2s->Instance->I2SCFGR, (SPI_I2SCFGR_CHLEN | SPI_I2SCFGR_DATLEN | SPI_I2SCFGR_CKPOL | \
SPI_I2SCFGR_I2SSTD | SPI_I2SCFGR_PCMSYNC | SPI_I2SCFGR_I2SCFG | \
SPI_I2SCFGR_I2SE | SPI_I2SCFGR_I2SMOD));
hi2s->Instance->I2SPR = 0x0002U;
/*----------------------- I2SPR: I2SDIV and ODD Calculation -----------------*/
/* If the requested audio frequency is not the default, compute the prescaler */
if (hi2s->Init.AudioFreq != I2S_AUDIOFREQ_DEFAULT)
{
/* Check the frame length (For the Prescaler computing) ********************/
if (hi2s->Init.DataFormat == I2S_DATAFORMAT_16B)
{
/* Packet length is 16 bits */
packetlength = 16U;
}
else
{
/* Packet length is 32 bits */
packetlength = 32U;
}
/* I2S standard */
if (hi2s->Init.Standard <= I2S_STANDARD_LSB)
{
/* In I2S standard packet length is multiplied by 2 */
packetlength = packetlength * 2U;
}
/* Get the source clock value **********************************************/
if (hi2s->Instance == SPI2)
{
/* Get the source clock value: based on SPI2 Instance */
i2sclk = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_I2S2);
}
else if (hi2s->Instance == SPI3)
{
/* Get the source clock value: based on SPI3 Instance */
i2sclk = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_I2S3);
}
else
{
/* Get the source clock value: based on System Clock value */
i2sclk = HAL_RCC_GetSysClockFreq();
}
/* Compute the Real divider depending on the MCLK output state, with a floating point */
if (hi2s->Init.MCLKOutput == I2S_MCLKOUTPUT_ENABLE)
{
/* MCLK output is enabled */
if (hi2s->Init.DataFormat != I2S_DATAFORMAT_16B)
{
tmp = (uint32_t)(((((i2sclk / (packetlength * 4U)) * 10U) / hi2s->Init.AudioFreq)) + 5U);
}
else
{
tmp = (uint32_t)(((((i2sclk / (packetlength * 8U)) * 10U) / hi2s->Init.AudioFreq)) + 5U);
}
}
else
{
/* MCLK output is disabled */
tmp = (uint32_t)(((((i2sclk / packetlength) * 10U) / hi2s->Init.AudioFreq)) + 5U);
}
/* Remove the flatting point */
tmp = tmp / 10U;
/* Check the parity of the divider */
i2sodd = (uint32_t)(tmp & (uint32_t)1U);
/* Compute the i2sdiv prescaler */
i2sdiv = (uint32_t)((tmp - i2sodd) / 2U);
/* Get the Mask for the Odd bit (SPI_I2SPR[8]) register */
i2sodd = (uint32_t)(i2sodd << 8U);
}
else
{
/* Set the default values */
i2sdiv = 2U;
i2sodd = 0U;
}
/* Test if the divider is 1 or 0 or greater than 0xFF */
if ((i2sdiv < 2U) || (i2sdiv > 0xFFU))
{
/* Set the error code and execute error callback*/
SET_BIT(hi2s->ErrorCode, HAL_I2S_ERROR_PRESCALER);
return HAL_ERROR;
}
/*----------------------- SPIx I2SCFGR & I2SPR Configuration ----------------*/
/* Write to SPIx I2SPR register the computed value */
hi2s->Instance->I2SPR = (uint32_t)((uint32_t)i2sdiv | (uint32_t)(i2sodd | (uint32_t)hi2s->Init.MCLKOutput));
/* Clear I2SMOD, I2SE, I2SCFG, PCMSYNC, I2SSTD, CKPOL, DATLEN and CHLEN bits */
/* And configure the I2S with the I2S_InitStruct values */
MODIFY_REG(hi2s->Instance->I2SCFGR, (SPI_I2SCFGR_CHLEN | SPI_I2SCFGR_DATLEN | \
SPI_I2SCFGR_CKPOL | SPI_I2SCFGR_I2SSTD | \
SPI_I2SCFGR_PCMSYNC | SPI_I2SCFGR_I2SCFG | \
SPI_I2SCFGR_I2SE | SPI_I2SCFGR_I2SMOD), \
(SPI_I2SCFGR_I2SMOD | hi2s->Init.Mode | \
hi2s->Init.Standard | hi2s->Init.DataFormat | \
hi2s->Init.CPOL));
#if defined(SPI_I2SCFGR_ASTRTEN)
if ((hi2s->Init.Standard == I2S_STANDARD_PCM_SHORT) || ((hi2s->Init.Standard == I2S_STANDARD_PCM_LONG)))
{
/* Write to SPIx I2SCFGR */
SET_BIT(hi2s->Instance->I2SCFGR, SPI_I2SCFGR_ASTRTEN);
}
#endif /* SPI_I2SCFGR_ASTRTEN */
hi2s->ErrorCode = HAL_I2S_ERROR_NONE;
hi2s->State = HAL_I2S_STATE_READY;
return HAL_OK;
}
/**
* @brief DeInitializes the I2S peripheral
* @param hi2s pointer to a I2S_HandleTypeDef structure that contains
* the configuration information for I2S module
* @retval HAL status
*/
HAL_StatusTypeDef HAL_I2S_DeInit(I2S_HandleTypeDef *hi2s)
{
/* Check the I2S handle allocation */
if (hi2s == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_I2S_ALL_INSTANCE(hi2s->Instance));
hi2s->State = HAL_I2S_STATE_BUSY;
/* Disable the I2S Peripheral Clock */
__HAL_I2S_DISABLE(hi2s);
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 1U)
if (hi2s->MspDeInitCallback == NULL)
{
hi2s->MspDeInitCallback = HAL_I2S_MspDeInit; /* Legacy weak MspDeInit */
}
/* DeInit the low level hardware: GPIO, CLOCK, NVIC... */
hi2s->MspDeInitCallback(hi2s);
#else
/* DeInit the low level hardware: GPIO, CLOCK, NVIC... */
HAL_I2S_MspDeInit(hi2s);
#endif /* USE_HAL_I2S_REGISTER_CALLBACKS */
hi2s->ErrorCode = HAL_I2S_ERROR_NONE;
hi2s->State = HAL_I2S_STATE_RESET;
/* Release Lock */
__HAL_UNLOCK(hi2s);
return HAL_OK;
}
/**
* @brief I2S MSP Init
* @param hi2s pointer to a I2S_HandleTypeDef structure that contains
* the configuration information for I2S module
* @retval None
*/
__weak void HAL_I2S_MspInit(I2S_HandleTypeDef *hi2s)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hi2s);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_I2S_MspInit could be implemented in the user file
*/
}
/**
* @brief I2S MSP DeInit
* @param hi2s pointer to a I2S_HandleTypeDef structure that contains
* the configuration information for I2S module
* @retval None
*/
__weak void HAL_I2S_MspDeInit(I2S_HandleTypeDef *hi2s)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hi2s);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_I2S_MspDeInit could be implemented in the user file
*/
}
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 1U)
/**
* @brief Register a User I2S Callback
* To be used instead of the weak predefined callback
* @param hi2s Pointer to a I2S_HandleTypeDef structure that contains
* the configuration information for the specified I2S.
* @param CallbackID ID of the callback to be registered
* @param pCallback pointer to the Callback function
* @retval HAL status
*/
HAL_StatusTypeDef HAL_I2S_RegisterCallback(I2S_HandleTypeDef *hi2s, HAL_I2S_CallbackIDTypeDef CallbackID,
pI2S_CallbackTypeDef pCallback)
{
HAL_StatusTypeDef status = HAL_OK;
if (pCallback == NULL)
{
/* Update the error code */
hi2s->ErrorCode |= HAL_I2S_ERROR_INVALID_CALLBACK;
return HAL_ERROR;
}
/* Process locked */
__HAL_LOCK(hi2s);
if (HAL_I2S_STATE_READY == hi2s->State)
{
switch (CallbackID)
{
case HAL_I2S_TX_COMPLETE_CB_ID :
hi2s->TxCpltCallback = pCallback;
break;
case HAL_I2S_RX_COMPLETE_CB_ID :
hi2s->RxCpltCallback = pCallback;
break;
case HAL_I2S_TX_HALF_COMPLETE_CB_ID :
hi2s->TxHalfCpltCallback = pCallback;
break;
case HAL_I2S_RX_HALF_COMPLETE_CB_ID :
hi2s->RxHalfCpltCallback = pCallback;
break;
case HAL_I2S_ERROR_CB_ID :
hi2s->ErrorCallback = pCallback;
break;
case HAL_I2S_MSPINIT_CB_ID :
hi2s->MspInitCallback = pCallback;
break;
case HAL_I2S_MSPDEINIT_CB_ID :
hi2s->MspDeInitCallback = pCallback;
break;
default :
/* Update the error code */
SET_BIT(hi2s->ErrorCode, HAL_I2S_ERROR_INVALID_CALLBACK);
/* Return error status */
status = HAL_ERROR;
break;
}
}
else if (HAL_I2S_STATE_RESET == hi2s->State)
{
switch (CallbackID)
{
case HAL_I2S_MSPINIT_CB_ID :
hi2s->MspInitCallback = pCallback;
break;
case HAL_I2S_MSPDEINIT_CB_ID :
hi2s->MspDeInitCallback = pCallback;
break;
default :
/* Update the error code */
SET_BIT(hi2s->ErrorCode, HAL_I2S_ERROR_INVALID_CALLBACK);
/* Return error status */
status = HAL_ERROR;
break;
}
}
else
{
/* Update the error code */
SET_BIT(hi2s->ErrorCode, HAL_I2S_ERROR_INVALID_CALLBACK);
/* Return error status */
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(hi2s);
return status;
}
/**
* @brief Unregister an I2S Callback
* I2S callback is redirected to the weak predefined callback
* @param hi2s Pointer to a I2S_HandleTypeDef structure that contains
* the configuration information for the specified I2S.
* @param CallbackID ID of the callback to be unregistered
* @retval HAL status
*/
HAL_StatusTypeDef HAL_I2S_UnRegisterCallback(I2S_HandleTypeDef *hi2s, HAL_I2S_CallbackIDTypeDef CallbackID)
{
HAL_StatusTypeDef status = HAL_OK;
/* Process locked */
__HAL_LOCK(hi2s);
if (HAL_I2S_STATE_READY == hi2s->State)
{
switch (CallbackID)
{
case HAL_I2S_TX_COMPLETE_CB_ID :
hi2s->TxCpltCallback = HAL_I2S_TxCpltCallback; /* Legacy weak TxCpltCallback */
break;
case HAL_I2S_RX_COMPLETE_CB_ID :
hi2s->RxCpltCallback = HAL_I2S_RxCpltCallback; /* Legacy weak RxCpltCallback */
break;
case HAL_I2S_TX_HALF_COMPLETE_CB_ID :
hi2s->TxHalfCpltCallback = HAL_I2S_TxHalfCpltCallback; /* Legacy weak TxHalfCpltCallback */
break;
case HAL_I2S_RX_HALF_COMPLETE_CB_ID :
hi2s->RxHalfCpltCallback = HAL_I2S_RxHalfCpltCallback; /* Legacy weak RxHalfCpltCallback */
break;
case HAL_I2S_ERROR_CB_ID :
hi2s->ErrorCallback = HAL_I2S_ErrorCallback; /* Legacy weak ErrorCallback */
break;
case HAL_I2S_MSPINIT_CB_ID :
hi2s->MspInitCallback = HAL_I2S_MspInit; /* Legacy weak MspInit */
break;
case HAL_I2S_MSPDEINIT_CB_ID :
hi2s->MspDeInitCallback = HAL_I2S_MspDeInit; /* Legacy weak MspDeInit */
break;
default :
/* Update the error code */
SET_BIT(hi2s->ErrorCode, HAL_I2S_ERROR_INVALID_CALLBACK);
/* Return error status */
status = HAL_ERROR;
break;
}
}
else if (HAL_I2S_STATE_RESET == hi2s->State)
{
switch (CallbackID)
{
case HAL_I2S_MSPINIT_CB_ID :
hi2s->MspInitCallback = HAL_I2S_MspInit; /* Legacy weak MspInit */
break;
case HAL_I2S_MSPDEINIT_CB_ID :
hi2s->MspDeInitCallback = HAL_I2S_MspDeInit; /* Legacy weak MspDeInit */
break;
default :
/* Update the error code */
SET_BIT(hi2s->ErrorCode, HAL_I2S_ERROR_INVALID_CALLBACK);
/* Return error status */
status = HAL_ERROR;
break;
}
}
else
{
/* Update the error code */
SET_BIT(hi2s->ErrorCode, HAL_I2S_ERROR_INVALID_CALLBACK);
/* Return error status */
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(hi2s);
return status;
}
#endif /* USE_HAL_I2S_REGISTER_CALLBACKS */
/**
* @}
*/
/** @defgroup I2S_Exported_Functions_Group2 IO operation functions
* @brief Data transfers functions
*
@verbatim
===============================================================================
##### IO operation functions #####
===============================================================================
[..]
This subsection provides a set of functions allowing to manage the I2S data
transfers.
(#) There are two modes of transfer:
(++) Blocking mode : The communication is performed in the polling mode.
The status of all data processing is returned by the same function
after finishing transfer.
(++) No-Blocking mode : The communication is performed using Interrupts
or DMA. These functions return the status of the transfer startup.
The end of the data processing will be indicated through the
dedicated I2S IRQ when using Interrupt mode or the DMA IRQ when
using DMA mode.
(#) Blocking mode functions are :
(++) HAL_I2S_Transmit()
(++) HAL_I2S_Receive()
(#) No-Blocking mode functions with Interrupt are :
(++) HAL_I2S_Transmit_IT()
(++) HAL_I2S_Receive_IT()
(#) No-Blocking mode functions with DMA are :
(++) HAL_I2S_Transmit_DMA()
(++) HAL_I2S_Receive_DMA()
(#) A set of Transfer Complete Callbacks are provided in non Blocking mode:
(++) HAL_I2S_TxCpltCallback()
(++) HAL_I2S_RxCpltCallback()
(++) HAL_I2S_ErrorCallback()
@endverbatim
* @{
*/
/**
* @brief Transmit an amount of data in blocking mode
* @param hi2s pointer to a I2S_HandleTypeDef structure that contains
* the configuration information for I2S module
* @param pData a 16-bit pointer to data buffer.
* @param Size number of data sample to be sent:
* @note When a 16-bit data frame or a 16-bit data frame extended is selected during the I2S
* configuration phase, the Size parameter means the number of 16-bit data length
* in the transaction and when a 24-bit data frame or a 32-bit data frame is selected
* the Size parameter means the number of 24-bit or 32-bit data length.
* @param Timeout Timeout duration
* @note The I2S is kept enabled at the end of transaction to avoid the clock de-synchronization
* between Master and Slave(example: audio streaming).
* @retval HAL status
*/
HAL_StatusTypeDef HAL_I2S_Transmit(I2S_HandleTypeDef *hi2s, uint16_t *pData, uint16_t Size, uint32_t Timeout)
{
uint32_t tmpreg_cfgr;
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
if (hi2s->State != HAL_I2S_STATE_READY)
{
return HAL_BUSY;
}
/* Process Locked */
__HAL_LOCK(hi2s);
/* Set state and reset error code */
hi2s->State = HAL_I2S_STATE_BUSY_TX;
hi2s->ErrorCode = HAL_I2S_ERROR_NONE;
hi2s->pTxBuffPtr = pData;
tmpreg_cfgr = hi2s->Instance->I2SCFGR & (SPI_I2SCFGR_DATLEN | SPI_I2SCFGR_CHLEN);
if ((tmpreg_cfgr == I2S_DATAFORMAT_24B) || (tmpreg_cfgr == I2S_DATAFORMAT_32B))
{
hi2s->TxXferSize = (Size << 1U);
hi2s->TxXferCount = (Size << 1U);
}
else
{
hi2s->TxXferSize = Size;
hi2s->TxXferCount = Size;
}
tmpreg_cfgr = hi2s->Instance->I2SCFGR;
/* Check if the I2S is already enabled */
if ((hi2s->Instance->I2SCFGR & SPI_I2SCFGR_I2SE) != SPI_I2SCFGR_I2SE)
{
/* Enable I2S peripheral */
__HAL_I2S_ENABLE(hi2s);
}
/* Wait until TXE flag is set */
if (I2S_WaitFlagStateUntilTimeout(hi2s, I2S_FLAG_TXE, SET, Timeout) != HAL_OK)
{
/* Set the error code */
SET_BIT(hi2s->ErrorCode, HAL_I2S_ERROR_TIMEOUT);
hi2s->State = HAL_I2S_STATE_READY;
__HAL_UNLOCK(hi2s);
return HAL_ERROR;
}
while (hi2s->TxXferCount > 0U)
{
hi2s->Instance->DR = (*hi2s->pTxBuffPtr);
hi2s->pTxBuffPtr++;
hi2s->TxXferCount--;
/* Wait until TXE flag is set */
if (I2S_WaitFlagStateUntilTimeout(hi2s, I2S_FLAG_TXE, SET, Timeout) != HAL_OK)
{
/* Set the error code */
SET_BIT(hi2s->ErrorCode, HAL_I2S_ERROR_TIMEOUT);
hi2s->State = HAL_I2S_STATE_READY;
__HAL_UNLOCK(hi2s);
return HAL_ERROR;
}
/* Check if an underrun occurs */
if (__HAL_I2S_GET_FLAG(hi2s, I2S_FLAG_UDR) == SET)
{
/* Clear underrun flag */
__HAL_I2S_CLEAR_UDRFLAG(hi2s);
/* Set the error code */
SET_BIT(hi2s->ErrorCode, HAL_I2S_ERROR_UDR);
}
}
/* Check if Slave mode is selected */
if (((tmpreg_cfgr & SPI_I2SCFGR_I2SCFG) == I2S_MODE_SLAVE_TX)
|| ((tmpreg_cfgr & SPI_I2SCFGR_I2SCFG) == I2S_MODE_SLAVE_RX))
{
/* Wait until Busy flag is reset */
if (I2S_WaitFlagStateUntilTimeout(hi2s, I2S_FLAG_BSY, RESET, Timeout) != HAL_OK)
{
/* Set the error code */
SET_BIT(hi2s->ErrorCode, HAL_I2S_ERROR_TIMEOUT);
hi2s->State = HAL_I2S_STATE_READY;
__HAL_UNLOCK(hi2s);
return HAL_ERROR;
}
}
hi2s->State = HAL_I2S_STATE_READY;
__HAL_UNLOCK(hi2s);
return HAL_OK;
}
/**
* @brief Receive an amount of data in blocking mode
* @param hi2s pointer to a I2S_HandleTypeDef structure that contains
* the configuration information for I2S module
* @param pData a 16-bit pointer to data buffer.
* @param Size number of data sample to be sent:
* @note When a 16-bit data frame or a 16-bit data frame extended is selected during the I2S
* configuration phase, the Size parameter means the number of 16-bit data length
* in the transaction and when a 24-bit data frame or a 32-bit data frame is selected
* the Size parameter means the number of 24-bit or 32-bit data length.
* @param Timeout Timeout duration
* @note The I2S is kept enabled at the end of transaction to avoid the clock de-synchronization
* between Master and Slave(example: audio streaming).
* @note In I2S Master Receiver mode, just after enabling the peripheral the clock will be generate
* in continuous way and as the I2S is not disabled at the end of the I2S transaction.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_I2S_Receive(I2S_HandleTypeDef *hi2s, uint16_t *pData, uint16_t Size, uint32_t Timeout)
{
uint32_t tmpreg_cfgr;
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
if (hi2s->State != HAL_I2S_STATE_READY)
{
return HAL_BUSY;
}
/* Process Locked */
__HAL_LOCK(hi2s);
/* Set state and reset error code */
hi2s->State = HAL_I2S_STATE_BUSY_RX;
hi2s->ErrorCode = HAL_I2S_ERROR_NONE;
hi2s->pRxBuffPtr = pData;
tmpreg_cfgr = hi2s->Instance->I2SCFGR & (SPI_I2SCFGR_DATLEN | SPI_I2SCFGR_CHLEN);
if ((tmpreg_cfgr == I2S_DATAFORMAT_24B) || (tmpreg_cfgr == I2S_DATAFORMAT_32B))
{
hi2s->RxXferSize = (Size << 1U);
hi2s->RxXferCount = (Size << 1U);
}
else
{
hi2s->RxXferSize = Size;
hi2s->RxXferCount = Size;
}
/* Check if the I2S is already enabled */
if ((hi2s->Instance->I2SCFGR & SPI_I2SCFGR_I2SE) != SPI_I2SCFGR_I2SE)
{
/* Enable I2S peripheral */
__HAL_I2S_ENABLE(hi2s);
}
/* Check if Master Receiver mode is selected */
if ((hi2s->Instance->I2SCFGR & SPI_I2SCFGR_I2SCFG) == I2S_MODE_MASTER_RX)
{
/* Clear the Overrun Flag by a read operation on the SPI_DR register followed by a read
access to the SPI_SR register. */
__HAL_I2S_CLEAR_OVRFLAG(hi2s);
}
/* Receive data */
while (hi2s->RxXferCount > 0U)
{
/* Wait until RXNE flag is set */
if (I2S_WaitFlagStateUntilTimeout(hi2s, I2S_FLAG_RXNE, SET, Timeout) != HAL_OK)
{
/* Set the error code */
SET_BIT(hi2s->ErrorCode, HAL_I2S_ERROR_TIMEOUT);
hi2s->State = HAL_I2S_STATE_READY;
__HAL_UNLOCK(hi2s);
return HAL_ERROR;
}
(*hi2s->pRxBuffPtr) = (uint16_t)hi2s->Instance->DR;
hi2s->pRxBuffPtr++;
hi2s->RxXferCount--;
/* Check if an overrun occurs */
if (__HAL_I2S_GET_FLAG(hi2s, I2S_FLAG_OVR) == SET)
{
/* Clear overrun flag */
__HAL_I2S_CLEAR_OVRFLAG(hi2s);
/* Set the error code */
SET_BIT(hi2s->ErrorCode, HAL_I2S_ERROR_OVR);
}
}
hi2s->State = HAL_I2S_STATE_READY;
__HAL_UNLOCK(hi2s);
return HAL_OK;
}
/**
* @brief Transmit an amount of data in non-blocking mode with Interrupt
* @param hi2s pointer to a I2S_HandleTypeDef structure that contains
* the configuration information for I2S module
* @param pData a 16-bit pointer to data buffer.
* @param Size number of data sample to be sent:
* @note When a 16-bit data frame or a 16-bit data frame extended is selected during the I2S
* configuration phase, the Size parameter means the number of 16-bit data length
* in the transaction and when a 24-bit data frame or a 32-bit data frame is selected
* the Size parameter means the number of 24-bit or 32-bit data length.
* @note The I2S is kept enabled at the end of transaction to avoid the clock de-synchronization
* between Master and Slave(example: audio streaming).
* @retval HAL status
*/
HAL_StatusTypeDef HAL_I2S_Transmit_IT(I2S_HandleTypeDef *hi2s, uint16_t *pData, uint16_t Size)
{
uint32_t tmpreg_cfgr;
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
if (hi2s->State != HAL_I2S_STATE_READY)
{
return HAL_BUSY;
}
/* Process Locked */
__HAL_LOCK(hi2s);
/* Set state and reset error code */
hi2s->State = HAL_I2S_STATE_BUSY_TX;
hi2s->ErrorCode = HAL_I2S_ERROR_NONE;
hi2s->pTxBuffPtr = pData;
tmpreg_cfgr = hi2s->Instance->I2SCFGR & (SPI_I2SCFGR_DATLEN | SPI_I2SCFGR_CHLEN);
if ((tmpreg_cfgr == I2S_DATAFORMAT_24B) || (tmpreg_cfgr == I2S_DATAFORMAT_32B))
{
hi2s->TxXferSize = (Size << 1U);
hi2s->TxXferCount = (Size << 1U);
}
else
{
hi2s->TxXferSize = Size;
hi2s->TxXferCount = Size;
}
__HAL_UNLOCK(hi2s);
/* Enable TXE and ERR interrupt */
__HAL_I2S_ENABLE_IT(hi2s, (I2S_IT_TXE | I2S_IT_ERR));
/* Check if the I2S is already enabled */
if ((hi2s->Instance->I2SCFGR & SPI_I2SCFGR_I2SE) != SPI_I2SCFGR_I2SE)
{
/* Enable I2S peripheral */
__HAL_I2S_ENABLE(hi2s);
}
return HAL_OK;
}
/**
* @brief Receive an amount of data in non-blocking mode with Interrupt
* @param hi2s pointer to a I2S_HandleTypeDef structure that contains
* the configuration information for I2S module
* @param pData a 16-bit pointer to the Receive data buffer.
* @param Size number of data sample to be sent:
* @note When a 16-bit data frame or a 16-bit data frame extended is selected during the I2S
* configuration phase, the Size parameter means the number of 16-bit data length
* in the transaction and when a 24-bit data frame or a 32-bit data frame is selected
* the Size parameter means the number of 24-bit or 32-bit data length.
* @note The I2S is kept enabled at the end of transaction to avoid the clock de-synchronization
* between Master and Slave(example: audio streaming).
* @note It is recommended to use DMA for the I2S receiver to avoid de-synchronization
* between Master and Slave otherwise the I2S interrupt should be optimized.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_I2S_Receive_IT(I2S_HandleTypeDef *hi2s, uint16_t *pData, uint16_t Size)
{
uint32_t tmpreg_cfgr;
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
if (hi2s->State != HAL_I2S_STATE_READY)
{
return HAL_BUSY;
}
/* Process Locked */
__HAL_LOCK(hi2s);
/* Set state and reset error code */
hi2s->State = HAL_I2S_STATE_BUSY_RX;
hi2s->ErrorCode = HAL_I2S_ERROR_NONE;
hi2s->pRxBuffPtr = pData;
tmpreg_cfgr = hi2s->Instance->I2SCFGR & (SPI_I2SCFGR_DATLEN | SPI_I2SCFGR_CHLEN);
if ((tmpreg_cfgr == I2S_DATAFORMAT_24B) || (tmpreg_cfgr == I2S_DATAFORMAT_32B))
{
hi2s->RxXferSize = (Size << 1U);
hi2s->RxXferCount = (Size << 1U);
}
else
{
hi2s->RxXferSize = Size;
hi2s->RxXferCount = Size;
}
__HAL_UNLOCK(hi2s);
/* Enable RXNE and ERR interrupt */
__HAL_I2S_ENABLE_IT(hi2s, (I2S_IT_RXNE | I2S_IT_ERR));
/* Check if the I2S is already enabled */
if ((hi2s->Instance->I2SCFGR & SPI_I2SCFGR_I2SE) != SPI_I2SCFGR_I2SE)
{
/* Enable I2S peripheral */
__HAL_I2S_ENABLE(hi2s);
}
return HAL_OK;
}
/**
* @brief Transmit an amount of data in non-blocking mode with DMA
* @param hi2s pointer to a I2S_HandleTypeDef structure that contains
* the configuration information for I2S module
* @param pData a 16-bit pointer to the Transmit data buffer.
* @param Size number of data sample to be sent:
* @note When a 16-bit data frame or a 16-bit data frame extended is selected during the I2S
* configuration phase, the Size parameter means the number of 16-bit data length
* in the transaction and when a 24-bit data frame or a 32-bit data frame is selected
* the Size parameter means the number of 24-bit or 32-bit data length.
* @note The I2S is kept enabled at the end of transaction to avoid the clock de-synchronization
* between Master and Slave(example: audio streaming).
* @retval HAL status
*/
HAL_StatusTypeDef HAL_I2S_Transmit_DMA(I2S_HandleTypeDef *hi2s, uint16_t *pData, uint16_t Size)
{
uint32_t tmpreg_cfgr;
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
if (hi2s->State != HAL_I2S_STATE_READY)
{
return HAL_BUSY;
}
/* Process Locked */
__HAL_LOCK(hi2s);
/* Set state and reset error code */
hi2s->State = HAL_I2S_STATE_BUSY_TX;
hi2s->ErrorCode = HAL_I2S_ERROR_NONE;
hi2s->pTxBuffPtr = pData;
tmpreg_cfgr = hi2s->Instance->I2SCFGR & (SPI_I2SCFGR_DATLEN | SPI_I2SCFGR_CHLEN);
if ((tmpreg_cfgr == I2S_DATAFORMAT_24B) || (tmpreg_cfgr == I2S_DATAFORMAT_32B))
{
hi2s->TxXferSize = (Size << 1U);
hi2s->TxXferCount = (Size << 1U);
}
else
{
hi2s->TxXferSize = Size;
hi2s->TxXferCount = Size;
}
/* Set the I2S Tx DMA Half transfer complete callback */
hi2s->hdmatx->XferHalfCpltCallback = I2S_DMATxHalfCplt;
/* Set the I2S Tx DMA transfer complete callback */
hi2s->hdmatx->XferCpltCallback = I2S_DMATxCplt;
/* Set the DMA error callback */
hi2s->hdmatx->XferErrorCallback = I2S_DMAError;
/* Enable the Tx DMA Stream/Channel */
if (HAL_OK != HAL_DMA_Start_IT(hi2s->hdmatx,
(uint32_t)hi2s->pTxBuffPtr,
(uint32_t)&hi2s->Instance->DR,
hi2s->TxXferSize))
{
/* Update SPI error code */
SET_BIT(hi2s->ErrorCode, HAL_I2S_ERROR_DMA);
hi2s->State = HAL_I2S_STATE_READY;
__HAL_UNLOCK(hi2s);
return HAL_ERROR;
}
__HAL_UNLOCK(hi2s);
/* Check if the I2S Tx request is already enabled */
if (HAL_IS_BIT_CLR(hi2s->Instance->CR2, SPI_CR2_TXDMAEN))
{
/* Enable Tx DMA Request */
SET_BIT(hi2s->Instance->CR2, SPI_CR2_TXDMAEN);
}
/* Check if the I2S is already enabled */
if (HAL_IS_BIT_CLR(hi2s->Instance->I2SCFGR, SPI_I2SCFGR_I2SE))
{
/* Enable I2S peripheral */
__HAL_I2S_ENABLE(hi2s);
}
return HAL_OK;
}
/**
* @brief Receive an amount of data in non-blocking mode with DMA
* @param hi2s pointer to a I2S_HandleTypeDef structure that contains
* the configuration information for I2S module
* @param pData a 16-bit pointer to the Receive data buffer.
* @param Size number of data sample to be sent:
* @note When a 16-bit data frame or a 16-bit data frame extended is selected during the I2S
* configuration phase, the Size parameter means the number of 16-bit data length
* in the transaction and when a 24-bit data frame or a 32-bit data frame is selected
* the Size parameter means the number of 24-bit or 32-bit data length.
* @note The I2S is kept enabled at the end of transaction to avoid the clock de-synchronization
* between Master and Slave(example: audio streaming).
* @retval HAL status
*/
HAL_StatusTypeDef HAL_I2S_Receive_DMA(I2S_HandleTypeDef *hi2s, uint16_t *pData, uint16_t Size)
{
uint32_t tmpreg_cfgr;
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
if (hi2s->State != HAL_I2S_STATE_READY)
{
return HAL_BUSY;
}
/* Process Locked */
__HAL_LOCK(hi2s);
/* Set state and reset error code */
hi2s->State = HAL_I2S_STATE_BUSY_RX;
hi2s->ErrorCode = HAL_I2S_ERROR_NONE;
hi2s->pRxBuffPtr = pData;
tmpreg_cfgr = hi2s->Instance->I2SCFGR & (SPI_I2SCFGR_DATLEN | SPI_I2SCFGR_CHLEN);
if ((tmpreg_cfgr == I2S_DATAFORMAT_24B) || (tmpreg_cfgr == I2S_DATAFORMAT_32B))
{
hi2s->RxXferSize = (Size << 1U);
hi2s->RxXferCount = (Size << 1U);
}
else
{
hi2s->RxXferSize = Size;
hi2s->RxXferCount = Size;
}
/* Set the I2S Rx DMA Half transfer complete callback */
hi2s->hdmarx->XferHalfCpltCallback = I2S_DMARxHalfCplt;
/* Set the I2S Rx DMA transfer complete callback */
hi2s->hdmarx->XferCpltCallback = I2S_DMARxCplt;
/* Set the DMA error callback */
hi2s->hdmarx->XferErrorCallback = I2S_DMAError;
/* Check if Master Receiver mode is selected */
if ((hi2s->Instance->I2SCFGR & SPI_I2SCFGR_I2SCFG) == I2S_MODE_MASTER_RX)
{
/* Clear the Overrun Flag by a read operation to the SPI_DR register followed by a read
access to the SPI_SR register. */
__HAL_I2S_CLEAR_OVRFLAG(hi2s);
}
/* Enable the Rx DMA Stream/Channel */
if (HAL_OK != HAL_DMA_Start_IT(hi2s->hdmarx, (uint32_t)&hi2s->Instance->DR, (uint32_t)hi2s->pRxBuffPtr,
hi2s->RxXferSize))
{
/* Update SPI error code */
SET_BIT(hi2s->ErrorCode, HAL_I2S_ERROR_DMA);
hi2s->State = HAL_I2S_STATE_READY;
__HAL_UNLOCK(hi2s);
return HAL_ERROR;
}
__HAL_UNLOCK(hi2s);
/* Check if the I2S Rx request is already enabled */
if (HAL_IS_BIT_CLR(hi2s->Instance->CR2, SPI_CR2_RXDMAEN))
{
/* Enable Rx DMA Request */
SET_BIT(hi2s->Instance->CR2, SPI_CR2_RXDMAEN);
}
/* Check if the I2S is already enabled */
if (HAL_IS_BIT_CLR(hi2s->Instance->I2SCFGR, SPI_I2SCFGR_I2SE))
{
/* Enable I2S peripheral */
__HAL_I2S_ENABLE(hi2s);
}
return HAL_OK;
}
/**
* @brief Pauses the audio DMA Stream/Channel playing from the Media.
* @param hi2s pointer to a I2S_HandleTypeDef structure that contains
* the configuration information for I2S module
* @retval HAL status
*/
HAL_StatusTypeDef HAL_I2S_DMAPause(I2S_HandleTypeDef *hi2s)
{
/* Process Locked */
__HAL_LOCK(hi2s);
if (hi2s->State == HAL_I2S_STATE_BUSY_TX)
{
/* Disable the I2S DMA Tx request */
CLEAR_BIT(hi2s->Instance->CR2, SPI_CR2_TXDMAEN);
}
else if (hi2s->State == HAL_I2S_STATE_BUSY_RX)
{
/* Disable the I2S DMA Rx request */
CLEAR_BIT(hi2s->Instance->CR2, SPI_CR2_RXDMAEN);
}
else
{
/* nothing to do */
}
/* Process Unlocked */
__HAL_UNLOCK(hi2s);
return HAL_OK;
}
/**
* @brief Resumes the audio DMA Stream/Channel playing from the Media.
* @param hi2s pointer to a I2S_HandleTypeDef structure that contains
* the configuration information for I2S module
* @retval HAL status
*/
HAL_StatusTypeDef HAL_I2S_DMAResume(I2S_HandleTypeDef *hi2s)
{
/* Process Locked */
__HAL_LOCK(hi2s);
if (hi2s->State == HAL_I2S_STATE_BUSY_TX)
{
/* Enable the I2S DMA Tx request */
SET_BIT(hi2s->Instance->CR2, SPI_CR2_TXDMAEN);
}
else if (hi2s->State == HAL_I2S_STATE_BUSY_RX)
{
/* Enable the I2S DMA Rx request */
SET_BIT(hi2s->Instance->CR2, SPI_CR2_RXDMAEN);
}
else
{
/* nothing to do */
}
/* If the I2S peripheral is still not enabled, enable it */
if (HAL_IS_BIT_CLR(hi2s->Instance->I2SCFGR, SPI_I2SCFGR_I2SE))
{
/* Enable I2S peripheral */
__HAL_I2S_ENABLE(hi2s);
}
/* Process Unlocked */
__HAL_UNLOCK(hi2s);
return HAL_OK;
}
/**
* @brief Stops the audio DMA Stream/Channel playing from the Media.
* @param hi2s pointer to a I2S_HandleTypeDef structure that contains
* the configuration information for I2S module
* @retval HAL status
*/
HAL_StatusTypeDef HAL_I2S_DMAStop(I2S_HandleTypeDef *hi2s)
{
HAL_StatusTypeDef errorcode = HAL_OK;
/* The Lock is not implemented on this API to allow the user application
to call the HAL SPI API under callbacks HAL_I2S_TxCpltCallback() or HAL_I2S_RxCpltCallback()
when calling HAL_DMA_Abort() API the DMA TX or RX Transfer complete interrupt is generated
and the correspond call back is executed HAL_I2S_TxCpltCallback() or HAL_I2S_RxCpltCallback()
*/
if ((hi2s->Init.Mode == I2S_MODE_MASTER_TX) || (hi2s->Init.Mode == I2S_MODE_SLAVE_TX))
{
/* Abort the I2S DMA tx Stream/Channel */
if (hi2s->hdmatx != NULL)
{
/* Disable the I2S DMA tx Stream/Channel */
if (HAL_OK != HAL_DMA_Abort(hi2s->hdmatx))
{
SET_BIT(hi2s->ErrorCode, HAL_I2S_ERROR_DMA);
errorcode = HAL_ERROR;
}
}
/* Wait until TXE flag is set */
if (I2S_WaitFlagStateUntilTimeout(hi2s, I2S_FLAG_TXE, SET, I2S_TIMEOUT_FLAG) != HAL_OK)
{
/* Set the error code */
SET_BIT(hi2s->ErrorCode, HAL_I2S_ERROR_TIMEOUT);
hi2s->State = HAL_I2S_STATE_READY;
errorcode = HAL_ERROR;
}
/* Wait until BSY flag is Reset */
if (I2S_WaitFlagStateUntilTimeout(hi2s, I2S_FLAG_BSY, RESET, I2S_TIMEOUT_FLAG) != HAL_OK)
{
/* Set the error code */
SET_BIT(hi2s->ErrorCode, HAL_I2S_ERROR_TIMEOUT);
hi2s->State = HAL_I2S_STATE_READY;
errorcode = HAL_ERROR;
}
/* Disable I2S peripheral */
__HAL_I2S_DISABLE(hi2s);
/* Clear UDR flag */
__HAL_I2S_CLEAR_UDRFLAG(hi2s);
/* Disable the I2S Tx DMA requests */
CLEAR_BIT(hi2s->Instance->CR2, SPI_CR2_TXDMAEN);
}
else if ((hi2s->Init.Mode == I2S_MODE_MASTER_RX) || (hi2s->Init.Mode == I2S_MODE_SLAVE_RX))
{
/* Abort the I2S DMA rx Stream/Channel */
if (hi2s->hdmarx != NULL)
{
/* Disable the I2S DMA rx Stream/Channel */
if (HAL_OK != HAL_DMA_Abort(hi2s->hdmarx))
{
SET_BIT(hi2s->ErrorCode, HAL_I2S_ERROR_DMA);
errorcode = HAL_ERROR;
}
}
/* Disable I2S peripheral */
__HAL_I2S_DISABLE(hi2s);
/* Clear OVR flag */
__HAL_I2S_CLEAR_OVRFLAG(hi2s);
/* Disable the I2S Rx DMA request */
CLEAR_BIT(hi2s->Instance->CR2, SPI_CR2_RXDMAEN);
if (hi2s->Init.Mode == I2S_MODE_SLAVE_RX)
{
/* Set the error code */
SET_BIT(hi2s->ErrorCode, HAL_I2S_ERROR_BUSY_LINE_RX);
/* Set the I2S State ready */
hi2s->State = HAL_I2S_STATE_READY;
errorcode = HAL_ERROR;
}
else
{
/* Read DR to Flush RX Data */
READ_REG((hi2s->Instance)->DR);
}
}
hi2s->State = HAL_I2S_STATE_READY;
return errorcode;
}
/**
* @brief This function handles I2S interrupt request.
* @param hi2s pointer to a I2S_HandleTypeDef structure that contains
* the configuration information for I2S module
* @retval None
*/
void HAL_I2S_IRQHandler(I2S_HandleTypeDef *hi2s)
{
uint32_t itsource = hi2s->Instance->CR2;
uint32_t itflag = hi2s->Instance->SR;
/* I2S in mode Receiver ------------------------------------------------*/
if ((I2S_CHECK_FLAG(itflag, I2S_FLAG_OVR) == RESET) &&
(I2S_CHECK_FLAG(itflag, I2S_FLAG_RXNE) != RESET) && (I2S_CHECK_IT_SOURCE(itsource, I2S_IT_RXNE) != RESET))
{
I2S_Receive_IT(hi2s);
return;
}
/* I2S in mode Tramitter -----------------------------------------------*/
if ((I2S_CHECK_FLAG(itflag, I2S_FLAG_TXE) != RESET) && (I2S_CHECK_IT_SOURCE(itsource, I2S_IT_TXE) != RESET))
{
I2S_Transmit_IT(hi2s);
return;
}
/* I2S interrupt error -------------------------------------------------*/
if (I2S_CHECK_IT_SOURCE(itsource, I2S_IT_ERR) != RESET)
{
/* I2S Overrun error interrupt occurred ---------------------------------*/
if (I2S_CHECK_FLAG(itflag, I2S_FLAG_OVR) != RESET)
{
/* Disable RXNE and ERR interrupt */
__HAL_I2S_DISABLE_IT(hi2s, (I2S_IT_RXNE | I2S_IT_ERR));
/* Set the error code and execute error callback*/
SET_BIT(hi2s->ErrorCode, HAL_I2S_ERROR_OVR);
}
/* I2S Underrun error interrupt occurred --------------------------------*/
if (I2S_CHECK_FLAG(itflag, I2S_FLAG_UDR) != RESET)
{
/* Disable TXE and ERR interrupt */
__HAL_I2S_DISABLE_IT(hi2s, (I2S_IT_TXE | I2S_IT_ERR));
/* Set the error code and execute error callback*/
SET_BIT(hi2s->ErrorCode, HAL_I2S_ERROR_UDR);
}
/* Set the I2S State ready */
hi2s->State = HAL_I2S_STATE_READY;
/* Call user error callback */
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 1U)
hi2s->ErrorCallback(hi2s);
#else
HAL_I2S_ErrorCallback(hi2s);
#endif /* USE_HAL_I2S_REGISTER_CALLBACKS */
}
}
/**
* @brief Tx Transfer Half completed callbacks
* @param hi2s pointer to a I2S_HandleTypeDef structure that contains
* the configuration information for I2S module
* @retval None
*/
__weak void HAL_I2S_TxHalfCpltCallback(I2S_HandleTypeDef *hi2s)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hi2s);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_I2S_TxHalfCpltCallback could be implemented in the user file
*/
}
/**
* @brief Tx Transfer completed callbacks
* @param hi2s pointer to a I2S_HandleTypeDef structure that contains
* the configuration information for I2S module
* @retval None
*/
__weak void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hi2s);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_I2S_TxCpltCallback could be implemented in the user file
*/
}
/**
* @brief Rx Transfer half completed callbacks
* @param hi2s pointer to a I2S_HandleTypeDef structure that contains
* the configuration information for I2S module
* @retval None
*/
__weak void HAL_I2S_RxHalfCpltCallback(I2S_HandleTypeDef *hi2s)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hi2s);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_I2S_RxHalfCpltCallback could be implemented in the user file
*/
}
/**
* @brief Rx Transfer completed callbacks
* @param hi2s pointer to a I2S_HandleTypeDef structure that contains
* the configuration information for I2S module
* @retval None
*/
__weak void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hi2s);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_I2S_RxCpltCallback could be implemented in the user file
*/
}
/**
* @brief I2S error callbacks
* @param hi2s pointer to a I2S_HandleTypeDef structure that contains
* the configuration information for I2S module
* @retval None
*/
__weak void HAL_I2S_ErrorCallback(I2S_HandleTypeDef *hi2s)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hi2s);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_I2S_ErrorCallback could be implemented in the user file
*/
}
/**
* @}
*/
/** @defgroup I2S_Exported_Functions_Group3 Peripheral State and Errors functions
* @brief Peripheral State functions
*
@verbatim
===============================================================================
##### Peripheral State and Errors functions #####
===============================================================================
[..]
This subsection permits to get in run-time the status of the peripheral
and the data flow.
@endverbatim
* @{
*/
/**
* @brief Return the I2S state
* @param hi2s pointer to a I2S_HandleTypeDef structure that contains
* the configuration information for I2S module
* @retval HAL state
*/
HAL_I2S_StateTypeDef HAL_I2S_GetState(I2S_HandleTypeDef *hi2s)
{
return hi2s->State;
}
/**
* @brief Return the I2S error code
* @param hi2s pointer to a I2S_HandleTypeDef structure that contains
* the configuration information for I2S module
* @retval I2S Error Code
*/
uint32_t HAL_I2S_GetError(I2S_HandleTypeDef *hi2s)
{
return hi2s->ErrorCode;
}
/**
* @}
*/
/**
* @}
*/
/** @addtogroup I2S_Private_Functions I2S Private Functions
* @{
*/
/**
* @brief DMA I2S transmit process complete callback
* @param hdma pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
static void I2S_DMATxCplt(DMA_HandleTypeDef *hdma)
{
I2S_HandleTypeDef *hi2s = (I2S_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent; /* Derogation MISRAC2012-Rule-11.5 */
/* if DMA is configured in DMA_NORMAL Mode */
if (hdma->Init.Mode == DMA_NORMAL)
{
/* Disable Tx DMA Request */
CLEAR_BIT(hi2s->Instance->CR2, SPI_CR2_TXDMAEN);
hi2s->TxXferCount = 0U;
hi2s->State = HAL_I2S_STATE_READY;
}
/* Call user Tx complete callback */
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 1U)
hi2s->TxCpltCallback(hi2s);
#else
HAL_I2S_TxCpltCallback(hi2s);
#endif /* USE_HAL_I2S_REGISTER_CALLBACKS */
}
/**
* @brief DMA I2S transmit process half complete callback
* @param hdma pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
static void I2S_DMATxHalfCplt(DMA_HandleTypeDef *hdma)
{
I2S_HandleTypeDef *hi2s = (I2S_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent; /* Derogation MISRAC2012-Rule-11.5 */
/* Call user Tx half complete callback */
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 1U)
hi2s->TxHalfCpltCallback(hi2s);
#else
HAL_I2S_TxHalfCpltCallback(hi2s);
#endif /* USE_HAL_I2S_REGISTER_CALLBACKS */
}
/**
* @brief DMA I2S receive process complete callback
* @param hdma pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
static void I2S_DMARxCplt(DMA_HandleTypeDef *hdma)
{
I2S_HandleTypeDef *hi2s = (I2S_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent; /* Derogation MISRAC2012-Rule-11.5 */
/* if DMA is configured in DMA_NORMAL Mode */
if (hdma->Init.Mode == DMA_NORMAL)
{
/* Disable Rx DMA Request */
CLEAR_BIT(hi2s->Instance->CR2, SPI_CR2_RXDMAEN);
hi2s->RxXferCount = 0U;
hi2s->State = HAL_I2S_STATE_READY;
}
/* Call user Rx complete callback */
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 1U)
hi2s->RxCpltCallback(hi2s);
#else
HAL_I2S_RxCpltCallback(hi2s);
#endif /* USE_HAL_I2S_REGISTER_CALLBACKS */
}
/**
* @brief DMA I2S receive process half complete callback
* @param hdma pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
static void I2S_DMARxHalfCplt(DMA_HandleTypeDef *hdma)
{
I2S_HandleTypeDef *hi2s = (I2S_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent; /* Derogation MISRAC2012-Rule-11.5 */
/* Call user Rx half complete callback */
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 1U)
hi2s->RxHalfCpltCallback(hi2s);
#else
HAL_I2S_RxHalfCpltCallback(hi2s);
#endif /* USE_HAL_I2S_REGISTER_CALLBACKS */
}
/**
* @brief DMA I2S communication error callback
* @param hdma pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
static void I2S_DMAError(DMA_HandleTypeDef *hdma)
{
I2S_HandleTypeDef *hi2s = (I2S_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent; /* Derogation MISRAC2012-Rule-11.5 */
/* Disable Rx and Tx DMA Request */
CLEAR_BIT(hi2s->Instance->CR2, (SPI_CR2_RXDMAEN | SPI_CR2_TXDMAEN));
hi2s->TxXferCount = 0U;
hi2s->RxXferCount = 0U;
hi2s->State = HAL_I2S_STATE_READY;
/* Set the error code and execute error callback*/
SET_BIT(hi2s->ErrorCode, HAL_I2S_ERROR_DMA);
/* Call user error callback */
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 1U)
hi2s->ErrorCallback(hi2s);
#else
HAL_I2S_ErrorCallback(hi2s);
#endif /* USE_HAL_I2S_REGISTER_CALLBACKS */
}
/**
* @brief Transmit an amount of data in non-blocking mode with Interrupt
* @param hi2s pointer to a I2S_HandleTypeDef structure that contains
* the configuration information for I2S module
* @retval None
*/
static void I2S_Transmit_IT(I2S_HandleTypeDef *hi2s)
{
/* Transmit data */
hi2s->Instance->DR = (*hi2s->pTxBuffPtr);
hi2s->pTxBuffPtr++;
hi2s->TxXferCount--;
if (hi2s->TxXferCount == 0U)
{
/* Disable TXE and ERR interrupt */
__HAL_I2S_DISABLE_IT(hi2s, (I2S_IT_TXE | I2S_IT_ERR));
hi2s->State = HAL_I2S_STATE_READY;
/* Call user Tx complete callback */
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 1U)
hi2s->TxCpltCallback(hi2s);
#else
HAL_I2S_TxCpltCallback(hi2s);
#endif /* USE_HAL_I2S_REGISTER_CALLBACKS */
}
}
/**
* @brief Receive an amount of data in non-blocking mode with Interrupt
* @param hi2s pointer to a I2S_HandleTypeDef structure that contains
* the configuration information for I2S module
* @retval None
*/
static void I2S_Receive_IT(I2S_HandleTypeDef *hi2s)
{
/* Receive data */
(*hi2s->pRxBuffPtr) = (uint16_t)hi2s->Instance->DR;
hi2s->pRxBuffPtr++;
hi2s->RxXferCount--;
if (hi2s->RxXferCount == 0U)
{
/* Disable RXNE and ERR interrupt */
__HAL_I2S_DISABLE_IT(hi2s, (I2S_IT_RXNE | I2S_IT_ERR));
hi2s->State = HAL_I2S_STATE_READY;
/* Call user Rx complete callback */
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 1U)
hi2s->RxCpltCallback(hi2s);
#else
HAL_I2S_RxCpltCallback(hi2s);
#endif /* USE_HAL_I2S_REGISTER_CALLBACKS */
}
}
/**
* @brief This function handles I2S Communication Timeout.
* @param hi2s pointer to a I2S_HandleTypeDef structure that contains
* the configuration information for I2S module
* @param Flag Flag checked
* @param State Value of the flag expected
* @param Timeout Duration of the timeout
* @retval HAL status
*/
static HAL_StatusTypeDef I2S_WaitFlagStateUntilTimeout(I2S_HandleTypeDef *hi2s, uint32_t Flag, FlagStatus State,
uint32_t Timeout)
{
uint32_t tickstart;
/* Get tick */
tickstart = HAL_GetTick();
/* Wait until flag is set to status*/
while (((__HAL_I2S_GET_FLAG(hi2s, Flag)) ? SET : RESET) != State)
{
if (Timeout != HAL_MAX_DELAY)
{
if (((HAL_GetTick() - tickstart) >= Timeout) || (Timeout == 0U))
{
/* Set the I2S State ready */
hi2s->State = HAL_I2S_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(hi2s);
return HAL_TIMEOUT;
}
}
}
return HAL_OK;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#endif /* SPI_I2S_SUPPORT */
#endif /* HAL_I2S_MODULE_ENABLED */

View File

@@ -0,0 +1,2666 @@
/**
******************************************************************************
* @file stm32f1xx_hal_irda.c
* @author MCD Application Team
* @brief IRDA HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of the IrDA SIR ENDEC block (IrDA):
* + Initialization and de-initialization functions
* + IO operation functions
* + Peripheral Control functions
* + Peripheral State and Errors functions
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
==============================================================================
##### How to use this driver #####
==============================================================================
[..]
The IRDA HAL driver can be used as follows:
(#) Declare a IRDA_HandleTypeDef handle structure (eg. IRDA_HandleTypeDef hirda).
(#) Initialize the IRDA low level resources by implementing the HAL_IRDA_MspInit() API:
(##) Enable the USARTx interface clock.
(##) IRDA pins configuration:
(+++) Enable the clock for the IRDA GPIOs.
(+++) Configure IRDA pins as alternate function pull-up.
(##) NVIC configuration if you need to use interrupt process (HAL_IRDA_Transmit_IT()
and HAL_IRDA_Receive_IT() APIs):
(+++) Configure the USARTx interrupt priority.
(+++) Enable the NVIC USART IRQ handle.
(##) DMA Configuration if you need to use DMA process (HAL_IRDA_Transmit_DMA()
and HAL_IRDA_Receive_DMA() APIs):
(+++) Declare a DMA handle structure for the Tx/Rx channel.
(+++) Enable the DMAx interface clock.
(+++) Configure the declared DMA handle structure with the required Tx/Rx parameters.
(+++) Configure the DMA Tx/Rx channel.
(+++) Associate the initialized DMA handle to the IRDA DMA Tx/Rx handle.
(+++) Configure the priority and enable the NVIC for the transfer complete interrupt on the DMA Tx/Rx channel.
(+++) Configure the IRDAx interrupt priority and enable the NVIC USART IRQ handle
(used for last byte sending completion detection in DMA non circular mode)
(#) Program the Baud Rate, Word Length, Parity, IrDA Mode, Prescaler
and Mode(Receiver/Transmitter) in the hirda Init structure.
(#) Initialize the IRDA registers by calling the HAL_IRDA_Init() API:
(++) This API configures also the low level Hardware GPIO, CLOCK, CORTEX...etc)
by calling the customized HAL_IRDA_MspInit() API.
-@@- The specific IRDA interrupts (Transmission complete interrupt,
RXNE interrupt and Error Interrupts) will be managed using the macros
__HAL_IRDA_ENABLE_IT() and __HAL_IRDA_DISABLE_IT() inside the transmit and receive process.
(#) Three operation modes are available within this driver :
*** Polling mode IO operation ***
=================================
[..]
(+) Send an amount of data in blocking mode using HAL_IRDA_Transmit()
(+) Receive an amount of data in blocking mode using HAL_IRDA_Receive()
*** Interrupt mode IO operation ***
===================================
[..]
(+) Send an amount of data in non blocking mode using HAL_IRDA_Transmit_IT()
(+) At transmission end of transfer HAL_IRDA_TxCpltCallback is executed and user can
add his own code by customization of function pointer HAL_IRDA_TxCpltCallback
(+) Receive an amount of data in non blocking mode using HAL_IRDA_Receive_IT()
(+) At reception end of transfer HAL_IRDA_RxCpltCallback is executed and user can
add his own code by customization of function pointer HAL_IRDA_RxCpltCallback
(+) In case of transfer Error, HAL_IRDA_ErrorCallback() function is executed and user can
add his own code by customization of function pointer HAL_IRDA_ErrorCallback
*** DMA mode IO operation ***
=============================
[..]
(+) Send an amount of data in non blocking mode (DMA) using HAL_IRDA_Transmit_DMA()
(+) At transmission end of half transfer HAL_IRDA_TxHalfCpltCallback is executed and user can
add his own code by customization of function pointer HAL_IRDA_TxHalfCpltCallback
(+) At transmission end of transfer HAL_IRDA_TxCpltCallback is executed and user can
add his own code by customization of function pointer HAL_IRDA_TxCpltCallback
(+) Receive an amount of data in non blocking mode (DMA) using HAL_IRDA_Receive_DMA()
(+) At reception end of half transfer HAL_IRDA_RxHalfCpltCallback is executed and user can
add his own code by customization of function pointer HAL_IRDA_RxHalfCpltCallback
(+) At reception end of transfer HAL_IRDA_RxCpltCallback is executed and user can
add his own code by customization of function pointer HAL_IRDA_RxCpltCallback
(+) In case of transfer Error, HAL_IRDA_ErrorCallback() function is executed and user can
add his own code by customization of function pointer HAL_IRDA_ErrorCallback
(+) Pause the DMA Transfer using HAL_IRDA_DMAPause()
(+) Resume the DMA Transfer using HAL_IRDA_DMAResume()
(+) Stop the DMA Transfer using HAL_IRDA_DMAStop()
*** IRDA HAL driver macros list ***
===================================
[..]
Below the list of most used macros in IRDA HAL driver.
(+) __HAL_IRDA_ENABLE: Enable the IRDA peripheral
(+) __HAL_IRDA_DISABLE: Disable the IRDA peripheral
(+) __HAL_IRDA_GET_FLAG : Check whether the specified IRDA flag is set or not
(+) __HAL_IRDA_CLEAR_FLAG : Clear the specified IRDA pending flag
(+) __HAL_IRDA_ENABLE_IT: Enable the specified IRDA interrupt
(+) __HAL_IRDA_DISABLE_IT: Disable the specified IRDA interrupt
(+) __HAL_IRDA_GET_IT_SOURCE: Check whether the specified IRDA interrupt has occurred or not
[..]
(@) You can refer to the IRDA HAL driver header file for more useful macros
##### Callback registration #####
==================================
[..]
The compilation define USE_HAL_IRDA_REGISTER_CALLBACKS when set to 1
allows the user to configure dynamically the driver callbacks.
[..]
Use Function HAL_IRDA_RegisterCallback() to register a user callback.
Function HAL_IRDA_RegisterCallback() allows to register following callbacks:
(+) TxHalfCpltCallback : Tx Half Complete Callback.
(+) TxCpltCallback : Tx Complete Callback.
(+) RxHalfCpltCallback : Rx Half Complete Callback.
(+) RxCpltCallback : Rx Complete Callback.
(+) ErrorCallback : Error Callback.
(+) AbortCpltCallback : Abort Complete Callback.
(+) AbortTransmitCpltCallback : Abort Transmit Complete Callback.
(+) AbortReceiveCpltCallback : Abort Receive Complete Callback.
(+) MspInitCallback : IRDA MspInit.
(+) MspDeInitCallback : IRDA MspDeInit.
This function takes as parameters the HAL peripheral handle, the Callback ID
and a pointer to the user callback function.
[..]
Use function HAL_IRDA_UnRegisterCallback() to reset a callback to the default
weak (surcharged) function.
HAL_IRDA_UnRegisterCallback() takes as parameters the HAL peripheral handle,
and the Callback ID.
This function allows to reset following callbacks:
(+) TxHalfCpltCallback : Tx Half Complete Callback.
(+) TxCpltCallback : Tx Complete Callback.
(+) RxHalfCpltCallback : Rx Half Complete Callback.
(+) RxCpltCallback : Rx Complete Callback.
(+) ErrorCallback : Error Callback.
(+) AbortCpltCallback : Abort Complete Callback.
(+) AbortTransmitCpltCallback : Abort Transmit Complete Callback.
(+) AbortReceiveCpltCallback : Abort Receive Complete Callback.
(+) MspInitCallback : IRDA MspInit.
(+) MspDeInitCallback : IRDA MspDeInit.
[..]
By default, after the HAL_IRDA_Init() and when the state is HAL_IRDA_STATE_RESET
all callbacks are set to the corresponding weak (surcharged) functions:
examples HAL_IRDA_TxCpltCallback(), HAL_IRDA_RxHalfCpltCallback().
Exception done for MspInit and MspDeInit functions that are respectively
reset to the legacy weak (surcharged) functions in the HAL_IRDA_Init()
and HAL_IRDA_DeInit() only when these callbacks are null (not registered beforehand).
If not, MspInit or MspDeInit are not null, the HAL_IRDA_Init() and HAL_IRDA_DeInit()
keep and use the user MspInit/MspDeInit callbacks (registered beforehand).
[..]
Callbacks can be registered/unregistered in HAL_IRDA_STATE_READY state only.
Exception done MspInit/MspDeInit that can be registered/unregistered
in HAL_IRDA_STATE_READY or HAL_IRDA_STATE_RESET state, thus registered (user)
MspInit/DeInit callbacks can be used during the Init/DeInit.
In that case first register the MspInit/MspDeInit user callbacks
using HAL_IRDA_RegisterCallback() before calling HAL_IRDA_DeInit()
or HAL_IRDA_Init() function.
[..]
When The compilation define USE_HAL_IRDA_REGISTER_CALLBACKS is set to 0 or
not defined, the callback registration feature is not available
and weak (surcharged) callbacks are used.
@endverbatim
[..]
(@) Additional remark: If the parity is enabled, then the MSB bit of the data written
in the data register is transmitted but is changed by the parity bit.
Depending on the frame length defined by the M bit (8-bits or 9-bits),
the possible IRDA frame formats are as listed in the following table:
+-------------------------------------------------------------+
| M bit | PCE bit | IRDA frame |
|---------------------|---------------------------------------|
| 0 | 0 | | SB | 8 bit data | 1 STB | |
|---------|-----------|---------------------------------------|
| 0 | 1 | | SB | 7 bit data | PB | 1 STB | |
|---------|-----------|---------------------------------------|
| 1 | 0 | | SB | 9 bit data | 1 STB | |
|---------|-----------|---------------------------------------|
| 1 | 1 | | SB | 8 bit data | PB | 1 STB | |
+-------------------------------------------------------------+
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
/** @defgroup IRDA IRDA
* @brief HAL IRDA module driver
* @{
*/
#ifdef HAL_IRDA_MODULE_ENABLED
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/** @addtogroup IRDA_Private_Functions
* @{
*/
#if (USE_HAL_IRDA_REGISTER_CALLBACKS == 1)
void IRDA_InitCallbacksToDefault(IRDA_HandleTypeDef *hirda);
#endif /* USE_HAL_IRDA_REGISTER_CALLBACKS */
static void IRDA_SetConfig(IRDA_HandleTypeDef *hirda);
static HAL_StatusTypeDef IRDA_Transmit_IT(IRDA_HandleTypeDef *hirda);
static HAL_StatusTypeDef IRDA_EndTransmit_IT(IRDA_HandleTypeDef *hirda);
static HAL_StatusTypeDef IRDA_Receive_IT(IRDA_HandleTypeDef *hirda);
static void IRDA_DMATransmitCplt(DMA_HandleTypeDef *hdma);
static void IRDA_DMATransmitHalfCplt(DMA_HandleTypeDef *hdma);
static void IRDA_DMAReceiveCplt(DMA_HandleTypeDef *hdma);
static void IRDA_DMAReceiveHalfCplt(DMA_HandleTypeDef *hdma);
static void IRDA_DMAError(DMA_HandleTypeDef *hdma);
static void IRDA_DMAAbortOnError(DMA_HandleTypeDef *hdma);
static void IRDA_DMATxAbortCallback(DMA_HandleTypeDef *hdma);
static void IRDA_DMARxAbortCallback(DMA_HandleTypeDef *hdma);
static void IRDA_DMATxOnlyAbortCallback(DMA_HandleTypeDef *hdma);
static void IRDA_DMARxOnlyAbortCallback(DMA_HandleTypeDef *hdma);
static HAL_StatusTypeDef IRDA_WaitOnFlagUntilTimeout(IRDA_HandleTypeDef *hirda, uint32_t Flag, FlagStatus Status, uint32_t Tickstart, uint32_t Timeout);
static void IRDA_EndTxTransfer(IRDA_HandleTypeDef *hirda);
static void IRDA_EndRxTransfer(IRDA_HandleTypeDef *hirda);
/**
* @}
*/
/* Exported functions --------------------------------------------------------*/
/** @defgroup IRDA_Exported_Functions IrDA Exported Functions
* @{
*/
/** @defgroup IRDA_Exported_Functions_Group1 IrDA Initialization and de-initialization functions
* @brief Initialization and Configuration functions
*
@verbatim
==============================================================================
##### Initialization and Configuration functions #####
==============================================================================
[..]
This subsection provides a set of functions allowing to initialize the USARTx or the UARTy
in asynchronous IrDA mode.
(+) For the asynchronous mode only these parameters can be configured:
(++) BaudRate
(++) WordLength
(++) Parity: If the parity is enabled, then the MSB bit of the data written
in the data register is transmitted but is changed by the parity bit.
Depending on the frame length defined by the M bit (8-bits or 9-bits),
please refer to Reference manual for possible IRDA frame formats.
(++) Prescaler: A pulse of width less than two and greater than one PSC period(s) may or may
not be rejected. The receiver set up time should be managed by software. The IrDA physical layer
specification specifies a minimum of 10 ms delay between transmission and
reception (IrDA is a half duplex protocol).
(++) Mode: Receiver/transmitter modes
(++) IrDAMode: the IrDA can operate in the Normal mode or in the Low power mode.
[..]
The HAL_IRDA_Init() API follows IRDA configuration procedures (details for the procedures
are available in reference manual).
@endverbatim
* @{
*/
/**
* @brief Initializes the IRDA mode according to the specified
* parameters in the IRDA_InitTypeDef and create the associated handle.
* @param hirda Pointer to a IRDA_HandleTypeDef structure that contains
* the configuration information for the specified IRDA module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_IRDA_Init(IRDA_HandleTypeDef *hirda)
{
/* Check the IRDA handle allocation */
if (hirda == NULL)
{
return HAL_ERROR;
}
/* Check the IRDA instance parameters */
assert_param(IS_IRDA_INSTANCE(hirda->Instance));
/* Check the IRDA mode parameter in the IRDA handle */
assert_param(IS_IRDA_POWERMODE(hirda->Init.IrDAMode));
if (hirda->gState == HAL_IRDA_STATE_RESET)
{
/* Allocate lock resource and initialize it */
hirda->Lock = HAL_UNLOCKED;
#if USE_HAL_IRDA_REGISTER_CALLBACKS == 1
IRDA_InitCallbacksToDefault(hirda);
if (hirda->MspInitCallback == NULL)
{
hirda->MspInitCallback = HAL_IRDA_MspInit;
}
/* Init the low level hardware */
hirda->MspInitCallback(hirda);
#else
/* Init the low level hardware : GPIO, CLOCK */
HAL_IRDA_MspInit(hirda);
#endif /* USE_HAL_IRDA_REGISTER_CALLBACKS */
}
hirda->gState = HAL_IRDA_STATE_BUSY;
/* Disable the IRDA peripheral */
__HAL_IRDA_DISABLE(hirda);
/* Set the IRDA communication parameters */
IRDA_SetConfig(hirda);
/* In IrDA mode, the following bits must be kept cleared:
- LINEN, STOP and CLKEN bits in the USART_CR2 register,
- SCEN and HDSEL bits in the USART_CR3 register.*/
CLEAR_BIT(hirda->Instance->CR2, (USART_CR2_LINEN | USART_CR2_STOP | USART_CR2_CLKEN));
CLEAR_BIT(hirda->Instance->CR3, (USART_CR3_SCEN | USART_CR3_HDSEL));
/* Enable the IRDA peripheral */
__HAL_IRDA_ENABLE(hirda);
/* Set the prescaler */
MODIFY_REG(hirda->Instance->GTPR, USART_GTPR_PSC, hirda->Init.Prescaler);
/* Configure the IrDA mode */
MODIFY_REG(hirda->Instance->CR3, USART_CR3_IRLP, hirda->Init.IrDAMode);
/* Enable the IrDA mode by setting the IREN bit in the CR3 register */
SET_BIT(hirda->Instance->CR3, USART_CR3_IREN);
/* Initialize the IRDA state*/
hirda->ErrorCode = HAL_IRDA_ERROR_NONE;
hirda->gState = HAL_IRDA_STATE_READY;
hirda->RxState = HAL_IRDA_STATE_READY;
return HAL_OK;
}
/**
* @brief DeInitializes the IRDA peripheral
* @param hirda Pointer to a IRDA_HandleTypeDef structure that contains
* the configuration information for the specified IRDA module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_IRDA_DeInit(IRDA_HandleTypeDef *hirda)
{
/* Check the IRDA handle allocation */
if (hirda == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_IRDA_INSTANCE(hirda->Instance));
hirda->gState = HAL_IRDA_STATE_BUSY;
/* Disable the Peripheral */
__HAL_IRDA_DISABLE(hirda);
/* DeInit the low level hardware */
#if USE_HAL_IRDA_REGISTER_CALLBACKS == 1
if (hirda->MspDeInitCallback == NULL)
{
hirda->MspDeInitCallback = HAL_IRDA_MspDeInit;
}
/* DeInit the low level hardware */
hirda->MspDeInitCallback(hirda);
#else
HAL_IRDA_MspDeInit(hirda);
#endif /* USE_HAL_IRDA_REGISTER_CALLBACKS */
hirda->ErrorCode = HAL_IRDA_ERROR_NONE;
hirda->gState = HAL_IRDA_STATE_RESET;
hirda->RxState = HAL_IRDA_STATE_RESET;
/* Release Lock */
__HAL_UNLOCK(hirda);
return HAL_OK;
}
/**
* @brief IRDA MSP Init.
* @param hirda Pointer to a IRDA_HandleTypeDef structure that contains
* the configuration information for the specified IRDA module.
* @retval None
*/
__weak void HAL_IRDA_MspInit(IRDA_HandleTypeDef *hirda)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hirda);
/* NOTE: This function should not be modified, when the callback is needed,
the HAL_IRDA_MspInit can be implemented in the user file
*/
}
/**
* @brief IRDA MSP DeInit.
* @param hirda Pointer to a IRDA_HandleTypeDef structure that contains
* the configuration information for the specified IRDA module.
* @retval None
*/
__weak void HAL_IRDA_MspDeInit(IRDA_HandleTypeDef *hirda)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hirda);
/* NOTE: This function should not be modified, when the callback is needed,
the HAL_IRDA_MspDeInit can be implemented in the user file
*/
}
#if (USE_HAL_IRDA_REGISTER_CALLBACKS == 1)
/**
* @brief Register a User IRDA Callback
* To be used instead of the weak predefined callback
* @note The HAL_IRDA_RegisterCallback() may be called before HAL_IRDA_Init() in HAL_IRDA_STATE_RESET
* to register callbacks for HAL_IRDA_MSPINIT_CB_ID and HAL_IRDA_MSPDEINIT_CB_ID
* @param hirda irda handle
* @param CallbackID ID of the callback to be registered
* This parameter can be one of the following values:
* @arg @ref HAL_IRDA_TX_HALFCOMPLETE_CB_ID Tx Half Complete Callback ID
* @arg @ref HAL_IRDA_TX_COMPLETE_CB_ID Tx Complete Callback ID
* @arg @ref HAL_IRDA_RX_HALFCOMPLETE_CB_ID Rx Half Complete Callback ID
* @arg @ref HAL_IRDA_RX_COMPLETE_CB_ID Rx Complete Callback ID
* @arg @ref HAL_IRDA_ERROR_CB_ID Error Callback ID
* @arg @ref HAL_IRDA_ABORT_COMPLETE_CB_ID Abort Complete Callback ID
* @arg @ref HAL_IRDA_ABORT_TRANSMIT_COMPLETE_CB_ID Abort Transmit Complete Callback ID
* @arg @ref HAL_IRDA_ABORT_RECEIVE_COMPLETE_CB_ID Abort Receive Complete Callback ID
* @arg @ref HAL_IRDA_MSPINIT_CB_ID MspInit Callback ID
* @arg @ref HAL_IRDA_MSPDEINIT_CB_ID MspDeInit Callback ID
* @param pCallback pointer to the Callback function
* @retval HAL status
*/
HAL_StatusTypeDef HAL_IRDA_RegisterCallback(IRDA_HandleTypeDef *hirda, HAL_IRDA_CallbackIDTypeDef CallbackID, pIRDA_CallbackTypeDef pCallback)
{
HAL_StatusTypeDef status = HAL_OK;
if (pCallback == NULL)
{
/* Update the error code */
hirda->ErrorCode |= HAL_IRDA_ERROR_INVALID_CALLBACK;
return HAL_ERROR;
}
if (hirda->gState == HAL_IRDA_STATE_READY)
{
switch (CallbackID)
{
case HAL_IRDA_TX_HALFCOMPLETE_CB_ID :
hirda->TxHalfCpltCallback = pCallback;
break;
case HAL_IRDA_TX_COMPLETE_CB_ID :
hirda->TxCpltCallback = pCallback;
break;
case HAL_IRDA_RX_HALFCOMPLETE_CB_ID :
hirda->RxHalfCpltCallback = pCallback;
break;
case HAL_IRDA_RX_COMPLETE_CB_ID :
hirda->RxCpltCallback = pCallback;
break;
case HAL_IRDA_ERROR_CB_ID :
hirda->ErrorCallback = pCallback;
break;
case HAL_IRDA_ABORT_COMPLETE_CB_ID :
hirda->AbortCpltCallback = pCallback;
break;
case HAL_IRDA_ABORT_TRANSMIT_COMPLETE_CB_ID :
hirda->AbortTransmitCpltCallback = pCallback;
break;
case HAL_IRDA_ABORT_RECEIVE_COMPLETE_CB_ID :
hirda->AbortReceiveCpltCallback = pCallback;
break;
case HAL_IRDA_MSPINIT_CB_ID :
hirda->MspInitCallback = pCallback;
break;
case HAL_IRDA_MSPDEINIT_CB_ID :
hirda->MspDeInitCallback = pCallback;
break;
default :
/* Update the error code */
hirda->ErrorCode |= HAL_IRDA_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else if (hirda->gState == HAL_IRDA_STATE_RESET)
{
switch (CallbackID)
{
case HAL_IRDA_MSPINIT_CB_ID :
hirda->MspInitCallback = pCallback;
break;
case HAL_IRDA_MSPDEINIT_CB_ID :
hirda->MspDeInitCallback = pCallback;
break;
default :
/* Update the error code */
hirda->ErrorCode |= HAL_IRDA_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else
{
/* Update the error code */
hirda->ErrorCode |= HAL_IRDA_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
}
return status;
}
/**
* @brief Unregister an IRDA callback
* IRDA callback is redirected to the weak predefined callback
* @note The HAL_IRDA_UnRegisterCallback() may be called before HAL_IRDA_Init() in HAL_IRDA_STATE_RESET
* to un-register callbacks for HAL_IRDA_MSPINIT_CB_ID and HAL_IRDA_MSPDEINIT_CB_ID
* @param hirda irda handle
* @param CallbackID ID of the callback to be unregistered
* This parameter can be one of the following values:
* @arg @ref HAL_IRDA_TX_HALFCOMPLETE_CB_ID Tx Half Complete Callback ID
* @arg @ref HAL_IRDA_TX_COMPLETE_CB_ID Tx Complete Callback ID
* @arg @ref HAL_IRDA_RX_HALFCOMPLETE_CB_ID Rx Half Complete Callback ID
* @arg @ref HAL_IRDA_RX_COMPLETE_CB_ID Rx Complete Callback ID
* @arg @ref HAL_IRDA_ERROR_CB_ID Error Callback ID
* @arg @ref HAL_IRDA_ABORT_COMPLETE_CB_ID Abort Complete Callback ID
* @arg @ref HAL_IRDA_ABORT_TRANSMIT_COMPLETE_CB_ID Abort Transmit Complete Callback ID
* @arg @ref HAL_IRDA_ABORT_RECEIVE_COMPLETE_CB_ID Abort Receive Complete Callback ID
* @arg @ref HAL_IRDA_MSPINIT_CB_ID MspInit Callback ID
* @arg @ref HAL_IRDA_MSPDEINIT_CB_ID MspDeInit Callback ID
* @retval HAL status
*/
HAL_StatusTypeDef HAL_IRDA_UnRegisterCallback(IRDA_HandleTypeDef *hirda, HAL_IRDA_CallbackIDTypeDef CallbackID)
{
HAL_StatusTypeDef status = HAL_OK;
if (HAL_IRDA_STATE_READY == hirda->gState)
{
switch (CallbackID)
{
case HAL_IRDA_TX_HALFCOMPLETE_CB_ID :
hirda->TxHalfCpltCallback = HAL_IRDA_TxHalfCpltCallback; /* Legacy weak TxHalfCpltCallback */
break;
case HAL_IRDA_TX_COMPLETE_CB_ID :
hirda->TxCpltCallback = HAL_IRDA_TxCpltCallback; /* Legacy weak TxCpltCallback */
break;
case HAL_IRDA_RX_HALFCOMPLETE_CB_ID :
hirda->RxHalfCpltCallback = HAL_IRDA_RxHalfCpltCallback; /* Legacy weak RxHalfCpltCallback */
break;
case HAL_IRDA_RX_COMPLETE_CB_ID :
hirda->RxCpltCallback = HAL_IRDA_RxCpltCallback; /* Legacy weak RxCpltCallback */
break;
case HAL_IRDA_ERROR_CB_ID :
hirda->ErrorCallback = HAL_IRDA_ErrorCallback; /* Legacy weak ErrorCallback */
break;
case HAL_IRDA_ABORT_COMPLETE_CB_ID :
hirda->AbortCpltCallback = HAL_IRDA_AbortCpltCallback; /* Legacy weak AbortCpltCallback */
break;
case HAL_IRDA_ABORT_TRANSMIT_COMPLETE_CB_ID :
hirda->AbortTransmitCpltCallback = HAL_IRDA_AbortTransmitCpltCallback; /* Legacy weak AbortTransmitCpltCallback */
break;
case HAL_IRDA_ABORT_RECEIVE_COMPLETE_CB_ID :
hirda->AbortReceiveCpltCallback = HAL_IRDA_AbortReceiveCpltCallback; /* Legacy weak AbortReceiveCpltCallback */
break;
case HAL_IRDA_MSPINIT_CB_ID :
hirda->MspInitCallback = HAL_IRDA_MspInit; /* Legacy weak MspInitCallback */
break;
case HAL_IRDA_MSPDEINIT_CB_ID :
hirda->MspDeInitCallback = HAL_IRDA_MspDeInit; /* Legacy weak MspDeInitCallback */
break;
default :
/* Update the error code */
hirda->ErrorCode |= HAL_IRDA_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else if (HAL_IRDA_STATE_RESET == hirda->gState)
{
switch (CallbackID)
{
case HAL_IRDA_MSPINIT_CB_ID :
hirda->MspInitCallback = HAL_IRDA_MspInit;
break;
case HAL_IRDA_MSPDEINIT_CB_ID :
hirda->MspDeInitCallback = HAL_IRDA_MspDeInit;
break;
default :
/* Update the error code */
hirda->ErrorCode |= HAL_IRDA_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else
{
/* Update the error code */
hirda->ErrorCode |= HAL_IRDA_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
}
return status;
}
#endif /* USE_HAL_IRDA_REGISTER_CALLBACKS */
/**
* @}
*/
/** @defgroup IRDA_Exported_Functions_Group2 IO operation functions
* @brief IRDA Transmit and Receive functions
*
@verbatim
==============================================================================
##### IO operation functions #####
==============================================================================
[..]
This subsection provides a set of functions allowing to manage the IRDA data transfers.
IrDA is a half duplex communication protocol. If the Transmitter is busy, any data
on the IrDA receive line will be ignored by the IrDA decoder and if the Receiver
is busy, data on the TX from the USART to IrDA will not be encoded by IrDA.
While receiving data, transmission should be avoided as the data to be transmitted
could be corrupted.
(#) There are two modes of transfer:
(++) Blocking mode: The communication is performed in polling mode.
The HAL status of all data processing is returned by the same function
after finishing transfer.
(++) Non-Blocking mode: The communication is performed using Interrupts
or DMA, these API's return the HAL status.
The end of the data processing will be indicated through the
dedicated IRDA IRQ when using Interrupt mode or the DMA IRQ when
using DMA mode.
The HAL_IRDA_TxCpltCallback(), HAL_IRDA_RxCpltCallback() user callbacks
will be executed respectively at the end of the Transmit or Receive process
The HAL_IRDA_ErrorCallback() user callback will be executed when a communication error is detected
(#) Blocking mode APIs are :
(++) HAL_IRDA_Transmit()
(++) HAL_IRDA_Receive()
(#) Non Blocking mode APIs with Interrupt are :
(++) HAL_IRDA_Transmit_IT()
(++) HAL_IRDA_Receive_IT()
(++) HAL_IRDA_IRQHandler()
(#) Non Blocking mode functions with DMA are :
(++) HAL_IRDA_Transmit_DMA()
(++) HAL_IRDA_Receive_DMA()
(++) HAL_IRDA_DMAPause()
(++) HAL_IRDA_DMAResume()
(++) HAL_IRDA_DMAStop()
(#) A set of Transfer Complete Callbacks are provided in Non Blocking mode:
(++) HAL_IRDA_TxHalfCpltCallback()
(++) HAL_IRDA_TxCpltCallback()
(++) HAL_IRDA_RxHalfCpltCallback()
(++) HAL_IRDA_RxCpltCallback()
(++) HAL_IRDA_ErrorCallback()
(#) Non-Blocking mode transfers could be aborted using Abort API's :
(+) HAL_IRDA_Abort()
(+) HAL_IRDA_AbortTransmit()
(+) HAL_IRDA_AbortReceive()
(+) HAL_IRDA_Abort_IT()
(+) HAL_IRDA_AbortTransmit_IT()
(+) HAL_IRDA_AbortReceive_IT()
(#) For Abort services based on interrupts (HAL_IRDA_Abortxxx_IT), a set of Abort Complete Callbacks are provided:
(+) HAL_IRDA_AbortCpltCallback()
(+) HAL_IRDA_AbortTransmitCpltCallback()
(+) HAL_IRDA_AbortReceiveCpltCallback()
(#) In Non-Blocking mode transfers, possible errors are split into 2 categories.
Errors are handled as follows :
(+) Error is considered as Recoverable and non blocking : Transfer could go till end, but error severity is
to be evaluated by user : this concerns Frame Error, Parity Error or Noise Error in Interrupt mode reception .
Received character is then retrieved and stored in Rx buffer, Error code is set to allow user to identify error type,
and HAL_IRDA_ErrorCallback() user callback is executed. Transfer is kept ongoing on IRDA side.
If user wants to abort it, Abort services should be called by user.
(+) Error is considered as Blocking : Transfer could not be completed properly and is aborted.
This concerns Overrun Error In Interrupt mode reception and all errors in DMA mode.
Error code is set to allow user to identify error type, and HAL_IRDA_ErrorCallback() user callback is executed.
@endverbatim
* @{
*/
/**
* @brief Sends an amount of data in blocking mode.
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the sent data is handled as a set of u16. In this case, Size must reflect the number
* of u16 available through pData.
* @param hirda Pointer to a IRDA_HandleTypeDef structure that contains
* the configuration information for the specified IRDA module.
* @param pData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be sent.
* @param Timeout Specify timeout value.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_IRDA_Transmit(IRDA_HandleTypeDef *hirda, const uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
const uint16_t *tmp;
uint32_t tickstart = 0U;
/* Check that a Tx process is not already ongoing */
if (hirda->gState == HAL_IRDA_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(hirda);
hirda->ErrorCode = HAL_IRDA_ERROR_NONE;
hirda->gState = HAL_IRDA_STATE_BUSY_TX;
/* Init tickstart for timeout management*/
tickstart = HAL_GetTick();
hirda->TxXferSize = Size;
hirda->TxXferCount = Size;
while (hirda->TxXferCount > 0U)
{
hirda->TxXferCount--;
if (hirda->Init.WordLength == IRDA_WORDLENGTH_9B)
{
if (IRDA_WaitOnFlagUntilTimeout(hirda, IRDA_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK)
{
return HAL_TIMEOUT;
}
tmp = (const uint16_t *) pData;
hirda->Instance->DR = (*tmp & (uint16_t)0x01FF);
if (hirda->Init.Parity == IRDA_PARITY_NONE)
{
pData += 2U;
}
else
{
pData += 1U;
}
}
else
{
if (IRDA_WaitOnFlagUntilTimeout(hirda, IRDA_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK)
{
return HAL_TIMEOUT;
}
hirda->Instance->DR = (*pData++ & (uint8_t)0xFF);
}
}
if (IRDA_WaitOnFlagUntilTimeout(hirda, IRDA_FLAG_TC, RESET, tickstart, Timeout) != HAL_OK)
{
return HAL_TIMEOUT;
}
/* At end of Tx process, restore hirda->gState to Ready */
hirda->gState = HAL_IRDA_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(hirda);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Receive an amount of data in blocking mode.
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the received data is handled as a set of u16. In this case, Size must reflect the number
* of u16 available through pData.
* @param hirda Pointer to a IRDA_HandleTypeDef structure that contains
* the configuration information for the specified IRDA module.
* @param pData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be received.
* @param Timeout Specify timeout value
* @retval HAL status
*/
HAL_StatusTypeDef HAL_IRDA_Receive(IRDA_HandleTypeDef *hirda, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
uint16_t *tmp;
uint32_t tickstart = 0U;
/* Check that a Rx process is not already ongoing */
if (hirda->RxState == HAL_IRDA_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(hirda);
hirda->ErrorCode = HAL_IRDA_ERROR_NONE;
hirda->RxState = HAL_IRDA_STATE_BUSY_RX;
/* Init tickstart for timeout management*/
tickstart = HAL_GetTick();
hirda->RxXferSize = Size;
hirda->RxXferCount = Size;
/* Check the remain data to be received */
while (hirda->RxXferCount > 0U)
{
hirda->RxXferCount--;
if (hirda->Init.WordLength == IRDA_WORDLENGTH_9B)
{
if (IRDA_WaitOnFlagUntilTimeout(hirda, IRDA_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
{
return HAL_TIMEOUT;
}
tmp = (uint16_t *) pData ;
if (hirda->Init.Parity == IRDA_PARITY_NONE)
{
*tmp = (uint16_t)(hirda->Instance->DR & (uint16_t)0x01FF);
pData += 2U;
}
else
{
*tmp = (uint16_t)(hirda->Instance->DR & (uint16_t)0x00FF);
pData += 1U;
}
}
else
{
if (IRDA_WaitOnFlagUntilTimeout(hirda, IRDA_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
{
return HAL_TIMEOUT;
}
if (hirda->Init.Parity == IRDA_PARITY_NONE)
{
*pData++ = (uint8_t)(hirda->Instance->DR & (uint8_t)0x00FF);
}
else
{
*pData++ = (uint8_t)(hirda->Instance->DR & (uint8_t)0x007F);
}
}
}
/* At end of Rx process, restore hirda->RxState to Ready */
hirda->RxState = HAL_IRDA_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(hirda);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Send an amount of data in non blocking mode.
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the sent data is handled as a set of u16. In this case, Size must reflect the number
* of u16 available through pData.
* @param hirda Pointer to a IRDA_HandleTypeDef structure that contains
* the configuration information for the specified IRDA module.
* @param pData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be sent.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_IRDA_Transmit_IT(IRDA_HandleTypeDef *hirda, const uint8_t *pData, uint16_t Size)
{
/* Check that a Tx process is not already ongoing */
if (hirda->gState == HAL_IRDA_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(hirda);
hirda->pTxBuffPtr = pData;
hirda->TxXferSize = Size;
hirda->TxXferCount = Size;
hirda->ErrorCode = HAL_IRDA_ERROR_NONE;
hirda->gState = HAL_IRDA_STATE_BUSY_TX;
/* Process Unlocked */
__HAL_UNLOCK(hirda);
/* Enable the IRDA Transmit Data Register Empty Interrupt */
SET_BIT(hirda->Instance->CR1, USART_CR1_TXEIE);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Receive an amount of data in non blocking mode.
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the received data is handled as a set of u16. In this case, Size must reflect the number
* of u16 available through pData.
* @param hirda Pointer to a IRDA_HandleTypeDef structure that contains
* the configuration information for the specified IRDA module.
* @param pData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be received.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_IRDA_Receive_IT(IRDA_HandleTypeDef *hirda, uint8_t *pData, uint16_t Size)
{
/* Check that a Rx process is not already ongoing */
if (hirda->RxState == HAL_IRDA_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(hirda);
hirda->pRxBuffPtr = pData;
hirda->RxXferSize = Size;
hirda->RxXferCount = Size;
hirda->ErrorCode = HAL_IRDA_ERROR_NONE;
hirda->RxState = HAL_IRDA_STATE_BUSY_RX;
/* Process Unlocked */
__HAL_UNLOCK(hirda);
if (hirda->Init.Parity != IRDA_PARITY_NONE)
{
/* Enable the IRDA Parity Error and Data Register Not Empty Interrupts */
SET_BIT(hirda->Instance->CR1, USART_CR1_PEIE | USART_CR1_RXNEIE);
}
else
{
/* Enable the IRDA Data Register Not Empty Interrupts */
SET_BIT(hirda->Instance->CR1, USART_CR1_RXNEIE);
}
/* Enable the IRDA Error Interrupt: (Frame error, Noise error, Overrun error) */
SET_BIT(hirda->Instance->CR3, USART_CR3_EIE);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Send an amount of data in DMA mode.
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the sent data is handled as a set of u16. In this case, Size must reflect the number
* of u16 available through pData.
* @param hirda Pointer to a IRDA_HandleTypeDef structure that contains
* the configuration information for the specified IRDA module.
* @param pData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be sent.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_IRDA_Transmit_DMA(IRDA_HandleTypeDef *hirda, const uint8_t *pData, uint16_t Size)
{
const uint32_t *tmp;
/* Check that a Tx process is not already ongoing */
if (hirda->gState == HAL_IRDA_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(hirda);
hirda->pTxBuffPtr = pData;
hirda->TxXferSize = Size;
hirda->TxXferCount = Size;
hirda->ErrorCode = HAL_IRDA_ERROR_NONE;
hirda->gState = HAL_IRDA_STATE_BUSY_TX;
/* Set the IRDA DMA transfer complete callback */
hirda->hdmatx->XferCpltCallback = IRDA_DMATransmitCplt;
/* Set the IRDA DMA half transfer complete callback */
hirda->hdmatx->XferHalfCpltCallback = IRDA_DMATransmitHalfCplt;
/* Set the DMA error callback */
hirda->hdmatx->XferErrorCallback = IRDA_DMAError;
/* Set the DMA abort callback */
hirda->hdmatx->XferAbortCallback = NULL;
/* Enable the IRDA transmit DMA channel */
tmp = (const uint32_t *)&pData;
HAL_DMA_Start_IT(hirda->hdmatx, *(const uint32_t *)tmp, (uint32_t)&hirda->Instance->DR, Size);
/* Clear the TC flag in the SR register by writing 0 to it */
__HAL_IRDA_CLEAR_FLAG(hirda, IRDA_FLAG_TC);
/* Process Unlocked */
__HAL_UNLOCK(hirda);
/* Enable the DMA transfer for transmit request by setting the DMAT bit
in the USART CR3 register */
SET_BIT(hirda->Instance->CR3, USART_CR3_DMAT);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Receives an amount of data in DMA mode.
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the received data is handled as a set of u16. In this case, Size must reflect the number
* of u16 available through pData.
* @param hirda Pointer to a IRDA_HandleTypeDef structure that contains
* the configuration information for the specified IRDA module.
* @param pData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be received.
* @note When the IRDA parity is enabled (PCE = 1) the data received contain the parity bit.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_IRDA_Receive_DMA(IRDA_HandleTypeDef *hirda, uint8_t *pData, uint16_t Size)
{
uint32_t *tmp;
/* Check that a Rx process is not already ongoing */
if (hirda->RxState == HAL_IRDA_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(hirda);
hirda->pRxBuffPtr = pData;
hirda->RxXferSize = Size;
hirda->ErrorCode = HAL_IRDA_ERROR_NONE;
hirda->RxState = HAL_IRDA_STATE_BUSY_RX;
/* Set the IRDA DMA transfer complete callback */
hirda->hdmarx->XferCpltCallback = IRDA_DMAReceiveCplt;
/* Set the IRDA DMA half transfer complete callback */
hirda->hdmarx->XferHalfCpltCallback = IRDA_DMAReceiveHalfCplt;
/* Set the DMA error callback */
hirda->hdmarx->XferErrorCallback = IRDA_DMAError;
/* Set the DMA abort callback */
hirda->hdmarx->XferAbortCallback = NULL;
/* Enable the DMA channel */
tmp = (uint32_t *)&pData;
HAL_DMA_Start_IT(hirda->hdmarx, (uint32_t)&hirda->Instance->DR, *(uint32_t *)tmp, Size);
/* Clear the Overrun flag just before enabling the DMA Rx request: can be mandatory for the second transfer */
__HAL_IRDA_CLEAR_OREFLAG(hirda);
/* Process Unlocked */
__HAL_UNLOCK(hirda);
if (hirda->Init.Parity != IRDA_PARITY_NONE)
{
/* Enable the IRDA Parity Error Interrupt */
SET_BIT(hirda->Instance->CR1, USART_CR1_PEIE);
}
/* Enable the IRDA Error Interrupt: (Frame error, Noise error, Overrun error) */
SET_BIT(hirda->Instance->CR3, USART_CR3_EIE);
/* Enable the DMA transfer for the receiver request by setting the DMAR bit
in the USART CR3 register */
SET_BIT(hirda->Instance->CR3, USART_CR3_DMAR);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Pauses the DMA Transfer.
* @param hirda Pointer to a IRDA_HandleTypeDef structure that contains
* the configuration information for the specified IRDA module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_IRDA_DMAPause(IRDA_HandleTypeDef *hirda)
{
uint32_t dmarequest = 0x00U;
/* Process Locked */
__HAL_LOCK(hirda);
dmarequest = HAL_IS_BIT_SET(hirda->Instance->CR3, USART_CR3_DMAT);
if ((hirda->gState == HAL_IRDA_STATE_BUSY_TX) && dmarequest)
{
/* Disable the IRDA DMA Tx request */
CLEAR_BIT(hirda->Instance->CR3, USART_CR3_DMAT);
}
dmarequest = HAL_IS_BIT_SET(hirda->Instance->CR3, USART_CR3_DMAR);
if ((hirda->RxState == HAL_IRDA_STATE_BUSY_RX) && dmarequest)
{
/* Disable PE and ERR (Frame error, noise error, overrun error) interrupts */
CLEAR_BIT(hirda->Instance->CR1, USART_CR1_PEIE);
CLEAR_BIT(hirda->Instance->CR3, USART_CR3_EIE);
/* Disable the IRDA DMA Rx request */
CLEAR_BIT(hirda->Instance->CR3, USART_CR3_DMAR);
}
/* Process Unlocked */
__HAL_UNLOCK(hirda);
return HAL_OK;
}
/**
* @brief Resumes the DMA Transfer.
* @param hirda Pointer to a IRDA_HandleTypeDef structure that contains
* the configuration information for the specified IRDA module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_IRDA_DMAResume(IRDA_HandleTypeDef *hirda)
{
/* Process Locked */
__HAL_LOCK(hirda);
if (hirda->gState == HAL_IRDA_STATE_BUSY_TX)
{
/* Enable the IRDA DMA Tx request */
SET_BIT(hirda->Instance->CR3, USART_CR3_DMAT);
}
if (hirda->RxState == HAL_IRDA_STATE_BUSY_RX)
{
/* Clear the Overrun flag before resuming the Rx transfer */
__HAL_IRDA_CLEAR_OREFLAG(hirda);
/* Re-enable PE and ERR (Frame error, noise error, overrun error) interrupts */
if (hirda->Init.Parity != IRDA_PARITY_NONE)
{
SET_BIT(hirda->Instance->CR1, USART_CR1_PEIE);
}
SET_BIT(hirda->Instance->CR3, USART_CR3_EIE);
/* Enable the IRDA DMA Rx request */
SET_BIT(hirda->Instance->CR3, USART_CR3_DMAR);
}
/* Process Unlocked */
__HAL_UNLOCK(hirda);
return HAL_OK;
}
/**
* @brief Stops the DMA Transfer.
* @param hirda Pointer to a IRDA_HandleTypeDef structure that contains
* the configuration information for the specified IRDA module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_IRDA_DMAStop(IRDA_HandleTypeDef *hirda)
{
uint32_t dmarequest = 0x00U;
/* The Lock is not implemented on this API to allow the user application
to call the HAL IRDA API under callbacks HAL_IRDA_TxCpltCallback() / HAL_IRDA_RxCpltCallback():
when calling HAL_DMA_Abort() API the DMA TX/RX Transfer complete interrupt is generated
and the correspond call back is executed HAL_IRDA_TxCpltCallback() / HAL_IRDA_RxCpltCallback()
*/
/* Stop IRDA DMA Tx request if ongoing */
dmarequest = HAL_IS_BIT_SET(hirda->Instance->CR3, USART_CR3_DMAT);
if ((hirda->gState == HAL_IRDA_STATE_BUSY_TX) && dmarequest)
{
CLEAR_BIT(hirda->Instance->CR3, USART_CR3_DMAT);
/* Abort the IRDA DMA Tx channel */
if (hirda->hdmatx != NULL)
{
HAL_DMA_Abort(hirda->hdmatx);
}
IRDA_EndTxTransfer(hirda);
}
/* Stop IRDA DMA Rx request if ongoing */
dmarequest = HAL_IS_BIT_SET(hirda->Instance->CR3, USART_CR3_DMAR);
if ((hirda->RxState == HAL_IRDA_STATE_BUSY_RX) && dmarequest)
{
CLEAR_BIT(hirda->Instance->CR3, USART_CR3_DMAR);
/* Abort the IRDA DMA Rx channel */
if (hirda->hdmarx != NULL)
{
HAL_DMA_Abort(hirda->hdmarx);
}
IRDA_EndRxTransfer(hirda);
}
return HAL_OK;
}
/**
* @brief Abort ongoing transfers (blocking mode).
* @param hirda IRDA handle.
* @note This procedure could be used for aborting any ongoing transfer started in Interrupt or DMA mode.
* This procedure performs following operations :
* - Disable PPP Interrupts
* - Disable the DMA transfer in the peripheral register (if enabled)
* - Abort DMA transfer by calling HAL_DMA_Abort (in case of transfer in DMA mode)
* - Set handle State to READY
* @note This procedure is executed in blocking mode : when exiting function, Abort is considered as completed.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_IRDA_Abort(IRDA_HandleTypeDef *hirda)
{
/* Disable TXEIE, TCIE, RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
CLEAR_BIT(hirda->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE | USART_CR1_TXEIE | USART_CR1_TCIE));
CLEAR_BIT(hirda->Instance->CR3, USART_CR3_EIE);
/* Disable the IRDA DMA Tx request if enabled */
if (HAL_IS_BIT_SET(hirda->Instance->CR3, USART_CR3_DMAT))
{
CLEAR_BIT(hirda->Instance->CR3, USART_CR3_DMAT);
/* Abort the IRDA DMA Tx channel : use blocking DMA Abort API (no callback) */
if (hirda->hdmatx != NULL)
{
/* Set the IRDA DMA Abort callback to Null.
No call back execution at end of DMA abort procedure */
hirda->hdmatx->XferAbortCallback = NULL;
HAL_DMA_Abort(hirda->hdmatx);
}
}
/* Disable the IRDA DMA Rx request if enabled */
if (HAL_IS_BIT_SET(hirda->Instance->CR3, USART_CR3_DMAR))
{
CLEAR_BIT(hirda->Instance->CR3, USART_CR3_DMAR);
/* Abort the IRDA DMA Rx channel : use blocking DMA Abort API (no callback) */
if (hirda->hdmarx != NULL)
{
/* Set the IRDA DMA Abort callback to Null.
No call back execution at end of DMA abort procedure */
hirda->hdmarx->XferAbortCallback = NULL;
HAL_DMA_Abort(hirda->hdmarx);
}
}
/* Reset Tx and Rx transfer counters */
hirda->TxXferCount = 0x00U;
hirda->RxXferCount = 0x00U;
/* Reset ErrorCode */
hirda->ErrorCode = HAL_IRDA_ERROR_NONE;
/* Restore hirda->RxState and hirda->gState to Ready */
hirda->RxState = HAL_IRDA_STATE_READY;
hirda->gState = HAL_IRDA_STATE_READY;
return HAL_OK;
}
/**
* @brief Abort ongoing Transmit transfer (blocking mode).
* @param hirda IRDA handle.
* @note This procedure could be used for aborting any ongoing transfer started in Interrupt or DMA mode.
* This procedure performs following operations :
* - Disable PPP Interrupts
* - Disable the DMA transfer in the peripheral register (if enabled)
* - Abort DMA transfer by calling HAL_DMA_Abort (in case of transfer in DMA mode)
* - Set handle State to READY
* @note This procedure is executed in blocking mode : when exiting function, Abort is considered as completed.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_IRDA_AbortTransmit(IRDA_HandleTypeDef *hirda)
{
/* Disable TXEIE and TCIE interrupts */
CLEAR_BIT(hirda->Instance->CR1, (USART_CR1_TXEIE | USART_CR1_TCIE));
/* Disable the IRDA DMA Tx request if enabled */
if (HAL_IS_BIT_SET(hirda->Instance->CR3, USART_CR3_DMAT))
{
CLEAR_BIT(hirda->Instance->CR3, USART_CR3_DMAT);
/* Abort the IRDA DMA Tx channel : use blocking DMA Abort API (no callback) */
if (hirda->hdmatx != NULL)
{
/* Set the IRDA DMA Abort callback to Null.
No call back execution at end of DMA abort procedure */
hirda->hdmatx->XferAbortCallback = NULL;
HAL_DMA_Abort(hirda->hdmatx);
}
}
/* Reset Tx transfer counter */
hirda->TxXferCount = 0x00U;
/* Restore hirda->gState to Ready */
hirda->gState = HAL_IRDA_STATE_READY;
return HAL_OK;
}
/**
* @brief Abort ongoing Receive transfer (blocking mode).
* @param hirda IRDA handle.
* @note This procedure could be used for aborting any ongoing transfer started in Interrupt or DMA mode.
* This procedure performs following operations :
* - Disable PPP Interrupts
* - Disable the DMA transfer in the peripheral register (if enabled)
* - Abort DMA transfer by calling HAL_DMA_Abort (in case of transfer in DMA mode)
* - Set handle State to READY
* @note This procedure is executed in blocking mode : when exiting function, Abort is considered as completed.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_IRDA_AbortReceive(IRDA_HandleTypeDef *hirda)
{
/* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
CLEAR_BIT(hirda->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
CLEAR_BIT(hirda->Instance->CR3, USART_CR3_EIE);
/* Disable the IRDA DMA Rx request if enabled */
if (HAL_IS_BIT_SET(hirda->Instance->CR3, USART_CR3_DMAR))
{
CLEAR_BIT(hirda->Instance->CR3, USART_CR3_DMAR);
/* Abort the IRDA DMA Rx channel : use blocking DMA Abort API (no callback) */
if (hirda->hdmarx != NULL)
{
/* Set the IRDA DMA Abort callback to Null.
No call back execution at end of DMA abort procedure */
hirda->hdmarx->XferAbortCallback = NULL;
HAL_DMA_Abort(hirda->hdmarx);
}
}
/* Reset Rx transfer counter */
hirda->RxXferCount = 0x00U;
/* Restore hirda->RxState to Ready */
hirda->RxState = HAL_IRDA_STATE_READY;
return HAL_OK;
}
/**
* @brief Abort ongoing transfers (Interrupt mode).
* @param hirda IRDA handle.
* @note This procedure could be used for aborting any ongoing transfer started in Interrupt or DMA mode.
* This procedure performs following operations :
* - Disable PPP Interrupts
* - Disable the DMA transfer in the peripheral register (if enabled)
* - Abort DMA transfer by calling HAL_DMA_Abort_IT (in case of transfer in DMA mode)
* - Set handle State to READY
* - At abort completion, call user abort complete callback
* @note This procedure is executed in Interrupt mode, meaning that abort procedure could be
* considered as completed only when user abort complete callback is executed (not when exiting function).
* @retval HAL status
*/
HAL_StatusTypeDef HAL_IRDA_Abort_IT(IRDA_HandleTypeDef *hirda)
{
uint32_t AbortCplt = 0x01U;
/* Disable TXEIE, TCIE, RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
CLEAR_BIT(hirda->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE | USART_CR1_TXEIE | USART_CR1_TCIE));
CLEAR_BIT(hirda->Instance->CR3, USART_CR3_EIE);
/* If DMA Tx and/or DMA Rx Handles are associated to IRDA Handle, DMA Abort complete callbacks should be initialised
before any call to DMA Abort functions */
/* DMA Tx Handle is valid */
if (hirda->hdmatx != NULL)
{
/* Set DMA Abort Complete callback if IRDA DMA Tx request if enabled.
Otherwise, set it to NULL */
if (HAL_IS_BIT_SET(hirda->Instance->CR3, USART_CR3_DMAT))
{
hirda->hdmatx->XferAbortCallback = IRDA_DMATxAbortCallback;
}
else
{
hirda->hdmatx->XferAbortCallback = NULL;
}
}
/* DMA Rx Handle is valid */
if (hirda->hdmarx != NULL)
{
/* Set DMA Abort Complete callback if IRDA DMA Rx request if enabled.
Otherwise, set it to NULL */
if (HAL_IS_BIT_SET(hirda->Instance->CR3, USART_CR3_DMAR))
{
hirda->hdmarx->XferAbortCallback = IRDA_DMARxAbortCallback;
}
else
{
hirda->hdmarx->XferAbortCallback = NULL;
}
}
/* Disable the IRDA DMA Tx request if enabled */
if (HAL_IS_BIT_SET(hirda->Instance->CR3, USART_CR3_DMAT))
{
/* Disable DMA Tx at IRDA level */
CLEAR_BIT(hirda->Instance->CR3, USART_CR3_DMAT);
/* Abort the IRDA DMA Tx channel : use non blocking DMA Abort API (callback) */
if (hirda->hdmatx != NULL)
{
/* IRDA Tx DMA Abort callback has already been initialised :
will lead to call HAL_IRDA_AbortCpltCallback() at end of DMA abort procedure */
/* Abort DMA TX */
if (HAL_DMA_Abort_IT(hirda->hdmatx) != HAL_OK)
{
hirda->hdmatx->XferAbortCallback = NULL;
}
else
{
AbortCplt = 0x00U;
}
}
}
/* Disable the IRDA DMA Rx request if enabled */
if (HAL_IS_BIT_SET(hirda->Instance->CR3, USART_CR3_DMAR))
{
CLEAR_BIT(hirda->Instance->CR3, USART_CR3_DMAR);
/* Abort the IRDA DMA Rx channel : use non blocking DMA Abort API (callback) */
if (hirda->hdmarx != NULL)
{
/* IRDA Rx DMA Abort callback has already been initialised :
will lead to call HAL_IRDA_AbortCpltCallback() at end of DMA abort procedure */
/* Abort DMA RX */
if (HAL_DMA_Abort_IT(hirda->hdmarx) != HAL_OK)
{
hirda->hdmarx->XferAbortCallback = NULL;
AbortCplt = 0x01U;
}
else
{
AbortCplt = 0x00U;
}
}
}
/* if no DMA abort complete callback execution is required => call user Abort Complete callback */
if (AbortCplt == 0x01U)
{
/* Reset Tx and Rx transfer counters */
hirda->TxXferCount = 0x00U;
hirda->RxXferCount = 0x00U;
/* Reset ErrorCode */
hirda->ErrorCode = HAL_IRDA_ERROR_NONE;
/* Restore hirda->gState and hirda->RxState to Ready */
hirda->gState = HAL_IRDA_STATE_READY;
hirda->RxState = HAL_IRDA_STATE_READY;
/* As no DMA to be aborted, call directly user Abort complete callback */
#if (USE_HAL_IRDA_REGISTER_CALLBACKS == 1)
/* Call registered Abort complete callback */
hirda->AbortCpltCallback(hirda);
#else
/* Call legacy weak Abort complete callback */
HAL_IRDA_AbortCpltCallback(hirda);
#endif /* USE_HAL_IRDA_REGISTER_CALLBACK */
}
return HAL_OK;
}
/**
* @brief Abort ongoing Transmit transfer (Interrupt mode).
* @param hirda IRDA handle.
* @note This procedure could be used for aborting any ongoing transfer started in Interrupt or DMA mode.
* This procedure performs following operations :
* - Disable IRDA Interrupts (Tx)
* - Disable the DMA transfer in the peripheral register (if enabled)
* - Abort DMA transfer by calling HAL_DMA_Abort_IT (in case of transfer in DMA mode)
* - Set handle State to READY
* - At abort completion, call user abort complete callback
* @note This procedure is executed in Interrupt mode, meaning that abort procedure could be
* considered as completed only when user abort complete callback is executed (not when exiting function).
* @retval HAL status
*/
HAL_StatusTypeDef HAL_IRDA_AbortTransmit_IT(IRDA_HandleTypeDef *hirda)
{
/* Disable TXEIE and TCIE interrupts */
CLEAR_BIT(hirda->Instance->CR1, (USART_CR1_TXEIE | USART_CR1_TCIE));
/* Disable the IRDA DMA Tx request if enabled */
if (HAL_IS_BIT_SET(hirda->Instance->CR3, USART_CR3_DMAT))
{
CLEAR_BIT(hirda->Instance->CR3, USART_CR3_DMAT);
/* Abort the IRDA DMA Tx channel : use non blocking DMA Abort API (callback) */
if (hirda->hdmatx != NULL)
{
/* Set the IRDA DMA Abort callback :
will lead to call HAL_IRDA_AbortCpltCallback() at end of DMA abort procedure */
hirda->hdmatx->XferAbortCallback = IRDA_DMATxOnlyAbortCallback;
/* Abort DMA TX */
if (HAL_DMA_Abort_IT(hirda->hdmatx) != HAL_OK)
{
/* Call Directly hirda->hdmatx->XferAbortCallback function in case of error */
hirda->hdmatx->XferAbortCallback(hirda->hdmatx);
}
}
else
{
/* Reset Tx transfer counter */
hirda->TxXferCount = 0x00U;
/* Restore hirda->gState to Ready */
hirda->gState = HAL_IRDA_STATE_READY;
/* As no DMA to be aborted, call directly user Abort complete callback */
#if (USE_HAL_IRDA_REGISTER_CALLBACKS == 1)
/* Call registered Abort Transmit Complete Callback */
hirda->AbortTransmitCpltCallback(hirda);
#else
/* Call legacy weak Abort Transmit Complete Callback */
HAL_IRDA_AbortTransmitCpltCallback(hirda);
#endif /* USE_HAL_IRDA_REGISTER_CALLBACK */
}
}
else
{
/* Reset Tx transfer counter */
hirda->TxXferCount = 0x00U;
/* Restore hirda->gState to Ready */
hirda->gState = HAL_IRDA_STATE_READY;
/* As no DMA to be aborted, call directly user Abort complete callback */
#if (USE_HAL_IRDA_REGISTER_CALLBACKS == 1)
/* Call registered Abort Transmit Complete Callback */
hirda->AbortTransmitCpltCallback(hirda);
#else
/* Call legacy weak Abort Transmit Complete Callback */
HAL_IRDA_AbortTransmitCpltCallback(hirda);
#endif /* USE_HAL_IRDA_REGISTER_CALLBACK */
}
return HAL_OK;
}
/**
* @brief Abort ongoing Receive transfer (Interrupt mode).
* @param hirda IRDA handle.
* @note This procedure could be used for aborting any ongoing transfer started in Interrupt or DMA mode.
* This procedure performs following operations :
* - Disable PPP Interrupts
* - Disable the DMA transfer in the peripheral register (if enabled)
* - Abort DMA transfer by calling HAL_DMA_Abort_IT (in case of transfer in DMA mode)
* - Set handle State to READY
* - At abort completion, call user abort complete callback
* @note This procedure is executed in Interrupt mode, meaning that abort procedure could be
* considered as completed only when user abort complete callback is executed (not when exiting function).
* @retval HAL status
*/
HAL_StatusTypeDef HAL_IRDA_AbortReceive_IT(IRDA_HandleTypeDef *hirda)
{
/* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
CLEAR_BIT(hirda->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
CLEAR_BIT(hirda->Instance->CR3, USART_CR3_EIE);
/* Disable the IRDA DMA Rx request if enabled */
if (HAL_IS_BIT_SET(hirda->Instance->CR3, USART_CR3_DMAR))
{
CLEAR_BIT(hirda->Instance->CR3, USART_CR3_DMAR);
/* Abort the IRDA DMA Rx channel : use non blocking DMA Abort API (callback) */
if (hirda->hdmarx != NULL)
{
/* Set the IRDA DMA Abort callback :
will lead to call HAL_IRDA_AbortCpltCallback() at end of DMA abort procedure */
hirda->hdmarx->XferAbortCallback = IRDA_DMARxOnlyAbortCallback;
/* Abort DMA RX */
if (HAL_DMA_Abort_IT(hirda->hdmarx) != HAL_OK)
{
/* Call Directly hirda->hdmarx->XferAbortCallback function in case of error */
hirda->hdmarx->XferAbortCallback(hirda->hdmarx);
}
}
else
{
/* Reset Rx transfer counter */
hirda->RxXferCount = 0x00U;
/* Restore hirda->RxState to Ready */
hirda->RxState = HAL_IRDA_STATE_READY;
/* As no DMA to be aborted, call directly user Abort complete callback */
#if (USE_HAL_IRDA_REGISTER_CALLBACKS == 1)
/* Call registered Abort Receive Complete Callback */
hirda->AbortReceiveCpltCallback(hirda);
#else
/* Call legacy weak Abort Receive Complete Callback */
HAL_IRDA_AbortReceiveCpltCallback(hirda);
#endif /* USE_HAL_IRDA_REGISTER_CALLBACK */
}
}
else
{
/* Reset Rx transfer counter */
hirda->RxXferCount = 0x00U;
/* Restore hirda->RxState to Ready */
hirda->RxState = HAL_IRDA_STATE_READY;
/* As no DMA to be aborted, call directly user Abort complete callback */
#if (USE_HAL_IRDA_REGISTER_CALLBACKS == 1)
/* Call registered Abort Receive Complete Callback */
hirda->AbortReceiveCpltCallback(hirda);
#else
/* Call legacy weak Abort Receive Complete Callback */
HAL_IRDA_AbortReceiveCpltCallback(hirda);
#endif /* USE_HAL_IRDA_REGISTER_CALLBACK */
}
return HAL_OK;
}
/**
* @brief This function handles IRDA interrupt request.
* @param hirda Pointer to a IRDA_HandleTypeDef structure that contains
* the configuration information for the specified IRDA module.
* @retval None
*/
void HAL_IRDA_IRQHandler(IRDA_HandleTypeDef *hirda)
{
uint32_t isrflags = READ_REG(hirda->Instance->SR);
uint32_t cr1its = READ_REG(hirda->Instance->CR1);
uint32_t cr3its = READ_REG(hirda->Instance->CR3);
uint32_t errorflags = 0x00U;
uint32_t dmarequest = 0x00U;
/* If no error occurs */
errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
if (errorflags == RESET)
{
/* IRDA in mode Receiver -----------------------------------------------*/
if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
{
IRDA_Receive_IT(hirda);
return;
}
}
/* If some errors occur */
if ((errorflags != RESET) && (((cr3its & USART_CR3_EIE) != RESET) || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET)))
{
/* IRDA parity error interrupt occurred -------------------------------*/
if (((isrflags & USART_SR_PE) != RESET) && ((cr1its & USART_CR1_PEIE) != RESET))
{
hirda->ErrorCode |= HAL_IRDA_ERROR_PE;
}
/* IRDA noise error interrupt occurred --------------------------------*/
if (((isrflags & USART_SR_NE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
{
hirda->ErrorCode |= HAL_IRDA_ERROR_NE;
}
/* IRDA frame error interrupt occurred --------------------------------*/
if (((isrflags & USART_SR_FE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
{
hirda->ErrorCode |= HAL_IRDA_ERROR_FE;
}
/* IRDA Over-Run interrupt occurred -----------------------------------*/
if (((isrflags & USART_SR_ORE) != RESET) && (((cr1its & USART_CR1_RXNEIE) != RESET) || ((cr3its & USART_CR3_EIE) != RESET)))
{
hirda->ErrorCode |= HAL_IRDA_ERROR_ORE;
}
/* Call IRDA Error Call back function if need be -----------------------*/
if (hirda->ErrorCode != HAL_IRDA_ERROR_NONE)
{
/* IRDA in mode Receiver ---------------------------------------------*/
if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
{
IRDA_Receive_IT(hirda);
}
/* If Overrun error occurs, or if any error occurs in DMA mode reception,
consider error as blocking */
dmarequest = HAL_IS_BIT_SET(hirda->Instance->CR3, USART_CR3_DMAR);
if (((hirda->ErrorCode & HAL_IRDA_ERROR_ORE) != RESET) || dmarequest)
{
/* Blocking error : transfer is aborted
Set the IRDA state ready to be able to start again the process,
Disable Rx Interrupts, and disable Rx DMA request, if ongoing */
IRDA_EndRxTransfer(hirda);
/* Disable the IRDA DMA Rx request if enabled */
if (HAL_IS_BIT_SET(hirda->Instance->CR3, USART_CR3_DMAR))
{
CLEAR_BIT(hirda->Instance->CR3, USART_CR3_DMAR);
/* Abort the IRDA DMA Rx channel */
if (hirda->hdmarx != NULL)
{
/* Set the IRDA DMA Abort callback :
will lead to call HAL_IRDA_ErrorCallback() at end of DMA abort procedure */
hirda->hdmarx->XferAbortCallback = IRDA_DMAAbortOnError;
/* Abort DMA RX */
if (HAL_DMA_Abort_IT(hirda->hdmarx) != HAL_OK)
{
/* Call Directly XferAbortCallback function in case of error */
hirda->hdmarx->XferAbortCallback(hirda->hdmarx);
}
}
else
{
#if (USE_HAL_IRDA_REGISTER_CALLBACKS == 1)
/* Call registered user error callback */
hirda->ErrorCallback(hirda);
#else
/* Call legacy weak user error callback */
HAL_IRDA_ErrorCallback(hirda);
#endif /* USE_HAL_IRDA_REGISTER_CALLBACK */
}
}
else
{
#if (USE_HAL_IRDA_REGISTER_CALLBACKS == 1)
/* Call registered user error callback */
hirda->ErrorCallback(hirda);
#else
/* Call legacy weak user error callback */
HAL_IRDA_ErrorCallback(hirda);
#endif /* USE_HAL_IRDA_REGISTER_CALLBACK */
}
}
else
{
/* Non Blocking error : transfer could go on.
Error is notified to user through user error callback */
#if (USE_HAL_IRDA_REGISTER_CALLBACKS == 1)
/* Call registered user error callback */
hirda->ErrorCallback(hirda);
#else
/* Call legacy weak user error callback */
HAL_IRDA_ErrorCallback(hirda);
#endif /* USE_HAL_IRDA_REGISTER_CALLBACK */
hirda->ErrorCode = HAL_IRDA_ERROR_NONE;
}
}
return;
} /* End if some error occurs */
/* IRDA in mode Transmitter ------------------------------------------------*/
if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
{
IRDA_Transmit_IT(hirda);
return;
}
/* IRDA in mode Transmitter end --------------------------------------------*/
if (((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))
{
IRDA_EndTransmit_IT(hirda);
return;
}
}
/**
* @brief Tx Transfer complete callback.
* @param hirda Pointer to a IRDA_HandleTypeDef structure that contains
* the configuration information for the specified IRDA module.
* @retval None
*/
__weak void HAL_IRDA_TxCpltCallback(IRDA_HandleTypeDef *hirda)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hirda);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_IRDA_TxCpltCallback can be implemented in the user file.
*/
}
/**
* @brief Tx Half Transfer completed callback.
* @param hirda Pointer to a IRDA_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @retval None
*/
__weak void HAL_IRDA_TxHalfCpltCallback(IRDA_HandleTypeDef *hirda)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hirda);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_IRDA_TxHalfCpltCallback can be implemented in the user file.
*/
}
/**
* @brief Rx Transfer complete callback.
* @param hirda Pointer to a IRDA_HandleTypeDef structure that contains
* the configuration information for the specified IRDA module.
* @retval None
*/
__weak void HAL_IRDA_RxCpltCallback(IRDA_HandleTypeDef *hirda)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hirda);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_IRDA_RxCpltCallback can be implemented in the user file.
*/
}
/**
* @brief Rx Half Transfer complete callback.
* @param hirda Pointer to a IRDA_HandleTypeDef structure that contains
* the configuration information for the specified IRDA module.
* @retval None
*/
__weak void HAL_IRDA_RxHalfCpltCallback(IRDA_HandleTypeDef *hirda)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hirda);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_IRDA_RxHalfCpltCallback can be implemented in the user file.
*/
}
/**
* @brief IRDA error callback.
* @param hirda Pointer to a IRDA_HandleTypeDef structure that contains
* the configuration information for the specified IRDA module.
* @retval None
*/
__weak void HAL_IRDA_ErrorCallback(IRDA_HandleTypeDef *hirda)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hirda);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_IRDA_ErrorCallback can be implemented in the user file.
*/
}
/**
* @brief IRDA Abort Complete callback.
* @param hirda Pointer to a IRDA_HandleTypeDef structure that contains
* the configuration information for the specified IRDA module.
* @retval None
*/
__weak void HAL_IRDA_AbortCpltCallback(IRDA_HandleTypeDef *hirda)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hirda);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_IRDA_AbortCpltCallback can be implemented in the user file.
*/
}
/**
* @brief IRDA Abort Transmit Complete callback.
* @param hirda Pointer to a IRDA_HandleTypeDef structure that contains
* the configuration information for the specified IRDA module.
* @retval None
*/
__weak void HAL_IRDA_AbortTransmitCpltCallback(IRDA_HandleTypeDef *hirda)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hirda);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_IRDA_AbortTransmitCpltCallback can be implemented in the user file.
*/
}
/**
* @brief IRDA Abort Receive Complete callback.
* @param hirda Pointer to a IRDA_HandleTypeDef structure that contains
* the configuration information for the specified IRDA module.
* @retval None
*/
__weak void HAL_IRDA_AbortReceiveCpltCallback(IRDA_HandleTypeDef *hirda)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hirda);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_IRDA_AbortReceiveCpltCallback can be implemented in the user file.
*/
}
/**
* @}
*/
/** @defgroup IRDA_Exported_Functions_Group3 Peripheral State and Errors functions
* @brief IRDA State and Errors functions
*
@verbatim
==============================================================================
##### Peripheral State and Errors functions #####
==============================================================================
[..]
This subsection provides a set of functions allowing to return the State of IrDA
communication process and also return Peripheral Errors occurred during communication process
(+) HAL_IRDA_GetState() API can be helpful to check in run-time the state of the IrDA peripheral.
(+) HAL_IRDA_GetError() check in run-time errors that could be occurred during communication.
@endverbatim
* @{
*/
/**
* @brief Return the IRDA state.
* @param hirda Pointer to a IRDA_HandleTypeDef structure that contains
* the configuration information for the specified IRDA.
* @retval HAL state
*/
HAL_IRDA_StateTypeDef HAL_IRDA_GetState(const IRDA_HandleTypeDef *hirda)
{
uint32_t temp1 = 0x00U, temp2 = 0x00U;
temp1 = hirda->gState;
temp2 = hirda->RxState;
return (HAL_IRDA_StateTypeDef)(temp1 | temp2);
}
/**
* @brief Return the IRDA error code
* @param hirda Pointer to a IRDA_HandleTypeDef structure that contains
* the configuration information for the specified IRDA.
* @retval IRDA Error Code
*/
uint32_t HAL_IRDA_GetError(const IRDA_HandleTypeDef *hirda)
{
return hirda->ErrorCode;
}
/**
* @}
*/
/**
* @}
*/
/** @defgroup IRDA_Private_Functions IRDA Private Functions
* @{
*/
#if (USE_HAL_IRDA_REGISTER_CALLBACKS == 1)
/**
* @brief Initialize the callbacks to their default values.
* @param hirda IRDA handle.
* @retval none
*/
void IRDA_InitCallbacksToDefault(IRDA_HandleTypeDef *hirda)
{
/* Init the IRDA Callback settings */
hirda->TxHalfCpltCallback = HAL_IRDA_TxHalfCpltCallback; /* Legacy weak TxHalfCpltCallback */
hirda->TxCpltCallback = HAL_IRDA_TxCpltCallback; /* Legacy weak TxCpltCallback */
hirda->RxHalfCpltCallback = HAL_IRDA_RxHalfCpltCallback; /* Legacy weak RxHalfCpltCallback */
hirda->RxCpltCallback = HAL_IRDA_RxCpltCallback; /* Legacy weak RxCpltCallback */
hirda->ErrorCallback = HAL_IRDA_ErrorCallback; /* Legacy weak ErrorCallback */
hirda->AbortCpltCallback = HAL_IRDA_AbortCpltCallback; /* Legacy weak AbortCpltCallback */
hirda->AbortTransmitCpltCallback = HAL_IRDA_AbortTransmitCpltCallback; /* Legacy weak AbortTransmitCpltCallback */
hirda->AbortReceiveCpltCallback = HAL_IRDA_AbortReceiveCpltCallback; /* Legacy weak AbortReceiveCpltCallback */
}
#endif /* USE_HAL_IRDA_REGISTER_CALLBACKS */
/**
* @brief DMA IRDA transmit process complete callback.
* @param hdma Pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA.
* @retval None
*/
static void IRDA_DMATransmitCplt(DMA_HandleTypeDef *hdma)
{
IRDA_HandleTypeDef *hirda = (IRDA_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
/* DMA Normal mode */
if ((hdma->Instance->CCR & DMA_CCR_CIRC) == 0U)
{
hirda->TxXferCount = 0U;
/* Disable the DMA transfer for transmit request by resetting the DMAT bit
in the IRDA CR3 register */
CLEAR_BIT(hirda->Instance->CR3, USART_CR3_DMAT);
/* Enable the IRDA Transmit Complete Interrupt */
SET_BIT(hirda->Instance->CR1, USART_CR1_TCIE);
}
/* DMA Circular mode */
else
{
#if (USE_HAL_IRDA_REGISTER_CALLBACKS == 1)
/* Call registered Tx complete callback */
hirda->TxCpltCallback(hirda);
#else
/* Call legacy weak Tx complete callback */
HAL_IRDA_TxCpltCallback(hirda);
#endif /* USE_HAL_IRDA_REGISTER_CALLBACK */
}
}
/**
* @brief DMA IRDA receive process half complete callback
* @param hdma Pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA.
* @retval None
*/
static void IRDA_DMATransmitHalfCplt(DMA_HandleTypeDef *hdma)
{
IRDA_HandleTypeDef *hirda = (IRDA_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
#if (USE_HAL_IRDA_REGISTER_CALLBACKS == 1)
/* Call registered Tx Half complete callback */
hirda->TxHalfCpltCallback(hirda);
#else
/* Call legacy weak Tx complete callback */
HAL_IRDA_TxHalfCpltCallback(hirda);
#endif /* USE_HAL_IRDA_REGISTER_CALLBACK */
}
/**
* @brief DMA IRDA receive process complete callback.
* @param hdma Pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA.
* @retval None
*/
static void IRDA_DMAReceiveCplt(DMA_HandleTypeDef *hdma)
{
IRDA_HandleTypeDef *hirda = (IRDA_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
/* DMA Normal mode */
if ((hdma->Instance->CCR & DMA_CCR_CIRC) == 0U)
{
hirda->RxXferCount = 0U;
/* Disable PE and ERR (Frame error, noise error, overrun error) interrupts */
CLEAR_BIT(hirda->Instance->CR1, USART_CR1_PEIE);
CLEAR_BIT(hirda->Instance->CR3, USART_CR3_EIE);
/* Disable the DMA transfer for the receiver request by resetting the DMAR bit
in the IRDA CR3 register */
CLEAR_BIT(hirda->Instance->CR3, USART_CR3_DMAR);
/* At end of Rx process, restore hirda->RxState to Ready */
hirda->RxState = HAL_IRDA_STATE_READY;
}
#if (USE_HAL_IRDA_REGISTER_CALLBACKS == 1)
/* Call registered Rx complete callback */
hirda->RxCpltCallback(hirda);
#else
/* Call legacy weak Rx complete callback */
HAL_IRDA_RxCpltCallback(hirda);
#endif /* USE_HAL_IRDA_REGISTER_CALLBACKS */
}
/**
* @brief DMA IRDA receive process half complete callback.
* @param hdma Pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA.
* @retval None
*/
static void IRDA_DMAReceiveHalfCplt(DMA_HandleTypeDef *hdma)
{
IRDA_HandleTypeDef *hirda = (IRDA_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
#if (USE_HAL_IRDA_REGISTER_CALLBACKS == 1)
/*Call registered Rx Half complete callback*/
hirda->RxHalfCpltCallback(hirda);
#else
/* Call legacy weak Rx Half complete callback */
HAL_IRDA_RxHalfCpltCallback(hirda);
#endif /* USE_HAL_IRDA_REGISTER_CALLBACK */
}
/**
* @brief DMA IRDA communication error callback.
* @param hdma Pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA.
* @retval None
*/
static void IRDA_DMAError(DMA_HandleTypeDef *hdma)
{
uint32_t dmarequest = 0x00U;
IRDA_HandleTypeDef *hirda = (IRDA_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
/* Stop IRDA DMA Tx request if ongoing */
dmarequest = HAL_IS_BIT_SET(hirda->Instance->CR3, USART_CR3_DMAT);
if ((hirda->gState == HAL_IRDA_STATE_BUSY_TX) && dmarequest)
{
hirda->TxXferCount = 0U;
IRDA_EndTxTransfer(hirda);
}
/* Stop IRDA DMA Rx request if ongoing */
dmarequest = HAL_IS_BIT_SET(hirda->Instance->CR3, USART_CR3_DMAR);
if ((hirda->RxState == HAL_IRDA_STATE_BUSY_RX) && dmarequest)
{
hirda->RxXferCount = 0U;
IRDA_EndRxTransfer(hirda);
}
hirda->ErrorCode |= HAL_IRDA_ERROR_DMA;
#if (USE_HAL_IRDA_REGISTER_CALLBACKS == 1)
/* Call registered user error callback */
hirda->ErrorCallback(hirda);
#else
/* Call legacy weak user error callback */
HAL_IRDA_ErrorCallback(hirda);
#endif /* USE_HAL_IRDA_REGISTER_CALLBACK */
}
/**
* @brief This function handles IRDA Communication Timeout. It waits
* until a flag is no longer in the specified status.
* @param hirda Pointer to a IRDA_HandleTypeDef structure that contains
* the configuration information for the specified IRDA.
* @param Flag specifies the IRDA flag to check.
* @param Status The actual Flag status (SET or RESET).
* @param Tickstart Tick start value
* @param Timeout Timeout duration
* @retval HAL status
*/
static HAL_StatusTypeDef IRDA_WaitOnFlagUntilTimeout(IRDA_HandleTypeDef *hirda, uint32_t Flag, FlagStatus Status, uint32_t Tickstart, uint32_t Timeout)
{
/* Wait until flag is set */
while ((__HAL_IRDA_GET_FLAG(hirda, Flag) ? SET : RESET) == Status)
{
/* Check for the Timeout */
if (Timeout != HAL_MAX_DELAY)
{
if ((Timeout == 0U) || ((HAL_GetTick() - Tickstart) > Timeout))
{
/* Disable TXE, RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts for the interrupt process */
CLEAR_BIT(hirda->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE | USART_CR1_TXEIE));
CLEAR_BIT(hirda->Instance->CR3, USART_CR3_EIE);
hirda->gState = HAL_IRDA_STATE_READY;
hirda->RxState = HAL_IRDA_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(hirda);
return HAL_TIMEOUT;
}
}
}
return HAL_OK;
}
/**
* @brief End ongoing Tx transfer on IRDA peripheral (following error detection or Transmit completion).
* @param hirda IRDA handle.
* @retval None
*/
static void IRDA_EndTxTransfer(IRDA_HandleTypeDef *hirda)
{
/* Disable TXEIE and TCIE interrupts */
CLEAR_BIT(hirda->Instance->CR1, (USART_CR1_TXEIE | USART_CR1_TCIE));
/* At end of Tx process, restore hirda->gState to Ready */
hirda->gState = HAL_IRDA_STATE_READY;
}
/**
* @brief End ongoing Rx transfer on IRDA peripheral (following error detection or Reception completion).
* @param hirda IRDA handle.
* @retval None
*/
static void IRDA_EndRxTransfer(IRDA_HandleTypeDef *hirda)
{
/* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
CLEAR_BIT(hirda->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
CLEAR_BIT(hirda->Instance->CR3, USART_CR3_EIE);
/* At end of Rx process, restore hirda->RxState to Ready */
hirda->RxState = HAL_IRDA_STATE_READY;
}
/**
* @brief DMA IRDA communication abort callback, when initiated by HAL services on Error
* (To be called at end of DMA Abort procedure following error occurrence).
* @param hdma DMA handle.
* @retval None
*/
static void IRDA_DMAAbortOnError(DMA_HandleTypeDef *hdma)
{
IRDA_HandleTypeDef *hirda = (IRDA_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
hirda->RxXferCount = 0x00U;
hirda->TxXferCount = 0x00U;
#if (USE_HAL_IRDA_REGISTER_CALLBACKS == 1)
/* Call registered user error callback */
hirda->ErrorCallback(hirda);
#else
/* Call legacy weak user error callback */
HAL_IRDA_ErrorCallback(hirda);
#endif /* USE_HAL_IRDA_REGISTER_CALLBACK */
}
/**
* @brief DMA IRDA Tx communication abort callback, when initiated by user
* (To be called at end of DMA Tx Abort procedure following user abort request).
* @note When this callback is executed, User Abort complete call back is called only if no
* Abort still ongoing for Rx DMA Handle.
* @param hdma DMA handle.
* @retval None
*/
static void IRDA_DMATxAbortCallback(DMA_HandleTypeDef *hdma)
{
IRDA_HandleTypeDef *hirda = (IRDA_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
hirda->hdmatx->XferAbortCallback = NULL;
/* Check if an Abort process is still ongoing */
if (hirda->hdmarx != NULL)
{
if (hirda->hdmarx->XferAbortCallback != NULL)
{
return;
}
}
/* No Abort process still ongoing : All DMA channels are aborted, call user Abort Complete callback */
hirda->TxXferCount = 0x00U;
hirda->RxXferCount = 0x00U;
/* Reset ErrorCode */
hirda->ErrorCode = HAL_IRDA_ERROR_NONE;
/* Restore hirda->gState and hirda->RxState to Ready */
hirda->gState = HAL_IRDA_STATE_READY;
hirda->RxState = HAL_IRDA_STATE_READY;
/* Call user Abort complete callback */
#if (USE_HAL_IRDA_REGISTER_CALLBACKS == 1)
/* Call registered Abort complete callback */
hirda->AbortCpltCallback(hirda);
#else
/* Call legacy weak Abort complete callback */
HAL_IRDA_AbortCpltCallback(hirda);
#endif /* USE_HAL_IRDA_REGISTER_CALLBACK */
}
/**
* @brief DMA IRDA Rx communication abort callback, when initiated by user
* (To be called at end of DMA Rx Abort procedure following user abort request).
* @note When this callback is executed, User Abort complete call back is called only if no
* Abort still ongoing for Tx DMA Handle.
* @param hdma DMA handle.
* @retval None
*/
static void IRDA_DMARxAbortCallback(DMA_HandleTypeDef *hdma)
{
IRDA_HandleTypeDef *hirda = (IRDA_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
hirda->hdmarx->XferAbortCallback = NULL;
/* Check if an Abort process is still ongoing */
if (hirda->hdmatx != NULL)
{
if (hirda->hdmatx->XferAbortCallback != NULL)
{
return;
}
}
/* No Abort process still ongoing : All DMA channels are aborted, call user Abort Complete callback */
hirda->TxXferCount = 0x00U;
hirda->RxXferCount = 0x00U;
/* Reset ErrorCode */
hirda->ErrorCode = HAL_IRDA_ERROR_NONE;
/* Restore hirda->gState and hirda->RxState to Ready */
hirda->gState = HAL_IRDA_STATE_READY;
hirda->RxState = HAL_IRDA_STATE_READY;
/* Call user Abort complete callback */
#if (USE_HAL_IRDA_REGISTER_CALLBACKS == 1)
/* Call registered Abort complete callback */
hirda->AbortCpltCallback(hirda);
#else
/* Call legacy weak Abort complete callback */
HAL_IRDA_AbortCpltCallback(hirda);
#endif /* USE_HAL_IRDA_REGISTER_CALLBACK */
}
/**
* @brief DMA IRDA Tx communication abort callback, when initiated by user by a call to
* HAL_IRDA_AbortTransmit_IT API (Abort only Tx transfer)
* (This callback is executed at end of DMA Tx Abort procedure following user abort request,
* and leads to user Tx Abort Complete callback execution).
* @param hdma DMA handle.
* @retval None
*/
static void IRDA_DMATxOnlyAbortCallback(DMA_HandleTypeDef *hdma)
{
IRDA_HandleTypeDef *hirda = (IRDA_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
hirda->TxXferCount = 0x00U;
/* Restore hirda->gState to Ready */
hirda->gState = HAL_IRDA_STATE_READY;
/* Call user Abort complete callback */
#if (USE_HAL_IRDA_REGISTER_CALLBACKS == 1)
/* Call registered Abort Transmit Complete Callback */
hirda->AbortTransmitCpltCallback(hirda);
#else
/* Call legacy weak Abort Transmit Complete Callback */
HAL_IRDA_AbortTransmitCpltCallback(hirda);
#endif /* USE_HAL_IRDA_REGISTER_CALLBACK */
}
/**
* @brief DMA IRDA Rx communication abort callback, when initiated by user by a call to
* HAL_IRDA_AbortReceive_IT API (Abort only Rx transfer)
* (This callback is executed at end of DMA Rx Abort procedure following user abort request,
* and leads to user Rx Abort Complete callback execution).
* @param hdma DMA handle.
* @retval None
*/
static void IRDA_DMARxOnlyAbortCallback(DMA_HandleTypeDef *hdma)
{
IRDA_HandleTypeDef *hirda = (IRDA_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
hirda->RxXferCount = 0x00U;
/* Restore hirda->RxState to Ready */
hirda->RxState = HAL_IRDA_STATE_READY;
/* Call user Abort complete callback */
#if (USE_HAL_IRDA_REGISTER_CALLBACKS == 1)
/* Call registered Abort Receive Complete Callback */
hirda->AbortReceiveCpltCallback(hirda);
#else
/* Call legacy weak Abort Receive Complete Callback */
HAL_IRDA_AbortReceiveCpltCallback(hirda);
#endif /* USE_HAL_IRDA_REGISTER_CALLBACK */
}
/**
* @brief Send an amount of data in non blocking mode.
* @param hirda Pointer to a IRDA_HandleTypeDef structure that contains
* the configuration information for the specified IRDA module.
* @retval HAL status
*/
static HAL_StatusTypeDef IRDA_Transmit_IT(IRDA_HandleTypeDef *hirda)
{
const uint16_t *tmp;
/* Check that a Tx process is ongoing */
if (hirda->gState == HAL_IRDA_STATE_BUSY_TX)
{
if (hirda->Init.WordLength == IRDA_WORDLENGTH_9B)
{
tmp = (const uint16_t *) hirda->pTxBuffPtr;
hirda->Instance->DR = (uint16_t)(*tmp & (uint16_t)0x01FF);
if (hirda->Init.Parity == IRDA_PARITY_NONE)
{
hirda->pTxBuffPtr += 2U;
}
else
{
hirda->pTxBuffPtr += 1U;
}
}
else
{
hirda->Instance->DR = (uint8_t)(*hirda->pTxBuffPtr++ & (uint8_t)0x00FF);
}
if (--hirda->TxXferCount == 0U)
{
/* Disable the IRDA Transmit Data Register Empty Interrupt */
CLEAR_BIT(hirda->Instance->CR1, USART_CR1_TXEIE);
/* Enable the IRDA Transmit Complete Interrupt */
SET_BIT(hirda->Instance->CR1, USART_CR1_TCIE);
}
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Wraps up transmission in non blocking mode.
* @param hirda Pointer to a IRDA_HandleTypeDef structure that contains
* the configuration information for the specified IRDA module.
* @retval HAL status
*/
static HAL_StatusTypeDef IRDA_EndTransmit_IT(IRDA_HandleTypeDef *hirda)
{
/* Disable the IRDA Transmit Complete Interrupt */
CLEAR_BIT(hirda->Instance->CR1, USART_CR1_TCIE);
/* Disable the IRDA Error Interrupt: (Frame error, noise error, overrun error) */
CLEAR_BIT(hirda->Instance->CR3, USART_CR3_EIE);
/* Tx process is ended, restore hirda->gState to Ready */
hirda->gState = HAL_IRDA_STATE_READY;
#if (USE_HAL_IRDA_REGISTER_CALLBACKS == 1)
/* Call registered Tx complete callback */
hirda->TxCpltCallback(hirda);
#else
/* Call legacy weak Tx complete callback */
HAL_IRDA_TxCpltCallback(hirda);
#endif /* USE_HAL_IRDA_REGISTER_CALLBACK */
return HAL_OK;
}
/**
* @brief Receives an amount of data in non blocking mode.
* @param hirda Pointer to a IRDA_HandleTypeDef structure that contains
* the configuration information for the specified IRDA module.
* @retval HAL status
*/
static HAL_StatusTypeDef IRDA_Receive_IT(IRDA_HandleTypeDef *hirda)
{
uint16_t *tmp;
uint16_t uhdata;
/* Check that a Rx process is ongoing */
if (hirda->RxState == HAL_IRDA_STATE_BUSY_RX)
{
uhdata = (uint16_t) READ_REG(hirda->Instance->DR);
if (hirda->Init.WordLength == IRDA_WORDLENGTH_9B)
{
tmp = (uint16_t *) hirda->pRxBuffPtr;
if (hirda->Init.Parity == IRDA_PARITY_NONE)
{
*tmp = (uint16_t)(uhdata & (uint16_t)0x01FF);
hirda->pRxBuffPtr += 2U;
}
else
{
*tmp = (uint16_t)(uhdata & (uint16_t)0x00FF);
hirda->pRxBuffPtr += 1U;
}
}
else
{
if (hirda->Init.Parity == IRDA_PARITY_NONE)
{
*hirda->pRxBuffPtr++ = (uint8_t)(uhdata & (uint8_t)0x00FF);
}
else
{
*hirda->pRxBuffPtr++ = (uint8_t)(uhdata & (uint8_t)0x007F);
}
}
if (--hirda->RxXferCount == 0U)
{
/* Disable the IRDA Data Register not empty Interrupt */
CLEAR_BIT(hirda->Instance->CR1, USART_CR1_RXNEIE);
/* Disable the IRDA Parity Error Interrupt */
CLEAR_BIT(hirda->Instance->CR1, USART_CR1_PEIE);
/* Disable the IRDA Error Interrupt: (Frame error, noise error, overrun error) */
CLEAR_BIT(hirda->Instance->CR3, USART_CR3_EIE);
/* Rx process is completed, restore hirda->RxState to Ready */
hirda->RxState = HAL_IRDA_STATE_READY;
#if (USE_HAL_IRDA_REGISTER_CALLBACKS == 1)
/* Call registered Rx complete callback */
hirda->RxCpltCallback(hirda);
#else
/* Call legacy weak Rx complete callback */
HAL_IRDA_RxCpltCallback(hirda);
#endif /* USE_HAL_IRDA_REGISTER_CALLBACKS */
return HAL_OK;
}
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Configures the IRDA peripheral.
* @param hirda Pointer to a IRDA_HandleTypeDef structure that contains
* the configuration information for the specified IRDA module.
* @retval None
*/
static void IRDA_SetConfig(IRDA_HandleTypeDef *hirda)
{
uint32_t pclk;
/* Check the parameters */
assert_param(IS_IRDA_INSTANCE(hirda->Instance));
assert_param(IS_IRDA_BAUDRATE(hirda->Init.BaudRate));
assert_param(IS_IRDA_WORD_LENGTH(hirda->Init.WordLength));
assert_param(IS_IRDA_PARITY(hirda->Init.Parity));
assert_param(IS_IRDA_MODE(hirda->Init.Mode));
assert_param(IS_IRDA_POWERMODE(hirda->Init.IrDAMode));
/*-------------------------- USART CR2 Configuration ------------------------*/
/* Clear STOP[13:12] bits */
CLEAR_BIT(hirda->Instance->CR2, USART_CR2_STOP);
/*-------------------------- USART CR1 Configuration -----------------------*/
/* Clear M, PCE, PS, TE and RE bits */
CLEAR_BIT(hirda->Instance->CR1, (USART_CR1_M | USART_CR1_PCE | USART_CR1_PS | USART_CR1_TE | USART_CR1_RE));
/* Configure the USART Word Length, Parity and mode:
Set the M bits according to hirda->Init.WordLength value
Set PCE and PS bits according to hirda->Init.Parity value
Set TE and RE bits according to hirda->Init.Mode value */
/* Write to USART CR1 */
SET_BIT(hirda->Instance->CR1, (hirda->Init.WordLength | hirda->Init.Parity | hirda->Init.Mode));
/*-------------------------- USART CR3 Configuration -----------------------*/
/* Clear CTSE and RTSE bits */
CLEAR_BIT(hirda->Instance->CR3, (USART_CR3_RTSE | USART_CR3_CTSE));
/*-------------------------- USART BRR Configuration -----------------------*/
if(hirda->Instance == USART1)
{
pclk = HAL_RCC_GetPCLK2Freq();
SET_BIT(hirda->Instance->BRR, IRDA_BRR(pclk, hirda->Init.BaudRate));
}
else
{
pclk = HAL_RCC_GetPCLK1Freq();
SET_BIT(hirda->Instance->BRR, IRDA_BRR(pclk, hirda->Init.BaudRate));
}
}
/**
* @}
*/
#endif /* HAL_IRDA_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/

View File

@@ -0,0 +1,263 @@
/**
******************************************************************************
* @file stm32f1xx_hal_iwdg.c
* @author MCD Application Team
* @brief IWDG HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of the Independent Watchdog (IWDG) peripheral:
* + Initialization and Start functions
* + IO operation functions
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
==============================================================================
##### IWDG Generic features #####
==============================================================================
[..]
(+) The IWDG can be started by either software or hardware (configurable
through option byte).
(+) The IWDG is clocked by the Low-Speed Internal clock (LSI) and thus stays
active even if the main clock fails.
(+) Once the IWDG is started, the LSI is forced ON and both cannot be
disabled. The counter starts counting down from the reset value (0xFFF).
When it reaches the end of count value (0x000) a reset signal is
generated (IWDG reset).
(+) Whenever the key value 0x0000 AAAA is written in the IWDG_KR register,
the IWDG_RLR value is reloaded into the counter and the watchdog reset
is prevented.
(+) The IWDG is implemented in the VDD voltage domain that is still functional
in STOP and STANDBY mode (IWDG reset can wake up the CPU from STANDBY).
IWDGRST flag in RCC_CSR register can be used to inform when an IWDG
reset occurs.
(+) Debug mode: When the microcontroller enters debug mode (core halted),
the IWDG counter either continues to work normally or stops, depending
on DBG_IWDG_STOP configuration bit in DBG module, accessible through
__HAL_DBGMCU_FREEZE_IWDG() and __HAL_DBGMCU_UNFREEZE_IWDG() macros.
[..] Min-max timeout value @32KHz (LSI): ~125us / ~32.7s
The IWDG timeout may vary due to LSI clock frequency dispersion.
STM32F1xx devices provide the capability to measure the LSI clock
frequency (LSI clock is internally connected to TIM5 CH4 input capture).
The measured value can be used to have an IWDG timeout with an
acceptable accuracy.
[..] Default timeout value (necessary for IWDG_SR status register update):
Constant LSI_VALUE is defined based on the nominal LSI clock frequency.
This frequency being subject to variations as mentioned above, the
default timeout value (defined through constant HAL_IWDG_DEFAULT_TIMEOUT
below) may become too short or too long.
In such cases, this default timeout value can be tuned by redefining
the constant LSI_VALUE at user-application level (based, for instance,
on the measured LSI clock frequency as explained above).
##### How to use this driver #####
==============================================================================
[..]
(#) Use IWDG using HAL_IWDG_Init() function to :
(++) Enable instance by writing Start keyword in IWDG_KEY register. LSI
clock is forced ON and IWDG counter starts counting down.
(++) Enable write access to configuration registers:
IWDG_PR and IWDG_RLR.
(++) Configure the IWDG prescaler and counter reload value. This reload
value will be loaded in the IWDG counter each time the watchdog is
reloaded, then the IWDG will start counting down from this value.
(++) Wait for status flags to be reset.
(#) Then the application program must refresh the IWDG counter at regular
intervals during normal operation to prevent an MCU reset, using
HAL_IWDG_Refresh() function.
*** IWDG HAL driver macros list ***
====================================
[..]
Below the list of most used macros in IWDG HAL driver:
(+) __HAL_IWDG_START: Enable the IWDG peripheral
(+) __HAL_IWDG_RELOAD_COUNTER: Reloads IWDG counter with value defined in
the reload register
@endverbatim
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
#ifdef HAL_IWDG_MODULE_ENABLED
/** @addtogroup IWDG
* @brief IWDG HAL module driver.
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/** @defgroup IWDG_Private_Defines IWDG Private Defines
* @{
*/
/* Status register needs up to 5 LSI clock periods divided by the clock
prescaler to be updated. The number of LSI clock periods is upper-rounded to
6 for the timeout value calculation.
The timeout value is calculated using the highest prescaler (256) and
the LSI_VALUE constant. The value of this constant can be changed by the user
to take into account possible LSI clock period variations.
The timeout value is multiplied by 1000 to be converted in milliseconds.
LSI startup time is also considered here by adding LSI_STARTUP_TIME
converted in milliseconds. */
#define HAL_IWDG_DEFAULT_TIMEOUT (((6UL * 256UL * 1000UL) / (LSI_VALUE / 128U)) + \
((LSI_STARTUP_TIME / 1000UL) + 1UL))
#define IWDG_KERNEL_UPDATE_FLAGS (IWDG_SR_RVU | IWDG_SR_PVU)
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup IWDG_Exported_Functions
* @{
*/
/** @addtogroup IWDG_Exported_Functions_Group1
* @brief Initialization and Start functions.
*
@verbatim
===============================================================================
##### Initialization and Start functions #####
===============================================================================
[..] This section provides functions allowing to:
(+) Initialize the IWDG according to the specified parameters in the
IWDG_InitTypeDef of associated handle.
(+) Once initialization is performed in HAL_IWDG_Init function, Watchdog
is reloaded in order to exit function with correct time base.
@endverbatim
* @{
*/
/**
* @brief Initialize the IWDG according to the specified parameters in the
* IWDG_InitTypeDef and start watchdog. Before exiting function,
* watchdog is refreshed in order to have correct time base.
* @param hiwdg pointer to a IWDG_HandleTypeDef structure that contains
* the configuration information for the specified IWDG module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_IWDG_Init(IWDG_HandleTypeDef *hiwdg)
{
uint32_t tickstart;
/* Check the IWDG handle allocation */
if (hiwdg == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_IWDG_ALL_INSTANCE(hiwdg->Instance));
assert_param(IS_IWDG_PRESCALER(hiwdg->Init.Prescaler));
assert_param(IS_IWDG_RELOAD(hiwdg->Init.Reload));
/* Enable IWDG. LSI is turned on automatically */
__HAL_IWDG_START(hiwdg);
/* Enable write access to IWDG_PR and IWDG_RLR registers by writing
0x5555 in KR */
IWDG_ENABLE_WRITE_ACCESS(hiwdg);
/* Write to IWDG registers the Prescaler & Reload values to work with */
hiwdg->Instance->PR = hiwdg->Init.Prescaler;
hiwdg->Instance->RLR = hiwdg->Init.Reload;
/* Check pending flag, if previous update not done, return timeout */
tickstart = HAL_GetTick();
/* Wait for register to be updated */
while ((hiwdg->Instance->SR & IWDG_KERNEL_UPDATE_FLAGS) != 0x00u)
{
if ((HAL_GetTick() - tickstart) > HAL_IWDG_DEFAULT_TIMEOUT)
{
if ((hiwdg->Instance->SR & IWDG_KERNEL_UPDATE_FLAGS) != 0x00u)
{
return HAL_TIMEOUT;
}
}
}
/* Reload IWDG counter with value defined in the reload register */
__HAL_IWDG_RELOAD_COUNTER(hiwdg);
/* Return function status */
return HAL_OK;
}
/**
* @}
*/
/** @addtogroup IWDG_Exported_Functions_Group2
* @brief IO operation functions
*
@verbatim
===============================================================================
##### IO operation functions #####
===============================================================================
[..] This section provides functions allowing to:
(+) Refresh the IWDG.
@endverbatim
* @{
*/
/**
* @brief Refresh the IWDG.
* @param hiwdg pointer to a IWDG_HandleTypeDef structure that contains
* the configuration information for the specified IWDG module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_IWDG_Refresh(IWDG_HandleTypeDef *hiwdg)
{
/* Reload IWDG counter with value defined in the reload register */
__HAL_IWDG_RELOAD_COUNTER(hiwdg);
/* Return function status */
return HAL_OK;
}
/**
* @}
*/
/**
* @}
*/
#endif /* HAL_IWDG_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/

View File

@@ -0,0 +1,3148 @@
/**
******************************************************************************
* @file stm32f1xx_hal_mmc.c
* @author MCD Application Team
* @brief MMC card HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of the Secure Digital (MMC) peripheral:
* + Initialization and de-initialization functions
* + IO operation functions
* + Peripheral Control functions
* + MMC card Control functions
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
==============================================================================
##### How to use this driver #####
==============================================================================
[..]
This driver implements a high level communication layer for read and write from/to
this memory. The needed STM32 hardware resources (SDMMC and GPIO) are performed by
the user in HAL_MMC_MspInit() function (MSP layer).
Basically, the MSP layer configuration should be the same as we provide in the
examples.
You can easily tailor this configuration according to hardware resources.
[..]
This driver is a generic layered driver for SDMMC memories which uses the HAL
SDMMC driver functions to interface with MMC and eMMC cards devices.
It is used as follows:
(#)Initialize the SDMMC low level resources by implement the HAL_MMC_MspInit() API:
(##) Enable the SDMMC interface clock using __HAL_RCC_SDMMC_CLK_ENABLE();
(##) SDMMC pins configuration for MMC card
(+++) Enable the clock for the SDMMC GPIOs using the functions __HAL_RCC_GPIOx_CLK_ENABLE();
(+++) Configure these SDMMC pins as alternate function pull-up using HAL_GPIO_Init()
and according to your pin assignment;
(##) DMA Configuration if you need to use DMA process (HAL_MMC_ReadBlocks_DMA()
and HAL_MMC_WriteBlocks_DMA() APIs).
(+++) Enable the DMAx interface clock using __HAL_RCC_DMAx_CLK_ENABLE();
(+++) Configure the DMA using the function HAL_DMA_Init() with predeclared and filled.
(##) NVIC configuration if you need to use interrupt process when using DMA transfer.
(+++) Configure the SDMMC and DMA interrupt priorities using function HAL_NVIC_SetPriority();
DMA priority is superior to SDMMC's priority
(+++) Enable the NVIC DMA and SDMMC IRQs using function HAL_NVIC_EnableIRQ()
(+++) SDMMC interrupts are managed using the macros __HAL_MMC_ENABLE_IT()
and __HAL_MMC_DISABLE_IT() inside the communication process.
(+++) SDMMC interrupts pending bits are managed using the macros __HAL_MMC_GET_IT()
and __HAL_MMC_CLEAR_IT()
(##) NVIC configuration if you need to use interrupt process (HAL_MMC_ReadBlocks_IT()
and HAL_MMC_WriteBlocks_IT() APIs).
(+++) Configure the SDMMC interrupt priorities using function HAL_NVIC_SetPriority();
(+++) Enable the NVIC SDMMC IRQs using function HAL_NVIC_EnableIRQ()
(+++) SDMMC interrupts are managed using the macros __HAL_MMC_ENABLE_IT()
and __HAL_MMC_DISABLE_IT() inside the communication process.
(+++) SDMMC interrupts pending bits are managed using the macros __HAL_MMC_GET_IT()
and __HAL_MMC_CLEAR_IT()
(#) At this stage, you can perform MMC read/write/erase operations after MMC card initialization
*** MMC Card Initialization and configuration ***
================================================
[..]
To initialize the MMC Card, use the HAL_MMC_Init() function. It Initializes
SDMMC Peripheral (STM32 side) and the MMC Card, and put it into StandBy State (Ready for data transfer).
This function provide the following operations:
(#) Initialize the SDMMC peripheral interface with default configuration.
The initialization process is done at 400KHz. You can change or adapt
this frequency by adjusting the "ClockDiv" field.
The MMC Card frequency (SDMMC_CK) is computed as follows:
SDMMC_CK = SDMMCCLK / (ClockDiv + 2)
In initialization mode and according to the MMC Card standard,
make sure that the SDMMC_CK frequency doesn't exceed 400KHz.
This phase of initialization is done through SDMMC_Init() and
SDMMC_PowerState_ON() SDMMC low level APIs.
(#) Initialize the MMC card. The API used is HAL_MMC_InitCard().
This phase allows the card initialization and identification
and check the MMC Card type (Standard Capacity or High Capacity)
The initialization flow is compatible with MMC standard.
This API (HAL_MMC_InitCard()) could be used also to reinitialize the card in case
of plug-off plug-in.
(#) Configure the MMC Card Data transfer frequency. By Default, the card transfer
frequency is set to 24MHz. You can change or adapt this frequency by adjusting
the "ClockDiv" field.
In transfer mode and according to the MMC Card standard, make sure that the
SDMMC_CK frequency doesn't exceed 25MHz and 50MHz in High-speed mode switch.
To be able to use a frequency higher than 24MHz, you should use the SDMMC
peripheral in bypass mode. Refer to the corresponding reference manual
for more details.
(#) Select the corresponding MMC Card according to the address read with the step 2.
(#) Configure the MMC Card in wide bus mode: 4-bits data.
*** MMC Card Read operation ***
==============================
[..]
(+) You can read from MMC card in polling mode by using function HAL_MMC_ReadBlocks().
This function support only 512-bytes block length (the block size should be
chosen as 512 bytes).
You can choose either one block read operation or multiple block read operation
by adjusting the "NumberOfBlocks" parameter.
After this, you have to ensure that the transfer is done correctly. The check is done
through HAL_MMC_GetCardState() function for MMC card state.
(+) You can read from MMC card in DMA mode by using function HAL_MMC_ReadBlocks_DMA().
This function support only 512-bytes block length (the block size should be
chosen as 512 bytes).
You can choose either one block read operation or multiple block read operation
by adjusting the "NumberOfBlocks" parameter.
After this, you have to ensure that the transfer is done correctly. The check is done
through HAL_MMC_GetCardState() function for MMC card state.
You could also check the DMA transfer process through the MMC Rx interrupt event.
(+) You can read from MMC card in Interrupt mode by using function HAL_MMC_ReadBlocks_IT().
This function allows the read of 512 bytes blocks.
You can choose either one block read operation or multiple block read operation
by adjusting the "NumberOfBlocks" parameter.
After this, you have to ensure that the transfer is done correctly. The check is done
through HAL_MMC_GetCardState() function for MMC card state.
You could also check the IT transfer process through the MMC Rx interrupt event.
*** MMC Card Write operation ***
===============================
[..]
(+) You can write to MMC card in polling mode by using function HAL_MMC_WriteBlocks().
This function support only 512-bytes block length (the block size should be
chosen as 512 bytes).
You can choose either one block read operation or multiple block read operation
by adjusting the "NumberOfBlocks" parameter.
After this, you have to ensure that the transfer is done correctly. The check is done
through HAL_MMC_GetCardState() function for MMC card state.
(+) You can write to MMC card in DMA mode by using function HAL_MMC_WriteBlocks_DMA().
This function support only 512-bytes block length (the block size should be
chosen as 512 byte).
You can choose either one block read operation or multiple block read operation
by adjusting the "NumberOfBlocks" parameter.
After this, you have to ensure that the transfer is done correctly. The check is done
through HAL_MMC_GetCardState() function for MMC card state.
You could also check the DMA transfer process through the MMC Tx interrupt event.
(+) You can write to MMC card in Interrupt mode by using function HAL_MMC_WriteBlocks_IT().
This function allows the read of 512 bytes blocks.
You can choose either one block read operation or multiple block read operation
by adjusting the "NumberOfBlocks" parameter.
After this, you have to ensure that the transfer is done correctly. The check is done
through HAL_MMC_GetCardState() function for MMC card state.
You could also check the IT transfer process through the MMC Tx interrupt event.
*** MMC card information ***
===========================
[..]
(+) To get MMC card information, you can use the function HAL_MMC_GetCardInfo().
It returns useful information about the MMC card such as block size, card type,
block number ...
*** MMC card CSD register ***
============================
[..]
(+) The HAL_MMC_GetCardCSD() API allows to get the parameters of the CSD register.
Some of the CSD parameters are useful for card initialization and identification.
*** MMC card CID register ***
============================
[..]
(+) The HAL_MMC_GetCardCID() API allows to get the parameters of the CID register.
Some of the CID parameters are useful for card initialization and identification.
*** MMC HAL driver macros list ***
==================================
[..]
Below the list of most used macros in MMC HAL driver.
(+) __HAL_MMC_ENABLE : Enable the MMC device
(+) __HAL_MMC_DISABLE : Disable the MMC device
(+) __HAL_MMC_DMA_ENABLE: Enable the SDMMC DMA transfer
(+) __HAL_MMC_DMA_DISABLE: Disable the SDMMC DMA transfer
(+) __HAL_MMC_ENABLE_IT: Enable the MMC device interrupt
(+) __HAL_MMC_DISABLE_IT: Disable the MMC device interrupt
(+) __HAL_MMC_GET_FLAG:Check whether the specified MMC flag is set or not
(+) __HAL_MMC_CLEAR_FLAG: Clear the MMC's pending flags
[..]
(@) You can refer to the MMC HAL driver header file for more useful macros
*** Callback registration ***
=============================================
[..]
The compilation define USE_HAL_MMC_REGISTER_CALLBACKS when set to 1
allows the user to configure dynamically the driver callbacks.
Use Functions HAL_MMC_RegisterCallback() to register a user callback,
it allows to register following callbacks:
(+) TxCpltCallback : callback when a transmission transfer is completed.
(+) RxCpltCallback : callback when a reception transfer is completed.
(+) ErrorCallback : callback when error occurs.
(+) AbortCpltCallback : callback when abort is completed.
(+) MspInitCallback : MMC MspInit.
(+) MspDeInitCallback : MMC MspDeInit.
This function takes as parameters the HAL peripheral handle, the Callback ID
and a pointer to the user callback function.
Use function HAL_MMC_UnRegisterCallback() to reset a callback to the default
weak (surcharged) function. It allows to reset following callbacks:
(+) TxCpltCallback : callback when a transmission transfer is completed.
(+) RxCpltCallback : callback when a reception transfer is completed.
(+) ErrorCallback : callback when error occurs.
(+) AbortCpltCallback : callback when abort is completed.
(+) MspInitCallback : MMC MspInit.
(+) MspDeInitCallback : MMC MspDeInit.
This function) takes as parameters the HAL peripheral handle and the Callback ID.
By default, after the HAL_MMC_Init and if the state is HAL_MMC_STATE_RESET
all callbacks are reset to the corresponding legacy weak (surcharged) functions.
Exception done for MspInit and MspDeInit callbacks that are respectively
reset to the legacy weak (surcharged) functions in the HAL_MMC_Init
and HAL_MMC_DeInit only when these callbacks are null (not registered beforehand).
If not, MspInit or MspDeInit are not null, the HAL_MMC_Init and HAL_MMC_DeInit
keep and use the user MspInit/MspDeInit callbacks (registered beforehand)
Callbacks can be registered/unregistered in READY state only.
Exception done for MspInit/MspDeInit callbacks that can be registered/unregistered
in READY or RESET state, thus registered (user) MspInit/DeInit callbacks can be used
during the Init/DeInit.
In that case first register the MspInit/MspDeInit user callbacks
using HAL_MMC_RegisterCallback before calling HAL_MMC_DeInit
or HAL_MMC_Init function.
When The compilation define USE_HAL_MMC_REGISTER_CALLBACKS is set to 0 or
not defined, the callback registering feature is not available
and weak (surcharged) callbacks are used.
@endverbatim
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
/** @defgroup MMC MMC
* @brief MMC HAL module driver
* @{
*/
#ifdef HAL_MMC_MODULE_ENABLED
#if defined(SDIO)
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/** @addtogroup MMC_Private_Defines
* @{
*/
#if defined (VDD_VALUE) && (VDD_VALUE <= 1950U)
#define MMC_VOLTAGE_RANGE EMMC_LOW_VOLTAGE_RANGE
#define MMC_EXT_CSD_PWR_CL_26_INDEX 201
#define MMC_EXT_CSD_PWR_CL_52_INDEX 200
#define MMC_EXT_CSD_PWR_CL_DDR_52_INDEX 238
#define MMC_EXT_CSD_PWR_CL_26_POS 8
#define MMC_EXT_CSD_PWR_CL_52_POS 0
#define MMC_EXT_CSD_PWR_CL_DDR_52_POS 16
#else
#define MMC_VOLTAGE_RANGE EMMC_HIGH_VOLTAGE_RANGE
#define MMC_EXT_CSD_PWR_CL_26_INDEX 203
#define MMC_EXT_CSD_PWR_CL_52_INDEX 202
#define MMC_EXT_CSD_PWR_CL_DDR_52_INDEX 239
#define MMC_EXT_CSD_PWR_CL_26_POS 24
#define MMC_EXT_CSD_PWR_CL_52_POS 16
#define MMC_EXT_CSD_PWR_CL_DDR_52_POS 24
#endif
/* Frequencies used in the driver for clock divider calculation */
#define MMC_INIT_FREQ 400000U /* Initialization phase : 400 kHz max */
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/** @defgroup MMC_Private_Functions MMC Private Functions
* @{
*/
static uint32_t MMC_InitCard(MMC_HandleTypeDef *hmmc);
static uint32_t MMC_PowerON(MMC_HandleTypeDef *hmmc);
static uint32_t MMC_SendStatus(MMC_HandleTypeDef *hmmc, uint32_t *pCardStatus);
static uint32_t MMC_ReadExtCSD(MMC_HandleTypeDef *hmmc, uint32_t *pFieldData, uint16_t FieldIndex, uint32_t Timeout);
static void MMC_PowerOFF(MMC_HandleTypeDef *hmmc);
static void MMC_Write_IT(MMC_HandleTypeDef *hmmc);
static void MMC_Read_IT(MMC_HandleTypeDef *hmmc);
static void MMC_DMATransmitCplt(DMA_HandleTypeDef *hdma);
static void MMC_DMAReceiveCplt(DMA_HandleTypeDef *hdma);
static void MMC_DMAError(DMA_HandleTypeDef *hdma);
static void MMC_DMATxAbort(DMA_HandleTypeDef *hdma);
static void MMC_DMARxAbort(DMA_HandleTypeDef *hdma);
static uint32_t MMC_PwrClassUpdate(MMC_HandleTypeDef *hmmc, uint32_t Wide);
/**
* @}
*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup MMC_Exported_Functions
* @{
*/
/** @addtogroup MMC_Exported_Functions_Group1
* @brief Initialization and de-initialization functions
*
@verbatim
==============================================================================
##### Initialization and de-initialization functions #####
==============================================================================
[..]
This section provides functions allowing to initialize/de-initialize the MMC
card device to be ready for use.
@endverbatim
* @{
*/
/**
* @brief Initializes the MMC according to the specified parameters in the
MMC_HandleTypeDef and create the associated handle.
* @param hmmc: Pointer to the MMC handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_MMC_Init(MMC_HandleTypeDef *hmmc)
{
/* Check the MMC handle allocation */
if(hmmc == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_SDIO_ALL_INSTANCE(hmmc->Instance));
assert_param(IS_SDIO_CLOCK_EDGE(hmmc->Init.ClockEdge));
assert_param(IS_SDIO_CLOCK_BYPASS(hmmc->Init.ClockBypass));
assert_param(IS_SDIO_CLOCK_POWER_SAVE(hmmc->Init.ClockPowerSave));
assert_param(IS_SDIO_BUS_WIDE(hmmc->Init.BusWide));
assert_param(IS_SDIO_HARDWARE_FLOW_CONTROL(hmmc->Init.HardwareFlowControl));
assert_param(IS_SDIO_CLKDIV(hmmc->Init.ClockDiv));
if(hmmc->State == HAL_MMC_STATE_RESET)
{
/* Allocate lock resource and initialize it */
hmmc->Lock = HAL_UNLOCKED;
#if defined (USE_HAL_MMC_REGISTER_CALLBACKS) && (USE_HAL_MMC_REGISTER_CALLBACKS == 1U)
/* Reset Callback pointers in HAL_MMC_STATE_RESET only */
hmmc->TxCpltCallback = HAL_MMC_TxCpltCallback;
hmmc->RxCpltCallback = HAL_MMC_RxCpltCallback;
hmmc->ErrorCallback = HAL_MMC_ErrorCallback;
hmmc->AbortCpltCallback = HAL_MMC_AbortCallback;
if(hmmc->MspInitCallback == NULL)
{
hmmc->MspInitCallback = HAL_MMC_MspInit;
}
/* Init the low level hardware */
hmmc->MspInitCallback(hmmc);
#else
/* Init the low level hardware : GPIO, CLOCK, CORTEX...etc */
HAL_MMC_MspInit(hmmc);
#endif
}
hmmc->State = HAL_MMC_STATE_BUSY;
/* Initialize the Card parameters */
if(HAL_MMC_InitCard(hmmc) == HAL_ERROR)
{
return HAL_ERROR;
}
/* Initialize the error code */
hmmc->ErrorCode = HAL_MMC_ERROR_NONE;
/* Initialize the MMC operation */
hmmc->Context = MMC_CONTEXT_NONE;
/* Initialize the MMC state */
hmmc->State = HAL_MMC_STATE_READY;
/* Configure bus width */
if (hmmc->Init.BusWide != SDIO_BUS_WIDE_1B)
{
if (HAL_MMC_ConfigWideBusOperation(hmmc, hmmc->Init.BusWide) != HAL_OK)
{
return HAL_ERROR;
}
}
return HAL_OK;
}
/**
* @brief Initializes the MMC Card.
* @param hmmc: Pointer to MMC handle
* @note This function initializes the MMC card. It could be used when a card
re-initialization is needed.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_MMC_InitCard(MMC_HandleTypeDef *hmmc)
{
uint32_t errorstate;
MMC_InitTypeDef Init;
HAL_StatusTypeDef status;
/* Default SDIO peripheral configuration for MMC card initialization */
Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;
Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
Init.BusWide = SDIO_BUS_WIDE_1B;
Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
Init.ClockDiv = SDIO_INIT_CLK_DIV;
/* Initialize SDIO peripheral interface with default configuration */
status = SDIO_Init(hmmc->Instance, Init);
if(status == HAL_ERROR)
{
return HAL_ERROR;
}
/* Disable SDIO Clock */
__HAL_MMC_DISABLE(hmmc);
/* Set Power State to ON */
status = SDIO_PowerState_ON(hmmc->Instance);
if(status == HAL_ERROR)
{
return HAL_ERROR;
}
/* Enable MMC Clock */
__HAL_MMC_ENABLE(hmmc);
/* Required power up waiting time before starting the MMC initialization sequence */
HAL_Delay(2);
/* Identify card operating voltage */
errorstate = MMC_PowerON(hmmc);
if(errorstate != HAL_MMC_ERROR_NONE)
{
hmmc->State = HAL_MMC_STATE_READY;
hmmc->ErrorCode |= errorstate;
return HAL_ERROR;
}
/* Card initialization */
errorstate = MMC_InitCard(hmmc);
if(errorstate != HAL_MMC_ERROR_NONE)
{
hmmc->State = HAL_MMC_STATE_READY;
hmmc->ErrorCode |= errorstate;
return HAL_ERROR;
}
/* Set Block Size for Card */
errorstate = SDMMC_CmdBlockLength(hmmc->Instance, MMC_BLOCKSIZE);
if(errorstate != HAL_MMC_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= errorstate;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief De-Initializes the MMC card.
* @param hmmc: Pointer to MMC handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_MMC_DeInit(MMC_HandleTypeDef *hmmc)
{
/* Check the MMC handle allocation */
if(hmmc == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_SDIO_ALL_INSTANCE(hmmc->Instance));
hmmc->State = HAL_MMC_STATE_BUSY;
/* Set MMC power state to off */
MMC_PowerOFF(hmmc);
#if defined (USE_HAL_MMC_REGISTER_CALLBACKS) && (USE_HAL_MMC_REGISTER_CALLBACKS == 1U)
if(hmmc->MspDeInitCallback == NULL)
{
hmmc->MspDeInitCallback = HAL_MMC_MspDeInit;
}
/* DeInit the low level hardware */
hmmc->MspDeInitCallback(hmmc);
#else
/* De-Initialize the MSP layer */
HAL_MMC_MspDeInit(hmmc);
#endif
hmmc->ErrorCode = HAL_MMC_ERROR_NONE;
hmmc->State = HAL_MMC_STATE_RESET;
return HAL_OK;
}
/**
* @brief Initializes the MMC MSP.
* @param hmmc: Pointer to MMC handle
* @retval None
*/
__weak void HAL_MMC_MspInit(MMC_HandleTypeDef *hmmc)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hmmc);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_MMC_MspInit could be implemented in the user file
*/
}
/**
* @brief De-Initialize MMC MSP.
* @param hmmc: Pointer to MMC handle
* @retval None
*/
__weak void HAL_MMC_MspDeInit(MMC_HandleTypeDef *hmmc)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hmmc);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_MMC_MspDeInit could be implemented in the user file
*/
}
/**
* @}
*/
/** @addtogroup MMC_Exported_Functions_Group2
* @brief Data transfer functions
*
@verbatim
==============================================================================
##### IO operation functions #####
==============================================================================
[..]
This subsection provides a set of functions allowing to manage the data
transfer from/to MMC card.
@endverbatim
* @{
*/
/**
* @brief Reads block(s) from a specified address in a card. The Data transfer
* is managed by polling mode.
* @note This API should be followed by a check on the card state through
* HAL_MMC_GetCardState().
* @param hmmc: Pointer to MMC handle
* @param pData: pointer to the buffer that will contain the received data
* @param BlockAdd: Block Address from where data is to be read
* @param NumberOfBlocks: Number of MMC blocks to read
* @param Timeout: Specify timeout value
* @retval HAL status
*/
HAL_StatusTypeDef HAL_MMC_ReadBlocks(MMC_HandleTypeDef *hmmc, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks, uint32_t Timeout)
{
SDIO_DataInitTypeDef config;
uint32_t errorstate;
uint32_t tickstart = HAL_GetTick();
uint32_t count, data, dataremaining;
uint32_t add = BlockAdd;
uint8_t *tempbuff = pData;
if(NULL == pData)
{
hmmc->ErrorCode |= HAL_MMC_ERROR_PARAM;
return HAL_ERROR;
}
if(hmmc->State == HAL_MMC_STATE_READY)
{
hmmc->ErrorCode = HAL_MMC_ERROR_NONE;
if((BlockAdd + NumberOfBlocks) > (hmmc->MmcCard.LogBlockNbr))
{
hmmc->ErrorCode |= HAL_MMC_ERROR_ADDR_OUT_OF_RANGE;
return HAL_ERROR;
}
hmmc->State = HAL_MMC_STATE_BUSY;
/* Initialize data control register */
hmmc->Instance->DCTRL = 0U;
if ((hmmc->MmcCard.CardType) != MMC_HIGH_CAPACITY_CARD)
{
add *= 512U;
}
/* Configure the MMC DPSM (Data Path State Machine) */
config.DataTimeOut = SDMMC_DATATIMEOUT;
config.DataLength = NumberOfBlocks * MMC_BLOCKSIZE;
config.DataBlockSize = SDIO_DATABLOCK_SIZE_512B;
config.TransferDir = SDIO_TRANSFER_DIR_TO_SDIO;
config.TransferMode = SDIO_TRANSFER_MODE_BLOCK;
config.DPSM = SDIO_DPSM_ENABLE;
(void)SDIO_ConfigData(hmmc->Instance, &config);
/* Read block(s) in polling mode */
if(NumberOfBlocks > 1U)
{
hmmc->Context = MMC_CONTEXT_READ_MULTIPLE_BLOCK;
/* Read Multi Block command */
errorstate = SDMMC_CmdReadMultiBlock(hmmc->Instance, add);
}
else
{
hmmc->Context = MMC_CONTEXT_READ_SINGLE_BLOCK;
/* Read Single Block command */
errorstate = SDMMC_CmdReadSingleBlock(hmmc->Instance, add);
}
if(errorstate != HAL_MMC_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= errorstate;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
/* Poll on SDIO flags */
dataremaining = config.DataLength;
while(!__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DATAEND | SDIO_FLAG_STBITERR))
{
if(__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_RXFIFOHF) && (dataremaining > 0U))
{
/* Read data from SDIO Rx FIFO */
for(count = 0U; count < 8U; count++)
{
data = SDIO_ReadFIFO(hmmc->Instance);
*tempbuff = (uint8_t)(data & 0xFFU);
tempbuff++;
dataremaining--;
*tempbuff = (uint8_t)((data >> 8U) & 0xFFU);
tempbuff++;
dataremaining--;
*tempbuff = (uint8_t)((data >> 16U) & 0xFFU);
tempbuff++;
dataremaining--;
*tempbuff = (uint8_t)((data >> 24U) & 0xFFU);
tempbuff++;
dataremaining--;
}
}
if(((HAL_GetTick()-tickstart) >= Timeout) || (Timeout == 0U))
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= HAL_MMC_ERROR_TIMEOUT;
hmmc->State= HAL_MMC_STATE_READY;
return HAL_TIMEOUT;
}
}
/* Send stop transmission command in case of multiblock read */
if(__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_DATAEND) && (NumberOfBlocks > 1U))
{
/* Send stop transmission command */
errorstate = SDMMC_CmdStopTransfer(hmmc->Instance);
if(errorstate != HAL_MMC_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= errorstate;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
}
/* Get error state */
if(__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_DTIMEOUT))
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= HAL_MMC_ERROR_DATA_TIMEOUT;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
else if(__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_DCRCFAIL))
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= HAL_MMC_ERROR_DATA_CRC_FAIL;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
else if(__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_RXOVERR))
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= HAL_MMC_ERROR_RX_OVERRUN;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
else
{
/* Nothing to do */
}
/* Empty FIFO if there is still any data */
while ((__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_RXDAVL)) && (dataremaining > 0U))
{
data = SDIO_ReadFIFO(hmmc->Instance);
*tempbuff = (uint8_t)(data & 0xFFU);
tempbuff++;
dataremaining--;
*tempbuff = (uint8_t)((data >> 8U) & 0xFFU);
tempbuff++;
dataremaining--;
*tempbuff = (uint8_t)((data >> 16U) & 0xFFU);
tempbuff++;
dataremaining--;
*tempbuff = (uint8_t)((data >> 24U) & 0xFFU);
tempbuff++;
dataremaining--;
if(((HAL_GetTick()-tickstart) >= Timeout) || (Timeout == 0U))
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= HAL_MMC_ERROR_TIMEOUT;
hmmc->State= HAL_MMC_STATE_READY;
return HAL_ERROR;
}
}
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_DATA_FLAGS);
hmmc->State = HAL_MMC_STATE_READY;
return HAL_OK;
}
else
{
hmmc->ErrorCode |= HAL_MMC_ERROR_BUSY;
return HAL_ERROR;
}
}
/**
* @brief Allows to write block(s) to a specified address in a card. The Data
* transfer is managed by polling mode.
* @note This API should be followed by a check on the card state through
* HAL_MMC_GetCardState().
* @param hmmc: Pointer to MMC handle
* @param pData: pointer to the buffer that will contain the data to transmit
* @param BlockAdd: Block Address where data will be written
* @param NumberOfBlocks: Number of MMC blocks to write
* @param Timeout: Specify timeout value
* @retval HAL status
*/
HAL_StatusTypeDef HAL_MMC_WriteBlocks(MMC_HandleTypeDef *hmmc, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks, uint32_t Timeout)
{
SDIO_DataInitTypeDef config;
uint32_t errorstate;
uint32_t tickstart = HAL_GetTick();
uint32_t count, data, dataremaining;
uint32_t add = BlockAdd;
uint8_t *tempbuff = pData;
if(NULL == pData)
{
hmmc->ErrorCode |= HAL_MMC_ERROR_PARAM;
return HAL_ERROR;
}
if(hmmc->State == HAL_MMC_STATE_READY)
{
hmmc->ErrorCode = HAL_MMC_ERROR_NONE;
if((BlockAdd + NumberOfBlocks) > (hmmc->MmcCard.LogBlockNbr))
{
hmmc->ErrorCode |= HAL_MMC_ERROR_ADDR_OUT_OF_RANGE;
return HAL_ERROR;
}
hmmc->State = HAL_MMC_STATE_BUSY;
/* Initialize data control register */
hmmc->Instance->DCTRL = 0U;
if ((hmmc->MmcCard.CardType) != MMC_HIGH_CAPACITY_CARD)
{
add *= 512U;
}
/* Write Blocks in Polling mode */
if(NumberOfBlocks > 1U)
{
hmmc->Context = MMC_CONTEXT_WRITE_MULTIPLE_BLOCK;
/* Write Multi Block command */
errorstate = SDMMC_CmdWriteMultiBlock(hmmc->Instance, add);
}
else
{
hmmc->Context = MMC_CONTEXT_WRITE_SINGLE_BLOCK;
/* Write Single Block command */
errorstate = SDMMC_CmdWriteSingleBlock(hmmc->Instance, add);
}
if(errorstate != HAL_MMC_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= errorstate;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
/* Configure the MMC DPSM (Data Path State Machine) */
config.DataTimeOut = SDMMC_DATATIMEOUT;
config.DataLength = NumberOfBlocks * MMC_BLOCKSIZE;
config.DataBlockSize = SDIO_DATABLOCK_SIZE_512B;
config.TransferDir = SDIO_TRANSFER_DIR_TO_CARD;
config.TransferMode = SDIO_TRANSFER_MODE_BLOCK;
config.DPSM = SDIO_DPSM_ENABLE;
(void)SDIO_ConfigData(hmmc->Instance, &config);
/* Write block(s) in polling mode */
dataremaining = config.DataLength;
while(!__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_TXUNDERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DATAEND | SDIO_FLAG_STBITERR))
{
if(__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_TXFIFOHE) && (dataremaining > 0U))
{
/* Write data to SDIO Tx FIFO */
for(count = 0U; count < 8U; count++)
{
data = (uint32_t)(*tempbuff);
tempbuff++;
dataremaining--;
data |= ((uint32_t)(*tempbuff) << 8U);
tempbuff++;
dataremaining--;
data |= ((uint32_t)(*tempbuff) << 16U);
tempbuff++;
dataremaining--;
data |= ((uint32_t)(*tempbuff) << 24U);
tempbuff++;
dataremaining--;
(void)SDIO_WriteFIFO(hmmc->Instance, &data);
}
}
if(((HAL_GetTick()-tickstart) >= Timeout) || (Timeout == 0U))
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= errorstate;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_TIMEOUT;
}
}
/* Send stop transmission command in case of multiblock write */
if(__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_DATAEND) && (NumberOfBlocks > 1U))
{
/* Send stop transmission command */
errorstate = SDMMC_CmdStopTransfer(hmmc->Instance);
if(errorstate != HAL_MMC_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= errorstate;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
}
/* Get error state */
if(__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_DTIMEOUT))
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= HAL_MMC_ERROR_DATA_TIMEOUT;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
else if(__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_DCRCFAIL))
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= HAL_MMC_ERROR_DATA_CRC_FAIL;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
else if(__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_TXUNDERR))
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= HAL_MMC_ERROR_TX_UNDERRUN;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
else
{
/* Nothing to do */
}
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_DATA_FLAGS);
hmmc->State = HAL_MMC_STATE_READY;
return HAL_OK;
}
else
{
hmmc->ErrorCode |= HAL_MMC_ERROR_BUSY;
return HAL_ERROR;
}
}
/**
* @brief Reads block(s) from a specified address in a card. The Data transfer
* is managed in interrupt mode.
* @note This API should be followed by a check on the card state through
* HAL_MMC_GetCardState().
* @note You could also check the IT transfer process through the MMC Rx
* interrupt event.
* @param hmmc: Pointer to MMC handle
* @param pData: Pointer to the buffer that will contain the received data
* @param BlockAdd: Block Address from where data is to be read
* @param NumberOfBlocks: Number of blocks to read.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_MMC_ReadBlocks_IT(MMC_HandleTypeDef *hmmc, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks)
{
SDIO_DataInitTypeDef config;
uint32_t errorstate;
uint32_t add = BlockAdd;
if(NULL == pData)
{
hmmc->ErrorCode |= HAL_MMC_ERROR_PARAM;
return HAL_ERROR;
}
if(hmmc->State == HAL_MMC_STATE_READY)
{
hmmc->ErrorCode = HAL_MMC_ERROR_NONE;
if((BlockAdd + NumberOfBlocks) > (hmmc->MmcCard.LogBlockNbr))
{
hmmc->ErrorCode |= HAL_MMC_ERROR_ADDR_OUT_OF_RANGE;
return HAL_ERROR;
}
hmmc->State = HAL_MMC_STATE_BUSY;
/* Initialize data control register */
hmmc->Instance->DCTRL = 0U;
hmmc->pRxBuffPtr = pData;
hmmc->RxXferSize = MMC_BLOCKSIZE * NumberOfBlocks;
__HAL_MMC_ENABLE_IT(hmmc, (SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_RXOVERR | SDIO_IT_DATAEND | SDIO_FLAG_RXFIFOHF));
if ((hmmc->MmcCard.CardType) != MMC_HIGH_CAPACITY_CARD)
{
add *= 512U;
}
/* Configure the MMC DPSM (Data Path State Machine) */
config.DataTimeOut = SDMMC_DATATIMEOUT;
config.DataLength = MMC_BLOCKSIZE * NumberOfBlocks;
config.DataBlockSize = SDIO_DATABLOCK_SIZE_512B;
config.TransferDir = SDIO_TRANSFER_DIR_TO_SDIO;
config.TransferMode = SDIO_TRANSFER_MODE_BLOCK;
config.DPSM = SDIO_DPSM_ENABLE;
(void)SDIO_ConfigData(hmmc->Instance, &config);
/* Read Blocks in IT mode */
if(NumberOfBlocks > 1U)
{
hmmc->Context = (MMC_CONTEXT_READ_MULTIPLE_BLOCK | MMC_CONTEXT_IT);
/* Read Multi Block command */
errorstate = SDMMC_CmdReadMultiBlock(hmmc->Instance, add);
}
else
{
hmmc->Context = (MMC_CONTEXT_READ_SINGLE_BLOCK | MMC_CONTEXT_IT);
/* Read Single Block command */
errorstate = SDMMC_CmdReadSingleBlock(hmmc->Instance, add);
}
if(errorstate != HAL_MMC_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= errorstate;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Writes block(s) to a specified address in a card. The Data transfer
* is managed in interrupt mode.
* @note This API should be followed by a check on the card state through
* HAL_MMC_GetCardState().
* @note You could also check the IT transfer process through the MMC Tx
* interrupt event.
* @param hmmc: Pointer to MMC handle
* @param pData: Pointer to the buffer that will contain the data to transmit
* @param BlockAdd: Block Address where data will be written
* @param NumberOfBlocks: Number of blocks to write
* @retval HAL status
*/
HAL_StatusTypeDef HAL_MMC_WriteBlocks_IT(MMC_HandleTypeDef *hmmc, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks)
{
SDIO_DataInitTypeDef config;
uint32_t errorstate;
uint32_t add = BlockAdd;
if(NULL == pData)
{
hmmc->ErrorCode |= HAL_MMC_ERROR_PARAM;
return HAL_ERROR;
}
if(hmmc->State == HAL_MMC_STATE_READY)
{
hmmc->ErrorCode = HAL_MMC_ERROR_NONE;
if((BlockAdd + NumberOfBlocks) > (hmmc->MmcCard.LogBlockNbr))
{
hmmc->ErrorCode |= HAL_MMC_ERROR_ADDR_OUT_OF_RANGE;
return HAL_ERROR;
}
hmmc->State = HAL_MMC_STATE_BUSY;
/* Initialize data control register */
hmmc->Instance->DCTRL = 0U;
hmmc->pTxBuffPtr = pData;
hmmc->TxXferSize = MMC_BLOCKSIZE * NumberOfBlocks;
/* Enable transfer interrupts */
__HAL_MMC_ENABLE_IT(hmmc, (SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_TXUNDERR | SDIO_IT_DATAEND | SDIO_FLAG_TXFIFOHE));
if ((hmmc->MmcCard.CardType) != MMC_HIGH_CAPACITY_CARD)
{
add *= 512U;
}
/* Write Blocks in Polling mode */
if(NumberOfBlocks > 1U)
{
hmmc->Context = (MMC_CONTEXT_WRITE_MULTIPLE_BLOCK| MMC_CONTEXT_IT);
/* Write Multi Block command */
errorstate = SDMMC_CmdWriteMultiBlock(hmmc->Instance, add);
}
else
{
hmmc->Context = (MMC_CONTEXT_WRITE_SINGLE_BLOCK | MMC_CONTEXT_IT);
/* Write Single Block command */
errorstate = SDMMC_CmdWriteSingleBlock(hmmc->Instance, add);
}
if(errorstate != HAL_MMC_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= errorstate;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
/* Configure the MMC DPSM (Data Path State Machine) */
config.DataTimeOut = SDMMC_DATATIMEOUT;
config.DataLength = MMC_BLOCKSIZE * NumberOfBlocks;
config.DataBlockSize = SDIO_DATABLOCK_SIZE_512B;
config.TransferDir = SDIO_TRANSFER_DIR_TO_CARD;
config.TransferMode = SDIO_TRANSFER_MODE_BLOCK;
config.DPSM = SDIO_DPSM_ENABLE;
(void)SDIO_ConfigData(hmmc->Instance, &config);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Reads block(s) from a specified address in a card. The Data transfer
* is managed by DMA mode.
* @note This API should be followed by a check on the card state through
* HAL_MMC_GetCardState().
* @note You could also check the DMA transfer process through the MMC Rx
* interrupt event.
* @param hmmc: Pointer MMC handle
* @param pData: Pointer to the buffer that will contain the received data
* @param BlockAdd: Block Address from where data is to be read
* @param NumberOfBlocks: Number of blocks to read.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_MMC_ReadBlocks_DMA(MMC_HandleTypeDef *hmmc, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks)
{
SDIO_DataInitTypeDef config;
uint32_t errorstate;
uint32_t add = BlockAdd;
if(NULL == pData)
{
hmmc->ErrorCode |= HAL_MMC_ERROR_PARAM;
return HAL_ERROR;
}
if(hmmc->State == HAL_MMC_STATE_READY)
{
hmmc->ErrorCode = HAL_MMC_ERROR_NONE;
if((BlockAdd + NumberOfBlocks) > (hmmc->MmcCard.LogBlockNbr))
{
hmmc->ErrorCode |= HAL_MMC_ERROR_ADDR_OUT_OF_RANGE;
return HAL_ERROR;
}
hmmc->State = HAL_MMC_STATE_BUSY;
/* Initialize data control register */
hmmc->Instance->DCTRL = 0U;
__HAL_MMC_ENABLE_IT(hmmc, (SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_RXOVERR | SDIO_IT_DATAEND));
/* Set the DMA transfer complete callback */
hmmc->hdmarx->XferCpltCallback = MMC_DMAReceiveCplt;
/* Set the DMA error callback */
hmmc->hdmarx->XferErrorCallback = MMC_DMAError;
/* Set the DMA Abort callback */
hmmc->hdmarx->XferAbortCallback = NULL;
if ((hmmc->MmcCard.CardType) != MMC_HIGH_CAPACITY_CARD)
{
add *= 512U;
}
/* Force DMA Direction */
hmmc->hdmarx->Init.Direction = DMA_PERIPH_TO_MEMORY;
MODIFY_REG(hmmc->hdmarx->Instance->CCR, DMA_CCR_DIR, hmmc->hdmarx->Init.Direction);
/* Enable the DMA Channel */
if(HAL_DMA_Start_IT(hmmc->hdmarx, (uint32_t)&hmmc->Instance->FIFO, (uint32_t)pData, (uint32_t)(MMC_BLOCKSIZE * NumberOfBlocks)/4) != HAL_OK)
{
__HAL_MMC_DISABLE_IT(hmmc, (SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_RXOVERR | SDIO_IT_DATAEND));
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode = HAL_MMC_ERROR_DMA;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
else
{
/* Enable MMC DMA transfer */
__HAL_MMC_DMA_ENABLE(hmmc);
/* Configure the MMC DPSM (Data Path State Machine) */
config.DataTimeOut = SDMMC_DATATIMEOUT;
config.DataLength = MMC_BLOCKSIZE * NumberOfBlocks;
config.DataBlockSize = SDIO_DATABLOCK_SIZE_512B;
config.TransferDir = SDIO_TRANSFER_DIR_TO_SDIO;
config.TransferMode = SDIO_TRANSFER_MODE_BLOCK;
config.DPSM = SDIO_DPSM_ENABLE;
(void)SDIO_ConfigData(hmmc->Instance, &config);
/* Read Blocks in DMA mode */
if(NumberOfBlocks > 1U)
{
hmmc->Context = (MMC_CONTEXT_READ_MULTIPLE_BLOCK | MMC_CONTEXT_DMA);
/* Read Multi Block command */
errorstate = SDMMC_CmdReadMultiBlock(hmmc->Instance, add);
}
else
{
hmmc->Context = (MMC_CONTEXT_READ_SINGLE_BLOCK | MMC_CONTEXT_DMA);
/* Read Single Block command */
errorstate = SDMMC_CmdReadSingleBlock(hmmc->Instance, add);
}
if(errorstate != HAL_MMC_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
__HAL_MMC_DISABLE_IT(hmmc, (SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_RXOVERR | SDIO_IT_DATAEND));
hmmc->ErrorCode = errorstate;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
return HAL_OK;
}
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Writes block(s) to a specified address in a card. The Data transfer
* is managed by DMA mode.
* @note This API should be followed by a check on the card state through
* HAL_MMC_GetCardState().
* @note You could also check the DMA transfer process through the MMC Tx
* interrupt event.
* @param hmmc: Pointer to MMC handle
* @param pData: Pointer to the buffer that will contain the data to transmit
* @param BlockAdd: Block Address where data will be written
* @param NumberOfBlocks: Number of blocks to write
* @retval HAL status
*/
HAL_StatusTypeDef HAL_MMC_WriteBlocks_DMA(MMC_HandleTypeDef *hmmc, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks)
{
SDIO_DataInitTypeDef config;
uint32_t errorstate;
uint32_t add = BlockAdd;
if(NULL == pData)
{
hmmc->ErrorCode |= HAL_MMC_ERROR_PARAM;
return HAL_ERROR;
}
if(hmmc->State == HAL_MMC_STATE_READY)
{
hmmc->ErrorCode = HAL_MMC_ERROR_NONE;
if((BlockAdd + NumberOfBlocks) > (hmmc->MmcCard.LogBlockNbr))
{
hmmc->ErrorCode |= HAL_MMC_ERROR_ADDR_OUT_OF_RANGE;
return HAL_ERROR;
}
hmmc->State = HAL_MMC_STATE_BUSY;
/* Initialize data control register */
hmmc->Instance->DCTRL = 0U;
/* Enable MMC Error interrupts */
__HAL_MMC_ENABLE_IT(hmmc, (SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_TXUNDERR));
/* Set the DMA transfer complete callback */
hmmc->hdmatx->XferCpltCallback = MMC_DMATransmitCplt;
/* Set the DMA error callback */
hmmc->hdmatx->XferErrorCallback = MMC_DMAError;
/* Set the DMA Abort callback */
hmmc->hdmatx->XferAbortCallback = NULL;
if ((hmmc->MmcCard.CardType) != MMC_HIGH_CAPACITY_CARD)
{
add *= 512U;
}
/* Write Blocks in Polling mode */
if(NumberOfBlocks > 1U)
{
hmmc->Context = (MMC_CONTEXT_WRITE_MULTIPLE_BLOCK | MMC_CONTEXT_DMA);
/* Write Multi Block command */
errorstate = SDMMC_CmdWriteMultiBlock(hmmc->Instance, add);
}
else
{
hmmc->Context = (MMC_CONTEXT_WRITE_SINGLE_BLOCK | MMC_CONTEXT_DMA);
/* Write Single Block command */
errorstate = SDMMC_CmdWriteSingleBlock(hmmc->Instance, add);
}
if(errorstate != HAL_MMC_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
__HAL_MMC_DISABLE_IT(hmmc, (SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_TXUNDERR | SDIO_IT_DATAEND));
hmmc->ErrorCode |= errorstate;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
/* Enable SDIO DMA transfer */
__HAL_MMC_DMA_ENABLE(hmmc);
/* Force DMA Direction */
hmmc->hdmatx->Init.Direction = DMA_MEMORY_TO_PERIPH;
MODIFY_REG(hmmc->hdmatx->Instance->CCR, DMA_CCR_DIR, hmmc->hdmatx->Init.Direction);
/* Enable the DMA Channel */
if(HAL_DMA_Start_IT(hmmc->hdmatx, (uint32_t)pData, (uint32_t)&hmmc->Instance->FIFO, (uint32_t)(MMC_BLOCKSIZE * NumberOfBlocks)/4) != HAL_OK)
{
__HAL_MMC_DISABLE_IT(hmmc, (SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_TXUNDERR | SDIO_IT_DATAEND));
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= HAL_MMC_ERROR_DMA;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
else
{
/* Configure the MMC DPSM (Data Path State Machine) */
config.DataTimeOut = SDMMC_DATATIMEOUT;
config.DataLength = MMC_BLOCKSIZE * NumberOfBlocks;
config.DataBlockSize = SDIO_DATABLOCK_SIZE_512B;
config.TransferDir = SDIO_TRANSFER_DIR_TO_CARD;
config.TransferMode = SDIO_TRANSFER_MODE_BLOCK;
config.DPSM = SDIO_DPSM_ENABLE;
(void)SDIO_ConfigData(hmmc->Instance, &config);
return HAL_OK;
}
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Erases the specified memory area of the given MMC card.
* @note This API should be followed by a check on the card state through
* HAL_MMC_GetCardState().
* @param hmmc: Pointer to MMC handle
* @param BlockStartAdd: Start Block address
* @param BlockEndAdd: End Block address
* @retval HAL status
*/
HAL_StatusTypeDef HAL_MMC_Erase(MMC_HandleTypeDef *hmmc, uint32_t BlockStartAdd, uint32_t BlockEndAdd)
{
uint32_t errorstate;
uint32_t start_add = BlockStartAdd;
uint32_t end_add = BlockEndAdd;
if(hmmc->State == HAL_MMC_STATE_READY)
{
hmmc->ErrorCode = HAL_MMC_ERROR_NONE;
if(end_add < start_add)
{
hmmc->ErrorCode |= HAL_MMC_ERROR_PARAM;
return HAL_ERROR;
}
if(end_add > (hmmc->MmcCard.LogBlockNbr))
{
hmmc->ErrorCode |= HAL_MMC_ERROR_ADDR_OUT_OF_RANGE;
return HAL_ERROR;
}
hmmc->State = HAL_MMC_STATE_BUSY;
/* Check if the card command class supports erase command */
if(((hmmc->MmcCard.Class) & SDIO_CCCC_ERASE) == 0U)
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= HAL_MMC_ERROR_REQUEST_NOT_APPLICABLE;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
if((SDIO_GetResponse(hmmc->Instance, SDIO_RESP1) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED)
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= HAL_MMC_ERROR_LOCK_UNLOCK_FAILED;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
if ((hmmc->MmcCard.CardType) != MMC_HIGH_CAPACITY_CARD)
{
start_add *= 512U;
end_add *= 512U;
}
/* Send CMD35 MMC_ERASE_GRP_START with argument as addr */
errorstate = SDMMC_CmdEraseStartAdd(hmmc->Instance, start_add);
if(errorstate != HAL_MMC_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= errorstate;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
/* Send CMD36 MMC_ERASE_GRP_END with argument as addr */
errorstate = SDMMC_CmdEraseEndAdd(hmmc->Instance, end_add);
if(errorstate != HAL_MMC_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= errorstate;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
/* Send CMD38 ERASE */
errorstate = SDMMC_CmdErase(hmmc->Instance);
if(errorstate != HAL_MMC_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= errorstate;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
hmmc->State = HAL_MMC_STATE_READY;
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief This function handles MMC card interrupt request.
* @param hmmc: Pointer to MMC handle
* @retval None
*/
void HAL_MMC_IRQHandler(MMC_HandleTypeDef *hmmc)
{
uint32_t errorstate;
uint32_t context = hmmc->Context;
/* Check for SDIO interrupt flags */
if((__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_RXFIFOHF) != RESET) && ((context & MMC_CONTEXT_IT) != 0U))
{
MMC_Read_IT(hmmc);
}
else if(__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_DATAEND) != RESET)
{
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_FLAG_DATAEND);
__HAL_MMC_DISABLE_IT(hmmc, SDIO_IT_DATAEND | SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT|\
SDIO_IT_TXUNDERR| SDIO_IT_RXOVERR);
hmmc->Instance->DCTRL &= ~(SDIO_DCTRL_DTEN);
if((context & MMC_CONTEXT_DMA) != 0U)
{
if((context & MMC_CONTEXT_WRITE_MULTIPLE_BLOCK) != 0U)
{
errorstate = SDMMC_CmdStopTransfer(hmmc->Instance);
if(errorstate != HAL_MMC_ERROR_NONE)
{
hmmc->ErrorCode |= errorstate;
#if defined (USE_HAL_MMC_REGISTER_CALLBACKS) && (USE_HAL_MMC_REGISTER_CALLBACKS == 1U)
hmmc->ErrorCallback(hmmc);
#else
HAL_MMC_ErrorCallback(hmmc);
#endif
}
}
if(((context & MMC_CONTEXT_READ_SINGLE_BLOCK) == 0U) && ((context & MMC_CONTEXT_READ_MULTIPLE_BLOCK) == 0U))
{
/* Disable the DMA transfer for transmit request by setting the DMAEN bit
in the MMC DCTRL register */
hmmc->Instance->DCTRL &= (uint32_t)~((uint32_t)SDIO_DCTRL_DMAEN);
hmmc->State = HAL_MMC_STATE_READY;
#if defined (USE_HAL_MMC_REGISTER_CALLBACKS) && (USE_HAL_MMC_REGISTER_CALLBACKS == 1U)
hmmc->TxCpltCallback(hmmc);
#else
HAL_MMC_TxCpltCallback(hmmc);
#endif
}
}
else if((context & MMC_CONTEXT_IT) != 0U)
{
/* Stop Transfer for Write Multi blocks or Read Multi blocks */
if(((context & MMC_CONTEXT_READ_MULTIPLE_BLOCK) != 0U) || ((context & MMC_CONTEXT_WRITE_MULTIPLE_BLOCK) != 0U))
{
errorstate = SDMMC_CmdStopTransfer(hmmc->Instance);
if(errorstate != HAL_MMC_ERROR_NONE)
{
hmmc->ErrorCode |= errorstate;
#if defined (USE_HAL_MMC_REGISTER_CALLBACKS) && (USE_HAL_MMC_REGISTER_CALLBACKS == 1U)
hmmc->ErrorCallback(hmmc);
#else
HAL_MMC_ErrorCallback(hmmc);
#endif
}
}
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_DATA_FLAGS);
hmmc->State = HAL_MMC_STATE_READY;
if(((context & MMC_CONTEXT_READ_SINGLE_BLOCK) != 0U) || ((context & MMC_CONTEXT_READ_MULTIPLE_BLOCK) != 0U))
{
#if defined (USE_HAL_MMC_REGISTER_CALLBACKS) && (USE_HAL_MMC_REGISTER_CALLBACKS == 1U)
hmmc->RxCpltCallback(hmmc);
#else
HAL_MMC_RxCpltCallback(hmmc);
#endif
}
else
{
#if defined (USE_HAL_MMC_REGISTER_CALLBACKS) && (USE_HAL_MMC_REGISTER_CALLBACKS == 1U)
hmmc->TxCpltCallback(hmmc);
#else
HAL_MMC_TxCpltCallback(hmmc);
#endif
}
}
else
{
/* Nothing to do */
}
}
else if((__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_TXFIFOHE) != RESET) && ((context & MMC_CONTEXT_IT) != 0U))
{
MMC_Write_IT(hmmc);
}
else if(__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_RXOVERR | SDIO_FLAG_TXUNDERR) != RESET)
{
/* Set Error code */
if(__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_DCRCFAIL) != RESET)
{
hmmc->ErrorCode |= HAL_MMC_ERROR_DATA_CRC_FAIL;
}
if(__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_DTIMEOUT) != RESET)
{
hmmc->ErrorCode |= HAL_MMC_ERROR_DATA_TIMEOUT;
}
if(__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_RXOVERR) != RESET)
{
hmmc->ErrorCode |= HAL_MMC_ERROR_RX_OVERRUN;
}
if(__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_TXUNDERR) != RESET)
{
hmmc->ErrorCode |= HAL_MMC_ERROR_TX_UNDERRUN;
}
/* Clear All flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_DATA_FLAGS | SDIO_FLAG_STBITERR);
/* Disable all interrupts */
__HAL_MMC_DISABLE_IT(hmmc, SDIO_IT_DATAEND | SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT|\
SDIO_IT_TXUNDERR| SDIO_IT_RXOVERR | SDIO_IT_STBITERR);
hmmc->ErrorCode |= SDMMC_CmdStopTransfer(hmmc->Instance);
if((context & MMC_CONTEXT_IT) != 0U)
{
/* Set the MMC state to ready to be able to start again the process */
hmmc->State = HAL_MMC_STATE_READY;
#if defined (USE_HAL_MMC_REGISTER_CALLBACKS) && (USE_HAL_MMC_REGISTER_CALLBACKS == 1U)
hmmc->ErrorCallback(hmmc);
#else
HAL_MMC_ErrorCallback(hmmc);
#endif /* USE_HAL_MMC_REGISTER_CALLBACKS */
}
else if((context & MMC_CONTEXT_DMA) != 0U)
{
/* Abort the MMC DMA Streams */
if(hmmc->hdmatx != NULL)
{
/* Set the DMA Tx abort callback */
hmmc->hdmatx->XferAbortCallback = MMC_DMATxAbort;
/* Abort DMA in IT mode */
if(HAL_DMA_Abort_IT(hmmc->hdmatx) != HAL_OK)
{
MMC_DMATxAbort(hmmc->hdmatx);
}
}
else if(hmmc->hdmarx != NULL)
{
/* Set the DMA Rx abort callback */
hmmc->hdmarx->XferAbortCallback = MMC_DMARxAbort;
/* Abort DMA in IT mode */
if(HAL_DMA_Abort_IT(hmmc->hdmarx) != HAL_OK)
{
MMC_DMARxAbort(hmmc->hdmarx);
}
}
else
{
hmmc->ErrorCode = HAL_MMC_ERROR_NONE;
hmmc->State = HAL_MMC_STATE_READY;
#if defined (USE_HAL_MMC_REGISTER_CALLBACKS) && (USE_HAL_MMC_REGISTER_CALLBACKS == 1U)
hmmc->AbortCpltCallback(hmmc);
#else
HAL_MMC_AbortCallback(hmmc);
#endif
}
}
else
{
/* Nothing to do */
}
}
else
{
/* Nothing to do */
}
}
/**
* @brief return the MMC state
* @param hmmc: Pointer to mmc handle
* @retval HAL state
*/
HAL_MMC_StateTypeDef HAL_MMC_GetState(MMC_HandleTypeDef *hmmc)
{
return hmmc->State;
}
/**
* @brief Return the MMC error code
* @param hmmc : Pointer to a MMC_HandleTypeDef structure that contains
* the configuration information.
* @retval MMC Error Code
*/
uint32_t HAL_MMC_GetError(MMC_HandleTypeDef *hmmc)
{
return hmmc->ErrorCode;
}
/**
* @brief Tx Transfer completed callbacks
* @param hmmc: Pointer to MMC handle
* @retval None
*/
__weak void HAL_MMC_TxCpltCallback(MMC_HandleTypeDef *hmmc)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hmmc);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_MMC_TxCpltCallback can be implemented in the user file
*/
}
/**
* @brief Rx Transfer completed callbacks
* @param hmmc: Pointer MMC handle
* @retval None
*/
__weak void HAL_MMC_RxCpltCallback(MMC_HandleTypeDef *hmmc)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hmmc);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_MMC_RxCpltCallback can be implemented in the user file
*/
}
/**
* @brief MMC error callbacks
* @param hmmc: Pointer MMC handle
* @retval None
*/
__weak void HAL_MMC_ErrorCallback(MMC_HandleTypeDef *hmmc)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hmmc);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_MMC_ErrorCallback can be implemented in the user file
*/
}
/**
* @brief MMC Abort callbacks
* @param hmmc: Pointer MMC handle
* @retval None
*/
__weak void HAL_MMC_AbortCallback(MMC_HandleTypeDef *hmmc)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hmmc);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_MMC_AbortCallback can be implemented in the user file
*/
}
#if defined (USE_HAL_MMC_REGISTER_CALLBACKS) && (USE_HAL_MMC_REGISTER_CALLBACKS == 1U)
/**
* @brief Register a User MMC Callback
* To be used instead of the weak (surcharged) predefined callback
* @param hmmc : MMC handle
* @param CallbackId : ID of the callback to be registered
* This parameter can be one of the following values:
* @arg @ref HAL_MMC_TX_CPLT_CB_ID MMC Tx Complete Callback ID
* @arg @ref HAL_MMC_RX_CPLT_CB_ID MMC Rx Complete Callback ID
* @arg @ref HAL_MMC_ERROR_CB_ID MMC Error Callback ID
* @arg @ref HAL_MMC_ABORT_CB_ID MMC Abort Callback ID
* @arg @ref HAL_MMC_MSP_INIT_CB_ID MMC MspInit Callback ID
* @arg @ref HAL_MMC_MSP_DEINIT_CB_ID MMC MspDeInit Callback ID
* @param pCallback : pointer to the Callback function
* @retval status
*/
HAL_StatusTypeDef HAL_MMC_RegisterCallback(MMC_HandleTypeDef *hmmc, HAL_MMC_CallbackIDTypeDef CallbackId, pMMC_CallbackTypeDef pCallback)
{
HAL_StatusTypeDef status = HAL_OK;
if(pCallback == NULL)
{
/* Update the error code */
hmmc->ErrorCode |= HAL_MMC_ERROR_INVALID_CALLBACK;
return HAL_ERROR;
}
/* Process locked */
__HAL_LOCK(hmmc);
if(hmmc->State == HAL_MMC_STATE_READY)
{
switch (CallbackId)
{
case HAL_MMC_TX_CPLT_CB_ID :
hmmc->TxCpltCallback = pCallback;
break;
case HAL_MMC_RX_CPLT_CB_ID :
hmmc->RxCpltCallback = pCallback;
break;
case HAL_MMC_ERROR_CB_ID :
hmmc->ErrorCallback = pCallback;
break;
case HAL_MMC_ABORT_CB_ID :
hmmc->AbortCpltCallback = pCallback;
break;
case HAL_MMC_MSP_INIT_CB_ID :
hmmc->MspInitCallback = pCallback;
break;
case HAL_MMC_MSP_DEINIT_CB_ID :
hmmc->MspDeInitCallback = pCallback;
break;
default :
/* Update the error code */
hmmc->ErrorCode |= HAL_MMC_ERROR_INVALID_CALLBACK;
/* update return status */
status = HAL_ERROR;
break;
}
}
else if (hmmc->State == HAL_MMC_STATE_RESET)
{
switch (CallbackId)
{
case HAL_MMC_MSP_INIT_CB_ID :
hmmc->MspInitCallback = pCallback;
break;
case HAL_MMC_MSP_DEINIT_CB_ID :
hmmc->MspDeInitCallback = pCallback;
break;
default :
/* Update the error code */
hmmc->ErrorCode |= HAL_MMC_ERROR_INVALID_CALLBACK;
/* update return status */
status = HAL_ERROR;
break;
}
}
else
{
/* Update the error code */
hmmc->ErrorCode |= HAL_MMC_ERROR_INVALID_CALLBACK;
/* update return status */
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(hmmc);
return status;
}
/**
* @brief Unregister a User MMC Callback
* MMC Callback is redirected to the weak (surcharged) predefined callback
* @param hmmc : MMC handle
* @param CallbackId : ID of the callback to be unregistered
* This parameter can be one of the following values:
* @arg @ref HAL_MMC_TX_CPLT_CB_ID MMC Tx Complete Callback ID
* @arg @ref HAL_MMC_RX_CPLT_CB_ID MMC Rx Complete Callback ID
* @arg @ref HAL_MMC_ERROR_CB_ID MMC Error Callback ID
* @arg @ref HAL_MMC_ABORT_CB_ID MMC Abort Callback ID
* @arg @ref HAL_MMC_MSP_INIT_CB_ID MMC MspInit Callback ID
* @arg @ref HAL_MMC_MSP_DEINIT_CB_ID MMC MspDeInit Callback ID
* @retval status
*/
HAL_StatusTypeDef HAL_MMC_UnRegisterCallback(MMC_HandleTypeDef *hmmc, HAL_MMC_CallbackIDTypeDef CallbackId)
{
HAL_StatusTypeDef status = HAL_OK;
/* Process locked */
__HAL_LOCK(hmmc);
if(hmmc->State == HAL_MMC_STATE_READY)
{
switch (CallbackId)
{
case HAL_MMC_TX_CPLT_CB_ID :
hmmc->TxCpltCallback = HAL_MMC_TxCpltCallback;
break;
case HAL_MMC_RX_CPLT_CB_ID :
hmmc->RxCpltCallback = HAL_MMC_RxCpltCallback;
break;
case HAL_MMC_ERROR_CB_ID :
hmmc->ErrorCallback = HAL_MMC_ErrorCallback;
break;
case HAL_MMC_ABORT_CB_ID :
hmmc->AbortCpltCallback = HAL_MMC_AbortCallback;
break;
case HAL_MMC_MSP_INIT_CB_ID :
hmmc->MspInitCallback = HAL_MMC_MspInit;
break;
case HAL_MMC_MSP_DEINIT_CB_ID :
hmmc->MspDeInitCallback = HAL_MMC_MspDeInit;
break;
default :
/* Update the error code */
hmmc->ErrorCode |= HAL_MMC_ERROR_INVALID_CALLBACK;
/* update return status */
status = HAL_ERROR;
break;
}
}
else if (hmmc->State == HAL_MMC_STATE_RESET)
{
switch (CallbackId)
{
case HAL_MMC_MSP_INIT_CB_ID :
hmmc->MspInitCallback = HAL_MMC_MspInit;
break;
case HAL_MMC_MSP_DEINIT_CB_ID :
hmmc->MspDeInitCallback = HAL_MMC_MspDeInit;
break;
default :
/* Update the error code */
hmmc->ErrorCode |= HAL_MMC_ERROR_INVALID_CALLBACK;
/* update return status */
status = HAL_ERROR;
break;
}
}
else
{
/* Update the error code */
hmmc->ErrorCode |= HAL_MMC_ERROR_INVALID_CALLBACK;
/* update return status */
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(hmmc);
return status;
}
#endif
/**
* @}
*/
/** @addtogroup MMC_Exported_Functions_Group3
* @brief management functions
*
@verbatim
==============================================================================
##### Peripheral Control functions #####
==============================================================================
[..]
This subsection provides a set of functions allowing to control the MMC card
operations and get the related information
@endverbatim
* @{
*/
/**
* @brief Returns information the information of the card which are stored on
* the CID register.
* @param hmmc: Pointer to MMC handle
* @param pCID: Pointer to a HAL_MMC_CIDTypedef structure that
* contains all CID register parameters
* @retval HAL status
*/
HAL_StatusTypeDef HAL_MMC_GetCardCID(MMC_HandleTypeDef *hmmc, HAL_MMC_CardCIDTypeDef *pCID)
{
pCID->ManufacturerID = (uint8_t)((hmmc->CID[0] & 0xFF000000U) >> 24U);
pCID->OEM_AppliID = (uint16_t)((hmmc->CID[0] & 0x00FFFF00U) >> 8U);
pCID->ProdName1 = (((hmmc->CID[0] & 0x000000FFU) << 24U) | ((hmmc->CID[1] & 0xFFFFFF00U) >> 8U));
pCID->ProdName2 = (uint8_t)(hmmc->CID[1] & 0x000000FFU);
pCID->ProdRev = (uint8_t)((hmmc->CID[2] & 0xFF000000U) >> 24U);
pCID->ProdSN = (((hmmc->CID[2] & 0x00FFFFFFU) << 8U) | ((hmmc->CID[3] & 0xFF000000U) >> 24U));
pCID->Reserved1 = (uint8_t)((hmmc->CID[3] & 0x00F00000U) >> 20U);
pCID->ManufactDate = (uint16_t)((hmmc->CID[3] & 0x000FFF00U) >> 8U);
pCID->CID_CRC = (uint8_t)((hmmc->CID[3] & 0x000000FEU) >> 1U);
pCID->Reserved2 = 1U;
return HAL_OK;
}
/**
* @brief Returns information the information of the card which are stored on
* the CSD register.
* @param hmmc: Pointer to MMC handle
* @param pCSD: Pointer to a HAL_MMC_CardCSDTypeDef structure that
* contains all CSD register parameters
* @retval HAL status
*/
HAL_StatusTypeDef HAL_MMC_GetCardCSD(MMC_HandleTypeDef *hmmc, HAL_MMC_CardCSDTypeDef *pCSD)
{
uint32_t block_nbr = 0;
pCSD->CSDStruct = (uint8_t)((hmmc->CSD[0] & 0xC0000000U) >> 30U);
pCSD->SysSpecVersion = (uint8_t)((hmmc->CSD[0] & 0x3C000000U) >> 26U);
pCSD->Reserved1 = (uint8_t)((hmmc->CSD[0] & 0x03000000U) >> 24U);
pCSD->TAAC = (uint8_t)((hmmc->CSD[0] & 0x00FF0000U) >> 16U);
pCSD->NSAC = (uint8_t)((hmmc->CSD[0] & 0x0000FF00U) >> 8U);
pCSD->MaxBusClkFrec = (uint8_t)(hmmc->CSD[0] & 0x000000FFU);
pCSD->CardComdClasses = (uint16_t)((hmmc->CSD[1] & 0xFFF00000U) >> 20U);
pCSD->RdBlockLen = (uint8_t)((hmmc->CSD[1] & 0x000F0000U) >> 16U);
pCSD->PartBlockRead = (uint8_t)((hmmc->CSD[1] & 0x00008000U) >> 15U);
pCSD->WrBlockMisalign = (uint8_t)((hmmc->CSD[1] & 0x00004000U) >> 14U);
pCSD->RdBlockMisalign = (uint8_t)((hmmc->CSD[1] & 0x00002000U) >> 13U);
pCSD->DSRImpl = (uint8_t)((hmmc->CSD[1] & 0x00001000U) >> 12U);
pCSD->Reserved2 = 0U; /*!< Reserved */
pCSD->DeviceSize = (((hmmc->CSD[1] & 0x000003FFU) << 2U) | ((hmmc->CSD[2] & 0xC0000000U) >> 30U));
pCSD->MaxRdCurrentVDDMin = (uint8_t)((hmmc->CSD[2] & 0x38000000U) >> 27U);
pCSD->MaxRdCurrentVDDMax = (uint8_t)((hmmc->CSD[2] & 0x07000000U) >> 24U);
pCSD->MaxWrCurrentVDDMin = (uint8_t)((hmmc->CSD[2] & 0x00E00000U) >> 21U);
pCSD->MaxWrCurrentVDDMax = (uint8_t)((hmmc->CSD[2] & 0x001C0000U) >> 18U);
pCSD->DeviceSizeMul = (uint8_t)((hmmc->CSD[2] & 0x00038000U) >> 15U);
if(MMC_ReadExtCSD(hmmc, &block_nbr, 212, 0x0FFFFFFFU) != HAL_OK) /* Field SEC_COUNT [215:212] */
{
return HAL_ERROR;
}
if(hmmc->MmcCard.CardType == MMC_LOW_CAPACITY_CARD)
{
hmmc->MmcCard.BlockNbr = (pCSD->DeviceSize + 1U) ;
hmmc->MmcCard.BlockNbr *= (1UL << ((pCSD->DeviceSizeMul & 0x07U) + 2U));
hmmc->MmcCard.BlockSize = (1UL << (pCSD->RdBlockLen & 0x0FU));
hmmc->MmcCard.LogBlockNbr = (hmmc->MmcCard.BlockNbr) * ((hmmc->MmcCard.BlockSize) / 512U);
hmmc->MmcCard.LogBlockSize = 512U;
}
else if(hmmc->MmcCard.CardType == MMC_HIGH_CAPACITY_CARD)
{
hmmc->MmcCard.BlockNbr = block_nbr;
hmmc->MmcCard.LogBlockNbr = hmmc->MmcCard.BlockNbr;
hmmc->MmcCard.BlockSize = 512U;
hmmc->MmcCard.LogBlockSize = hmmc->MmcCard.BlockSize;
}
else
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= HAL_MMC_ERROR_UNSUPPORTED_FEATURE;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
pCSD->EraseGrSize = (uint8_t)((hmmc->CSD[2] & 0x00004000U) >> 14U);
pCSD->EraseGrMul = (uint8_t)((hmmc->CSD[2] & 0x00003F80U) >> 7U);
pCSD->WrProtectGrSize = (uint8_t)(hmmc->CSD[2] & 0x0000007FU);
pCSD->WrProtectGrEnable = (uint8_t)((hmmc->CSD[3] & 0x80000000U) >> 31U);
pCSD->ManDeflECC = (uint8_t)((hmmc->CSD[3] & 0x60000000U) >> 29U);
pCSD->WrSpeedFact = (uint8_t)((hmmc->CSD[3] & 0x1C000000U) >> 26U);
pCSD->MaxWrBlockLen= (uint8_t)((hmmc->CSD[3] & 0x03C00000U) >> 22U);
pCSD->WriteBlockPaPartial = (uint8_t)((hmmc->CSD[3] & 0x00200000U) >> 21U);
pCSD->Reserved3 = 0;
pCSD->ContentProtectAppli = (uint8_t)((hmmc->CSD[3] & 0x00010000U) >> 16U);
pCSD->FileFormatGroup = (uint8_t)((hmmc->CSD[3] & 0x00008000U) >> 15U);
pCSD->CopyFlag = (uint8_t)((hmmc->CSD[3] & 0x00004000U) >> 14U);
pCSD->PermWrProtect = (uint8_t)((hmmc->CSD[3] & 0x00002000U) >> 13U);
pCSD->TempWrProtect = (uint8_t)((hmmc->CSD[3] & 0x00001000U) >> 12U);
pCSD->FileFormat = (uint8_t)((hmmc->CSD[3] & 0x00000C00U) >> 10U);
pCSD->ECC= (uint8_t)((hmmc->CSD[3] & 0x00000300U) >> 8U);
pCSD->CSD_CRC = (uint8_t)((hmmc->CSD[3] & 0x000000FEU) >> 1U);
pCSD->Reserved4 = 1;
return HAL_OK;
}
/**
* @brief Gets the MMC card info.
* @param hmmc: Pointer to MMC handle
* @param pCardInfo: Pointer to the HAL_MMC_CardInfoTypeDef structure that
* will contain the MMC card status information
* @retval HAL status
*/
HAL_StatusTypeDef HAL_MMC_GetCardInfo(MMC_HandleTypeDef *hmmc, HAL_MMC_CardInfoTypeDef *pCardInfo)
{
pCardInfo->CardType = (uint32_t)(hmmc->MmcCard.CardType);
pCardInfo->Class = (uint32_t)(hmmc->MmcCard.Class);
pCardInfo->RelCardAdd = (uint32_t)(hmmc->MmcCard.RelCardAdd);
pCardInfo->BlockNbr = (uint32_t)(hmmc->MmcCard.BlockNbr);
pCardInfo->BlockSize = (uint32_t)(hmmc->MmcCard.BlockSize);
pCardInfo->LogBlockNbr = (uint32_t)(hmmc->MmcCard.LogBlockNbr);
pCardInfo->LogBlockSize = (uint32_t)(hmmc->MmcCard.LogBlockSize);
return HAL_OK;
}
/**
* @brief Returns information the information of the card which are stored on
* the Extended CSD register.
* @param hmmc Pointer to MMC handle
* @param pExtCSD Pointer to a memory area (512 bytes) that contains all
* Extended CSD register parameters
* @param Timeout Specify timeout value
* @retval HAL status
*/
HAL_StatusTypeDef HAL_MMC_GetCardExtCSD(MMC_HandleTypeDef *hmmc, uint32_t *pExtCSD, uint32_t Timeout)
{
SDIO_DataInitTypeDef config;
uint32_t errorstate;
uint32_t tickstart = HAL_GetTick();
uint32_t count;
uint32_t *tmp_buf;
if(NULL == pExtCSD)
{
hmmc->ErrorCode |= HAL_MMC_ERROR_PARAM;
return HAL_ERROR;
}
if(hmmc->State == HAL_MMC_STATE_READY)
{
hmmc->ErrorCode = HAL_MMC_ERROR_NONE;
hmmc->State = HAL_MMC_STATE_BUSY;
/* Initialize data control register */
hmmc->Instance->DCTRL = 0;
/* Initiaize the destination pointer */
tmp_buf = pExtCSD;
/* Configure the MMC DPSM (Data Path State Machine) */
config.DataTimeOut = SDMMC_DATATIMEOUT;
config.DataLength = 512;
config.DataBlockSize = SDIO_DATABLOCK_SIZE_512B;
config.TransferDir = SDIO_TRANSFER_DIR_TO_SDIO;
config.TransferMode = SDIO_TRANSFER_MODE_BLOCK;
config.DPSM = SDIO_DPSM_ENABLE;
(void)SDIO_ConfigData(hmmc->Instance, &config);
/* Send ExtCSD Read command to Card */
errorstate = SDMMC_CmdSendEXTCSD(hmmc->Instance, 0);
if(errorstate != HAL_MMC_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= errorstate;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
/* Poll on SDMMC flags */
while(!__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DATAEND))
{
if(__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_RXFIFOHF))
{
/* Read data from SDMMC Rx FIFO */
for(count = 0U; count < 8U; count++)
{
*tmp_buf = SDIO_ReadFIFO(hmmc->Instance);
tmp_buf++;
}
}
if(((HAL_GetTick()-tickstart) >= Timeout) || (Timeout == 0U))
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= HAL_MMC_ERROR_TIMEOUT;
hmmc->State= HAL_MMC_STATE_READY;
return HAL_TIMEOUT;
}
}
/* Get error state */
if(__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_DTIMEOUT))
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= HAL_MMC_ERROR_DATA_TIMEOUT;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
else if(__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_DCRCFAIL))
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= HAL_MMC_ERROR_DATA_CRC_FAIL;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
else if(__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_RXOVERR))
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= HAL_MMC_ERROR_RX_OVERRUN;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
else
{
/* Nothing to do */
}
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_DATA_FLAGS);
hmmc->State = HAL_MMC_STATE_READY;
}
return HAL_OK;
}
/**
* @brief Enables wide bus operation for the requested card if supported by
* card.
* @param hmmc: Pointer to MMC handle
* @param WideMode: Specifies the MMC card wide bus mode
* This parameter can be one of the following values:
* @arg SDIO_BUS_WIDE_8B: 8-bit data transfer
* @arg SDIO_BUS_WIDE_4B: 4-bit data transfer
* @arg SDIO_BUS_WIDE_1B: 1-bit data transfer
* @retval HAL status
*/
HAL_StatusTypeDef HAL_MMC_ConfigWideBusOperation(MMC_HandleTypeDef *hmmc, uint32_t WideMode)
{
uint32_t count;
SDIO_InitTypeDef Init;
uint32_t errorstate;
uint32_t response = 0U;
/* Check the parameters */
assert_param(IS_SDIO_BUS_WIDE(WideMode));
/* Change State */
hmmc->State = HAL_MMC_STATE_BUSY;
errorstate = MMC_PwrClassUpdate(hmmc, WideMode);
if(errorstate == HAL_MMC_ERROR_NONE)
{
if(WideMode == SDIO_BUS_WIDE_8B)
{
errorstate = SDMMC_CmdSwitch(hmmc->Instance, 0x03B70200U);
}
else if(WideMode == SDIO_BUS_WIDE_4B)
{
errorstate = SDMMC_CmdSwitch(hmmc->Instance, 0x03B70100U);
}
else if(WideMode == SDIO_BUS_WIDE_1B)
{
errorstate = SDMMC_CmdSwitch(hmmc->Instance, 0x03B70000U);
}
else
{
/* WideMode is not a valid argument*/
errorstate = HAL_MMC_ERROR_PARAM;
}
/* Check for switch error and violation of the trial number of sending CMD 13 */
if(errorstate == HAL_MMC_ERROR_NONE)
{
/* While card is not ready for data and trial number for sending CMD13 is not exceeded */
count = SDMMC_MAX_TRIAL;
do
{
errorstate = SDMMC_CmdSendStatus(hmmc->Instance, (uint32_t)(((uint32_t)hmmc->MmcCard.RelCardAdd) << 16U));
if(errorstate != HAL_MMC_ERROR_NONE)
{
break;
}
/* Get command response */
response = SDIO_GetResponse(hmmc->Instance, SDIO_RESP1);
count--;
}while(((response & 0x100U) == 0U) && (count != 0U));
/* Check the status after the switch command execution */
if ((count != 0U) && (errorstate == HAL_MMC_ERROR_NONE))
{
/* Check the bit SWITCH_ERROR of the device status */
if ((response & 0x80U) != 0U)
{
errorstate = SDMMC_ERROR_GENERAL_UNKNOWN_ERR;
}
else
{
/* Configure the SDIO peripheral */
Init = hmmc->Init;
Init.BusWide = WideMode;
(void)SDIO_Init(hmmc->Instance, Init);
}
}
else if (count == 0U)
{
errorstate = SDMMC_ERROR_TIMEOUT;
}
else
{
/* Nothing to do */
}
}
}
/* Change State */
hmmc->State = HAL_MMC_STATE_READY;
if(errorstate != HAL_MMC_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= errorstate;
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Gets the current mmc card data state.
* @param hmmc: pointer to MMC handle
* @retval Card state
*/
HAL_MMC_CardStateTypeDef HAL_MMC_GetCardState(MMC_HandleTypeDef *hmmc)
{
uint32_t cardstate;
uint32_t errorstate;
uint32_t resp1 = 0U;
errorstate = MMC_SendStatus(hmmc, &resp1);
if(errorstate != HAL_MMC_ERROR_NONE)
{
hmmc->ErrorCode |= errorstate;
}
cardstate = ((resp1 >> 9U) & 0x0FU);
return (HAL_MMC_CardStateTypeDef)cardstate;
}
/**
* @brief Abort the current transfer and disable the MMC.
* @param hmmc: pointer to a MMC_HandleTypeDef structure that contains
* the configuration information for MMC module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_MMC_Abort(MMC_HandleTypeDef *hmmc)
{
HAL_MMC_CardStateTypeDef CardState;
/* DIsable All interrupts */
__HAL_MMC_DISABLE_IT(hmmc, SDIO_IT_DATAEND | SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT|\
SDIO_IT_TXUNDERR| SDIO_IT_RXOVERR);
/* Clear All flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_DATA_FLAGS);
if((hmmc->hdmatx != NULL) || (hmmc->hdmarx != NULL))
{
/* Disable the MMC DMA request */
hmmc->Instance->DCTRL &= (uint32_t)~((uint32_t)SDIO_DCTRL_DMAEN);
/* Abort the MMC DMA Tx Stream */
if(hmmc->hdmatx != NULL)
{
if(HAL_DMA_Abort(hmmc->hdmatx) != HAL_OK)
{
hmmc->ErrorCode |= HAL_MMC_ERROR_DMA;
}
}
/* Abort the MMC DMA Rx Stream */
if(hmmc->hdmarx != NULL)
{
if(HAL_DMA_Abort(hmmc->hdmarx) != HAL_OK)
{
hmmc->ErrorCode |= HAL_MMC_ERROR_DMA;
}
}
}
hmmc->State = HAL_MMC_STATE_READY;
/* Initialize the MMC operation */
hmmc->Context = MMC_CONTEXT_NONE;
CardState = HAL_MMC_GetCardState(hmmc);
if((CardState == HAL_MMC_CARD_RECEIVING) || (CardState == HAL_MMC_CARD_SENDING))
{
hmmc->ErrorCode = SDMMC_CmdStopTransfer(hmmc->Instance);
}
if(hmmc->ErrorCode != HAL_MMC_ERROR_NONE)
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Abort the current transfer and disable the MMC (IT mode).
* @param hmmc: pointer to a MMC_HandleTypeDef structure that contains
* the configuration information for MMC module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_MMC_Abort_IT(MMC_HandleTypeDef *hmmc)
{
HAL_MMC_CardStateTypeDef CardState;
/* DIsable All interrupts */
__HAL_MMC_DISABLE_IT(hmmc, SDIO_IT_DATAEND | SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT|\
SDIO_IT_TXUNDERR| SDIO_IT_RXOVERR);
/* Clear All flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_DATA_FLAGS);
if((hmmc->hdmatx != NULL) || (hmmc->hdmarx != NULL))
{
/* Disable the MMC DMA request */
hmmc->Instance->DCTRL &= (uint32_t)~((uint32_t)SDIO_DCTRL_DMAEN);
/* Abort the MMC DMA Tx Stream */
if(hmmc->hdmatx != NULL)
{
hmmc->hdmatx->XferAbortCallback = MMC_DMATxAbort;
if(HAL_DMA_Abort_IT(hmmc->hdmatx) != HAL_OK)
{
hmmc->hdmatx = NULL;
}
}
/* Abort the MMC DMA Rx Stream */
if(hmmc->hdmarx != NULL)
{
hmmc->hdmarx->XferAbortCallback = MMC_DMARxAbort;
if(HAL_DMA_Abort_IT(hmmc->hdmarx) != HAL_OK)
{
hmmc->hdmarx = NULL;
}
}
}
/* No transfer ongoing on both DMA channels*/
if((hmmc->hdmatx == NULL) && (hmmc->hdmarx == NULL))
{
CardState = HAL_MMC_GetCardState(hmmc);
hmmc->State = HAL_MMC_STATE_READY;
if((CardState == HAL_MMC_CARD_RECEIVING) || (CardState == HAL_MMC_CARD_SENDING))
{
hmmc->ErrorCode = SDMMC_CmdStopTransfer(hmmc->Instance);
}
if(hmmc->ErrorCode != HAL_MMC_ERROR_NONE)
{
return HAL_ERROR;
}
else
{
#if defined (USE_HAL_MMC_REGISTER_CALLBACKS) && (USE_HAL_MMC_REGISTER_CALLBACKS == 1U)
hmmc->AbortCpltCallback(hmmc);
#else
HAL_MMC_AbortCallback(hmmc);
#endif
}
}
return HAL_OK;
}
/**
* @}
*/
/**
* @}
*/
/* Private function ----------------------------------------------------------*/
/** @addtogroup MMC_Private_Functions
* @{
*/
/**
* @brief DMA MMC transmit process complete callback
* @param hdma: DMA handle
* @retval None
*/
static void MMC_DMATransmitCplt(DMA_HandleTypeDef *hdma)
{
MMC_HandleTypeDef* hmmc = (MMC_HandleTypeDef* )(hdma->Parent);
/* Enable DATAEND Interrupt */
__HAL_MMC_ENABLE_IT(hmmc, (SDIO_IT_DATAEND));
}
/**
* @brief DMA MMC receive process complete callback
* @param hdma: DMA handle
* @retval None
*/
static void MMC_DMAReceiveCplt(DMA_HandleTypeDef *hdma)
{
MMC_HandleTypeDef* hmmc = (MMC_HandleTypeDef* )(hdma->Parent);
uint32_t errorstate;
/* Send stop command in multiblock write */
if(hmmc->Context == (MMC_CONTEXT_READ_MULTIPLE_BLOCK | MMC_CONTEXT_DMA))
{
errorstate = SDMMC_CmdStopTransfer(hmmc->Instance);
if(errorstate != HAL_MMC_ERROR_NONE)
{
hmmc->ErrorCode |= errorstate;
#if defined (USE_HAL_MMC_REGISTER_CALLBACKS) && (USE_HAL_MMC_REGISTER_CALLBACKS == 1U)
hmmc->ErrorCallback(hmmc);
#else
HAL_MMC_ErrorCallback(hmmc);
#endif
}
}
/* Disable the DMA transfer for transmit request by setting the DMAEN bit
in the MMC DCTRL register */
hmmc->Instance->DCTRL &= (uint32_t)~((uint32_t)SDIO_DCTRL_DMAEN);
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_DATA_FLAGS);
hmmc->State = HAL_MMC_STATE_READY;
#if defined (USE_HAL_MMC_REGISTER_CALLBACKS) && (USE_HAL_MMC_REGISTER_CALLBACKS == 1U)
hmmc->RxCpltCallback(hmmc);
#else
HAL_MMC_RxCpltCallback(hmmc);
#endif
}
/**
* @brief DMA MMC communication error callback
* @param hdma: DMA handle
* @retval None
*/
static void MMC_DMAError(DMA_HandleTypeDef *hdma)
{
MMC_HandleTypeDef* hmmc = (MMC_HandleTypeDef* )(hdma->Parent);
HAL_MMC_CardStateTypeDef CardState;
uint32_t RxErrorCode, TxErrorCode;
RxErrorCode = hmmc->hdmarx->ErrorCode;
TxErrorCode = hmmc->hdmatx->ErrorCode;
if((RxErrorCode == HAL_DMA_ERROR_TE) || (TxErrorCode == HAL_DMA_ERROR_TE))
{
/* Clear All flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
/* Disable All interrupts */
__HAL_MMC_DISABLE_IT(hmmc, SDIO_IT_DATAEND | SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT|\
SDIO_IT_TXUNDERR| SDIO_IT_RXOVERR);
hmmc->ErrorCode |= HAL_MMC_ERROR_DMA;
CardState = HAL_MMC_GetCardState(hmmc);
if((CardState == HAL_MMC_CARD_RECEIVING) || (CardState == HAL_MMC_CARD_SENDING))
{
hmmc->ErrorCode |= SDMMC_CmdStopTransfer(hmmc->Instance);
}
hmmc->State= HAL_MMC_STATE_READY;
}
#if defined (USE_HAL_MMC_REGISTER_CALLBACKS) && (USE_HAL_MMC_REGISTER_CALLBACKS == 1U)
hmmc->ErrorCallback(hmmc);
#else
HAL_MMC_ErrorCallback(hmmc);
#endif
}
/**
* @brief DMA MMC Tx Abort callback
* @param hdma: DMA handle
* @retval None
*/
static void MMC_DMATxAbort(DMA_HandleTypeDef *hdma)
{
MMC_HandleTypeDef* hmmc = (MMC_HandleTypeDef* )(hdma->Parent);
HAL_MMC_CardStateTypeDef CardState;
if(hmmc->hdmatx != NULL)
{
hmmc->hdmatx = NULL;
}
/* All DMA channels are aborted */
if(hmmc->hdmarx == NULL)
{
CardState = HAL_MMC_GetCardState(hmmc);
hmmc->ErrorCode = HAL_MMC_ERROR_NONE;
hmmc->State = HAL_MMC_STATE_READY;
if((CardState == HAL_MMC_CARD_RECEIVING) || (CardState == HAL_MMC_CARD_SENDING))
{
hmmc->ErrorCode |= SDMMC_CmdStopTransfer(hmmc->Instance);
if(hmmc->ErrorCode != HAL_MMC_ERROR_NONE)
{
#if defined (USE_HAL_MMC_REGISTER_CALLBACKS) && (USE_HAL_MMC_REGISTER_CALLBACKS == 1U)
hmmc->AbortCpltCallback(hmmc);
#else
HAL_MMC_AbortCallback(hmmc);
#endif
}
else
{
#if defined (USE_HAL_MMC_REGISTER_CALLBACKS) && (USE_HAL_MMC_REGISTER_CALLBACKS == 1U)
hmmc->ErrorCallback(hmmc);
#else
HAL_MMC_ErrorCallback(hmmc);
#endif
}
}
}
}
/**
* @brief DMA MMC Rx Abort callback
* @param hdma: DMA handle
* @retval None
*/
static void MMC_DMARxAbort(DMA_HandleTypeDef *hdma)
{
MMC_HandleTypeDef* hmmc = (MMC_HandleTypeDef* )(hdma->Parent);
HAL_MMC_CardStateTypeDef CardState;
if(hmmc->hdmarx != NULL)
{
hmmc->hdmarx = NULL;
}
/* All DMA channels are aborted */
if(hmmc->hdmatx == NULL)
{
CardState = HAL_MMC_GetCardState(hmmc);
hmmc->ErrorCode = HAL_MMC_ERROR_NONE;
hmmc->State = HAL_MMC_STATE_READY;
if((CardState == HAL_MMC_CARD_RECEIVING) || (CardState == HAL_MMC_CARD_SENDING))
{
hmmc->ErrorCode |= SDMMC_CmdStopTransfer(hmmc->Instance);
if(hmmc->ErrorCode != HAL_MMC_ERROR_NONE)
{
#if defined (USE_HAL_MMC_REGISTER_CALLBACKS) && (USE_HAL_MMC_REGISTER_CALLBACKS == 1U)
hmmc->AbortCpltCallback(hmmc);
#else
HAL_MMC_AbortCallback(hmmc);
#endif
}
else
{
#if defined (USE_HAL_MMC_REGISTER_CALLBACKS) && (USE_HAL_MMC_REGISTER_CALLBACKS == 1U)
hmmc->ErrorCallback(hmmc);
#else
HAL_MMC_ErrorCallback(hmmc);
#endif
}
}
}
}
/**
* @brief Initializes the mmc card.
* @param hmmc: Pointer to MMC handle
* @retval MMC Card error state
*/
static uint32_t MMC_InitCard(MMC_HandleTypeDef *hmmc)
{
HAL_MMC_CardCSDTypeDef CSD;
uint32_t errorstate;
uint16_t mmc_rca = 2U;
MMC_InitTypeDef Init;
/* Check the power State */
if(SDIO_GetPowerState(hmmc->Instance) == 0U)
{
/* Power off */
return HAL_MMC_ERROR_REQUEST_NOT_APPLICABLE;
}
/* Send CMD2 ALL_SEND_CID */
errorstate = SDMMC_CmdSendCID(hmmc->Instance);
if(errorstate != HAL_MMC_ERROR_NONE)
{
return errorstate;
}
else
{
/* Get Card identification number data */
hmmc->CID[0U] = SDIO_GetResponse(hmmc->Instance, SDIO_RESP1);
hmmc->CID[1U] = SDIO_GetResponse(hmmc->Instance, SDIO_RESP2);
hmmc->CID[2U] = SDIO_GetResponse(hmmc->Instance, SDIO_RESP3);
hmmc->CID[3U] = SDIO_GetResponse(hmmc->Instance, SDIO_RESP4);
}
/* Send CMD3 SET_REL_ADDR with RCA = 2 (should be greater than 1) */
/* MMC Card publishes its RCA. */
errorstate = SDMMC_CmdSetRelAddMmc(hmmc->Instance, mmc_rca);
if(errorstate != HAL_MMC_ERROR_NONE)
{
return errorstate;
}
/* Get the MMC card RCA */
hmmc->MmcCard.RelCardAdd = mmc_rca;
/* Send CMD9 SEND_CSD with argument as card's RCA */
errorstate = SDMMC_CmdSendCSD(hmmc->Instance, (uint32_t)(hmmc->MmcCard.RelCardAdd << 16U));
if(errorstate != HAL_MMC_ERROR_NONE)
{
return errorstate;
}
else
{
/* Get Card Specific Data */
hmmc->CSD[0U] = SDIO_GetResponse(hmmc->Instance, SDIO_RESP1);
hmmc->CSD[1U] = SDIO_GetResponse(hmmc->Instance, SDIO_RESP2);
hmmc->CSD[2U] = SDIO_GetResponse(hmmc->Instance, SDIO_RESP3);
hmmc->CSD[3U] = SDIO_GetResponse(hmmc->Instance, SDIO_RESP4);
}
/* Get the Card Class */
hmmc->MmcCard.Class = (SDIO_GetResponse(hmmc->Instance, SDIO_RESP2) >> 20U);
/* Select the Card */
errorstate = SDMMC_CmdSelDesel(hmmc->Instance, (uint32_t)(((uint32_t)hmmc->MmcCard.RelCardAdd) << 16U));
if(errorstate != HAL_MMC_ERROR_NONE)
{
return errorstate;
}
/* Get CSD parameters */
if (HAL_MMC_GetCardCSD(hmmc, &CSD) != HAL_OK)
{
return hmmc->ErrorCode;
}
/* While card is not ready for data and trial number for sending CMD13 is not exceeded */
errorstate = SDMMC_CmdSendStatus(hmmc->Instance, (uint32_t)(((uint32_t)hmmc->MmcCard.RelCardAdd) << 16U));
if(errorstate != HAL_MMC_ERROR_NONE)
{
hmmc->ErrorCode |= errorstate;
}
/* Get Extended CSD parameters */
if (HAL_MMC_GetCardExtCSD(hmmc, hmmc->Ext_CSD, SDMMC_DATATIMEOUT) != HAL_OK)
{
return hmmc->ErrorCode;
}
/* While card is not ready for data and trial number for sending CMD13 is not exceeded */
errorstate = SDMMC_CmdSendStatus(hmmc->Instance, (uint32_t)(((uint32_t)hmmc->MmcCard.RelCardAdd) << 16U));
if(errorstate != HAL_MMC_ERROR_NONE)
{
hmmc->ErrorCode |= errorstate;
}
/* Configure the SDIO peripheral */
Init = hmmc->Init;
Init.BusWide = SDIO_BUS_WIDE_1B;
(void)SDIO_Init(hmmc->Instance, Init);
/* All cards are initialized */
return HAL_MMC_ERROR_NONE;
}
/**
* @brief Enquires cards about their operating voltage and configures clock
* controls and stores MMC information that will be needed in future
* in the MMC handle.
* @param hmmc: Pointer to MMC handle
* @retval error state
*/
static uint32_t MMC_PowerON(MMC_HandleTypeDef *hmmc)
{
__IO uint32_t count = 0U;
uint32_t response = 0U, validvoltage = 0U;
uint32_t errorstate;
/* CMD0: GO_IDLE_STATE */
errorstate = SDMMC_CmdGoIdleState(hmmc->Instance);
if(errorstate != HAL_MMC_ERROR_NONE)
{
return errorstate;
}
while(validvoltage == 0U)
{
if(count++ == SDMMC_MAX_VOLT_TRIAL)
{
return HAL_MMC_ERROR_INVALID_VOLTRANGE;
}
/* SEND CMD1 APP_CMD with voltage range as argument */
errorstate = SDMMC_CmdOpCondition(hmmc->Instance, MMC_VOLTAGE_RANGE);
if(errorstate != HAL_MMC_ERROR_NONE)
{
return HAL_MMC_ERROR_UNSUPPORTED_FEATURE;
}
/* Get command response */
response = SDIO_GetResponse(hmmc->Instance, SDIO_RESP1);
/* Get operating voltage*/
validvoltage = (((response >> 31U) == 1U) ? 1U : 0U);
}
/* When power routine is finished and command returns valid voltage */
if (((response & (0xFF000000U)) >> 24U) == 0xC0U)
{
hmmc->MmcCard.CardType = MMC_HIGH_CAPACITY_CARD;
}
else
{
hmmc->MmcCard.CardType = MMC_LOW_CAPACITY_CARD;
}
return HAL_MMC_ERROR_NONE;
}
/**
* @brief Turns the SDIO output signals off.
* @param hmmc: Pointer to MMC handle
* @retval None
*/
static void MMC_PowerOFF(MMC_HandleTypeDef *hmmc)
{
/* Set Power State to OFF */
(void)SDIO_PowerState_OFF(hmmc->Instance);
}
/**
* @brief Returns the current card's status.
* @param hmmc: Pointer to MMC handle
* @param pCardStatus: pointer to the buffer that will contain the MMC card
* status (Card Status register)
* @retval error state
*/
static uint32_t MMC_SendStatus(MMC_HandleTypeDef *hmmc, uint32_t *pCardStatus)
{
uint32_t errorstate;
if(pCardStatus == NULL)
{
return HAL_MMC_ERROR_PARAM;
}
/* Send Status command */
errorstate = SDMMC_CmdSendStatus(hmmc->Instance, (uint32_t)(hmmc->MmcCard.RelCardAdd << 16U));
if(errorstate != HAL_MMC_ERROR_NONE)
{
return errorstate;
}
/* Get MMC card status */
*pCardStatus = SDIO_GetResponse(hmmc->Instance, SDIO_RESP1);
return HAL_MMC_ERROR_NONE;
}
/**
* @brief Reads extended CSD register to get the sectors number of the device
* @param hmmc: Pointer to MMC handle
* @param pFieldData: Pointer to the read buffer
* @param FieldIndex: Index of the field to be read
* @param Timeout: Specify timeout value
* @retval HAL status
*/
static uint32_t MMC_ReadExtCSD(MMC_HandleTypeDef *hmmc, uint32_t *pFieldData, uint16_t FieldIndex, uint32_t Timeout)
{
SDIO_DataInitTypeDef config;
uint32_t errorstate;
uint32_t tickstart = HAL_GetTick();
uint32_t count;
uint32_t i = 0;
uint32_t tmp_data;
hmmc->ErrorCode = HAL_MMC_ERROR_NONE;
/* Initialize data control register */
hmmc->Instance->DCTRL = 0;
/* Configure the MMC DPSM (Data Path State Machine) */
config.DataTimeOut = SDMMC_DATATIMEOUT;
config.DataLength = 512;
config.DataBlockSize = SDIO_DATABLOCK_SIZE_512B;
config.TransferDir = SDIO_TRANSFER_DIR_TO_SDIO;
config.TransferMode = SDIO_TRANSFER_MODE_BLOCK;
config.DPSM = SDIO_DPSM_ENABLE;
(void)SDIO_ConfigData(hmmc->Instance, &config);
/* Set Block Size for Card */
errorstate = SDMMC_CmdSendEXTCSD(hmmc->Instance, 0);
if(errorstate != HAL_MMC_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= errorstate;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
/* Poll on SDMMC flags */
while(!__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DATAEND))
{
if(__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_RXFIFOHF))
{
/* Read data from SDMMC Rx FIFO */
for(count = 0U; count < 8U; count++)
{
tmp_data = SDIO_ReadFIFO(hmmc->Instance);
/* eg : SEC_COUNT : FieldIndex = 212 => i+count = 53 */
/* DEVICE_TYPE : FieldIndex = 196 => i+count = 49 */
if ((i + count) == ((uint32_t)FieldIndex/4U))
{
*pFieldData = tmp_data;
}
}
i += 8U;
}
if(((HAL_GetTick()-tickstart) >= Timeout) || (Timeout == 0U))
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_FLAGS);
hmmc->ErrorCode |= HAL_MMC_ERROR_TIMEOUT;
hmmc->State= HAL_MMC_STATE_READY;
return HAL_TIMEOUT;
}
}
/* While card is not ready for data and trial number for sending CMD13 is not exceeded */
errorstate = SDMMC_CmdSendStatus(hmmc->Instance, (uint32_t)(((uint32_t)hmmc->MmcCard.RelCardAdd) << 16));
if(errorstate != HAL_MMC_ERROR_NONE)
{
hmmc->ErrorCode |= errorstate;
}
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDIO_STATIC_DATA_FLAGS);
hmmc->State = HAL_MMC_STATE_READY;
return HAL_OK;
}
/**
* @brief Wrap up reading in non-blocking mode.
* @param hmmc: pointer to a MMC_HandleTypeDef structure that contains
* the configuration information.
* @retval None
*/
static void MMC_Read_IT(MMC_HandleTypeDef *hmmc)
{
uint32_t count, data, dataremaining;
uint8_t* tmp;
tmp = hmmc->pRxBuffPtr;
dataremaining = hmmc->RxXferSize;
if (dataremaining > 0U)
{
/* Read data from SDIO Rx FIFO */
for(count = 0U; count < 8U; count++)
{
data = SDIO_ReadFIFO(hmmc->Instance);
*tmp = (uint8_t)(data & 0xFFU);
tmp++;
dataremaining--;
*tmp = (uint8_t)((data >> 8U) & 0xFFU);
tmp++;
dataremaining--;
*tmp = (uint8_t)((data >> 16U) & 0xFFU);
tmp++;
dataremaining--;
*tmp = (uint8_t)((data >> 24U) & 0xFFU);
tmp++;
dataremaining--;
}
hmmc->pRxBuffPtr = tmp;
hmmc->RxXferSize = dataremaining;
}
}
/**
* @brief Wrap up writing in non-blocking mode.
* @param hmmc: pointer to a MMC_HandleTypeDef structure that contains
* the configuration information.
* @retval None
*/
static void MMC_Write_IT(MMC_HandleTypeDef *hmmc)
{
uint32_t count, data, dataremaining;
uint8_t* tmp;
tmp = hmmc->pTxBuffPtr;
dataremaining = hmmc->TxXferSize;
if (dataremaining > 0U)
{
/* Write data to SDIO Tx FIFO */
for(count = 0U; count < 8U; count++)
{
data = (uint32_t)(*tmp);
tmp++;
dataremaining--;
data |= ((uint32_t)(*tmp) << 8U);
tmp++;
dataremaining--;
data |= ((uint32_t)(*tmp) << 16U);
tmp++;
dataremaining--;
data |= ((uint32_t)(*tmp) << 24U);
tmp++;
dataremaining--;
(void)SDIO_WriteFIFO(hmmc->Instance, &data);
}
hmmc->pTxBuffPtr = tmp;
hmmc->TxXferSize = dataremaining;
}
}
/**
* @brief Update the power class of the device.
* @param hmmc MMC handle
* @param Wide Wide of MMC bus
* @param Speed Speed of the MMC bus
* @retval MMC Card error state
*/
static uint32_t MMC_PwrClassUpdate(MMC_HandleTypeDef *hmmc, uint32_t Wide)
{
uint32_t count;
uint32_t response = 0U;
uint32_t errorstate = HAL_MMC_ERROR_NONE;
uint32_t power_class, supported_pwr_class;
if((Wide == SDIO_BUS_WIDE_8B) || (Wide == SDIO_BUS_WIDE_4B))
{
power_class = 0U; /* Default value after power-on or software reset */
/* Read the PowerClass field of the Extended CSD register */
if(MMC_ReadExtCSD(hmmc, &power_class, 187, SDMMC_DATATIMEOUT) != HAL_OK) /* Field POWER_CLASS [187] */
{
errorstate = SDMMC_ERROR_GENERAL_UNKNOWN_ERR;
}
else
{
power_class = ((power_class >> 24U) & 0x000000FFU);
}
/* Get the supported PowerClass field of the Extended CSD register */
/* Field PWR_CL_26_xxx [201 or 203] */
supported_pwr_class = ((hmmc->Ext_CSD[(MMC_EXT_CSD_PWR_CL_26_INDEX/4)] >> MMC_EXT_CSD_PWR_CL_26_POS) & 0x000000FFU);
if(errorstate == HAL_MMC_ERROR_NONE)
{
if(Wide == SDIO_BUS_WIDE_8B)
{
/* Bit [7:4] : power class for 8-bits bus configuration - Bit [3:0] : power class for 4-bits bus configuration */
supported_pwr_class = (supported_pwr_class >> 4U);
}
if ((power_class & 0x0FU) != (supported_pwr_class & 0x0FU))
{
/* Need to change current power class */
errorstate = SDMMC_CmdSwitch(hmmc->Instance, (0x03BB0000U | ((supported_pwr_class & 0x0FU) << 8U)));
if(errorstate == HAL_MMC_ERROR_NONE)
{
/* While card is not ready for data and trial number for sending CMD13 is not exceeded */
count = SDMMC_MAX_TRIAL;
do
{
errorstate = SDMMC_CmdSendStatus(hmmc->Instance, (uint32_t)(((uint32_t)hmmc->MmcCard.RelCardAdd) << 16U));
if(errorstate != HAL_MMC_ERROR_NONE)
{
break;
}
/* Get command response */
response = SDIO_GetResponse(hmmc->Instance, SDIO_RESP1);
count--;
}while(((response & 0x100U) == 0U) && (count != 0U));
/* Check the status after the switch command execution */
if ((count != 0U) && (errorstate == HAL_MMC_ERROR_NONE))
{
/* Check the bit SWITCH_ERROR of the device status */
if ((response & 0x80U) != 0U)
{
errorstate = SDMMC_ERROR_UNSUPPORTED_FEATURE;
}
}
else if (count == 0U)
{
errorstate = SDMMC_ERROR_TIMEOUT;
}
else
{
/* Nothing to do */
}
}
}
}
}
return errorstate;
}
/**
* @}
*/
#endif /* SDIO */
#endif /* HAL_MMC_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/

View File

@@ -0,0 +1,92 @@
/**
******************************************************************************
* @file stm32f1xx_hal_msp_template.c
* @author MCD Application Team
* @brief HAL BSP module.
* This file template is located in the HAL folder and should be copied
* to the user folder.
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
/** @defgroup HAL_MSP HAL_MSP
* @brief HAL MSP module.
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/** @defgroup HAL_MSP_Exported_Functions HAL MSP Exported Functions
* @{
*/
/**
* @brief Initializes the Global MSP.
* @retval None
*/
void HAL_MspInit(void)
{
}
/**
* @brief DeInitializes the Global MSP.
* @retval None
*/
void HAL_MspDeInit(void)
{
}
/**
* @brief Initializes the PPP MSP.
* @retval None
*/
void HAL_PPP_MspInit(void)
{
}
/**
* @brief DeInitializes the PPP MSP.
* @retval None
*/
void HAL_PPP_MspDeInit(void)
{
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/

View File

@@ -0,0 +1,2315 @@
/**
******************************************************************************
* @file stm32f1xx_hal_nand.c
* @author MCD Application Team
* @brief NAND HAL module driver.
* This file provides a generic firmware to drive NAND memories mounted
* as external device.
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
==============================================================================
##### How to use this driver #####
==============================================================================
[..]
This driver is a generic layered driver which contains a set of APIs used to
control NAND flash memories. It uses the FSMC layer functions to interface
with NAND devices. This driver is used as follows:
(+) NAND flash memory configuration sequence using the function HAL_NAND_Init()
with control and timing parameters for both common and attribute spaces.
(+) Read NAND flash memory maker and device IDs using the function
HAL_NAND_Read_ID(). The read information is stored in the NAND_ID_TypeDef
structure declared by the function caller.
(+) Access NAND flash memory by read/write operations using the functions
HAL_NAND_Read_Page_8b()/HAL_NAND_Read_SpareArea_8b(),
HAL_NAND_Write_Page_8b()/HAL_NAND_Write_SpareArea_8b(),
HAL_NAND_Read_Page_16b()/HAL_NAND_Read_SpareArea_16b(),
HAL_NAND_Write_Page_16b()/HAL_NAND_Write_SpareArea_16b()
to read/write page(s)/spare area(s). These functions use specific device
information (Block, page size..) predefined by the user in the NAND_DeviceConfigTypeDef
structure. The read/write address information is contained by the Nand_Address_Typedef
structure passed as parameter.
(+) Perform NAND flash Reset chip operation using the function HAL_NAND_Reset().
(+) Perform NAND flash erase block operation using the function HAL_NAND_Erase_Block().
The erase block address information is contained in the Nand_Address_Typedef
structure passed as parameter.
(+) Read the NAND flash status operation using the function HAL_NAND_Read_Status().
(+) You can also control the NAND device by calling the control APIs HAL_NAND_ECC_Enable()/
HAL_NAND_ECC_Disable() to respectively enable/disable the ECC code correction
feature or the function HAL_NAND_GetECC() to get the ECC correction code.
(+) You can monitor the NAND device HAL state by calling the function
HAL_NAND_GetState()
[..]
(@) This driver is a set of generic APIs which handle standard NAND flash operations.
If a NAND flash device contains different operations and/or implementations,
it should be implemented separately.
*** Callback registration ***
=============================================
[..]
The compilation define USE_HAL_NAND_REGISTER_CALLBACKS when set to 1
allows the user to configure dynamically the driver callbacks.
Use Functions HAL_NAND_RegisterCallback() to register a user callback,
it allows to register following callbacks:
(+) MspInitCallback : NAND MspInit.
(+) MspDeInitCallback : NAND MspDeInit.
This function takes as parameters the HAL peripheral handle, the Callback ID
and a pointer to the user callback function.
Use function HAL_NAND_UnRegisterCallback() to reset a callback to the default
weak (overridden) function. It allows to reset following callbacks:
(+) MspInitCallback : NAND MspInit.
(+) MspDeInitCallback : NAND MspDeInit.
This function) takes as parameters the HAL peripheral handle and the Callback ID.
By default, after the HAL_NAND_Init and if the state is HAL_NAND_STATE_RESET
all callbacks are reset to the corresponding legacy weak (overridden) functions.
Exception done for MspInit and MspDeInit callbacks that are respectively
reset to the legacy weak (overridden) functions in the HAL_NAND_Init
and HAL_NAND_DeInit only when these callbacks are null (not registered beforehand).
If not, MspInit or MspDeInit are not null, the HAL_NAND_Init and HAL_NAND_DeInit
keep and use the user MspInit/MspDeInit callbacks (registered beforehand)
Callbacks can be registered/unregistered in READY state only.
Exception done for MspInit/MspDeInit callbacks that can be registered/unregistered
in READY or RESET state, thus registered (user) MspInit/DeInit callbacks can be used
during the Init/DeInit.
In that case first register the MspInit/MspDeInit user callbacks
using HAL_NAND_RegisterCallback before calling HAL_NAND_DeInit
or HAL_NAND_Init function.
When The compilation define USE_HAL_NAND_REGISTER_CALLBACKS is set to 0 or
not defined, the callback registering feature is not available
and weak (overridden) callbacks are used.
@endverbatim
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
#if defined(FSMC_BANK3)
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
#ifdef HAL_NAND_MODULE_ENABLED
/** @defgroup NAND NAND
* @brief NAND HAL module driver
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private Constants ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions ---------------------------------------------------------*/
/** @defgroup NAND_Exported_Functions NAND Exported Functions
* @{
*/
/** @defgroup NAND_Exported_Functions_Group1 Initialization and de-initialization functions
* @brief Initialization and Configuration functions
*
@verbatim
==============================================================================
##### NAND Initialization and de-initialization functions #####
==============================================================================
[..]
This section provides functions allowing to initialize/de-initialize
the NAND memory
@endverbatim
* @{
*/
/**
* @brief Perform NAND memory Initialization sequence
* @param hnand pointer to a NAND_HandleTypeDef structure that contains
* the configuration information for NAND module.
* @param ComSpace_Timing pointer to Common space timing structure
* @param AttSpace_Timing pointer to Attribute space timing structure
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NAND_Init(NAND_HandleTypeDef *hnand, FSMC_NAND_PCC_TimingTypeDef *ComSpace_Timing,
FSMC_NAND_PCC_TimingTypeDef *AttSpace_Timing)
{
/* Check the NAND handle state */
if (hnand == NULL)
{
return HAL_ERROR;
}
if (hnand->State == HAL_NAND_STATE_RESET)
{
/* Allocate lock resource and initialize it */
hnand->Lock = HAL_UNLOCKED;
#if (USE_HAL_NAND_REGISTER_CALLBACKS == 1)
if (hnand->MspInitCallback == NULL)
{
hnand->MspInitCallback = HAL_NAND_MspInit;
}
hnand->ItCallback = HAL_NAND_ITCallback;
/* Init the low level hardware */
hnand->MspInitCallback(hnand);
#else
/* Initialize the low level hardware (MSP) */
HAL_NAND_MspInit(hnand);
#endif /* (USE_HAL_NAND_REGISTER_CALLBACKS) */
}
/* Initialize NAND control Interface */
(void)FSMC_NAND_Init(hnand->Instance, &(hnand->Init));
/* Initialize NAND common space timing Interface */
(void)FSMC_NAND_CommonSpace_Timing_Init(hnand->Instance, ComSpace_Timing, hnand->Init.NandBank);
/* Initialize NAND attribute space timing Interface */
(void)FSMC_NAND_AttributeSpace_Timing_Init(hnand->Instance, AttSpace_Timing, hnand->Init.NandBank);
/* Enable the NAND device */
__FSMC_NAND_ENABLE(hnand->Instance, hnand->Init.NandBank);
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_READY;
return HAL_OK;
}
/**
* @brief Perform NAND memory De-Initialization sequence
* @param hnand pointer to a NAND_HandleTypeDef structure that contains
* the configuration information for NAND module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NAND_DeInit(NAND_HandleTypeDef *hnand)
{
#if (USE_HAL_NAND_REGISTER_CALLBACKS == 1)
if (hnand->MspDeInitCallback == NULL)
{
hnand->MspDeInitCallback = HAL_NAND_MspDeInit;
}
/* DeInit the low level hardware */
hnand->MspDeInitCallback(hnand);
#else
/* Initialize the low level hardware (MSP) */
HAL_NAND_MspDeInit(hnand);
#endif /* (USE_HAL_NAND_REGISTER_CALLBACKS) */
/* Configure the NAND registers with their reset values */
(void)FSMC_NAND_DeInit(hnand->Instance, hnand->Init.NandBank);
/* Reset the NAND controller state */
hnand->State = HAL_NAND_STATE_RESET;
/* Release Lock */
__HAL_UNLOCK(hnand);
return HAL_OK;
}
/**
* @brief NAND MSP Init
* @param hnand pointer to a NAND_HandleTypeDef structure that contains
* the configuration information for NAND module.
* @retval None
*/
__weak void HAL_NAND_MspInit(NAND_HandleTypeDef *hnand)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hnand);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_NAND_MspInit could be implemented in the user file
*/
}
/**
* @brief NAND MSP DeInit
* @param hnand pointer to a NAND_HandleTypeDef structure that contains
* the configuration information for NAND module.
* @retval None
*/
__weak void HAL_NAND_MspDeInit(NAND_HandleTypeDef *hnand)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hnand);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_NAND_MspDeInit could be implemented in the user file
*/
}
/**
* @brief This function handles NAND device interrupt request.
* @param hnand pointer to a NAND_HandleTypeDef structure that contains
* the configuration information for NAND module.
* @retval HAL status
*/
void HAL_NAND_IRQHandler(NAND_HandleTypeDef *hnand)
{
/* Check NAND interrupt Rising edge flag */
if (__FSMC_NAND_GET_FLAG(hnand->Instance, hnand->Init.NandBank, FSMC_FLAG_RISING_EDGE))
{
/* NAND interrupt callback*/
#if (USE_HAL_NAND_REGISTER_CALLBACKS == 1)
hnand->ItCallback(hnand);
#else
HAL_NAND_ITCallback(hnand);
#endif /* (USE_HAL_NAND_REGISTER_CALLBACKS) */
/* Clear NAND interrupt Rising edge pending bit */
__FSMC_NAND_CLEAR_FLAG(hnand->Instance, hnand->Init.NandBank, FSMC_FLAG_RISING_EDGE);
}
/* Check NAND interrupt Level flag */
if (__FSMC_NAND_GET_FLAG(hnand->Instance, hnand->Init.NandBank, FSMC_FLAG_LEVEL))
{
/* NAND interrupt callback*/
#if (USE_HAL_NAND_REGISTER_CALLBACKS == 1)
hnand->ItCallback(hnand);
#else
HAL_NAND_ITCallback(hnand);
#endif /* (USE_HAL_NAND_REGISTER_CALLBACKS) */
/* Clear NAND interrupt Level pending bit */
__FSMC_NAND_CLEAR_FLAG(hnand->Instance, hnand->Init.NandBank, FSMC_FLAG_LEVEL);
}
/* Check NAND interrupt Falling edge flag */
if (__FSMC_NAND_GET_FLAG(hnand->Instance, hnand->Init.NandBank, FSMC_FLAG_FALLING_EDGE))
{
/* NAND interrupt callback*/
#if (USE_HAL_NAND_REGISTER_CALLBACKS == 1)
hnand->ItCallback(hnand);
#else
HAL_NAND_ITCallback(hnand);
#endif /* (USE_HAL_NAND_REGISTER_CALLBACKS) */
/* Clear NAND interrupt Falling edge pending bit */
__FSMC_NAND_CLEAR_FLAG(hnand->Instance, hnand->Init.NandBank, FSMC_FLAG_FALLING_EDGE);
}
/* Check NAND interrupt FIFO empty flag */
if (__FSMC_NAND_GET_FLAG(hnand->Instance, hnand->Init.NandBank, FSMC_FLAG_FEMPT))
{
/* NAND interrupt callback*/
#if (USE_HAL_NAND_REGISTER_CALLBACKS == 1)
hnand->ItCallback(hnand);
#else
HAL_NAND_ITCallback(hnand);
#endif /* (USE_HAL_NAND_REGISTER_CALLBACKS) */
/* Clear NAND interrupt FIFO empty pending bit */
__FSMC_NAND_CLEAR_FLAG(hnand->Instance, hnand->Init.NandBank, FSMC_FLAG_FEMPT);
}
}
/**
* @brief NAND interrupt feature callback
* @param hnand pointer to a NAND_HandleTypeDef structure that contains
* the configuration information for NAND module.
* @retval None
*/
__weak void HAL_NAND_ITCallback(NAND_HandleTypeDef *hnand)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hnand);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_NAND_ITCallback could be implemented in the user file
*/
}
/**
* @}
*/
/** @defgroup NAND_Exported_Functions_Group2 Input and Output functions
* @brief Input Output and memory control functions
*
@verbatim
==============================================================================
##### NAND Input and Output functions #####
==============================================================================
[..]
This section provides functions allowing to use and control the NAND
memory
@endverbatim
* @{
*/
/**
* @brief Read the NAND memory electronic signature
* @param hnand pointer to a NAND_HandleTypeDef structure that contains
* the configuration information for NAND module.
* @param pNAND_ID NAND ID structure
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NAND_Read_ID(NAND_HandleTypeDef *hnand, NAND_IDTypeDef *pNAND_ID)
{
__IO uint32_t data = 0;
__IO uint32_t data1 = 0;
uint32_t deviceaddress;
/* Check the NAND controller state */
if (hnand->State == HAL_NAND_STATE_BUSY)
{
return HAL_BUSY;
}
else if (hnand->State == HAL_NAND_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(hnand);
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_BUSY;
/* Identify the device address */
if (hnand->Init.NandBank == FSMC_NAND_BANK2)
{
deviceaddress = NAND_DEVICE1;
}
else
{
deviceaddress = NAND_DEVICE2;
}
/* Send Read ID command sequence */
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_READID;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00;
__DSB();
/* Read the electronic signature from NAND flash */
if (hnand->Init.MemoryDataWidth == FSMC_NAND_PCC_MEM_BUS_WIDTH_8)
{
data = *(__IO uint32_t *)deviceaddress;
/* Return the data read */
pNAND_ID->Maker_Id = ADDR_1ST_CYCLE(data);
pNAND_ID->Device_Id = ADDR_2ND_CYCLE(data);
pNAND_ID->Third_Id = ADDR_3RD_CYCLE(data);
pNAND_ID->Fourth_Id = ADDR_4TH_CYCLE(data);
}
else
{
data = *(__IO uint32_t *)deviceaddress;
data1 = *((__IO uint32_t *)deviceaddress + 4);
/* Return the data read */
pNAND_ID->Maker_Id = ADDR_1ST_CYCLE(data);
pNAND_ID->Device_Id = ADDR_3RD_CYCLE(data);
pNAND_ID->Third_Id = ADDR_1ST_CYCLE(data1);
pNAND_ID->Fourth_Id = ADDR_3RD_CYCLE(data1);
}
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hnand);
}
else
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief NAND memory reset
* @param hnand pointer to a NAND_HandleTypeDef structure that contains
* the configuration information for NAND module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NAND_Reset(NAND_HandleTypeDef *hnand)
{
uint32_t deviceaddress;
/* Check the NAND controller state */
if (hnand->State == HAL_NAND_STATE_BUSY)
{
return HAL_BUSY;
}
else if (hnand->State == HAL_NAND_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(hnand);
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_BUSY;
/* Identify the device address */
if (hnand->Init.NandBank == FSMC_NAND_BANK2)
{
deviceaddress = NAND_DEVICE1;
}
else
{
deviceaddress = NAND_DEVICE2;
}
/* Send NAND reset command */
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = 0xFF;
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hnand);
}
else
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Configure the device: Enter the physical parameters of the device
* @param hnand pointer to a NAND_HandleTypeDef structure that contains
* the configuration information for NAND module.
* @param pDeviceConfig pointer to NAND_DeviceConfigTypeDef structure
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NAND_ConfigDevice(NAND_HandleTypeDef *hnand, const NAND_DeviceConfigTypeDef *pDeviceConfig)
{
hnand->Config.PageSize = pDeviceConfig->PageSize;
hnand->Config.SpareAreaSize = pDeviceConfig->SpareAreaSize;
hnand->Config.BlockSize = pDeviceConfig->BlockSize;
hnand->Config.BlockNbr = pDeviceConfig->BlockNbr;
hnand->Config.PlaneSize = pDeviceConfig->PlaneSize;
hnand->Config.PlaneNbr = pDeviceConfig->PlaneNbr;
hnand->Config.ExtraCommandEnable = pDeviceConfig->ExtraCommandEnable;
return HAL_OK;
}
/**
* @brief Read Page(s) from NAND memory block (8-bits addressing)
* @param hnand pointer to a NAND_HandleTypeDef structure that contains
* the configuration information for NAND module.
* @param pAddress pointer to NAND address structure
* @param pBuffer pointer to destination read buffer
* @param NumPageToRead number of pages to read from block
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NAND_Read_Page_8b(NAND_HandleTypeDef *hnand, const NAND_AddressTypeDef *pAddress,
uint8_t *pBuffer, uint32_t NumPageToRead)
{
uint32_t index;
uint32_t tickstart;
uint32_t deviceaddress;
uint32_t numpagesread = 0U;
uint32_t nandaddress;
uint32_t nbpages = NumPageToRead;
uint8_t *buff = pBuffer;
/* Check the NAND controller state */
if (hnand->State == HAL_NAND_STATE_BUSY)
{
return HAL_BUSY;
}
else if (hnand->State == HAL_NAND_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(hnand);
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_BUSY;
/* Identify the device address */
if (hnand->Init.NandBank == FSMC_NAND_BANK2)
{
deviceaddress = NAND_DEVICE1;
}
else
{
deviceaddress = NAND_DEVICE2;
}
/* NAND raw address calculation */
nandaddress = ARRAY_ADDRESS(pAddress, hnand);
/* Page(s) read loop */
while ((nbpages != 0U) && (nandaddress < ((hnand->Config.BlockSize) * (hnand->Config.BlockNbr))))
{
/* Send read page command sequence */
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_AREA_A;
__DSB();
/* Cards with page size <= 512 bytes */
if ((hnand->Config.PageSize) <= 512U)
{
if (((hnand->Config.BlockSize) * (hnand->Config.BlockNbr)) <= 65535U)
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
}
else /* ((hnand->Config.BlockSize)*(hnand->Config.BlockNbr)) > 65535 */
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_3RD_CYCLE(nandaddress);
__DSB();
}
}
else /* (hnand->Config.PageSize) > 512 */
{
if (((hnand->Config.BlockSize) * (hnand->Config.BlockNbr)) <= 65535U)
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
}
else /* ((hnand->Config.BlockSize)*(hnand->Config.BlockNbr)) > 65535 */
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_3RD_CYCLE(nandaddress);
__DSB();
}
}
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_AREA_TRUE1;
__DSB();
if (hnand->Config.ExtraCommandEnable == ENABLE)
{
/* Get tick */
tickstart = HAL_GetTick();
/* Read status until NAND is ready */
while (HAL_NAND_Read_Status(hnand) != NAND_READY)
{
if ((HAL_GetTick() - tickstart) > NAND_WRITE_TIMEOUT)
{
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_ERROR;
/* Process unlocked */
__HAL_UNLOCK(hnand);
return HAL_TIMEOUT;
}
}
/* Go back to read mode */
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = ((uint8_t)0x00);
__DSB();
}
/* Get Data into Buffer */
for (index = 0U; index < hnand->Config.PageSize; index++)
{
*buff = *(uint8_t *)deviceaddress;
buff++;
}
/* Increment read pages number */
numpagesread++;
/* Decrement pages to read */
nbpages--;
/* Increment the NAND address */
nandaddress = (uint32_t)(nandaddress + 1U);
}
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hnand);
}
else
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Read Page(s) from NAND memory block (16-bits addressing)
* @param hnand pointer to a NAND_HandleTypeDef structure that contains
* the configuration information for NAND module.
* @param pAddress pointer to NAND address structure
* @param pBuffer pointer to destination read buffer. pBuffer should be 16bits aligned
* @param NumPageToRead number of pages to read from block
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NAND_Read_Page_16b(NAND_HandleTypeDef *hnand, const NAND_AddressTypeDef *pAddress,
uint16_t *pBuffer, uint32_t NumPageToRead)
{
uint32_t index;
uint32_t tickstart;
uint32_t deviceaddress;
uint32_t numpagesread = 0U;
uint32_t nandaddress;
uint32_t nbpages = NumPageToRead;
uint16_t *buff = pBuffer;
/* Check the NAND controller state */
if (hnand->State == HAL_NAND_STATE_BUSY)
{
return HAL_BUSY;
}
else if (hnand->State == HAL_NAND_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(hnand);
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_BUSY;
/* Identify the device address */
if (hnand->Init.NandBank == FSMC_NAND_BANK2)
{
deviceaddress = NAND_DEVICE1;
}
else
{
deviceaddress = NAND_DEVICE2;
}
/* NAND raw address calculation */
nandaddress = ARRAY_ADDRESS(pAddress, hnand);
/* Page(s) read loop */
while ((nbpages != 0U) && (nandaddress < ((hnand->Config.BlockSize) * (hnand->Config.BlockNbr))))
{
/* Send read page command sequence */
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_AREA_A;
__DSB();
/* Cards with page size <= 512 bytes */
if ((hnand->Config.PageSize) <= 512U)
{
if (((hnand->Config.BlockSize) * (hnand->Config.BlockNbr)) <= 65535U)
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
}
else /* ((hnand->Config.BlockSize)*(hnand->Config.BlockNbr)) > 65535 */
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_3RD_CYCLE(nandaddress);
__DSB();
}
}
else /* (hnand->Config.PageSize) > 512 */
{
if (((hnand->Config.BlockSize) * (hnand->Config.BlockNbr)) <= 65535U)
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
}
else /* ((hnand->Config.BlockSize)*(hnand->Config.BlockNbr)) > 65535 */
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_3RD_CYCLE(nandaddress);
__DSB();
}
}
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_AREA_TRUE1;
__DSB();
if (hnand->Config.ExtraCommandEnable == ENABLE)
{
/* Get tick */
tickstart = HAL_GetTick();
/* Read status until NAND is ready */
while (HAL_NAND_Read_Status(hnand) != NAND_READY)
{
if ((HAL_GetTick() - tickstart) > NAND_WRITE_TIMEOUT)
{
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_ERROR;
/* Process unlocked */
__HAL_UNLOCK(hnand);
return HAL_TIMEOUT;
}
}
/* Go back to read mode */
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = ((uint8_t)0x00);
__DSB();
}
/* Calculate PageSize */
if (hnand->Init.MemoryDataWidth == FSMC_NAND_PCC_MEM_BUS_WIDTH_8)
{
hnand->Config.PageSize = hnand->Config.PageSize / 2U;
}
else
{
/* Do nothing */
/* Keep the same PageSize for FMC_NAND_MEM_BUS_WIDTH_16*/
}
/* Get Data into Buffer */
for (index = 0U; index < hnand->Config.PageSize; index++)
{
*buff = *(uint16_t *)deviceaddress;
buff++;
}
/* Increment read pages number */
numpagesread++;
/* Decrement pages to read */
nbpages--;
/* Increment the NAND address */
nandaddress = (uint32_t)(nandaddress + 1U);
}
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hnand);
}
else
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Write Page(s) to NAND memory block (8-bits addressing)
* @param hnand pointer to a NAND_HandleTypeDef structure that contains
* the configuration information for NAND module.
* @param pAddress pointer to NAND address structure
* @param pBuffer pointer to source buffer to write
* @param NumPageToWrite number of pages to write to block
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NAND_Write_Page_8b(NAND_HandleTypeDef *hnand, const NAND_AddressTypeDef *pAddress,
const uint8_t *pBuffer, uint32_t NumPageToWrite)
{
uint32_t index;
uint32_t tickstart;
uint32_t deviceaddress;
uint32_t numpageswritten = 0U;
uint32_t nandaddress;
uint32_t nbpages = NumPageToWrite;
const uint8_t *buff = pBuffer;
/* Check the NAND controller state */
if (hnand->State == HAL_NAND_STATE_BUSY)
{
return HAL_BUSY;
}
else if (hnand->State == HAL_NAND_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(hnand);
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_BUSY;
/* Identify the device address */
if (hnand->Init.NandBank == FSMC_NAND_BANK2)
{
deviceaddress = NAND_DEVICE1;
}
else
{
deviceaddress = NAND_DEVICE2;
}
/* NAND raw address calculation */
nandaddress = ARRAY_ADDRESS(pAddress, hnand);
/* Page(s) write loop */
while ((nbpages != 0U) && (nandaddress < ((hnand->Config.BlockSize) * (hnand->Config.BlockNbr))))
{
/* Send write page command sequence */
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_AREA_A;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_WRITE0;
__DSB();
/* Cards with page size <= 512 bytes */
if ((hnand->Config.PageSize) <= 512U)
{
if (((hnand->Config.BlockSize) * (hnand->Config.BlockNbr)) <= 65535U)
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
}
else /* ((hnand->Config.BlockSize)*(hnand->Config.BlockNbr)) > 65535 */
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_3RD_CYCLE(nandaddress);
__DSB();
}
}
else /* (hnand->Config.PageSize) > 512 */
{
if (((hnand->Config.BlockSize) * (hnand->Config.BlockNbr)) <= 65535U)
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
}
else /* ((hnand->Config.BlockSize)*(hnand->Config.BlockNbr)) > 65535 */
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_3RD_CYCLE(nandaddress);
__DSB();
}
}
/* Write data to memory */
for (index = 0U; index < hnand->Config.PageSize; index++)
{
*(__IO uint8_t *)deviceaddress = *buff;
buff++;
__DSB();
}
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_WRITE_TRUE1;
__DSB();
/* Get tick */
tickstart = HAL_GetTick();
/* Read status until NAND is ready */
while (HAL_NAND_Read_Status(hnand) != NAND_READY)
{
if ((HAL_GetTick() - tickstart) > NAND_WRITE_TIMEOUT)
{
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_ERROR;
/* Process unlocked */
__HAL_UNLOCK(hnand);
return HAL_TIMEOUT;
}
}
/* Increment written pages number */
numpageswritten++;
/* Decrement pages to write */
nbpages--;
/* Increment the NAND address */
nandaddress = (uint32_t)(nandaddress + 1U);
}
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hnand);
}
else
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Write Page(s) to NAND memory block (16-bits addressing)
* @param hnand pointer to a NAND_HandleTypeDef structure that contains
* the configuration information for NAND module.
* @param pAddress pointer to NAND address structure
* @param pBuffer pointer to source buffer to write. pBuffer should be 16bits aligned
* @param NumPageToWrite number of pages to write to block
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NAND_Write_Page_16b(NAND_HandleTypeDef *hnand, const NAND_AddressTypeDef *pAddress,
const uint16_t *pBuffer, uint32_t NumPageToWrite)
{
uint32_t index;
uint32_t tickstart;
uint32_t deviceaddress;
uint32_t numpageswritten = 0U;
uint32_t nandaddress;
uint32_t nbpages = NumPageToWrite;
const uint16_t *buff = pBuffer;
/* Check the NAND controller state */
if (hnand->State == HAL_NAND_STATE_BUSY)
{
return HAL_BUSY;
}
else if (hnand->State == HAL_NAND_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(hnand);
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_BUSY;
/* Identify the device address */
if (hnand->Init.NandBank == FSMC_NAND_BANK2)
{
deviceaddress = NAND_DEVICE1;
}
else
{
deviceaddress = NAND_DEVICE2;
}
/* NAND raw address calculation */
nandaddress = ARRAY_ADDRESS(pAddress, hnand);
/* Page(s) write loop */
while ((nbpages != 0U) && (nandaddress < ((hnand->Config.BlockSize) * (hnand->Config.BlockNbr))))
{
/* Send write page command sequence */
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_AREA_A;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_WRITE0;
__DSB();
/* Cards with page size <= 512 bytes */
if ((hnand->Config.PageSize) <= 512U)
{
if (((hnand->Config.BlockSize) * (hnand->Config.BlockNbr)) <= 65535U)
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
}
else /* ((hnand->Config.BlockSize)*(hnand->Config.BlockNbr)) > 65535 */
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_3RD_CYCLE(nandaddress);
__DSB();
}
}
else /* (hnand->Config.PageSize) > 512 */
{
if (((hnand->Config.BlockSize) * (hnand->Config.BlockNbr)) <= 65535U)
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
}
else /* ((hnand->Config.BlockSize)*(hnand->Config.BlockNbr)) > 65535 */
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_3RD_CYCLE(nandaddress);
__DSB();
}
}
/* Calculate PageSize */
if (hnand->Init.MemoryDataWidth == FSMC_NAND_PCC_MEM_BUS_WIDTH_8)
{
hnand->Config.PageSize = hnand->Config.PageSize / 2U;
}
else
{
/* Do nothing */
/* Keep the same PageSize for FMC_NAND_MEM_BUS_WIDTH_16*/
}
/* Write data to memory */
for (index = 0U; index < hnand->Config.PageSize; index++)
{
*(__IO uint16_t *)deviceaddress = *buff;
buff++;
__DSB();
}
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_WRITE_TRUE1;
__DSB();
/* Get tick */
tickstart = HAL_GetTick();
/* Read status until NAND is ready */
while (HAL_NAND_Read_Status(hnand) != NAND_READY)
{
if ((HAL_GetTick() - tickstart) > NAND_WRITE_TIMEOUT)
{
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_ERROR;
/* Process unlocked */
__HAL_UNLOCK(hnand);
return HAL_TIMEOUT;
}
}
/* Increment written pages number */
numpageswritten++;
/* Decrement pages to write */
nbpages--;
/* Increment the NAND address */
nandaddress = (uint32_t)(nandaddress + 1U);
}
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hnand);
}
else
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Read Spare area(s) from NAND memory (8-bits addressing)
* @param hnand pointer to a NAND_HandleTypeDef structure that contains
* the configuration information for NAND module.
* @param pAddress pointer to NAND address structure
* @param pBuffer pointer to source buffer to write
* @param NumSpareAreaToRead Number of spare area to read
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NAND_Read_SpareArea_8b(NAND_HandleTypeDef *hnand, const NAND_AddressTypeDef *pAddress,
uint8_t *pBuffer, uint32_t NumSpareAreaToRead)
{
uint32_t index;
uint32_t tickstart;
uint32_t deviceaddress;
uint32_t numsparearearead = 0U;
uint32_t nandaddress;
uint32_t columnaddress;
uint32_t nbspare = NumSpareAreaToRead;
uint8_t *buff = pBuffer;
/* Check the NAND controller state */
if (hnand->State == HAL_NAND_STATE_BUSY)
{
return HAL_BUSY;
}
else if (hnand->State == HAL_NAND_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(hnand);
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_BUSY;
/* Identify the device address */
if (hnand->Init.NandBank == FSMC_NAND_BANK2)
{
deviceaddress = NAND_DEVICE1;
}
else
{
deviceaddress = NAND_DEVICE2;
}
/* NAND raw address calculation */
nandaddress = ARRAY_ADDRESS(pAddress, hnand);
/* Column in page address */
columnaddress = COLUMN_ADDRESS(hnand);
/* Spare area(s) read loop */
while ((nbspare != 0U) && (nandaddress < ((hnand->Config.BlockSize) * (hnand->Config.BlockNbr))))
{
/* Cards with page size <= 512 bytes */
if ((hnand->Config.PageSize) <= 512U)
{
/* Send read spare area command sequence */
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_AREA_C;
__DSB();
if (((hnand->Config.BlockSize) * (hnand->Config.BlockNbr)) <= 65535U)
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
}
else /* ((hnand->Config.BlockSize)*(hnand->Config.BlockNbr)) > 65535 */
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_3RD_CYCLE(nandaddress);
__DSB();
}
}
else /* (hnand->Config.PageSize) > 512 */
{
/* Send read spare area command sequence */
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_AREA_A;
__DSB();
if (((hnand->Config.BlockSize) * (hnand->Config.BlockNbr)) <= 65535U)
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = COLUMN_1ST_CYCLE(columnaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = COLUMN_2ND_CYCLE(columnaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
}
else /* ((hnand->Config.BlockSize)*(hnand->Config.BlockNbr)) > 65535 */
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = COLUMN_1ST_CYCLE(columnaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = COLUMN_2ND_CYCLE(columnaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_3RD_CYCLE(nandaddress);
__DSB();
}
}
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_AREA_TRUE1;
__DSB();
if (hnand->Config.ExtraCommandEnable == ENABLE)
{
/* Get tick */
tickstart = HAL_GetTick();
/* Read status until NAND is ready */
while (HAL_NAND_Read_Status(hnand) != NAND_READY)
{
if ((HAL_GetTick() - tickstart) > NAND_WRITE_TIMEOUT)
{
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_ERROR;
/* Process unlocked */
__HAL_UNLOCK(hnand);
return HAL_TIMEOUT;
}
}
/* Go back to read mode */
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = ((uint8_t)0x00);
__DSB();
}
/* Get Data into Buffer */
for (index = 0U; index < hnand->Config.SpareAreaSize; index++)
{
*buff = *(uint8_t *)deviceaddress;
buff++;
}
/* Increment read spare areas number */
numsparearearead++;
/* Decrement spare areas to read */
nbspare--;
/* Increment the NAND address */
nandaddress = (uint32_t)(nandaddress + 1U);
}
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hnand);
}
else
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Read Spare area(s) from NAND memory (16-bits addressing)
* @param hnand pointer to a NAND_HandleTypeDef structure that contains
* the configuration information for NAND module.
* @param pAddress pointer to NAND address structure
* @param pBuffer pointer to source buffer to write. pBuffer should be 16bits aligned.
* @param NumSpareAreaToRead Number of spare area to read
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NAND_Read_SpareArea_16b(NAND_HandleTypeDef *hnand, const NAND_AddressTypeDef *pAddress,
uint16_t *pBuffer, uint32_t NumSpareAreaToRead)
{
uint32_t index;
uint32_t tickstart;
uint32_t deviceaddress;
uint32_t numsparearearead = 0U;
uint32_t nandaddress;
uint32_t columnaddress;
uint32_t nbspare = NumSpareAreaToRead;
uint16_t *buff = pBuffer;
/* Check the NAND controller state */
if (hnand->State == HAL_NAND_STATE_BUSY)
{
return HAL_BUSY;
}
else if (hnand->State == HAL_NAND_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(hnand);
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_BUSY;
/* Identify the device address */
if (hnand->Init.NandBank == FSMC_NAND_BANK2)
{
deviceaddress = NAND_DEVICE1;
}
else
{
deviceaddress = NAND_DEVICE2;
}
/* NAND raw address calculation */
nandaddress = ARRAY_ADDRESS(pAddress, hnand);
/* Column in page address */
columnaddress = (uint32_t)(COLUMN_ADDRESS(hnand));
/* Spare area(s) read loop */
while ((nbspare != 0U) && (nandaddress < ((hnand->Config.BlockSize) * (hnand->Config.BlockNbr))))
{
/* Cards with page size <= 512 bytes */
if ((hnand->Config.PageSize) <= 512U)
{
/* Send read spare area command sequence */
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_AREA_C;
__DSB();
if (((hnand->Config.BlockSize) * (hnand->Config.BlockNbr)) <= 65535U)
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
}
else /* ((hnand->Config.BlockSize)*(hnand->Config.BlockNbr)) > 65535 */
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_3RD_CYCLE(nandaddress);
__DSB();
}
}
else /* (hnand->Config.PageSize) > 512 */
{
/* Send read spare area command sequence */
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_AREA_A;
__DSB();
if (((hnand->Config.BlockSize) * (hnand->Config.BlockNbr)) <= 65535U)
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = COLUMN_1ST_CYCLE(columnaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = COLUMN_2ND_CYCLE(columnaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
}
else /* ((hnand->Config.BlockSize)*(hnand->Config.BlockNbr)) > 65535 */
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = COLUMN_1ST_CYCLE(columnaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = COLUMN_2ND_CYCLE(columnaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_3RD_CYCLE(nandaddress);
__DSB();
}
}
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_AREA_TRUE1;
__DSB();
if (hnand->Config.ExtraCommandEnable == ENABLE)
{
/* Get tick */
tickstart = HAL_GetTick();
/* Read status until NAND is ready */
while (HAL_NAND_Read_Status(hnand) != NAND_READY)
{
if ((HAL_GetTick() - tickstart) > NAND_WRITE_TIMEOUT)
{
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_ERROR;
/* Process unlocked */
__HAL_UNLOCK(hnand);
return HAL_TIMEOUT;
}
}
/* Go back to read mode */
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = ((uint8_t)0x00);
__DSB();
}
/* Get Data into Buffer */
for (index = 0U; index < hnand->Config.SpareAreaSize; index++)
{
*buff = *(uint16_t *)deviceaddress;
buff++;
}
/* Increment read spare areas number */
numsparearearead++;
/* Decrement spare areas to read */
nbspare--;
/* Increment the NAND address */
nandaddress = (uint32_t)(nandaddress + 1U);
}
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hnand);
}
else
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Write Spare area(s) to NAND memory (8-bits addressing)
* @param hnand pointer to a NAND_HandleTypeDef structure that contains
* the configuration information for NAND module.
* @param pAddress pointer to NAND address structure
* @param pBuffer pointer to source buffer to write
* @param NumSpareAreaTowrite number of spare areas to write to block
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NAND_Write_SpareArea_8b(NAND_HandleTypeDef *hnand, const NAND_AddressTypeDef *pAddress,
const uint8_t *pBuffer, uint32_t NumSpareAreaTowrite)
{
uint32_t index;
uint32_t tickstart;
uint32_t deviceaddress;
uint32_t numspareareawritten = 0U;
uint32_t nandaddress;
uint32_t columnaddress;
uint32_t nbspare = NumSpareAreaTowrite;
const uint8_t *buff = pBuffer;
/* Check the NAND controller state */
if (hnand->State == HAL_NAND_STATE_BUSY)
{
return HAL_BUSY;
}
else if (hnand->State == HAL_NAND_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(hnand);
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_BUSY;
/* Identify the device address */
if (hnand->Init.NandBank == FSMC_NAND_BANK2)
{
deviceaddress = NAND_DEVICE1;
}
else
{
deviceaddress = NAND_DEVICE2;
}
/* Page address calculation */
nandaddress = ARRAY_ADDRESS(pAddress, hnand);
/* Column in page address */
columnaddress = COLUMN_ADDRESS(hnand);
/* Spare area(s) write loop */
while ((nbspare != 0U) && (nandaddress < ((hnand->Config.BlockSize) * (hnand->Config.BlockNbr))))
{
/* Cards with page size <= 512 bytes */
if ((hnand->Config.PageSize) <= 512U)
{
/* Send write Spare area command sequence */
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_AREA_C;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_WRITE0;
__DSB();
if (((hnand->Config.BlockSize) * (hnand->Config.BlockNbr)) <= 65535U)
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
}
else /* ((hnand->Config.BlockSize)*(hnand->Config.BlockNbr)) > 65535 */
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_3RD_CYCLE(nandaddress);
__DSB();
}
}
else /* (hnand->Config.PageSize) > 512 */
{
/* Send write Spare area command sequence */
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_AREA_A;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_WRITE0;
__DSB();
if (((hnand->Config.BlockSize) * (hnand->Config.BlockNbr)) <= 65535U)
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = COLUMN_1ST_CYCLE(columnaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = COLUMN_2ND_CYCLE(columnaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
}
else /* ((hnand->Config.BlockSize)*(hnand->Config.BlockNbr)) > 65535 */
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = COLUMN_1ST_CYCLE(columnaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = COLUMN_2ND_CYCLE(columnaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_3RD_CYCLE(nandaddress);
__DSB();
}
}
/* Write data to memory */
for (index = 0U; index < hnand->Config.SpareAreaSize; index++)
{
*(__IO uint8_t *)deviceaddress = *buff;
buff++;
__DSB();
}
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_WRITE_TRUE1;
__DSB();
/* Get tick */
tickstart = HAL_GetTick();
/* Read status until NAND is ready */
while (HAL_NAND_Read_Status(hnand) != NAND_READY)
{
if ((HAL_GetTick() - tickstart) > NAND_WRITE_TIMEOUT)
{
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_ERROR;
/* Process unlocked */
__HAL_UNLOCK(hnand);
return HAL_TIMEOUT;
}
}
/* Increment written spare areas number */
numspareareawritten++;
/* Decrement spare areas to write */
nbspare--;
/* Increment the NAND address */
nandaddress = (uint32_t)(nandaddress + 1U);
}
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hnand);
}
else
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Write Spare area(s) to NAND memory (16-bits addressing)
* @param hnand pointer to a NAND_HandleTypeDef structure that contains
* the configuration information for NAND module.
* @param pAddress pointer to NAND address structure
* @param pBuffer pointer to source buffer to write. pBuffer should be 16bits aligned.
* @param NumSpareAreaTowrite number of spare areas to write to block
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NAND_Write_SpareArea_16b(NAND_HandleTypeDef *hnand, const NAND_AddressTypeDef *pAddress,
const uint16_t *pBuffer, uint32_t NumSpareAreaTowrite)
{
uint32_t index;
uint32_t tickstart;
uint32_t deviceaddress;
uint32_t numspareareawritten = 0U;
uint32_t nandaddress;
uint32_t columnaddress;
uint32_t nbspare = NumSpareAreaTowrite;
const uint16_t *buff = pBuffer;
/* Check the NAND controller state */
if (hnand->State == HAL_NAND_STATE_BUSY)
{
return HAL_BUSY;
}
else if (hnand->State == HAL_NAND_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(hnand);
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_BUSY;
/* Identify the device address */
if (hnand->Init.NandBank == FSMC_NAND_BANK2)
{
deviceaddress = NAND_DEVICE1;
}
else
{
deviceaddress = NAND_DEVICE2;
}
/* NAND raw address calculation */
nandaddress = ARRAY_ADDRESS(pAddress, hnand);
/* Column in page address */
columnaddress = (uint32_t)(COLUMN_ADDRESS(hnand));
/* Spare area(s) write loop */
while ((nbspare != 0U) && (nandaddress < ((hnand->Config.BlockSize) * (hnand->Config.BlockNbr))))
{
/* Cards with page size <= 512 bytes */
if ((hnand->Config.PageSize) <= 512U)
{
/* Send write Spare area command sequence */
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_AREA_C;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_WRITE0;
__DSB();
if (((hnand->Config.BlockSize) * (hnand->Config.BlockNbr)) <= 65535U)
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
}
else /* ((hnand->Config.BlockSize)*(hnand->Config.BlockNbr)) > 65535 */
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_3RD_CYCLE(nandaddress);
__DSB();
}
}
else /* (hnand->Config.PageSize) > 512 */
{
/* Send write Spare area command sequence */
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_AREA_A;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_WRITE0;
__DSB();
if (((hnand->Config.BlockSize) * (hnand->Config.BlockNbr)) <= 65535U)
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = COLUMN_1ST_CYCLE(columnaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = COLUMN_2ND_CYCLE(columnaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
}
else /* ((hnand->Config.BlockSize)*(hnand->Config.BlockNbr)) > 65535 */
{
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = COLUMN_1ST_CYCLE(columnaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = COLUMN_2ND_CYCLE(columnaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_3RD_CYCLE(nandaddress);
__DSB();
}
}
/* Write data to memory */
for (index = 0U; index < hnand->Config.SpareAreaSize; index++)
{
*(__IO uint16_t *)deviceaddress = *buff;
buff++;
__DSB();
}
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_WRITE_TRUE1;
__DSB();
/* Get tick */
tickstart = HAL_GetTick();
/* Read status until NAND is ready */
while (HAL_NAND_Read_Status(hnand) != NAND_READY)
{
if ((HAL_GetTick() - tickstart) > NAND_WRITE_TIMEOUT)
{
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_ERROR;
/* Process unlocked */
__HAL_UNLOCK(hnand);
return HAL_TIMEOUT;
}
}
/* Increment written spare areas number */
numspareareawritten++;
/* Decrement spare areas to write */
nbspare--;
/* Increment the NAND address */
nandaddress = (uint32_t)(nandaddress + 1U);
}
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hnand);
}
else
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief NAND memory Block erase
* @param hnand pointer to a NAND_HandleTypeDef structure that contains
* the configuration information for NAND module.
* @param pAddress pointer to NAND address structure
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NAND_Erase_Block(NAND_HandleTypeDef *hnand, const NAND_AddressTypeDef *pAddress)
{
uint32_t deviceaddress;
/* Check the NAND controller state */
if (hnand->State == HAL_NAND_STATE_BUSY)
{
return HAL_BUSY;
}
else if (hnand->State == HAL_NAND_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(hnand);
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_BUSY;
/* Identify the device address */
if (hnand->Init.NandBank == FSMC_NAND_BANK2)
{
deviceaddress = NAND_DEVICE1;
}
else
{
deviceaddress = NAND_DEVICE2;
}
/* Send Erase block command sequence */
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_ERASE0;
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(ARRAY_ADDRESS(pAddress, hnand));
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(ARRAY_ADDRESS(pAddress, hnand));
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_3RD_CYCLE(ARRAY_ADDRESS(pAddress, hnand));
__DSB();
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_ERASE1;
__DSB();
/* Update the NAND controller state */
hnand->State = HAL_NAND_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hnand);
}
else
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Increment the NAND memory address
* @param hnand pointer to a NAND_HandleTypeDef structure that contains
* the configuration information for NAND module.
* @param pAddress pointer to NAND address structure
* @retval The new status of the increment address operation. It can be:
* - NAND_VALID_ADDRESS: When the new address is valid address
* - NAND_INVALID_ADDRESS: When the new address is invalid address
*/
uint32_t HAL_NAND_Address_Inc(const NAND_HandleTypeDef *hnand, NAND_AddressTypeDef *pAddress)
{
uint32_t status = NAND_VALID_ADDRESS;
/* Increment page address */
pAddress->Page++;
/* Check NAND address is valid */
if (pAddress->Page == hnand->Config.BlockSize)
{
pAddress->Page = 0;
pAddress->Block++;
if (pAddress->Block == hnand->Config.PlaneSize)
{
pAddress->Block = 0;
pAddress->Plane++;
if (pAddress->Plane == (hnand->Config.PlaneNbr))
{
status = NAND_INVALID_ADDRESS;
}
}
}
return (status);
}
#if (USE_HAL_NAND_REGISTER_CALLBACKS == 1)
/**
* @brief Register a User NAND Callback
* To be used to override the weak predefined callback
* @param hnand : NAND handle
* @param CallbackId : ID of the callback to be registered
* This parameter can be one of the following values:
* @arg @ref HAL_NAND_MSP_INIT_CB_ID NAND MspInit callback ID
* @arg @ref HAL_NAND_MSP_DEINIT_CB_ID NAND MspDeInit callback ID
* @arg @ref HAL_NAND_IT_CB_ID NAND IT callback ID
* @param pCallback : pointer to the Callback function
* @retval status
*/
HAL_StatusTypeDef HAL_NAND_RegisterCallback(NAND_HandleTypeDef *hnand, HAL_NAND_CallbackIDTypeDef CallbackId,
pNAND_CallbackTypeDef pCallback)
{
HAL_StatusTypeDef status = HAL_OK;
if (pCallback == NULL)
{
return HAL_ERROR;
}
if (hnand->State == HAL_NAND_STATE_READY)
{
switch (CallbackId)
{
case HAL_NAND_MSP_INIT_CB_ID :
hnand->MspInitCallback = pCallback;
break;
case HAL_NAND_MSP_DEINIT_CB_ID :
hnand->MspDeInitCallback = pCallback;
break;
case HAL_NAND_IT_CB_ID :
hnand->ItCallback = pCallback;
break;
default :
/* update return status */
status = HAL_ERROR;
break;
}
}
else if (hnand->State == HAL_NAND_STATE_RESET)
{
switch (CallbackId)
{
case HAL_NAND_MSP_INIT_CB_ID :
hnand->MspInitCallback = pCallback;
break;
case HAL_NAND_MSP_DEINIT_CB_ID :
hnand->MspDeInitCallback = pCallback;
break;
default :
/* update return status */
status = HAL_ERROR;
break;
}
}
else
{
/* update return status */
status = HAL_ERROR;
}
return status;
}
/**
* @brief Unregister a User NAND Callback
* NAND Callback is redirected to the weak predefined callback
* @param hnand : NAND handle
* @param CallbackId : ID of the callback to be unregistered
* This parameter can be one of the following values:
* @arg @ref HAL_NAND_MSP_INIT_CB_ID NAND MspInit callback ID
* @arg @ref HAL_NAND_MSP_DEINIT_CB_ID NAND MspDeInit callback ID
* @arg @ref HAL_NAND_IT_CB_ID NAND IT callback ID
* @retval status
*/
HAL_StatusTypeDef HAL_NAND_UnRegisterCallback(NAND_HandleTypeDef *hnand, HAL_NAND_CallbackIDTypeDef CallbackId)
{
HAL_StatusTypeDef status = HAL_OK;
if (hnand->State == HAL_NAND_STATE_READY)
{
switch (CallbackId)
{
case HAL_NAND_MSP_INIT_CB_ID :
hnand->MspInitCallback = HAL_NAND_MspInit;
break;
case HAL_NAND_MSP_DEINIT_CB_ID :
hnand->MspDeInitCallback = HAL_NAND_MspDeInit;
break;
case HAL_NAND_IT_CB_ID :
hnand->ItCallback = HAL_NAND_ITCallback;
break;
default :
/* update return status */
status = HAL_ERROR;
break;
}
}
else if (hnand->State == HAL_NAND_STATE_RESET)
{
switch (CallbackId)
{
case HAL_NAND_MSP_INIT_CB_ID :
hnand->MspInitCallback = HAL_NAND_MspInit;
break;
case HAL_NAND_MSP_DEINIT_CB_ID :
hnand->MspDeInitCallback = HAL_NAND_MspDeInit;
break;
default :
/* update return status */
status = HAL_ERROR;
break;
}
}
else
{
/* update return status */
status = HAL_ERROR;
}
return status;
}
#endif /* USE_HAL_NAND_REGISTER_CALLBACKS */
/**
* @}
*/
/** @defgroup NAND_Exported_Functions_Group3 Peripheral Control functions
* @brief management functions
*
@verbatim
==============================================================================
##### NAND Control functions #####
==============================================================================
[..]
This subsection provides a set of functions allowing to control dynamically
the NAND interface.
@endverbatim
* @{
*/
/**
* @brief Enables dynamically NAND ECC feature.
* @param hnand pointer to a NAND_HandleTypeDef structure that contains
* the configuration information for NAND module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NAND_ECC_Enable(NAND_HandleTypeDef *hnand)
{
/* Check the NAND controller state */
if (hnand->State == HAL_NAND_STATE_BUSY)
{
return HAL_BUSY;
}
else if (hnand->State == HAL_NAND_STATE_READY)
{
/* Update the NAND state */
hnand->State = HAL_NAND_STATE_BUSY;
/* Enable ECC feature */
(void)FSMC_NAND_ECC_Enable(hnand->Instance, hnand->Init.NandBank);
/* Update the NAND state */
hnand->State = HAL_NAND_STATE_READY;
}
else
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Disables dynamically FSMC_NAND ECC feature.
* @param hnand pointer to a NAND_HandleTypeDef structure that contains
* the configuration information for NAND module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NAND_ECC_Disable(NAND_HandleTypeDef *hnand)
{
/* Check the NAND controller state */
if (hnand->State == HAL_NAND_STATE_BUSY)
{
return HAL_BUSY;
}
else if (hnand->State == HAL_NAND_STATE_READY)
{
/* Update the NAND state */
hnand->State = HAL_NAND_STATE_BUSY;
/* Disable ECC feature */
(void)FSMC_NAND_ECC_Disable(hnand->Instance, hnand->Init.NandBank);
/* Update the NAND state */
hnand->State = HAL_NAND_STATE_READY;
}
else
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Disables dynamically NAND ECC feature.
* @param hnand pointer to a NAND_HandleTypeDef structure that contains
* the configuration information for NAND module.
* @param ECCval pointer to ECC value
* @param Timeout maximum timeout to wait
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NAND_GetECC(NAND_HandleTypeDef *hnand, uint32_t *ECCval, uint32_t Timeout)
{
HAL_StatusTypeDef status;
/* Check the NAND controller state */
if (hnand->State == HAL_NAND_STATE_BUSY)
{
return HAL_BUSY;
}
else if (hnand->State == HAL_NAND_STATE_READY)
{
/* Update the NAND state */
hnand->State = HAL_NAND_STATE_BUSY;
/* Get NAND ECC value */
status = FSMC_NAND_GetECC(hnand->Instance, ECCval, hnand->Init.NandBank, Timeout);
/* Update the NAND state */
hnand->State = HAL_NAND_STATE_READY;
}
else
{
return HAL_ERROR;
}
return status;
}
/**
* @}
*/
/** @defgroup NAND_Exported_Functions_Group4 Peripheral State functions
* @brief Peripheral State functions
*
@verbatim
==============================================================================
##### NAND State functions #####
==============================================================================
[..]
This subsection permits to get in run-time the status of the NAND controller
and the data flow.
@endverbatim
* @{
*/
/**
* @brief return the NAND state
* @param hnand pointer to a NAND_HandleTypeDef structure that contains
* the configuration information for NAND module.
* @retval HAL state
*/
HAL_NAND_StateTypeDef HAL_NAND_GetState(const NAND_HandleTypeDef *hnand)
{
return hnand->State;
}
/**
* @brief NAND memory read status
* @param hnand pointer to a NAND_HandleTypeDef structure that contains
* the configuration information for NAND module.
* @retval NAND status
*/
uint32_t HAL_NAND_Read_Status(const NAND_HandleTypeDef *hnand)
{
uint32_t data;
uint32_t deviceaddress;
UNUSED(hnand);
/* Identify the device address */
if (hnand->Init.NandBank == FSMC_NAND_BANK2)
{
deviceaddress = NAND_DEVICE1;
}
else
{
deviceaddress = NAND_DEVICE2;
}
/* Send Read status operation command */
*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_STATUS;
/* Read status register data */
data = *(__IO uint8_t *)deviceaddress;
/* Return the status */
if ((data & NAND_ERROR) == NAND_ERROR)
{
return NAND_ERROR;
}
else if ((data & NAND_READY) == NAND_READY)
{
return NAND_READY;
}
else
{
return NAND_BUSY;
}
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#endif /* HAL_NAND_MODULE_ENABLED */
/**
* @}
*/
#endif /* FSMC_BANK3 */

View File

@@ -0,0 +1,1641 @@
/**
******************************************************************************
* @file stm32f1xx_hal_nor.c
* @author MCD Application Team
* @brief NOR HAL module driver.
* This file provides a generic firmware to drive NOR memories mounted
* as external device.
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
==============================================================================
##### How to use this driver #####
==============================================================================
[..]
This driver is a generic layered driver which contains a set of APIs used to
control NOR flash memories. It uses the FSMC layer functions to interface
with NOR devices. This driver is used as follows:
(+) NOR flash memory configuration sequence using the function HAL_NOR_Init()
with control and timing parameters for both normal and extended mode.
(+) Read NOR flash memory manufacturer code and device IDs using the function
HAL_NOR_Read_ID(). The read information is stored in the NOR_ID_TypeDef
structure declared by the function caller.
(+) Access NOR flash memory by read/write data unit operations using the functions
HAL_NOR_Read(), HAL_NOR_Program().
(+) Perform NOR flash erase block/chip operations using the functions
HAL_NOR_Erase_Block() and HAL_NOR_Erase_Chip().
(+) Read the NOR flash CFI (common flash interface) IDs using the function
HAL_NOR_Read_CFI(). The read information is stored in the NOR_CFI_TypeDef
structure declared by the function caller.
(+) You can also control the NOR device by calling the control APIs HAL_NOR_WriteOperation_Enable()/
HAL_NOR_WriteOperation_Disable() to respectively enable/disable the NOR write operation
(+) You can monitor the NOR device HAL state by calling the function
HAL_NOR_GetState()
[..]
(@) This driver is a set of generic APIs which handle standard NOR flash operations.
If a NOR flash device contains different operations and/or implementations,
it should be implemented separately.
*** NOR HAL driver macros list ***
=============================================
[..]
Below the list of most used macros in NOR HAL driver.
(+) NOR_WRITE : NOR memory write data to specified address
*** Callback registration ***
=============================================
[..]
The compilation define USE_HAL_NOR_REGISTER_CALLBACKS when set to 1
allows the user to configure dynamically the driver callbacks.
Use Functions HAL_NOR_RegisterCallback() to register a user callback,
it allows to register following callbacks:
(+) MspInitCallback : NOR MspInit.
(+) MspDeInitCallback : NOR MspDeInit.
This function takes as parameters the HAL peripheral handle, the Callback ID
and a pointer to the user callback function.
Use function HAL_NOR_UnRegisterCallback() to reset a callback to the default
weak (overridden) function. It allows to reset following callbacks:
(+) MspInitCallback : NOR MspInit.
(+) MspDeInitCallback : NOR MspDeInit.
This function) takes as parameters the HAL peripheral handle and the Callback ID.
By default, after the HAL_NOR_Init and if the state is HAL_NOR_STATE_RESET
all callbacks are reset to the corresponding legacy weak (overridden) functions.
Exception done for MspInit and MspDeInit callbacks that are respectively
reset to the legacy weak (overridden) functions in the HAL_NOR_Init
and HAL_NOR_DeInit only when these callbacks are null (not registered beforehand).
If not, MspInit or MspDeInit are not null, the HAL_NOR_Init and HAL_NOR_DeInit
keep and use the user MspInit/MspDeInit callbacks (registered beforehand)
Callbacks can be registered/unregistered in READY state only.
Exception done for MspInit/MspDeInit callbacks that can be registered/unregistered
in READY or RESET state, thus registered (user) MspInit/DeInit callbacks can be used
during the Init/DeInit.
In that case first register the MspInit/MspDeInit user callbacks
using HAL_NOR_RegisterCallback before calling HAL_NOR_DeInit
or HAL_NOR_Init function.
When The compilation define USE_HAL_NOR_REGISTER_CALLBACKS is set to 0 or
not defined, the callback registering feature is not available
and weak (overridden) callbacks are used.
@endverbatim
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
#if defined(FSMC_BANK1)
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
#ifdef HAL_NOR_MODULE_ENABLED
/** @defgroup NOR NOR
* @brief NOR driver modules
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/** @defgroup NOR_Private_Defines NOR Private Defines
* @{
*/
/* Constants to define address to set to write a command */
#define NOR_CMD_ADDRESS_FIRST_BYTE (uint16_t)0x0AAA
#define NOR_CMD_ADDRESS_FIRST_CFI_BYTE (uint16_t)0x00AA
#define NOR_CMD_ADDRESS_SECOND_BYTE (uint16_t)0x0555
#define NOR_CMD_ADDRESS_THIRD_BYTE (uint16_t)0x0AAA
#define NOR_CMD_ADDRESS_FIRST (uint16_t)0x0555
#define NOR_CMD_ADDRESS_FIRST_CFI (uint16_t)0x0055
#define NOR_CMD_ADDRESS_SECOND (uint16_t)0x02AA
#define NOR_CMD_ADDRESS_THIRD (uint16_t)0x0555
#define NOR_CMD_ADDRESS_FOURTH (uint16_t)0x0555
#define NOR_CMD_ADDRESS_FIFTH (uint16_t)0x02AA
#define NOR_CMD_ADDRESS_SIXTH (uint16_t)0x0555
/* Constants to define data to program a command */
#define NOR_CMD_DATA_READ_RESET (uint16_t)0x00F0
#define NOR_CMD_DATA_FIRST (uint16_t)0x00AA
#define NOR_CMD_DATA_SECOND (uint16_t)0x0055
#define NOR_CMD_DATA_AUTO_SELECT (uint16_t)0x0090
#define NOR_CMD_DATA_PROGRAM (uint16_t)0x00A0
#define NOR_CMD_DATA_CHIP_BLOCK_ERASE_THIRD (uint16_t)0x0080
#define NOR_CMD_DATA_CHIP_BLOCK_ERASE_FOURTH (uint16_t)0x00AA
#define NOR_CMD_DATA_CHIP_BLOCK_ERASE_FIFTH (uint16_t)0x0055
#define NOR_CMD_DATA_CHIP_ERASE (uint16_t)0x0010
#define NOR_CMD_DATA_CFI (uint16_t)0x0098
#define NOR_CMD_DATA_BUFFER_AND_PROG (uint8_t)0x25
#define NOR_CMD_DATA_BUFFER_AND_PROG_CONFIRM (uint8_t)0x29
#define NOR_CMD_DATA_BLOCK_ERASE (uint8_t)0x30
#define NOR_CMD_READ_ARRAY (uint16_t)0x00FF
#define NOR_CMD_WORD_PROGRAM (uint16_t)0x0040
#define NOR_CMD_BUFFERED_PROGRAM (uint16_t)0x00E8
#define NOR_CMD_CONFIRM (uint16_t)0x00D0
#define NOR_CMD_BLOCK_ERASE (uint16_t)0x0020
#define NOR_CMD_BLOCK_UNLOCK (uint16_t)0x0060
#define NOR_CMD_READ_STATUS_REG (uint16_t)0x0070
#define NOR_CMD_CLEAR_STATUS_REG (uint16_t)0x0050
/* Mask on NOR STATUS REGISTER */
#define NOR_MASK_STATUS_DQ4 (uint16_t)0x0010
#define NOR_MASK_STATUS_DQ5 (uint16_t)0x0020
#define NOR_MASK_STATUS_DQ6 (uint16_t)0x0040
#define NOR_MASK_STATUS_DQ7 (uint16_t)0x0080
/* Address of the primary command set */
#define NOR_ADDRESS_COMMAND_SET (uint16_t)0x0013
/* Command set code assignment (defined in JEDEC JEP137B version may 2004) */
#define NOR_INTEL_SHARP_EXT_COMMAND_SET (uint16_t)0x0001 /* Supported in this driver */
#define NOR_AMD_FUJITSU_COMMAND_SET (uint16_t)0x0002 /* Supported in this driver */
#define NOR_INTEL_STANDARD_COMMAND_SET (uint16_t)0x0003 /* Not Supported in this driver */
#define NOR_AMD_FUJITSU_EXT_COMMAND_SET (uint16_t)0x0004 /* Not Supported in this driver */
#define NOR_WINDBOND_STANDARD_COMMAND_SET (uint16_t)0x0006 /* Not Supported in this driver */
#define NOR_MITSUBISHI_STANDARD_COMMAND_SET (uint16_t)0x0100 /* Not Supported in this driver */
#define NOR_MITSUBISHI_EXT_COMMAND_SET (uint16_t)0x0101 /* Not Supported in this driver */
#define NOR_PAGE_WRITE_COMMAND_SET (uint16_t)0x0102 /* Not Supported in this driver */
#define NOR_INTEL_PERFORMANCE_COMMAND_SET (uint16_t)0x0200 /* Not Supported in this driver */
#define NOR_INTEL_DATA_COMMAND_SET (uint16_t)0x0210 /* Not Supported in this driver */
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/** @defgroup NOR_Private_Variables NOR Private Variables
* @{
*/
static uint32_t uwNORMemoryDataWidth = NOR_MEMORY_8B;
/**
* @}
*/
/* Private functions ---------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @defgroup NOR_Exported_Functions NOR Exported Functions
* @{
*/
/** @defgroup NOR_Exported_Functions_Group1 Initialization and de-initialization functions
* @brief Initialization and Configuration functions
*
@verbatim
==============================================================================
##### NOR Initialization and de_initialization functions #####
==============================================================================
[..]
This section provides functions allowing to initialize/de-initialize
the NOR memory
@endverbatim
* @{
*/
/**
* @brief Perform the NOR memory Initialization sequence
* @param hnor pointer to a NOR_HandleTypeDef structure that contains
* the configuration information for NOR module.
* @param Timing pointer to NOR control timing structure
* @param ExtTiming pointer to NOR extended mode timing structure
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NOR_Init(NOR_HandleTypeDef *hnor, FSMC_NORSRAM_TimingTypeDef *Timing,
FSMC_NORSRAM_TimingTypeDef *ExtTiming)
{
uint32_t deviceaddress;
HAL_StatusTypeDef status = HAL_OK;
/* Check the NOR handle parameter */
if (hnor == NULL)
{
return HAL_ERROR;
}
if (hnor->State == HAL_NOR_STATE_RESET)
{
/* Allocate lock resource and initialize it */
hnor->Lock = HAL_UNLOCKED;
#if (USE_HAL_NOR_REGISTER_CALLBACKS == 1)
if (hnor->MspInitCallback == NULL)
{
hnor->MspInitCallback = HAL_NOR_MspInit;
}
/* Init the low level hardware */
hnor->MspInitCallback(hnor);
#else
/* Initialize the low level hardware (MSP) */
HAL_NOR_MspInit(hnor);
#endif /* (USE_HAL_NOR_REGISTER_CALLBACKS) */
}
/* Initialize NOR control Interface */
(void)FSMC_NORSRAM_Init(hnor->Instance, &(hnor->Init));
/* Initialize NOR timing Interface */
(void)FSMC_NORSRAM_Timing_Init(hnor->Instance, Timing, hnor->Init.NSBank);
/* Initialize NOR extended mode timing Interface */
(void)FSMC_NORSRAM_Extended_Timing_Init(hnor->Extended, ExtTiming,
hnor->Init.NSBank, hnor->Init.ExtendedMode);
/* Enable the NORSRAM device */
__FSMC_NORSRAM_ENABLE(hnor->Instance, hnor->Init.NSBank);
/* Initialize NOR Memory Data Width*/
if (hnor->Init.MemoryDataWidth == FSMC_NORSRAM_MEM_BUS_WIDTH_8)
{
uwNORMemoryDataWidth = NOR_MEMORY_8B;
}
else
{
uwNORMemoryDataWidth = NOR_MEMORY_16B;
}
/* Initialize the NOR controller state */
hnor->State = HAL_NOR_STATE_READY;
/* Select the NOR device address */
if (hnor->Init.NSBank == FSMC_NORSRAM_BANK1)
{
deviceaddress = NOR_MEMORY_ADRESS1;
}
else if (hnor->Init.NSBank == FSMC_NORSRAM_BANK2)
{
deviceaddress = NOR_MEMORY_ADRESS2;
}
else if (hnor->Init.NSBank == FSMC_NORSRAM_BANK3)
{
deviceaddress = NOR_MEMORY_ADRESS3;
}
else /* FSMC_NORSRAM_BANK4 */
{
deviceaddress = NOR_MEMORY_ADRESS4;
}
if (hnor->Init.WriteOperation == FSMC_WRITE_OPERATION_DISABLE)
{
(void)FSMC_NORSRAM_WriteOperation_Disable(hnor->Instance, hnor->Init.NSBank);
/* Update the NOR controller state */
hnor->State = HAL_NOR_STATE_PROTECTED;
}
else
{
/* Get the value of the command set */
if (uwNORMemoryDataWidth == NOR_MEMORY_8B)
{
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FIRST_CFI_BYTE),
NOR_CMD_DATA_CFI);
}
else
{
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FIRST_CFI), NOR_CMD_DATA_CFI);
}
hnor->CommandSet = *(__IO uint16_t *) NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_ADDRESS_COMMAND_SET);
status = HAL_NOR_ReturnToReadMode(hnor);
}
return status;
}
/**
* @brief Perform NOR memory De-Initialization sequence
* @param hnor pointer to a NOR_HandleTypeDef structure that contains
* the configuration information for NOR module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NOR_DeInit(NOR_HandleTypeDef *hnor)
{
#if (USE_HAL_NOR_REGISTER_CALLBACKS == 1)
if (hnor->MspDeInitCallback == NULL)
{
hnor->MspDeInitCallback = HAL_NOR_MspDeInit;
}
/* DeInit the low level hardware */
hnor->MspDeInitCallback(hnor);
#else
/* De-Initialize the low level hardware (MSP) */
HAL_NOR_MspDeInit(hnor);
#endif /* (USE_HAL_NOR_REGISTER_CALLBACKS) */
/* Configure the NOR registers with their reset values */
(void)FSMC_NORSRAM_DeInit(hnor->Instance, hnor->Extended, hnor->Init.NSBank);
/* Reset the NOR controller state */
hnor->State = HAL_NOR_STATE_RESET;
/* Release Lock */
__HAL_UNLOCK(hnor);
return HAL_OK;
}
/**
* @brief NOR MSP Init
* @param hnor pointer to a NOR_HandleTypeDef structure that contains
* the configuration information for NOR module.
* @retval None
*/
__weak void HAL_NOR_MspInit(NOR_HandleTypeDef *hnor)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hnor);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_NOR_MspInit could be implemented in the user file
*/
}
/**
* @brief NOR MSP DeInit
* @param hnor pointer to a NOR_HandleTypeDef structure that contains
* the configuration information for NOR module.
* @retval None
*/
__weak void HAL_NOR_MspDeInit(NOR_HandleTypeDef *hnor)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hnor);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_NOR_MspDeInit could be implemented in the user file
*/
}
/**
* @brief NOR MSP Wait for Ready/Busy signal
* @param hnor pointer to a NOR_HandleTypeDef structure that contains
* the configuration information for NOR module.
* @param Timeout Maximum timeout value
* @retval None
*/
__weak void HAL_NOR_MspWait(NOR_HandleTypeDef *hnor, uint32_t Timeout)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hnor);
UNUSED(Timeout);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_NOR_MspWait could be implemented in the user file
*/
}
/**
* @}
*/
/** @defgroup NOR_Exported_Functions_Group2 Input and Output functions
* @brief Input Output and memory control functions
*
@verbatim
==============================================================================
##### NOR Input and Output functions #####
==============================================================================
[..]
This section provides functions allowing to use and control the NOR memory
@endverbatim
* @{
*/
/**
* @brief Read NOR flash IDs
* @param hnor pointer to a NOR_HandleTypeDef structure that contains
* the configuration information for NOR module.
* @param pNOR_ID pointer to NOR ID structure
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NOR_Read_ID(NOR_HandleTypeDef *hnor, NOR_IDTypeDef *pNOR_ID)
{
uint32_t deviceaddress;
HAL_NOR_StateTypeDef state;
HAL_StatusTypeDef status = HAL_OK;
/* Check the NOR controller state */
state = hnor->State;
if (state == HAL_NOR_STATE_BUSY)
{
return HAL_BUSY;
}
else if (state == HAL_NOR_STATE_PROTECTED)
{
return HAL_ERROR;
}
else if (state == HAL_NOR_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(hnor);
/* Update the NOR controller state */
hnor->State = HAL_NOR_STATE_BUSY;
/* Select the NOR device address */
if (hnor->Init.NSBank == FSMC_NORSRAM_BANK1)
{
deviceaddress = NOR_MEMORY_ADRESS1;
}
else if (hnor->Init.NSBank == FSMC_NORSRAM_BANK2)
{
deviceaddress = NOR_MEMORY_ADRESS2;
}
else if (hnor->Init.NSBank == FSMC_NORSRAM_BANK3)
{
deviceaddress = NOR_MEMORY_ADRESS3;
}
else /* FSMC_NORSRAM_BANK4 */
{
deviceaddress = NOR_MEMORY_ADRESS4;
}
/* Send read ID command */
if (hnor->CommandSet == NOR_AMD_FUJITSU_COMMAND_SET)
{
if (uwNORMemoryDataWidth == NOR_MEMORY_8B)
{
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FIRST_BYTE),
NOR_CMD_DATA_FIRST);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_SECOND_BYTE),
NOR_CMD_DATA_SECOND);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_THIRD_BYTE),
NOR_CMD_DATA_AUTO_SELECT);
}
else
{
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FIRST), NOR_CMD_DATA_FIRST);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_SECOND), NOR_CMD_DATA_SECOND);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_THIRD),
NOR_CMD_DATA_AUTO_SELECT);
}
}
else if (hnor->CommandSet == NOR_INTEL_SHARP_EXT_COMMAND_SET)
{
NOR_WRITE(deviceaddress, NOR_CMD_DATA_AUTO_SELECT);
}
else
{
/* Primary command set not supported by the driver */
status = HAL_ERROR;
}
if (status != HAL_ERROR)
{
/* Read the NOR IDs */
pNOR_ID->Manufacturer_Code = *(__IO uint16_t *) NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, MC_ADDRESS);
pNOR_ID->Device_Code1 = *(__IO uint16_t *) NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth,
DEVICE_CODE1_ADDR);
pNOR_ID->Device_Code2 = *(__IO uint16_t *) NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth,
DEVICE_CODE2_ADDR);
pNOR_ID->Device_Code3 = *(__IO uint16_t *) NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth,
DEVICE_CODE3_ADDR);
}
/* Check the NOR controller state */
hnor->State = state;
/* Process unlocked */
__HAL_UNLOCK(hnor);
}
else
{
return HAL_ERROR;
}
return status;
}
/**
* @brief Returns the NOR memory to Read mode.
* @param hnor pointer to a NOR_HandleTypeDef structure that contains
* the configuration information for NOR module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NOR_ReturnToReadMode(NOR_HandleTypeDef *hnor)
{
uint32_t deviceaddress;
HAL_NOR_StateTypeDef state;
HAL_StatusTypeDef status = HAL_OK;
/* Check the NOR controller state */
state = hnor->State;
if (state == HAL_NOR_STATE_BUSY)
{
return HAL_BUSY;
}
else if (state == HAL_NOR_STATE_PROTECTED)
{
return HAL_ERROR;
}
else if (state == HAL_NOR_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(hnor);
/* Update the NOR controller state */
hnor->State = HAL_NOR_STATE_BUSY;
/* Select the NOR device address */
if (hnor->Init.NSBank == FSMC_NORSRAM_BANK1)
{
deviceaddress = NOR_MEMORY_ADRESS1;
}
else if (hnor->Init.NSBank == FSMC_NORSRAM_BANK2)
{
deviceaddress = NOR_MEMORY_ADRESS2;
}
else if (hnor->Init.NSBank == FSMC_NORSRAM_BANK3)
{
deviceaddress = NOR_MEMORY_ADRESS3;
}
else /* FSMC_NORSRAM_BANK4 */
{
deviceaddress = NOR_MEMORY_ADRESS4;
}
if (hnor->CommandSet == NOR_AMD_FUJITSU_COMMAND_SET)
{
NOR_WRITE(deviceaddress, NOR_CMD_DATA_READ_RESET);
}
else if (hnor->CommandSet == NOR_INTEL_SHARP_EXT_COMMAND_SET)
{
NOR_WRITE(deviceaddress, NOR_CMD_READ_ARRAY);
}
else
{
/* Primary command set not supported by the driver */
status = HAL_ERROR;
}
/* Check the NOR controller state */
hnor->State = state;
/* Process unlocked */
__HAL_UNLOCK(hnor);
}
else
{
return HAL_ERROR;
}
return status;
}
/**
* @brief Read data from NOR memory
* @param hnor pointer to a NOR_HandleTypeDef structure that contains
* the configuration information for NOR module.
* @param pAddress pointer to Device address
* @param pData pointer to read data
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NOR_Read(NOR_HandleTypeDef *hnor, uint32_t *pAddress, uint16_t *pData)
{
uint32_t deviceaddress;
HAL_NOR_StateTypeDef state;
HAL_StatusTypeDef status = HAL_OK;
/* Check the NOR controller state */
state = hnor->State;
if (state == HAL_NOR_STATE_BUSY)
{
return HAL_BUSY;
}
else if (state == HAL_NOR_STATE_PROTECTED)
{
return HAL_ERROR;
}
else if (state == HAL_NOR_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(hnor);
/* Update the NOR controller state */
hnor->State = HAL_NOR_STATE_BUSY;
/* Select the NOR device address */
if (hnor->Init.NSBank == FSMC_NORSRAM_BANK1)
{
deviceaddress = NOR_MEMORY_ADRESS1;
}
else if (hnor->Init.NSBank == FSMC_NORSRAM_BANK2)
{
deviceaddress = NOR_MEMORY_ADRESS2;
}
else if (hnor->Init.NSBank == FSMC_NORSRAM_BANK3)
{
deviceaddress = NOR_MEMORY_ADRESS3;
}
else /* FSMC_NORSRAM_BANK4 */
{
deviceaddress = NOR_MEMORY_ADRESS4;
}
/* Send read data command */
if (hnor->CommandSet == NOR_AMD_FUJITSU_COMMAND_SET)
{
if (uwNORMemoryDataWidth == NOR_MEMORY_8B)
{
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FIRST_BYTE),
NOR_CMD_DATA_FIRST);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_SECOND_BYTE),
NOR_CMD_DATA_SECOND);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_THIRD_BYTE),
NOR_CMD_DATA_READ_RESET);
}
else
{
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FIRST), NOR_CMD_DATA_FIRST);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_SECOND), NOR_CMD_DATA_SECOND);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_THIRD),
NOR_CMD_DATA_READ_RESET);
}
}
else if (hnor->CommandSet == NOR_INTEL_SHARP_EXT_COMMAND_SET)
{
NOR_WRITE(pAddress, NOR_CMD_READ_ARRAY);
}
else
{
/* Primary command set not supported by the driver */
status = HAL_ERROR;
}
if (status != HAL_ERROR)
{
/* Read the data */
*pData = (uint16_t)(*(__IO uint32_t *)pAddress);
}
/* Check the NOR controller state */
hnor->State = state;
/* Process unlocked */
__HAL_UNLOCK(hnor);
}
else
{
return HAL_ERROR;
}
return status;
}
/**
* @brief Program data to NOR memory
* @param hnor pointer to a NOR_HandleTypeDef structure that contains
* the configuration information for NOR module.
* @param pAddress Device address
* @param pData pointer to the data to write
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NOR_Program(NOR_HandleTypeDef *hnor, uint32_t *pAddress, uint16_t *pData)
{
uint32_t deviceaddress;
HAL_StatusTypeDef status = HAL_OK;
/* Check the NOR controller state */
if (hnor->State == HAL_NOR_STATE_BUSY)
{
return HAL_BUSY;
}
else if (hnor->State == HAL_NOR_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(hnor);
/* Update the NOR controller state */
hnor->State = HAL_NOR_STATE_BUSY;
/* Select the NOR device address */
if (hnor->Init.NSBank == FSMC_NORSRAM_BANK1)
{
deviceaddress = NOR_MEMORY_ADRESS1;
}
else if (hnor->Init.NSBank == FSMC_NORSRAM_BANK2)
{
deviceaddress = NOR_MEMORY_ADRESS2;
}
else if (hnor->Init.NSBank == FSMC_NORSRAM_BANK3)
{
deviceaddress = NOR_MEMORY_ADRESS3;
}
else /* FSMC_NORSRAM_BANK4 */
{
deviceaddress = NOR_MEMORY_ADRESS4;
}
/* Send program data command */
if (hnor->CommandSet == NOR_AMD_FUJITSU_COMMAND_SET)
{
if (uwNORMemoryDataWidth == NOR_MEMORY_8B)
{
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FIRST_BYTE),
NOR_CMD_DATA_FIRST);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_SECOND_BYTE),
NOR_CMD_DATA_SECOND);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_THIRD_BYTE),
NOR_CMD_DATA_PROGRAM);
}
else
{
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FIRST), NOR_CMD_DATA_FIRST);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_SECOND), NOR_CMD_DATA_SECOND);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_THIRD), NOR_CMD_DATA_PROGRAM);
}
}
else if (hnor->CommandSet == NOR_INTEL_SHARP_EXT_COMMAND_SET)
{
NOR_WRITE(pAddress, NOR_CMD_WORD_PROGRAM);
}
else
{
/* Primary command set not supported by the driver */
status = HAL_ERROR;
}
if (status != HAL_ERROR)
{
/* Write the data */
NOR_WRITE(pAddress, *pData);
}
/* Check the NOR controller state */
hnor->State = HAL_NOR_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hnor);
}
else
{
return HAL_ERROR;
}
return status;
}
/**
* @brief Reads a half-word buffer from the NOR memory.
* @param hnor pointer to the NOR handle
* @param uwAddress NOR memory internal address to read from.
* @param pData pointer to the buffer that receives the data read from the
* NOR memory.
* @param uwBufferSize number of Half word to read.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NOR_ReadBuffer(NOR_HandleTypeDef *hnor, uint32_t uwAddress, uint16_t *pData,
uint32_t uwBufferSize)
{
uint32_t deviceaddress;
uint32_t size = uwBufferSize;
uint32_t address = uwAddress;
uint16_t *data = pData;
HAL_NOR_StateTypeDef state;
HAL_StatusTypeDef status = HAL_OK;
/* Check the NOR controller state */
state = hnor->State;
if (state == HAL_NOR_STATE_BUSY)
{
return HAL_BUSY;
}
else if (state == HAL_NOR_STATE_PROTECTED)
{
return HAL_ERROR;
}
else if (state == HAL_NOR_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(hnor);
/* Update the NOR controller state */
hnor->State = HAL_NOR_STATE_BUSY;
/* Select the NOR device address */
if (hnor->Init.NSBank == FSMC_NORSRAM_BANK1)
{
deviceaddress = NOR_MEMORY_ADRESS1;
}
else if (hnor->Init.NSBank == FSMC_NORSRAM_BANK2)
{
deviceaddress = NOR_MEMORY_ADRESS2;
}
else if (hnor->Init.NSBank == FSMC_NORSRAM_BANK3)
{
deviceaddress = NOR_MEMORY_ADRESS3;
}
else /* FSMC_NORSRAM_BANK4 */
{
deviceaddress = NOR_MEMORY_ADRESS4;
}
/* Send read data command */
if (hnor->CommandSet == NOR_AMD_FUJITSU_COMMAND_SET)
{
if (uwNORMemoryDataWidth == NOR_MEMORY_8B)
{
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FIRST_BYTE),
NOR_CMD_DATA_FIRST);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_SECOND_BYTE),
NOR_CMD_DATA_SECOND);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_THIRD_BYTE),
NOR_CMD_DATA_READ_RESET);
}
else
{
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FIRST), NOR_CMD_DATA_FIRST);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_SECOND), NOR_CMD_DATA_SECOND);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_THIRD),
NOR_CMD_DATA_READ_RESET);
}
}
else if (hnor->CommandSet == NOR_INTEL_SHARP_EXT_COMMAND_SET)
{
NOR_WRITE(deviceaddress, NOR_CMD_READ_ARRAY);
}
else
{
/* Primary command set not supported by the driver */
status = HAL_ERROR;
}
if (status != HAL_ERROR)
{
/* Read buffer */
while (size > 0U)
{
*data = *(__IO uint16_t *)address;
data++;
address += 2U;
size--;
}
}
/* Check the NOR controller state */
hnor->State = state;
/* Process unlocked */
__HAL_UNLOCK(hnor);
}
else
{
return HAL_ERROR;
}
return status;
}
/**
* @brief Writes a half-word buffer to the NOR memory. This function must be used
only with S29GL128P NOR memory.
* @param hnor pointer to the NOR handle
* @param uwAddress NOR memory internal start write address
* @param pData pointer to source data buffer.
* @param uwBufferSize Size of the buffer to write
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NOR_ProgramBuffer(NOR_HandleTypeDef *hnor, uint32_t uwAddress, uint16_t *pData,
uint32_t uwBufferSize)
{
uint16_t *p_currentaddress;
const uint16_t *p_endaddress;
uint16_t *data = pData;
uint32_t deviceaddress;
HAL_StatusTypeDef status = HAL_OK;
/* Check the NOR controller state */
if (hnor->State == HAL_NOR_STATE_BUSY)
{
return HAL_BUSY;
}
else if (hnor->State == HAL_NOR_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(hnor);
/* Update the NOR controller state */
hnor->State = HAL_NOR_STATE_BUSY;
/* Select the NOR device address */
if (hnor->Init.NSBank == FSMC_NORSRAM_BANK1)
{
deviceaddress = NOR_MEMORY_ADRESS1;
}
else if (hnor->Init.NSBank == FSMC_NORSRAM_BANK2)
{
deviceaddress = NOR_MEMORY_ADRESS2;
}
else if (hnor->Init.NSBank == FSMC_NORSRAM_BANK3)
{
deviceaddress = NOR_MEMORY_ADRESS3;
}
else /* FSMC_NORSRAM_BANK4 */
{
deviceaddress = NOR_MEMORY_ADRESS4;
}
/* Initialize variables */
p_currentaddress = (uint16_t *)(deviceaddress + uwAddress);
p_endaddress = (uint16_t *)(deviceaddress + uwAddress + (2U * (uwBufferSize - 1U)));
if (hnor->CommandSet == NOR_AMD_FUJITSU_COMMAND_SET)
{
if (uwNORMemoryDataWidth == NOR_MEMORY_8B)
{
/* Issue unlock command sequence */
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FIRST_BYTE),
NOR_CMD_DATA_FIRST);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_SECOND_BYTE),
NOR_CMD_DATA_SECOND);
}
else
{
/* Issue unlock command sequence */
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FIRST), NOR_CMD_DATA_FIRST);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_SECOND), NOR_CMD_DATA_SECOND);
}
/* Write Buffer Load Command */
NOR_WRITE((deviceaddress + uwAddress), NOR_CMD_DATA_BUFFER_AND_PROG);
NOR_WRITE((deviceaddress + uwAddress), (uint16_t)(uwBufferSize - 1U));
}
else if (hnor->CommandSet == NOR_INTEL_SHARP_EXT_COMMAND_SET)
{
/* Write Buffer Load Command */
NOR_WRITE((deviceaddress + uwAddress), NOR_CMD_BUFFERED_PROGRAM);
NOR_WRITE((deviceaddress + uwAddress), (uint16_t)(uwBufferSize - 1U));
}
else
{
/* Primary command set not supported by the driver */
status = HAL_ERROR;
}
if (status != HAL_ERROR)
{
/* Load Data into NOR Buffer */
while (p_currentaddress <= p_endaddress)
{
NOR_WRITE(p_currentaddress, *data);
data++;
p_currentaddress ++;
}
if (hnor->CommandSet == NOR_AMD_FUJITSU_COMMAND_SET)
{
NOR_WRITE((deviceaddress + uwAddress), NOR_CMD_DATA_BUFFER_AND_PROG_CONFIRM);
}
else /* => hnor->CommandSet == NOR_INTEL_SHARP_EXT_COMMAND_SET */
{
NOR_WRITE((deviceaddress + uwAddress), NOR_CMD_CONFIRM);
}
}
/* Check the NOR controller state */
hnor->State = HAL_NOR_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hnor);
}
else
{
return HAL_ERROR;
}
return status;
}
/**
* @brief Erase the specified block of the NOR memory
* @param hnor pointer to a NOR_HandleTypeDef structure that contains
* the configuration information for NOR module.
* @param BlockAddress Block to erase address
* @param Address Device address
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NOR_Erase_Block(NOR_HandleTypeDef *hnor, uint32_t BlockAddress, uint32_t Address)
{
uint32_t deviceaddress;
HAL_StatusTypeDef status = HAL_OK;
/* Check the NOR controller state */
if (hnor->State == HAL_NOR_STATE_BUSY)
{
return HAL_BUSY;
}
else if (hnor->State == HAL_NOR_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(hnor);
/* Update the NOR controller state */
hnor->State = HAL_NOR_STATE_BUSY;
/* Select the NOR device address */
if (hnor->Init.NSBank == FSMC_NORSRAM_BANK1)
{
deviceaddress = NOR_MEMORY_ADRESS1;
}
else if (hnor->Init.NSBank == FSMC_NORSRAM_BANK2)
{
deviceaddress = NOR_MEMORY_ADRESS2;
}
else if (hnor->Init.NSBank == FSMC_NORSRAM_BANK3)
{
deviceaddress = NOR_MEMORY_ADRESS3;
}
else /* FSMC_NORSRAM_BANK4 */
{
deviceaddress = NOR_MEMORY_ADRESS4;
}
/* Send block erase command sequence */
if (hnor->CommandSet == NOR_AMD_FUJITSU_COMMAND_SET)
{
if (uwNORMemoryDataWidth == NOR_MEMORY_8B)
{
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FIRST_BYTE),
NOR_CMD_DATA_FIRST);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_SECOND_BYTE),
NOR_CMD_DATA_SECOND);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_THIRD_BYTE),
NOR_CMD_DATA_CHIP_BLOCK_ERASE_THIRD);
}
else
{
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FIRST), NOR_CMD_DATA_FIRST);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_SECOND), NOR_CMD_DATA_SECOND);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_THIRD),
NOR_CMD_DATA_CHIP_BLOCK_ERASE_THIRD);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FOURTH),
NOR_CMD_DATA_CHIP_BLOCK_ERASE_FOURTH);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FIFTH),
NOR_CMD_DATA_CHIP_BLOCK_ERASE_FIFTH);
}
NOR_WRITE((uint32_t)(BlockAddress + Address), NOR_CMD_DATA_BLOCK_ERASE);
}
else if (hnor->CommandSet == NOR_INTEL_SHARP_EXT_COMMAND_SET)
{
NOR_WRITE((BlockAddress + Address), NOR_CMD_BLOCK_UNLOCK);
NOR_WRITE((BlockAddress + Address), NOR_CMD_CONFIRM);
NOR_WRITE((BlockAddress + Address), NOR_CMD_BLOCK_ERASE);
NOR_WRITE((BlockAddress + Address), NOR_CMD_CONFIRM);
}
else
{
/* Primary command set not supported by the driver */
status = HAL_ERROR;
}
/* Check the NOR memory status and update the controller state */
hnor->State = HAL_NOR_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hnor);
}
else
{
return HAL_ERROR;
}
return status;
}
/**
* @brief Erase the entire NOR chip.
* @param hnor pointer to a NOR_HandleTypeDef structure that contains
* the configuration information for NOR module.
* @param Address Device address
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NOR_Erase_Chip(NOR_HandleTypeDef *hnor, uint32_t Address)
{
uint32_t deviceaddress;
HAL_StatusTypeDef status = HAL_OK;
UNUSED(Address);
/* Check the NOR controller state */
if (hnor->State == HAL_NOR_STATE_BUSY)
{
return HAL_BUSY;
}
else if (hnor->State == HAL_NOR_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(hnor);
/* Update the NOR controller state */
hnor->State = HAL_NOR_STATE_BUSY;
/* Select the NOR device address */
if (hnor->Init.NSBank == FSMC_NORSRAM_BANK1)
{
deviceaddress = NOR_MEMORY_ADRESS1;
}
else if (hnor->Init.NSBank == FSMC_NORSRAM_BANK2)
{
deviceaddress = NOR_MEMORY_ADRESS2;
}
else if (hnor->Init.NSBank == FSMC_NORSRAM_BANK3)
{
deviceaddress = NOR_MEMORY_ADRESS3;
}
else /* FSMC_NORSRAM_BANK4 */
{
deviceaddress = NOR_MEMORY_ADRESS4;
}
/* Send NOR chip erase command sequence */
if (hnor->CommandSet == NOR_AMD_FUJITSU_COMMAND_SET)
{
if (uwNORMemoryDataWidth == NOR_MEMORY_8B)
{
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FIRST_BYTE),
NOR_CMD_DATA_FIRST);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_SECOND_BYTE),
NOR_CMD_DATA_SECOND);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_THIRD_BYTE),
NOR_CMD_DATA_CHIP_BLOCK_ERASE_THIRD);
}
else
{
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FIRST), NOR_CMD_DATA_FIRST);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_SECOND), NOR_CMD_DATA_SECOND);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_THIRD),
NOR_CMD_DATA_CHIP_BLOCK_ERASE_THIRD);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FOURTH),
NOR_CMD_DATA_CHIP_BLOCK_ERASE_FOURTH);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FIFTH),
NOR_CMD_DATA_CHIP_BLOCK_ERASE_FIFTH);
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_SIXTH),
NOR_CMD_DATA_CHIP_ERASE);
}
}
else
{
/* Primary command set not supported by the driver */
status = HAL_ERROR;
}
/* Check the NOR memory status and update the controller state */
hnor->State = HAL_NOR_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hnor);
}
else
{
return HAL_ERROR;
}
return status;
}
/**
* @brief Read NOR flash CFI IDs
* @param hnor pointer to a NOR_HandleTypeDef structure that contains
* the configuration information for NOR module.
* @param pNOR_CFI pointer to NOR CFI IDs structure
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NOR_Read_CFI(NOR_HandleTypeDef *hnor, NOR_CFITypeDef *pNOR_CFI)
{
uint32_t deviceaddress;
HAL_NOR_StateTypeDef state;
/* Check the NOR controller state */
state = hnor->State;
if (state == HAL_NOR_STATE_BUSY)
{
return HAL_BUSY;
}
else if (state == HAL_NOR_STATE_PROTECTED)
{
return HAL_ERROR;
}
else if (state == HAL_NOR_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(hnor);
/* Update the NOR controller state */
hnor->State = HAL_NOR_STATE_BUSY;
/* Select the NOR device address */
if (hnor->Init.NSBank == FSMC_NORSRAM_BANK1)
{
deviceaddress = NOR_MEMORY_ADRESS1;
}
else if (hnor->Init.NSBank == FSMC_NORSRAM_BANK2)
{
deviceaddress = NOR_MEMORY_ADRESS2;
}
else if (hnor->Init.NSBank == FSMC_NORSRAM_BANK3)
{
deviceaddress = NOR_MEMORY_ADRESS3;
}
else /* FSMC_NORSRAM_BANK4 */
{
deviceaddress = NOR_MEMORY_ADRESS4;
}
/* Send read CFI query command */
if (uwNORMemoryDataWidth == NOR_MEMORY_8B)
{
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FIRST_CFI_BYTE),
NOR_CMD_DATA_CFI);
}
else
{
NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FIRST_CFI), NOR_CMD_DATA_CFI);
}
/* read the NOR CFI information */
pNOR_CFI->CFI_1 = *(__IO uint16_t *) NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, CFI1_ADDRESS);
pNOR_CFI->CFI_2 = *(__IO uint16_t *) NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, CFI2_ADDRESS);
pNOR_CFI->CFI_3 = *(__IO uint16_t *) NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, CFI3_ADDRESS);
pNOR_CFI->CFI_4 = *(__IO uint16_t *) NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, CFI4_ADDRESS);
/* Check the NOR controller state */
hnor->State = state;
/* Process unlocked */
__HAL_UNLOCK(hnor);
}
else
{
return HAL_ERROR;
}
return HAL_OK;
}
#if (USE_HAL_NOR_REGISTER_CALLBACKS == 1)
/**
* @brief Register a User NOR Callback
* To be used to override the weak predefined callback
* @param hnor : NOR handle
* @param CallbackId : ID of the callback to be registered
* This parameter can be one of the following values:
* @arg @ref HAL_NOR_MSP_INIT_CB_ID NOR MspInit callback ID
* @arg @ref HAL_NOR_MSP_DEINIT_CB_ID NOR MspDeInit callback ID
* @param pCallback : pointer to the Callback function
* @retval status
*/
HAL_StatusTypeDef HAL_NOR_RegisterCallback(NOR_HandleTypeDef *hnor, HAL_NOR_CallbackIDTypeDef CallbackId,
pNOR_CallbackTypeDef pCallback)
{
HAL_StatusTypeDef status = HAL_OK;
HAL_NOR_StateTypeDef state;
if (pCallback == NULL)
{
return HAL_ERROR;
}
state = hnor->State;
if ((state == HAL_NOR_STATE_READY) || (state == HAL_NOR_STATE_RESET) || (state == HAL_NOR_STATE_PROTECTED))
{
switch (CallbackId)
{
case HAL_NOR_MSP_INIT_CB_ID :
hnor->MspInitCallback = pCallback;
break;
case HAL_NOR_MSP_DEINIT_CB_ID :
hnor->MspDeInitCallback = pCallback;
break;
default :
/* update return status */
status = HAL_ERROR;
break;
}
}
else
{
/* update return status */
status = HAL_ERROR;
}
return status;
}
/**
* @brief Unregister a User NOR Callback
* NOR Callback is redirected to the weak predefined callback
* @param hnor : NOR handle
* @param CallbackId : ID of the callback to be unregistered
* This parameter can be one of the following values:
* @arg @ref HAL_NOR_MSP_INIT_CB_ID NOR MspInit callback ID
* @arg @ref HAL_NOR_MSP_DEINIT_CB_ID NOR MspDeInit callback ID
* @retval status
*/
HAL_StatusTypeDef HAL_NOR_UnRegisterCallback(NOR_HandleTypeDef *hnor, HAL_NOR_CallbackIDTypeDef CallbackId)
{
HAL_StatusTypeDef status = HAL_OK;
HAL_NOR_StateTypeDef state;
state = hnor->State;
if ((state == HAL_NOR_STATE_READY) || (state == HAL_NOR_STATE_RESET) || (state == HAL_NOR_STATE_PROTECTED))
{
switch (CallbackId)
{
case HAL_NOR_MSP_INIT_CB_ID :
hnor->MspInitCallback = HAL_NOR_MspInit;
break;
case HAL_NOR_MSP_DEINIT_CB_ID :
hnor->MspDeInitCallback = HAL_NOR_MspDeInit;
break;
default :
/* update return status */
status = HAL_ERROR;
break;
}
}
else
{
/* update return status */
status = HAL_ERROR;
}
return status;
}
#endif /* (USE_HAL_NOR_REGISTER_CALLBACKS) */
/**
* @}
*/
/** @defgroup NOR_Exported_Functions_Group3 NOR Control functions
* @brief management functions
*
@verbatim
==============================================================================
##### NOR Control functions #####
==============================================================================
[..]
This subsection provides a set of functions allowing to control dynamically
the NOR interface.
@endverbatim
* @{
*/
/**
* @brief Enables dynamically NOR write operation.
* @param hnor pointer to a NOR_HandleTypeDef structure that contains
* the configuration information for NOR module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NOR_WriteOperation_Enable(NOR_HandleTypeDef *hnor)
{
/* Check the NOR controller state */
if (hnor->State == HAL_NOR_STATE_PROTECTED)
{
/* Process Locked */
__HAL_LOCK(hnor);
/* Update the NOR controller state */
hnor->State = HAL_NOR_STATE_BUSY;
/* Enable write operation */
(void)FSMC_NORSRAM_WriteOperation_Enable(hnor->Instance, hnor->Init.NSBank);
/* Update the NOR controller state */
hnor->State = HAL_NOR_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hnor);
}
else
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Disables dynamically NOR write operation.
* @param hnor pointer to a NOR_HandleTypeDef structure that contains
* the configuration information for NOR module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_NOR_WriteOperation_Disable(NOR_HandleTypeDef *hnor)
{
/* Check the NOR controller state */
if (hnor->State == HAL_NOR_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(hnor);
/* Update the NOR controller state */
hnor->State = HAL_NOR_STATE_BUSY;
/* Disable write operation */
(void)FSMC_NORSRAM_WriteOperation_Disable(hnor->Instance, hnor->Init.NSBank);
/* Update the NOR controller state */
hnor->State = HAL_NOR_STATE_PROTECTED;
/* Process unlocked */
__HAL_UNLOCK(hnor);
}
else
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @}
*/
/** @defgroup NOR_Exported_Functions_Group4 NOR State functions
* @brief Peripheral State functions
*
@verbatim
==============================================================================
##### NOR State functions #####
==============================================================================
[..]
This subsection permits to get in run-time the status of the NOR controller
and the data flow.
@endverbatim
* @{
*/
/**
* @brief return the NOR controller state
* @param hnor pointer to a NOR_HandleTypeDef structure that contains
* the configuration information for NOR module.
* @retval NOR controller state
*/
HAL_NOR_StateTypeDef HAL_NOR_GetState(const NOR_HandleTypeDef *hnor)
{
return hnor->State;
}
/**
* @brief Returns the NOR operation status.
* @param hnor pointer to a NOR_HandleTypeDef structure that contains
* the configuration information for NOR module.
* @param Address Device address
* @param Timeout NOR programming Timeout
* @retval NOR_Status The returned value can be: HAL_NOR_STATUS_SUCCESS, HAL_NOR_STATUS_ERROR
* or HAL_NOR_STATUS_TIMEOUT
*/
HAL_NOR_StatusTypeDef HAL_NOR_GetStatus(NOR_HandleTypeDef *hnor, uint32_t Address, uint32_t Timeout)
{
HAL_NOR_StatusTypeDef status = HAL_NOR_STATUS_ONGOING;
uint16_t tmpsr1;
uint16_t tmpsr2;
uint32_t tickstart;
/* Poll on NOR memory Ready/Busy signal ------------------------------------*/
HAL_NOR_MspWait(hnor, Timeout);
/* Get the NOR memory operation status -------------------------------------*/
/* Get tick */
tickstart = HAL_GetTick();
if (hnor->CommandSet == NOR_AMD_FUJITSU_COMMAND_SET)
{
while ((status != HAL_NOR_STATUS_SUCCESS) && (status != HAL_NOR_STATUS_TIMEOUT))
{
/* Check for the Timeout */
if (Timeout != HAL_MAX_DELAY)
{
if (((HAL_GetTick() - tickstart) > Timeout) || (Timeout == 0U))
{
status = HAL_NOR_STATUS_TIMEOUT;
}
}
/* Read NOR status register (DQ6 and DQ5) */
tmpsr1 = *(__IO uint16_t *)Address;
tmpsr2 = *(__IO uint16_t *)Address;
/* If DQ6 did not toggle between the two reads then return HAL_NOR_STATUS_SUCCESS */
if ((tmpsr1 & NOR_MASK_STATUS_DQ6) == (tmpsr2 & NOR_MASK_STATUS_DQ6))
{
return HAL_NOR_STATUS_SUCCESS ;
}
if ((tmpsr1 & NOR_MASK_STATUS_DQ5) == NOR_MASK_STATUS_DQ5)
{
status = HAL_NOR_STATUS_ONGOING;
}
tmpsr1 = *(__IO uint16_t *)Address;
tmpsr2 = *(__IO uint16_t *)Address;
/* If DQ6 did not toggle between the two reads then return HAL_NOR_STATUS_SUCCESS */
if ((tmpsr1 & NOR_MASK_STATUS_DQ6) == (tmpsr2 & NOR_MASK_STATUS_DQ6))
{
return HAL_NOR_STATUS_SUCCESS;
}
if ((tmpsr1 & NOR_MASK_STATUS_DQ5) == NOR_MASK_STATUS_DQ5)
{
return HAL_NOR_STATUS_ERROR;
}
}
}
else if (hnor->CommandSet == NOR_INTEL_SHARP_EXT_COMMAND_SET)
{
do
{
NOR_WRITE(Address, NOR_CMD_READ_STATUS_REG);
tmpsr2 = *(__IO uint16_t *)(Address);
/* Check for the Timeout */
if (Timeout != HAL_MAX_DELAY)
{
if (((HAL_GetTick() - tickstart) > Timeout) || (Timeout == 0U))
{
return HAL_NOR_STATUS_TIMEOUT;
}
}
} while ((tmpsr2 & NOR_MASK_STATUS_DQ7) == 0U);
NOR_WRITE(Address, NOR_CMD_READ_STATUS_REG);
tmpsr1 = *(__IO uint16_t *)(Address);
if ((tmpsr1 & (NOR_MASK_STATUS_DQ5 | NOR_MASK_STATUS_DQ4)) != 0U)
{
/* Clear the Status Register */
NOR_WRITE(Address, NOR_CMD_READ_STATUS_REG);
status = HAL_NOR_STATUS_ERROR;
}
else
{
status = HAL_NOR_STATUS_SUCCESS;
}
}
else
{
/* Primary command set not supported by the driver */
status = HAL_NOR_STATUS_ERROR;
}
/* Return the operation status */
return status;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#endif /* HAL_NOR_MODULE_ENABLED */
/**
* @}
*/
#endif /* FSMC_BANK1 */

View File

@@ -0,0 +1,952 @@
/**
******************************************************************************
* @file stm32f1xx_hal_pccard.c
* @author MCD Application Team
* @brief PCCARD HAL module driver.
* This file provides a generic firmware to drive PCCARD memories mounted
* as external device.
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
===============================================================================
##### How to use this driver #####
===============================================================================
[..]
This driver is a generic layered driver which contains a set of APIs used to
control PCCARD/compact flash memories. It uses the FSMC layer functions
to interface with PCCARD devices. This driver is used for:
(+) PCCARD/Compact Flash memory configuration sequence using the function
HAL_PCCARD_Init()/HAL_CF_Init() with control and timing parameters for
both common and attribute spaces.
(+) Read PCCARD/Compact Flash memory maker and device IDs using the function
HAL_PCCARD_Read_ID()/HAL_CF_Read_ID(). The read information is stored in
the CompactFlash_ID structure declared by the function caller.
(+) Access PCCARD/Compact Flash memory by read/write operations using the functions
HAL_PCCARD_Read_Sector()/ HAL_PCCARD_Write_Sector() -
HAL_CF_Read_Sector()/HAL_CF_Write_Sector(), to read/write sector.
(+) Perform PCCARD/Compact Flash Reset chip operation using the function
HAL_PCCARD_Reset()/HAL_CF_Reset.
(+) Perform PCCARD/Compact Flash erase sector operation using the function
HAL_PCCARD_Erase_Sector()/HAL_CF_Erase_Sector.
(+) Read the PCCARD/Compact Flash status operation using the function
HAL_PCCARD_ReadStatus()/HAL_CF_ReadStatus().
(+) You can monitor the PCCARD/Compact Flash device HAL state by calling
the function HAL_PCCARD_GetState()/HAL_CF_GetState()
[..]
(@) This driver is a set of generic APIs which handle standard PCCARD/compact flash
operations. If a PCCARD/Compact Flash device contains different operations
and/or implementations, it should be implemented separately.
*** Callback registration ***
=============================================
[..]
The compilation define USE_HAL_PCCARD_REGISTER_CALLBACKS when set to 1
allows the user to configure dynamically the driver callbacks.
Use Functions HAL_PCCARD_RegisterCallback() to register a user callback,
it allows to register following callbacks:
(+) MspInitCallback : PCCARD MspInit.
(+) MspDeInitCallback : PCCARD MspDeInit.
This function takes as parameters the HAL peripheral handle, the Callback ID
and a pointer to the user callback function.
Use function HAL_PCCARD_UnRegisterCallback() to reset a callback to the default
weak (surcharged) function. It allows to reset following callbacks:
(+) MspInitCallback : PCCARD MspInit.
(+) MspDeInitCallback : PCCARD MspDeInit.
This function) takes as parameters the HAL peripheral handle and the Callback ID.
By default, after the HAL_PCCARD_Init and if the state is HAL_PCCARD_STATE_RESET
all callbacks are reset to the corresponding legacy weak (surcharged) functions.
Exception done for MspInit and MspDeInit callbacks that are respectively
reset to the legacy weak (surcharged) functions in the HAL_PCCARD_Init
and HAL_PCCARD_DeInit only when these callbacks are null (not registered beforehand).
If not, MspInit or MspDeInit are not null, the HAL_PCCARD_Init and HAL_PCCARD_DeInit
keep and use the user MspInit/MspDeInit callbacks (registered beforehand)
Callbacks can be registered/unregistered in READY state only.
Exception done for MspInit/MspDeInit callbacks that can be registered/unregistered
in READY or RESET state, thus registered (user) MspInit/DeInit callbacks can be used
during the Init/DeInit.
In that case first register the MspInit/MspDeInit user callbacks
using HAL_PCCARD_RegisterCallback before calling HAL_PCCARD_DeInit
or HAL_PCCARD_Init function.
When The compilation define USE_HAL_PCCARD_REGISTER_CALLBACKS is set to 0 or
not defined, the callback registering feature is not available
and weak (surcharged) callbacks are used.
@endverbatim
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
#if defined(FSMC_BANK4)
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
#ifdef HAL_PCCARD_MODULE_ENABLED
/** @defgroup PCCARD PCCARD
* @brief PCCARD HAL module driver
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/** @defgroup PCCARD_Private_Defines PCCARD Private Defines
* @{
*/
#define PCCARD_TIMEOUT_READ_ID 0x0000FFFFU
#define PCCARD_TIMEOUT_READ_WRITE_SECTOR 0x0000FFFFU
#define PCCARD_TIMEOUT_ERASE_SECTOR 0x00000400U
#define PCCARD_TIMEOUT_STATUS 0x01000000U
#define PCCARD_STATUS_OK (uint8_t)0x58
#define PCCARD_STATUS_WRITE_OK (uint8_t)0x50
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function ----------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @defgroup PCCARD_Exported_Functions PCCARD Exported Functions
* @{
*/
/** @defgroup PCCARD_Exported_Functions_Group1 Initialization and de-initialization functions
* @brief Initialization and Configuration functions
*
@verbatim
==============================================================================
##### PCCARD Initialization and de-initialization functions #####
==============================================================================
[..]
This section provides functions allowing to initialize/de-initialize
the PCCARD memory
@endverbatim
* @{
*/
/**
* @brief Perform the PCCARD memory Initialization sequence
* @param hpccard pointer to a PCCARD_HandleTypeDef structure that contains
* the configuration information for PCCARD module.
* @param ComSpaceTiming Common space timing structure
* @param AttSpaceTiming Attribute space timing structure
* @param IOSpaceTiming IO space timing structure
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCCARD_Init(PCCARD_HandleTypeDef *hpccard, FSMC_NAND_PCC_TimingTypeDef *ComSpaceTiming,
FSMC_NAND_PCC_TimingTypeDef *AttSpaceTiming,
FSMC_NAND_PCC_TimingTypeDef *IOSpaceTiming)
{
/* Check the PCCARD controller state */
if (hpccard == NULL)
{
return HAL_ERROR;
}
if (hpccard->State == HAL_PCCARD_STATE_RESET)
{
/* Allocate lock resource and initialize it */
hpccard->Lock = HAL_UNLOCKED;
#if (USE_HAL_PCCARD_REGISTER_CALLBACKS == 1)
if (hpccard->MspInitCallback == NULL)
{
hpccard->MspInitCallback = HAL_PCCARD_MspInit;
}
hpccard->ItCallback = HAL_PCCARD_ITCallback;
/* Init the low level hardware */
hpccard->MspInitCallback(hpccard);
#else
/* Initialize the low level hardware (MSP) */
HAL_PCCARD_MspInit(hpccard);
#endif /* USE_HAL_PCCARD_REGISTER_CALLBACKS */
}
/* Initialize the PCCARD state */
hpccard->State = HAL_PCCARD_STATE_BUSY;
/* Initialize PCCARD control Interface */
FSMC_PCCARD_Init(hpccard->Instance, &(hpccard->Init));
/* Init PCCARD common space timing Interface */
FSMC_PCCARD_CommonSpace_Timing_Init(hpccard->Instance, ComSpaceTiming);
/* Init PCCARD attribute space timing Interface */
FSMC_PCCARD_AttributeSpace_Timing_Init(hpccard->Instance, AttSpaceTiming);
/* Init PCCARD IO space timing Interface */
FSMC_PCCARD_IOSpace_Timing_Init(hpccard->Instance, IOSpaceTiming);
/* Enable the PCCARD device */
__FSMC_PCCARD_ENABLE(hpccard->Instance);
/* Update the PCCARD state */
hpccard->State = HAL_PCCARD_STATE_READY;
return HAL_OK;
}
/**
* @brief Perform the PCCARD memory De-initialization sequence
* @param hpccard pointer to a PCCARD_HandleTypeDef structure that contains
* the configuration information for PCCARD module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCCARD_DeInit(PCCARD_HandleTypeDef *hpccard)
{
#if (USE_HAL_PCCARD_REGISTER_CALLBACKS == 1)
if (hpccard->MspDeInitCallback == NULL)
{
hpccard->MspDeInitCallback = HAL_PCCARD_MspDeInit;
}
/* DeInit the low level hardware */
hpccard->MspDeInitCallback(hpccard);
#else
/* De-Initialize the low level hardware (MSP) */
HAL_PCCARD_MspDeInit(hpccard);
#endif /* USE_HAL_PCCARD_REGISTER_CALLBACKS */
/* Configure the PCCARD registers with their reset values */
FSMC_PCCARD_DeInit(hpccard->Instance);
/* Update the PCCARD controller state */
hpccard->State = HAL_PCCARD_STATE_RESET;
/* Release Lock */
__HAL_UNLOCK(hpccard);
return HAL_OK;
}
/**
* @brief PCCARD MSP Init
* @param hpccard pointer to a PCCARD_HandleTypeDef structure that contains
* the configuration information for PCCARD module.
* @retval None
*/
__weak void HAL_PCCARD_MspInit(PCCARD_HandleTypeDef *hpccard)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hpccard);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_PCCARD_MspInit could be implemented in the user file
*/
}
/**
* @brief PCCARD MSP DeInit
* @param hpccard pointer to a PCCARD_HandleTypeDef structure that contains
* the configuration information for PCCARD module.
* @retval None
*/
__weak void HAL_PCCARD_MspDeInit(PCCARD_HandleTypeDef *hpccard)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hpccard);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_PCCARD_MspDeInit could be implemented in the user file
*/
}
/**
* @}
*/
/** @defgroup PCCARD_Exported_Functions_Group2 Input and Output functions
* @brief Input Output and memory control functions
*
@verbatim
==============================================================================
##### PCCARD Input and Output functions #####
==============================================================================
[..]
This section provides functions allowing to use and control the PCCARD memory
@endverbatim
* @{
*/
/**
* @brief Read Compact Flash's ID.
* @param hpccard pointer to a PCCARD_HandleTypeDef structure that contains
* the configuration information for PCCARD module.
* @param CompactFlash_ID Compact flash ID structure.
* @param pStatus pointer to compact flash status
* @retval HAL status
*
*/
HAL_StatusTypeDef HAL_PCCARD_Read_ID(PCCARD_HandleTypeDef *hpccard, uint8_t CompactFlash_ID[], uint8_t *pStatus)
{
uint32_t timeout = 0U;
uint32_t index = 0U;
uint8_t status = 0U;
/* Process Locked */
__HAL_LOCK(hpccard);
/* Check the PCCARD controller state */
if (hpccard->State == HAL_PCCARD_STATE_BUSY)
{
return HAL_BUSY;
}
/* Update the PCCARD controller state */
hpccard->State = HAL_PCCARD_STATE_BUSY;
/* Initialize the PCCARD status */
*pStatus = PCCARD_READY;
/* Send the Identify Command */
*(__IO uint16_t *)(PCCARD_IO_SPACE_PRIMARY_ADDR | ATA_STATUS_CMD) = (uint16_t)0xECEC;
/* Read PCCARD IDs and timeout treatment */
do
{
/* Read the PCCARD status */
status = *(__IO uint8_t *)(PCCARD_IO_SPACE_PRIMARY_ADDR | ATA_STATUS_CMD_ALTERNATE);
timeout--;
} while ((status != PCCARD_STATUS_OK) && timeout);
if (timeout == 0U)
{
*pStatus = PCCARD_TIMEOUT_ERROR;
}
else
{
/* Read PCCARD ID bytes */
for (index = 0U; index < 16U; index++)
{
CompactFlash_ID[index] = *(__IO uint8_t *)(PCCARD_IO_SPACE_PRIMARY_ADDR | ATA_DATA);
}
}
/* Update the PCCARD controller state */
hpccard->State = HAL_PCCARD_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hpccard);
return HAL_OK;
}
/**
* @brief Read sector from PCCARD memory
* @param hpccard pointer to a PCCARD_HandleTypeDef structure that contains
* the configuration information for PCCARD module.
* @param pBuffer pointer to destination read buffer
* @param SectorAddress Sector address to read
* @param pStatus pointer to PCCARD status
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCCARD_Read_Sector(PCCARD_HandleTypeDef *hpccard, uint16_t *pBuffer, uint16_t SectorAddress,
uint8_t *pStatus)
{
uint32_t timeout = 0U;
uint32_t index = 0U;
uint8_t status = 0U;
/* Process Locked */
__HAL_LOCK(hpccard);
/* Check the PCCARD controller state */
if (hpccard->State == HAL_PCCARD_STATE_BUSY)
{
return HAL_BUSY;
}
/* Update the PCCARD controller state */
hpccard->State = HAL_PCCARD_STATE_BUSY;
/* Initialize PCCARD status */
*pStatus = PCCARD_READY;
/* Set the parameters to write a sector */
*(__IO uint16_t *)(PCCARD_IO_SPACE_PRIMARY_ADDR | ATA_CYLINDER_HIGH) = (uint16_t)0x0000;
*(__IO uint16_t *)(PCCARD_IO_SPACE_PRIMARY_ADDR | ATA_SECTOR_COUNT) = ((uint16_t)0x0100) | ((uint16_t)SectorAddress);
*(__IO uint16_t *)(PCCARD_IO_SPACE_PRIMARY_ADDR | ATA_STATUS_CMD) = (uint16_t)0xE4A0;
do
{
/* wait till the Status = 0x80 */
status = *(__IO uint16_t *)(PCCARD_IO_SPACE_PRIMARY_ADDR | ATA_STATUS_CMD_ALTERNATE);
timeout--;
} while ((status == 0x80U) && timeout);
if (timeout == 0U)
{
*pStatus = PCCARD_TIMEOUT_ERROR;
}
timeout = PCCARD_TIMEOUT_READ_WRITE_SECTOR;
do
{
/* wait till the Status = PCCARD_STATUS_OK */
status = *(__IO uint16_t *)(PCCARD_IO_SPACE_PRIMARY_ADDR | ATA_STATUS_CMD_ALTERNATE);
timeout--;
} while ((status != PCCARD_STATUS_OK) && timeout);
if (timeout == 0U)
{
*pStatus = PCCARD_TIMEOUT_ERROR;
}
/* Read bytes */
for (; index < PCCARD_SECTOR_SIZE; index++)
{
*(uint16_t *)pBuffer++ = *(uint16_t *)(PCCARD_IO_SPACE_PRIMARY_ADDR);
}
/* Update the PCCARD controller state */
hpccard->State = HAL_PCCARD_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hpccard);
return HAL_OK;
}
/**
* @brief Write sector to PCCARD memory
* @param hpccard pointer to a PCCARD_HandleTypeDef structure that contains
* the configuration information for PCCARD module.
* @param pBuffer pointer to source write buffer
* @param SectorAddress Sector address to write
* @param pStatus pointer to PCCARD status
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCCARD_Write_Sector(PCCARD_HandleTypeDef *hpccard, uint16_t *pBuffer, uint16_t SectorAddress,
uint8_t *pStatus)
{
uint32_t timeout = 0U;
uint32_t index = 0U;
uint8_t status = 0U;
/* Process Locked */
__HAL_LOCK(hpccard);
/* Check the PCCARD controller state */
if (hpccard->State == HAL_PCCARD_STATE_BUSY)
{
return HAL_BUSY;
}
/* Update the PCCARD controller state */
hpccard->State = HAL_PCCARD_STATE_BUSY;
/* Initialize PCCARD status */
*pStatus = PCCARD_READY;
/* Set the parameters to write a sector */
*(__IO uint16_t *)(PCCARD_IO_SPACE_PRIMARY_ADDR | ATA_CYLINDER_HIGH) = (uint16_t)0x0000;
*(__IO uint16_t *)(PCCARD_IO_SPACE_PRIMARY_ADDR | ATA_SECTOR_COUNT) = ((uint16_t)0x0100) | ((uint16_t)SectorAddress);
*(__IO uint16_t *)(PCCARD_IO_SPACE_PRIMARY_ADDR | ATA_STATUS_CMD) = (uint16_t)0x30A0;
do
{
/* Wait till the Status = PCCARD_STATUS_OK */
status = *(__IO uint8_t *)(PCCARD_IO_SPACE_PRIMARY_ADDR | ATA_STATUS_CMD_ALTERNATE);
timeout--;
} while ((status != PCCARD_STATUS_OK) && timeout);
if (timeout == 0U)
{
*pStatus = PCCARD_TIMEOUT_ERROR;
}
/* Write bytes */
for (; index < PCCARD_SECTOR_SIZE; index++)
{
*(uint16_t *)(PCCARD_IO_SPACE_PRIMARY_ADDR) = *(uint16_t *)pBuffer++;
}
do
{
/* Wait till the Status = PCCARD_STATUS_WRITE_OK */
status = *(__IO uint8_t *)(PCCARD_IO_SPACE_PRIMARY_ADDR | ATA_STATUS_CMD_ALTERNATE);
timeout--;
} while ((status != PCCARD_STATUS_WRITE_OK) && timeout);
if (timeout == 0U)
{
*pStatus = PCCARD_TIMEOUT_ERROR;
}
/* Update the PCCARD controller state */
hpccard->State = HAL_PCCARD_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hpccard);
return HAL_OK;
}
/**
* @brief Erase sector from PCCARD memory
* @param hpccard pointer to a PCCARD_HandleTypeDef structure that contains
* the configuration information for PCCARD module.
* @param SectorAddress Sector address to erase
* @param pStatus pointer to PCCARD status
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCCARD_Erase_Sector(PCCARD_HandleTypeDef *hpccard, uint16_t SectorAddress, uint8_t *pStatus)
{
uint32_t timeout = PCCARD_TIMEOUT_ERASE_SECTOR;
uint8_t status = 0U;
/* Process Locked */
__HAL_LOCK(hpccard);
/* Check the PCCARD controller state */
if (hpccard->State == HAL_PCCARD_STATE_BUSY)
{
return HAL_BUSY;
}
/* Update the PCCARD controller state */
hpccard->State = HAL_PCCARD_STATE_BUSY;
/* Initialize PCCARD status */
*pStatus = PCCARD_READY;
/* Set the parameters to write a sector */
*(__IO uint8_t *)(PCCARD_IO_SPACE_PRIMARY_ADDR | ATA_CYLINDER_LOW) = 0x00;
*(__IO uint8_t *)(PCCARD_IO_SPACE_PRIMARY_ADDR | ATA_CYLINDER_HIGH) = 0x00;
*(__IO uint8_t *)(PCCARD_IO_SPACE_PRIMARY_ADDR | ATA_SECTOR_NUMBER) = SectorAddress;
*(__IO uint8_t *)(PCCARD_IO_SPACE_PRIMARY_ADDR | ATA_SECTOR_COUNT) = 0x01;
*(__IO uint8_t *)(PCCARD_IO_SPACE_PRIMARY_ADDR | ATA_CARD_HEAD) = 0xA0;
*(__IO uint8_t *)(PCCARD_IO_SPACE_PRIMARY_ADDR | ATA_STATUS_CMD) = ATA_ERASE_SECTOR_CMD;
/* wait till the PCCARD is ready */
status = *(__IO uint8_t *)(PCCARD_IO_SPACE_PRIMARY_ADDR | ATA_STATUS_CMD_ALTERNATE);
while ((status != PCCARD_STATUS_WRITE_OK) && timeout)
{
status = *(__IO uint8_t *)(PCCARD_IO_SPACE_PRIMARY_ADDR | ATA_STATUS_CMD_ALTERNATE);
timeout--;
}
if (timeout == 0U)
{
*pStatus = PCCARD_TIMEOUT_ERROR;
}
/* Check the PCCARD controller state */
hpccard->State = HAL_PCCARD_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hpccard);
return HAL_OK;
}
/**
* @brief Reset the PCCARD memory
* @param hpccard pointer to a PCCARD_HandleTypeDef structure that contains
* the configuration information for PCCARD module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCCARD_Reset(PCCARD_HandleTypeDef *hpccard)
{
/* Process Locked */
__HAL_LOCK(hpccard);
/* Check the PCCARD controller state */
if (hpccard->State == HAL_PCCARD_STATE_BUSY)
{
return HAL_BUSY;
}
/* Provide a SW reset and Read and verify the:
- PCCard Configuration Option Register at address 0x98000200 --> 0x80
- Card Configuration and Status Register at address 0x98000202 --> 0x00
- Pin Replacement Register at address 0x98000204 --> 0x0C
- Socket and Copy Register at address 0x98000206 --> 0x00
*/
/* Check the PCCARD controller state */
hpccard->State = HAL_PCCARD_STATE_BUSY;
*(__IO uint8_t *)(PCCARD_ATTRIBUTE_SPACE_ADDRESS | ATA_CARD_CONFIGURATION) = 0x01;
/* Check the PCCARD controller state */
hpccard->State = HAL_PCCARD_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hpccard);
return HAL_OK;
}
/**
* @brief This function handles PCCARD device interrupt request.
* @param hpccard pointer to a PCCARD_HandleTypeDef structure that contains
* the configuration information for PCCARD module.
* @retval HAL status
*/
void HAL_PCCARD_IRQHandler(PCCARD_HandleTypeDef *hpccard)
{
/* Check PCCARD interrupt Rising edge flag */
if (__FSMC_PCCARD_GET_FLAG(hpccard->Instance, FSMC_FLAG_RISING_EDGE))
{
/* PCCARD interrupt callback*/
#if (USE_HAL_PCCARD_REGISTER_CALLBACKS == 1)
hpccard->ItCallback(hpccard);
#else
HAL_PCCARD_ITCallback(hpccard);
#endif /* USE_HAL_PCCARD_REGISTER_CALLBACKS */
/* Clear PCCARD interrupt Rising edge pending bit */
__FSMC_PCCARD_CLEAR_FLAG(hpccard->Instance, FSMC_FLAG_RISING_EDGE);
}
/* Check PCCARD interrupt Level flag */
if (__FSMC_PCCARD_GET_FLAG(hpccard->Instance, FSMC_FLAG_LEVEL))
{
/* PCCARD interrupt callback*/
#if (USE_HAL_PCCARD_REGISTER_CALLBACKS == 1)
hpccard->ItCallback(hpccard);
#else
HAL_PCCARD_ITCallback(hpccard);
#endif /* USE_HAL_PCCARD_REGISTER_CALLBACKS */
/* Clear PCCARD interrupt Level pending bit */
__FSMC_PCCARD_CLEAR_FLAG(hpccard->Instance, FSMC_FLAG_LEVEL);
}
/* Check PCCARD interrupt Falling edge flag */
if (__FSMC_PCCARD_GET_FLAG(hpccard->Instance, FSMC_FLAG_FALLING_EDGE))
{
/* PCCARD interrupt callback*/
#if (USE_HAL_PCCARD_REGISTER_CALLBACKS == 1)
hpccard->ItCallback(hpccard);
#else
HAL_PCCARD_ITCallback(hpccard);
#endif /* USE_HAL_PCCARD_REGISTER_CALLBACKS */
/* Clear PCCARD interrupt Falling edge pending bit */
__FSMC_PCCARD_CLEAR_FLAG(hpccard->Instance, FSMC_FLAG_FALLING_EDGE);
}
/* Check PCCARD interrupt FIFO empty flag */
if (__FSMC_PCCARD_GET_FLAG(hpccard->Instance, FSMC_FLAG_FEMPT))
{
/* PCCARD interrupt callback*/
#if (USE_HAL_PCCARD_REGISTER_CALLBACKS == 1)
hpccard->ItCallback(hpccard);
#else
HAL_PCCARD_ITCallback(hpccard);
#endif /* USE_HAL_PCCARD_REGISTER_CALLBACKS */
/* Clear PCCARD interrupt FIFO empty pending bit */
__FSMC_PCCARD_CLEAR_FLAG(hpccard->Instance, FSMC_FLAG_FEMPT);
}
}
/**
* @brief PCCARD interrupt feature callback
* @param hpccard pointer to a PCCARD_HandleTypeDef structure that contains
* the configuration information for PCCARD module.
* @retval None
*/
__weak void HAL_PCCARD_ITCallback(PCCARD_HandleTypeDef *hpccard)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hpccard);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_PCCARD_ITCallback could be implemented in the user file
*/
}
#if (USE_HAL_PCCARD_REGISTER_CALLBACKS == 1)
/**
* @brief Register a User PCCARD Callback
* To be used instead of the weak (surcharged) predefined callback
* @param hpccard : PCCARD handle
* @param CallbackId : ID of the callback to be registered
* This parameter can be one of the following values:
* @arg @ref HAL_PCCARD_MSP_INIT_CB_ID PCCARD MspInit callback ID
* @arg @ref HAL_PCCARD_MSP_DEINIT_CB_ID PCCARD MspDeInit callback ID
* @arg @ref HAL_PCCARD_IT_CB_ID PCCARD IT callback ID
* @param pCallback : pointer to the Callback function
* @retval status
*/
HAL_StatusTypeDef HAL_PCCARD_RegisterCallback(PCCARD_HandleTypeDef *hpccard, HAL_PCCARD_CallbackIDTypeDef CallbackId,
pPCCARD_CallbackTypeDef pCallback)
{
HAL_StatusTypeDef status = HAL_OK;
if (pCallback == NULL)
{
return HAL_ERROR;
}
/* Process locked */
__HAL_LOCK(hpccard);
if (hpccard->State == HAL_PCCARD_STATE_READY)
{
switch (CallbackId)
{
case HAL_PCCARD_MSP_INIT_CB_ID :
hpccard->MspInitCallback = pCallback;
break;
case HAL_PCCARD_MSP_DEINIT_CB_ID :
hpccard->MspDeInitCallback = pCallback;
break;
case HAL_PCCARD_IT_CB_ID :
hpccard->ItCallback = pCallback;
break;
default :
/* update return status */
status = HAL_ERROR;
break;
}
}
else if (hpccard->State == HAL_PCCARD_STATE_RESET)
{
switch (CallbackId)
{
case HAL_PCCARD_MSP_INIT_CB_ID :
hpccard->MspInitCallback = pCallback;
break;
case HAL_PCCARD_MSP_DEINIT_CB_ID :
hpccard->MspDeInitCallback = pCallback;
break;
default :
/* update return status */
status = HAL_ERROR;
break;
}
}
else
{
/* update return status */
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(hpccard);
return status;
}
/**
* @brief Unregister a User PCCARD Callback
* PCCARD Callback is redirected to the weak (surcharged) predefined callback
* @param hpccard : PCCARD handle
* @param CallbackId : ID of the callback to be unregistered
* This parameter can be one of the following values:
* @arg @ref HAL_PCCARD_MSP_INIT_CB_ID PCCARD MspInit callback ID
* @arg @ref HAL_PCCARD_MSP_DEINIT_CB_ID PCCARD MspDeInit callback ID
* @arg @ref HAL_PCCARD_IT_CB_ID PCCARD IT callback ID
* @retval status
*/
HAL_StatusTypeDef HAL_PCCARD_UnRegisterCallback(PCCARD_HandleTypeDef *hpccard, HAL_PCCARD_CallbackIDTypeDef CallbackId)
{
HAL_StatusTypeDef status = HAL_OK;
/* Process locked */
__HAL_LOCK(hpccard);
if (hpccard->State == HAL_PCCARD_STATE_READY)
{
switch (CallbackId)
{
case HAL_PCCARD_MSP_INIT_CB_ID :
hpccard->MspInitCallback = HAL_PCCARD_MspInit;
break;
case HAL_PCCARD_MSP_DEINIT_CB_ID :
hpccard->MspDeInitCallback = HAL_PCCARD_MspDeInit;
break;
case HAL_PCCARD_IT_CB_ID :
hpccard->ItCallback = HAL_PCCARD_ITCallback;
break;
default :
/* update return status */
status = HAL_ERROR;
break;
}
}
else if (hpccard->State == HAL_PCCARD_STATE_RESET)
{
switch (CallbackId)
{
case HAL_PCCARD_MSP_INIT_CB_ID :
hpccard->MspInitCallback = HAL_PCCARD_MspInit;
break;
case HAL_PCCARD_MSP_DEINIT_CB_ID :
hpccard->MspDeInitCallback = HAL_PCCARD_MspDeInit;
break;
default :
/* update return status */
status = HAL_ERROR;
break;
}
}
else
{
/* update return status */
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(hpccard);
return status;
}
#endif /* USE_HAL_PCCARD_REGISTER_CALLBACKS */
/**
* @}
*/
/** @defgroup PCCARD_Exported_Functions_Group3 State functions
* @brief Peripheral State functions
*
@verbatim
==============================================================================
##### PCCARD State functions #####
==============================================================================
[..]
This subsection permits to get in run-time the status of the PCCARD controller
and the data flow.
@endverbatim
* @{
*/
/**
* @brief return the PCCARD controller state
* @param hpccard pointer to a PCCARD_HandleTypeDef structure that contains
* the configuration information for PCCARD module.
* @retval HAL state
*/
HAL_PCCARD_StateTypeDef HAL_PCCARD_GetState(PCCARD_HandleTypeDef *hpccard)
{
return hpccard->State;
}
/**
* @brief Get the compact flash memory status
* @param hpccard pointer to a PCCARD_HandleTypeDef structure that contains
* the configuration information for PCCARD module.
* @retval New status of the PCCARD operation. This parameter can be:
* - CompactFlash_TIMEOUT_ERROR: when the previous operation generate
* a Timeout error
* - CompactFlash_READY: when memory is ready for the next operation
*/
HAL_PCCARD_StatusTypeDef HAL_PCCARD_GetStatus(PCCARD_HandleTypeDef *hpccard)
{
uint32_t timeout = PCCARD_TIMEOUT_STATUS;
uint32_t status_pccard = 0U;
/* Check the PCCARD controller state */
if (hpccard->State == HAL_PCCARD_STATE_BUSY)
{
return HAL_PCCARD_STATUS_ONGOING;
}
status_pccard = *(__IO uint8_t *)(PCCARD_IO_SPACE_PRIMARY_ADDR | ATA_STATUS_CMD_ALTERNATE);
while ((status_pccard == PCCARD_BUSY) && timeout)
{
status_pccard = *(__IO uint8_t *)(PCCARD_IO_SPACE_PRIMARY_ADDR | ATA_STATUS_CMD_ALTERNATE);
timeout--;
}
if (timeout == 0U)
{
status_pccard = PCCARD_TIMEOUT_ERROR;
}
/* Return the operation status */
return (HAL_PCCARD_StatusTypeDef) status_pccard;
}
/**
* @brief Reads the Compact Flash memory status using the Read status command
* @param hpccard pointer to a PCCARD_HandleTypeDef structure that contains
* the configuration information for PCCARD module.
* @retval The status of the Compact Flash memory. This parameter can be:
* - CompactFlash_BUSY: when memory is busy
* - CompactFlash_READY: when memory is ready for the next operation
* - CompactFlash_ERROR: when the previous operation generates error
*/
HAL_PCCARD_StatusTypeDef HAL_PCCARD_ReadStatus(PCCARD_HandleTypeDef *hpccard)
{
uint8_t data = 0U;
uint8_t status_pccard = PCCARD_BUSY;
/* Check the PCCARD controller state */
if (hpccard->State == HAL_PCCARD_STATE_BUSY)
{
return HAL_PCCARD_STATUS_ONGOING;
}
/* Read status operation */
data = *(__IO uint8_t *)(PCCARD_IO_SPACE_PRIMARY_ADDR | ATA_STATUS_CMD_ALTERNATE);
if ((data & PCCARD_TIMEOUT_ERROR) == PCCARD_TIMEOUT_ERROR)
{
status_pccard = PCCARD_TIMEOUT_ERROR;
}
else if ((data & PCCARD_READY) == PCCARD_READY)
{
status_pccard = PCCARD_READY;
}
return (HAL_PCCARD_StatusTypeDef) status_pccard;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#endif /* HAL_PCCARD_MODULE_ENABLED */
/**
* @}
*/
#endif /* FSMC_BANK4 */

View File

@@ -0,0 +1,2720 @@
/**
******************************************************************************
* @file stm32f1xx_hal_pcd.c
* @author MCD Application Team
* @brief PCD HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of the USB Peripheral Controller:
* + Initialization and de-initialization functions
* + IO operation functions
* + Peripheral Control functions
* + Peripheral State functions
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
==============================================================================
##### How to use this driver #####
==============================================================================
[..]
The PCD HAL driver can be used as follows:
(#) Declare a PCD_HandleTypeDef handle structure, for example:
PCD_HandleTypeDef hpcd;
(#) Fill parameters of Init structure in HCD handle
(#) Call HAL_PCD_Init() API to initialize the PCD peripheral (Core, Device core, ...)
(#) Initialize the PCD low level resources through the HAL_PCD_MspInit() API:
(##) Enable the PCD/USB Low Level interface clock using
(+++) __HAL_RCC_USB_CLK_ENABLE(); For USB Device FS peripheral
(+++) __HAL_RCC_USB_OTG_FS_CLK_ENABLE();
(##) Initialize the related GPIO clocks
(##) Configure PCD pin-out
(##) Configure PCD NVIC interrupt
(#)Associate the Upper USB device stack to the HAL PCD Driver:
(##) hpcd.pData = pdev;
(#)Enable PCD transmission and reception:
(##) HAL_PCD_Start();
@endverbatim
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
/** @defgroup PCD PCD
* @brief PCD HAL module driver
* @{
*/
#ifdef HAL_PCD_MODULE_ENABLED
#if defined (USB) || defined (USB_OTG_FS)
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/** @defgroup PCD_Private_Macros PCD Private Macros
* @{
*/
#define PCD_MIN(a, b) (((a) < (b)) ? (a) : (b))
#define PCD_MAX(a, b) (((a) > (b)) ? (a) : (b))
/**
* @}
*/
/* Private functions prototypes ----------------------------------------------*/
/** @defgroup PCD_Private_Functions PCD Private Functions
* @{
*/
#if defined (USB_OTG_FS)
static HAL_StatusTypeDef PCD_WriteEmptyTxFifo(PCD_HandleTypeDef *hpcd, uint32_t epnum);
static HAL_StatusTypeDef PCD_EP_OutXfrComplete_int(PCD_HandleTypeDef *hpcd, uint32_t epnum);
static HAL_StatusTypeDef PCD_EP_OutSetupPacket_int(PCD_HandleTypeDef *hpcd, uint32_t epnum);
#endif /* defined (USB_OTG_FS) */
#if defined (USB)
static HAL_StatusTypeDef PCD_EP_ISR_Handler(PCD_HandleTypeDef *hpcd);
#if (USE_USB_DOUBLE_BUFFER == 1U)
static HAL_StatusTypeDef HAL_PCD_EP_DB_Transmit(PCD_HandleTypeDef *hpcd, PCD_EPTypeDef *ep, uint16_t wEPVal);
static uint16_t HAL_PCD_EP_DB_Receive(PCD_HandleTypeDef *hpcd, PCD_EPTypeDef *ep, uint16_t wEPVal);
#endif /* (USE_USB_DOUBLE_BUFFER == 1U) */
#endif /* defined (USB) */
/**
* @}
*/
/* Exported functions --------------------------------------------------------*/
/** @defgroup PCD_Exported_Functions PCD Exported Functions
* @{
*/
/** @defgroup PCD_Exported_Functions_Group1 Initialization and de-initialization functions
* @brief Initialization and Configuration functions
*
@verbatim
===============================================================================
##### Initialization and de-initialization functions #####
===============================================================================
[..] This section provides functions allowing to:
@endverbatim
* @{
*/
/**
* @brief Initializes the PCD according to the specified
* parameters in the PCD_InitTypeDef and initialize the associated handle.
* @param hpcd PCD handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCD_Init(PCD_HandleTypeDef *hpcd)
{
uint8_t i;
/* Check the PCD handle allocation */
if (hpcd == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_PCD_ALL_INSTANCE(hpcd->Instance));
if (hpcd->State == HAL_PCD_STATE_RESET)
{
/* Allocate lock resource and initialize it */
hpcd->Lock = HAL_UNLOCKED;
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
hpcd->SOFCallback = HAL_PCD_SOFCallback;
hpcd->SetupStageCallback = HAL_PCD_SetupStageCallback;
hpcd->ResetCallback = HAL_PCD_ResetCallback;
hpcd->SuspendCallback = HAL_PCD_SuspendCallback;
hpcd->ResumeCallback = HAL_PCD_ResumeCallback;
hpcd->ConnectCallback = HAL_PCD_ConnectCallback;
hpcd->DisconnectCallback = HAL_PCD_DisconnectCallback;
hpcd->DataOutStageCallback = HAL_PCD_DataOutStageCallback;
hpcd->DataInStageCallback = HAL_PCD_DataInStageCallback;
hpcd->ISOOUTIncompleteCallback = HAL_PCD_ISOOUTIncompleteCallback;
hpcd->ISOINIncompleteCallback = HAL_PCD_ISOINIncompleteCallback;
if (hpcd->MspInitCallback == NULL)
{
hpcd->MspInitCallback = HAL_PCD_MspInit;
}
/* Init the low level hardware */
hpcd->MspInitCallback(hpcd);
#else
/* Init the low level hardware : GPIO, CLOCK, NVIC... */
HAL_PCD_MspInit(hpcd);
#endif /* (USE_HAL_PCD_REGISTER_CALLBACKS) */
}
hpcd->State = HAL_PCD_STATE_BUSY;
/* Disable DMA mode for FS instance */
hpcd->Init.dma_enable = 0U;
/* Disable the Interrupts */
__HAL_PCD_DISABLE(hpcd);
/*Init the Core (common init.) */
if (USB_CoreInit(hpcd->Instance, hpcd->Init) != HAL_OK)
{
hpcd->State = HAL_PCD_STATE_ERROR;
return HAL_ERROR;
}
/* Force Device Mode */
if (USB_SetCurrentMode(hpcd->Instance, USB_DEVICE_MODE) != HAL_OK)
{
hpcd->State = HAL_PCD_STATE_ERROR;
return HAL_ERROR;
}
/* Init endpoints structures */
for (i = 0U; i < hpcd->Init.dev_endpoints; i++)
{
/* Init ep structure */
hpcd->IN_ep[i].is_in = 1U;
hpcd->IN_ep[i].num = i;
#if defined (USB_OTG_FS)
hpcd->IN_ep[i].tx_fifo_num = i;
#endif /* defined (USB_OTG_FS) */
/* Control until ep is activated */
hpcd->IN_ep[i].type = EP_TYPE_CTRL;
hpcd->IN_ep[i].maxpacket = 0U;
hpcd->IN_ep[i].xfer_buff = 0U;
hpcd->IN_ep[i].xfer_len = 0U;
}
for (i = 0U; i < hpcd->Init.dev_endpoints; i++)
{
hpcd->OUT_ep[i].is_in = 0U;
hpcd->OUT_ep[i].num = i;
/* Control until ep is activated */
hpcd->OUT_ep[i].type = EP_TYPE_CTRL;
hpcd->OUT_ep[i].maxpacket = 0U;
hpcd->OUT_ep[i].xfer_buff = 0U;
hpcd->OUT_ep[i].xfer_len = 0U;
}
/* Init Device */
if (USB_DevInit(hpcd->Instance, hpcd->Init) != HAL_OK)
{
hpcd->State = HAL_PCD_STATE_ERROR;
return HAL_ERROR;
}
hpcd->USB_Address = 0U;
hpcd->State = HAL_PCD_STATE_READY;
(void)USB_DevDisconnect(hpcd->Instance);
return HAL_OK;
}
/**
* @brief DeInitializes the PCD peripheral.
* @param hpcd PCD handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCD_DeInit(PCD_HandleTypeDef *hpcd)
{
/* Check the PCD handle allocation */
if (hpcd == NULL)
{
return HAL_ERROR;
}
hpcd->State = HAL_PCD_STATE_BUSY;
/* Stop Device */
if (USB_StopDevice(hpcd->Instance) != HAL_OK)
{
return HAL_ERROR;
}
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
if (hpcd->MspDeInitCallback == NULL)
{
hpcd->MspDeInitCallback = HAL_PCD_MspDeInit; /* Legacy weak MspDeInit */
}
/* DeInit the low level hardware */
hpcd->MspDeInitCallback(hpcd);
#else
/* DeInit the low level hardware: CLOCK, NVIC.*/
HAL_PCD_MspDeInit(hpcd);
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
hpcd->State = HAL_PCD_STATE_RESET;
return HAL_OK;
}
/**
* @brief Initializes the PCD MSP.
* @param hpcd PCD handle
* @retval None
*/
__weak void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hpcd);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_PCD_MspInit could be implemented in the user file
*/
}
/**
* @brief DeInitializes PCD MSP.
* @param hpcd PCD handle
* @retval None
*/
__weak void HAL_PCD_MspDeInit(PCD_HandleTypeDef *hpcd)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hpcd);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_PCD_MspDeInit could be implemented in the user file
*/
}
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
/**
* @brief Register a User USB PCD Callback
* To be used instead of the weak predefined callback
* @param hpcd USB PCD handle
* @param CallbackID ID of the callback to be registered
* This parameter can be one of the following values:
* @arg @ref HAL_PCD_SOF_CB_ID USB PCD SOF callback ID
* @arg @ref HAL_PCD_SETUPSTAGE_CB_ID USB PCD Setup callback ID
* @arg @ref HAL_PCD_RESET_CB_ID USB PCD Reset callback ID
* @arg @ref HAL_PCD_SUSPEND_CB_ID USB PCD Suspend callback ID
* @arg @ref HAL_PCD_RESUME_CB_ID USB PCD Resume callback ID
* @arg @ref HAL_PCD_CONNECT_CB_ID USB PCD Connect callback ID
* @arg @ref HAL_PCD_DISCONNECT_CB_ID USB PCD Disconnect callback ID
* @arg @ref HAL_PCD_MSPINIT_CB_ID MspDeInit callback ID
* @arg @ref HAL_PCD_MSPDEINIT_CB_ID MspDeInit callback ID
* @param pCallback pointer to the Callback function
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCD_RegisterCallback(PCD_HandleTypeDef *hpcd,
HAL_PCD_CallbackIDTypeDef CallbackID,
pPCD_CallbackTypeDef pCallback)
{
HAL_StatusTypeDef status = HAL_OK;
if (pCallback == NULL)
{
/* Update the error code */
hpcd->ErrorCode |= HAL_PCD_ERROR_INVALID_CALLBACK;
return HAL_ERROR;
}
/* Process locked */
__HAL_LOCK(hpcd);
if (hpcd->State == HAL_PCD_STATE_READY)
{
switch (CallbackID)
{
case HAL_PCD_SOF_CB_ID :
hpcd->SOFCallback = pCallback;
break;
case HAL_PCD_SETUPSTAGE_CB_ID :
hpcd->SetupStageCallback = pCallback;
break;
case HAL_PCD_RESET_CB_ID :
hpcd->ResetCallback = pCallback;
break;
case HAL_PCD_SUSPEND_CB_ID :
hpcd->SuspendCallback = pCallback;
break;
case HAL_PCD_RESUME_CB_ID :
hpcd->ResumeCallback = pCallback;
break;
case HAL_PCD_CONNECT_CB_ID :
hpcd->ConnectCallback = pCallback;
break;
case HAL_PCD_DISCONNECT_CB_ID :
hpcd->DisconnectCallback = pCallback;
break;
case HAL_PCD_MSPINIT_CB_ID :
hpcd->MspInitCallback = pCallback;
break;
case HAL_PCD_MSPDEINIT_CB_ID :
hpcd->MspDeInitCallback = pCallback;
break;
default :
/* Update the error code */
hpcd->ErrorCode |= HAL_PCD_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else if (hpcd->State == HAL_PCD_STATE_RESET)
{
switch (CallbackID)
{
case HAL_PCD_MSPINIT_CB_ID :
hpcd->MspInitCallback = pCallback;
break;
case HAL_PCD_MSPDEINIT_CB_ID :
hpcd->MspDeInitCallback = pCallback;
break;
default :
/* Update the error code */
hpcd->ErrorCode |= HAL_PCD_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else
{
/* Update the error code */
hpcd->ErrorCode |= HAL_PCD_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(hpcd);
return status;
}
/**
* @brief Unregister an USB PCD Callback
* USB PCD callback is redirected to the weak predefined callback
* @param hpcd USB PCD handle
* @param CallbackID ID of the callback to be unregistered
* This parameter can be one of the following values:
* @arg @ref HAL_PCD_SOF_CB_ID USB PCD SOF callback ID
* @arg @ref HAL_PCD_SETUPSTAGE_CB_ID USB PCD Setup callback ID
* @arg @ref HAL_PCD_RESET_CB_ID USB PCD Reset callback ID
* @arg @ref HAL_PCD_SUSPEND_CB_ID USB PCD Suspend callback ID
* @arg @ref HAL_PCD_RESUME_CB_ID USB PCD Resume callback ID
* @arg @ref HAL_PCD_CONNECT_CB_ID USB PCD Connect callback ID
* @arg @ref HAL_PCD_DISCONNECT_CB_ID USB PCD Disconnect callback ID
* @arg @ref HAL_PCD_MSPINIT_CB_ID MspDeInit callback ID
* @arg @ref HAL_PCD_MSPDEINIT_CB_ID MspDeInit callback ID
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCD_UnRegisterCallback(PCD_HandleTypeDef *hpcd, HAL_PCD_CallbackIDTypeDef CallbackID)
{
HAL_StatusTypeDef status = HAL_OK;
/* Process locked */
__HAL_LOCK(hpcd);
/* Setup Legacy weak Callbacks */
if (hpcd->State == HAL_PCD_STATE_READY)
{
switch (CallbackID)
{
case HAL_PCD_SOF_CB_ID :
hpcd->SOFCallback = HAL_PCD_SOFCallback;
break;
case HAL_PCD_SETUPSTAGE_CB_ID :
hpcd->SetupStageCallback = HAL_PCD_SetupStageCallback;
break;
case HAL_PCD_RESET_CB_ID :
hpcd->ResetCallback = HAL_PCD_ResetCallback;
break;
case HAL_PCD_SUSPEND_CB_ID :
hpcd->SuspendCallback = HAL_PCD_SuspendCallback;
break;
case HAL_PCD_RESUME_CB_ID :
hpcd->ResumeCallback = HAL_PCD_ResumeCallback;
break;
case HAL_PCD_CONNECT_CB_ID :
hpcd->ConnectCallback = HAL_PCD_ConnectCallback;
break;
case HAL_PCD_DISCONNECT_CB_ID :
hpcd->DisconnectCallback = HAL_PCD_DisconnectCallback;
break;
case HAL_PCD_MSPINIT_CB_ID :
hpcd->MspInitCallback = HAL_PCD_MspInit;
break;
case HAL_PCD_MSPDEINIT_CB_ID :
hpcd->MspDeInitCallback = HAL_PCD_MspDeInit;
break;
default :
/* Update the error code */
hpcd->ErrorCode |= HAL_PCD_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else if (hpcd->State == HAL_PCD_STATE_RESET)
{
switch (CallbackID)
{
case HAL_PCD_MSPINIT_CB_ID :
hpcd->MspInitCallback = HAL_PCD_MspInit;
break;
case HAL_PCD_MSPDEINIT_CB_ID :
hpcd->MspDeInitCallback = HAL_PCD_MspDeInit;
break;
default :
/* Update the error code */
hpcd->ErrorCode |= HAL_PCD_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else
{
/* Update the error code */
hpcd->ErrorCode |= HAL_PCD_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(hpcd);
return status;
}
/**
* @brief Register USB PCD Data OUT Stage Callback
* To be used instead of the weak HAL_PCD_DataOutStageCallback() predefined callback
* @param hpcd PCD handle
* @param pCallback pointer to the USB PCD Data OUT Stage Callback function
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCD_RegisterDataOutStageCallback(PCD_HandleTypeDef *hpcd,
pPCD_DataOutStageCallbackTypeDef pCallback)
{
HAL_StatusTypeDef status = HAL_OK;
if (pCallback == NULL)
{
/* Update the error code */
hpcd->ErrorCode |= HAL_PCD_ERROR_INVALID_CALLBACK;
return HAL_ERROR;
}
/* Process locked */
__HAL_LOCK(hpcd);
if (hpcd->State == HAL_PCD_STATE_READY)
{
hpcd->DataOutStageCallback = pCallback;
}
else
{
/* Update the error code */
hpcd->ErrorCode |= HAL_PCD_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(hpcd);
return status;
}
/**
* @brief Unregister the USB PCD Data OUT Stage Callback
* USB PCD Data OUT Stage Callback is redirected to the weak HAL_PCD_DataOutStageCallback() predefined callback
* @param hpcd PCD handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCD_UnRegisterDataOutStageCallback(PCD_HandleTypeDef *hpcd)
{
HAL_StatusTypeDef status = HAL_OK;
/* Process locked */
__HAL_LOCK(hpcd);
if (hpcd->State == HAL_PCD_STATE_READY)
{
hpcd->DataOutStageCallback = HAL_PCD_DataOutStageCallback; /* Legacy weak DataOutStageCallback */
}
else
{
/* Update the error code */
hpcd->ErrorCode |= HAL_PCD_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(hpcd);
return status;
}
/**
* @brief Register USB PCD Data IN Stage Callback
* To be used instead of the weak HAL_PCD_DataInStageCallback() predefined callback
* @param hpcd PCD handle
* @param pCallback pointer to the USB PCD Data IN Stage Callback function
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCD_RegisterDataInStageCallback(PCD_HandleTypeDef *hpcd,
pPCD_DataInStageCallbackTypeDef pCallback)
{
HAL_StatusTypeDef status = HAL_OK;
if (pCallback == NULL)
{
/* Update the error code */
hpcd->ErrorCode |= HAL_PCD_ERROR_INVALID_CALLBACK;
return HAL_ERROR;
}
/* Process locked */
__HAL_LOCK(hpcd);
if (hpcd->State == HAL_PCD_STATE_READY)
{
hpcd->DataInStageCallback = pCallback;
}
else
{
/* Update the error code */
hpcd->ErrorCode |= HAL_PCD_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(hpcd);
return status;
}
/**
* @brief Unregister the USB PCD Data IN Stage Callback
* USB PCD Data OUT Stage Callback is redirected to the weak HAL_PCD_DataInStageCallback() predefined callback
* @param hpcd PCD handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCD_UnRegisterDataInStageCallback(PCD_HandleTypeDef *hpcd)
{
HAL_StatusTypeDef status = HAL_OK;
/* Process locked */
__HAL_LOCK(hpcd);
if (hpcd->State == HAL_PCD_STATE_READY)
{
hpcd->DataInStageCallback = HAL_PCD_DataInStageCallback; /* Legacy weak DataInStageCallback */
}
else
{
/* Update the error code */
hpcd->ErrorCode |= HAL_PCD_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(hpcd);
return status;
}
/**
* @brief Register USB PCD Iso OUT incomplete Callback
* To be used instead of the weak HAL_PCD_ISOOUTIncompleteCallback() predefined callback
* @param hpcd PCD handle
* @param pCallback pointer to the USB PCD Iso OUT incomplete Callback function
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCD_RegisterIsoOutIncpltCallback(PCD_HandleTypeDef *hpcd,
pPCD_IsoOutIncpltCallbackTypeDef pCallback)
{
HAL_StatusTypeDef status = HAL_OK;
if (pCallback == NULL)
{
/* Update the error code */
hpcd->ErrorCode |= HAL_PCD_ERROR_INVALID_CALLBACK;
return HAL_ERROR;
}
/* Process locked */
__HAL_LOCK(hpcd);
if (hpcd->State == HAL_PCD_STATE_READY)
{
hpcd->ISOOUTIncompleteCallback = pCallback;
}
else
{
/* Update the error code */
hpcd->ErrorCode |= HAL_PCD_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(hpcd);
return status;
}
/**
* @brief Unregister the USB PCD Iso OUT incomplete Callback
* USB PCD Iso OUT incomplete Callback is redirected
* to the weak HAL_PCD_ISOOUTIncompleteCallback() predefined callback
* @param hpcd PCD handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCD_UnRegisterIsoOutIncpltCallback(PCD_HandleTypeDef *hpcd)
{
HAL_StatusTypeDef status = HAL_OK;
/* Process locked */
__HAL_LOCK(hpcd);
if (hpcd->State == HAL_PCD_STATE_READY)
{
hpcd->ISOOUTIncompleteCallback = HAL_PCD_ISOOUTIncompleteCallback; /* Legacy weak ISOOUTIncompleteCallback */
}
else
{
/* Update the error code */
hpcd->ErrorCode |= HAL_PCD_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(hpcd);
return status;
}
/**
* @brief Register USB PCD Iso IN incomplete Callback
* To be used instead of the weak HAL_PCD_ISOINIncompleteCallback() predefined callback
* @param hpcd PCD handle
* @param pCallback pointer to the USB PCD Iso IN incomplete Callback function
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCD_RegisterIsoInIncpltCallback(PCD_HandleTypeDef *hpcd,
pPCD_IsoInIncpltCallbackTypeDef pCallback)
{
HAL_StatusTypeDef status = HAL_OK;
if (pCallback == NULL)
{
/* Update the error code */
hpcd->ErrorCode |= HAL_PCD_ERROR_INVALID_CALLBACK;
return HAL_ERROR;
}
/* Process locked */
__HAL_LOCK(hpcd);
if (hpcd->State == HAL_PCD_STATE_READY)
{
hpcd->ISOINIncompleteCallback = pCallback;
}
else
{
/* Update the error code */
hpcd->ErrorCode |= HAL_PCD_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(hpcd);
return status;
}
/**
* @brief Unregister the USB PCD Iso IN incomplete Callback
* USB PCD Iso IN incomplete Callback is redirected
* to the weak HAL_PCD_ISOINIncompleteCallback() predefined callback
* @param hpcd PCD handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCD_UnRegisterIsoInIncpltCallback(PCD_HandleTypeDef *hpcd)
{
HAL_StatusTypeDef status = HAL_OK;
/* Process locked */
__HAL_LOCK(hpcd);
if (hpcd->State == HAL_PCD_STATE_READY)
{
hpcd->ISOINIncompleteCallback = HAL_PCD_ISOINIncompleteCallback; /* Legacy weak ISOINIncompleteCallback */
}
else
{
/* Update the error code */
hpcd->ErrorCode |= HAL_PCD_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(hpcd);
return status;
}
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
/**
* @}
*/
/** @defgroup PCD_Exported_Functions_Group2 Input and Output operation functions
* @brief Data transfers functions
*
@verbatim
===============================================================================
##### IO operation functions #####
===============================================================================
[..]
This subsection provides a set of functions allowing to manage the PCD data
transfers.
@endverbatim
* @{
*/
/**
* @brief Start the USB device
* @param hpcd PCD handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCD_Start(PCD_HandleTypeDef *hpcd)
{
__HAL_LOCK(hpcd);
__HAL_PCD_ENABLE(hpcd);
#if defined (USB)
HAL_PCDEx_SetConnectionState(hpcd, 1U);
#endif /* defined (USB) */
(void)USB_DevConnect(hpcd->Instance);
__HAL_UNLOCK(hpcd);
return HAL_OK;
}
/**
* @brief Stop the USB device.
* @param hpcd PCD handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCD_Stop(PCD_HandleTypeDef *hpcd)
{
__HAL_LOCK(hpcd);
__HAL_PCD_DISABLE(hpcd);
#if defined (USB)
HAL_PCDEx_SetConnectionState(hpcd, 0U);
#endif /* defined (USB) */
(void)USB_DevDisconnect(hpcd->Instance);
#if defined (USB_OTG_FS)
(void)USB_FlushTxFifo(hpcd->Instance, 0x10U);
#endif /* defined (USB_OTG_FS) */
__HAL_UNLOCK(hpcd);
return HAL_OK;
}
#if defined (USB_OTG_FS)
/**
* @brief Handles PCD interrupt request.
* @param hpcd PCD handle
* @retval HAL status
*/
void HAL_PCD_IRQHandler(PCD_HandleTypeDef *hpcd)
{
USB_OTG_GlobalTypeDef *USBx = hpcd->Instance;
uint32_t USBx_BASE = (uint32_t)USBx;
USB_OTG_EPTypeDef *ep;
uint32_t i;
uint32_t ep_intr;
uint32_t epint;
uint32_t epnum;
uint32_t fifoemptymsk;
uint32_t RegVal;
/* ensure that we are in device mode */
if (USB_GetMode(hpcd->Instance) == USB_OTG_MODE_DEVICE)
{
/* avoid spurious interrupt */
if (__HAL_PCD_IS_INVALID_INTERRUPT(hpcd))
{
return;
}
/* store current frame number */
hpcd->FrameNumber = (USBx_DEVICE->DSTS & USB_OTG_DSTS_FNSOF_Msk) >> USB_OTG_DSTS_FNSOF_Pos;
if (__HAL_PCD_GET_FLAG(hpcd, USB_OTG_GINTSTS_MMIS))
{
/* incorrect mode, acknowledge the interrupt */
__HAL_PCD_CLEAR_FLAG(hpcd, USB_OTG_GINTSTS_MMIS);
}
/* Handle RxQLevel Interrupt */
if (__HAL_PCD_GET_FLAG(hpcd, USB_OTG_GINTSTS_RXFLVL))
{
USB_MASK_INTERRUPT(hpcd->Instance, USB_OTG_GINTSTS_RXFLVL);
RegVal = USBx->GRXSTSP;
ep = &hpcd->OUT_ep[RegVal & USB_OTG_GRXSTSP_EPNUM];
if (((RegVal & USB_OTG_GRXSTSP_PKTSTS) >> 17) == STS_DATA_UPDT)
{
if ((RegVal & USB_OTG_GRXSTSP_BCNT) != 0U)
{
(void)USB_ReadPacket(USBx, ep->xfer_buff,
(uint16_t)((RegVal & USB_OTG_GRXSTSP_BCNT) >> 4));
ep->xfer_buff += (RegVal & USB_OTG_GRXSTSP_BCNT) >> 4;
ep->xfer_count += (RegVal & USB_OTG_GRXSTSP_BCNT) >> 4;
}
}
else if (((RegVal & USB_OTG_GRXSTSP_PKTSTS) >> 17) == STS_SETUP_UPDT)
{
(void)USB_ReadPacket(USBx, (uint8_t *)hpcd->Setup, 8U);
ep->xfer_count += (RegVal & USB_OTG_GRXSTSP_BCNT) >> 4;
}
else
{
/* ... */
}
USB_UNMASK_INTERRUPT(hpcd->Instance, USB_OTG_GINTSTS_RXFLVL);
}
if (__HAL_PCD_GET_FLAG(hpcd, USB_OTG_GINTSTS_OEPINT))
{
epnum = 0U;
/* Read in the device interrupt bits */
ep_intr = USB_ReadDevAllOutEpInterrupt(hpcd->Instance);
while (ep_intr != 0U)
{
if ((ep_intr & 0x1U) != 0U)
{
epint = USB_ReadDevOutEPInterrupt(hpcd->Instance, (uint8_t)epnum);
if ((epint & USB_OTG_DOEPINT_XFRC) == USB_OTG_DOEPINT_XFRC)
{
CLEAR_OUT_EP_INTR(epnum, USB_OTG_DOEPINT_XFRC);
(void)PCD_EP_OutXfrComplete_int(hpcd, epnum);
}
if ((epint & USB_OTG_DOEPINT_STUP) == USB_OTG_DOEPINT_STUP)
{
CLEAR_OUT_EP_INTR(epnum, USB_OTG_DOEPINT_STUP);
/* Class B setup phase done for previous decoded setup */
(void)PCD_EP_OutSetupPacket_int(hpcd, epnum);
}
if ((epint & USB_OTG_DOEPINT_OTEPDIS) == USB_OTG_DOEPINT_OTEPDIS)
{
CLEAR_OUT_EP_INTR(epnum, USB_OTG_DOEPINT_OTEPDIS);
}
/* Clear OUT Endpoint disable interrupt */
if ((epint & USB_OTG_DOEPINT_EPDISD) == USB_OTG_DOEPINT_EPDISD)
{
if ((USBx->GINTSTS & USB_OTG_GINTSTS_BOUTNAKEFF) == USB_OTG_GINTSTS_BOUTNAKEFF)
{
USBx_DEVICE->DCTL |= USB_OTG_DCTL_CGONAK;
}
ep = &hpcd->OUT_ep[epnum];
if (ep->is_iso_incomplete == 1U)
{
ep->is_iso_incomplete = 0U;
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
hpcd->ISOOUTIncompleteCallback(hpcd, (uint8_t)epnum);
#else
HAL_PCD_ISOOUTIncompleteCallback(hpcd, (uint8_t)epnum);
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
}
CLEAR_OUT_EP_INTR(epnum, USB_OTG_DOEPINT_EPDISD);
}
/* Clear Status Phase Received interrupt */
if ((epint & USB_OTG_DOEPINT_OTEPSPR) == USB_OTG_DOEPINT_OTEPSPR)
{
CLEAR_OUT_EP_INTR(epnum, USB_OTG_DOEPINT_OTEPSPR);
}
/* Clear OUT NAK interrupt */
if ((epint & USB_OTG_DOEPINT_NAK) == USB_OTG_DOEPINT_NAK)
{
CLEAR_OUT_EP_INTR(epnum, USB_OTG_DOEPINT_NAK);
}
}
epnum++;
ep_intr >>= 1U;
}
}
if (__HAL_PCD_GET_FLAG(hpcd, USB_OTG_GINTSTS_IEPINT))
{
/* Read in the device interrupt bits */
ep_intr = USB_ReadDevAllInEpInterrupt(hpcd->Instance);
epnum = 0U;
while (ep_intr != 0U)
{
if ((ep_intr & 0x1U) != 0U) /* In ITR */
{
epint = USB_ReadDevInEPInterrupt(hpcd->Instance, (uint8_t)epnum);
if ((epint & USB_OTG_DIEPINT_XFRC) == USB_OTG_DIEPINT_XFRC)
{
fifoemptymsk = (uint32_t)(0x1UL << (epnum & EP_ADDR_MSK));
USBx_DEVICE->DIEPEMPMSK &= ~fifoemptymsk;
CLEAR_IN_EP_INTR(epnum, USB_OTG_DIEPINT_XFRC);
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
hpcd->DataInStageCallback(hpcd, (uint8_t)epnum);
#else
HAL_PCD_DataInStageCallback(hpcd, (uint8_t)epnum);
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
}
if ((epint & USB_OTG_DIEPINT_TOC) == USB_OTG_DIEPINT_TOC)
{
CLEAR_IN_EP_INTR(epnum, USB_OTG_DIEPINT_TOC);
}
if ((epint & USB_OTG_DIEPINT_ITTXFE) == USB_OTG_DIEPINT_ITTXFE)
{
CLEAR_IN_EP_INTR(epnum, USB_OTG_DIEPINT_ITTXFE);
}
if ((epint & USB_OTG_DIEPINT_INEPNE) == USB_OTG_DIEPINT_INEPNE)
{
CLEAR_IN_EP_INTR(epnum, USB_OTG_DIEPINT_INEPNE);
}
if ((epint & USB_OTG_DIEPINT_EPDISD) == USB_OTG_DIEPINT_EPDISD)
{
(void)USB_FlushTxFifo(USBx, epnum);
ep = &hpcd->IN_ep[epnum];
if (ep->is_iso_incomplete == 1U)
{
ep->is_iso_incomplete = 0U;
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
hpcd->ISOINIncompleteCallback(hpcd, (uint8_t)epnum);
#else
HAL_PCD_ISOINIncompleteCallback(hpcd, (uint8_t)epnum);
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
}
CLEAR_IN_EP_INTR(epnum, USB_OTG_DIEPINT_EPDISD);
}
if ((epint & USB_OTG_DIEPINT_TXFE) == USB_OTG_DIEPINT_TXFE)
{
(void)PCD_WriteEmptyTxFifo(hpcd, epnum);
}
}
epnum++;
ep_intr >>= 1U;
}
}
/* Handle Resume Interrupt */
if (__HAL_PCD_GET_FLAG(hpcd, USB_OTG_GINTSTS_WKUINT))
{
/* Clear the Remote Wake-up Signaling */
USBx_DEVICE->DCTL &= ~USB_OTG_DCTL_RWUSIG;
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
hpcd->ResumeCallback(hpcd);
#else
HAL_PCD_ResumeCallback(hpcd);
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
__HAL_PCD_CLEAR_FLAG(hpcd, USB_OTG_GINTSTS_WKUINT);
}
/* Handle Suspend Interrupt */
if (__HAL_PCD_GET_FLAG(hpcd, USB_OTG_GINTSTS_USBSUSP))
{
if ((USBx_DEVICE->DSTS & USB_OTG_DSTS_SUSPSTS) == USB_OTG_DSTS_SUSPSTS)
{
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
hpcd->SuspendCallback(hpcd);
#else
HAL_PCD_SuspendCallback(hpcd);
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
}
__HAL_PCD_CLEAR_FLAG(hpcd, USB_OTG_GINTSTS_USBSUSP);
}
/* Handle Reset Interrupt */
if (__HAL_PCD_GET_FLAG(hpcd, USB_OTG_GINTSTS_USBRST))
{
USBx_DEVICE->DCTL &= ~USB_OTG_DCTL_RWUSIG;
(void)USB_FlushTxFifo(hpcd->Instance, 0x10U);
for (i = 0U; i < hpcd->Init.dev_endpoints; i++)
{
USBx_INEP(i)->DIEPINT = 0xFB7FU;
USBx_INEP(i)->DIEPCTL &= ~USB_OTG_DIEPCTL_STALL;
USBx_OUTEP(i)->DOEPINT = 0xFB7FU;
USBx_OUTEP(i)->DOEPCTL &= ~USB_OTG_DOEPCTL_STALL;
USBx_OUTEP(i)->DOEPCTL |= USB_OTG_DOEPCTL_SNAK;
}
USBx_DEVICE->DAINTMSK |= 0x10001U;
if (hpcd->Init.use_dedicated_ep1 != 0U)
{
USBx_DEVICE->DOUTEP1MSK |= USB_OTG_DOEPMSK_STUPM |
USB_OTG_DOEPMSK_XFRCM |
USB_OTG_DOEPMSK_EPDM;
USBx_DEVICE->DINEP1MSK |= USB_OTG_DIEPMSK_TOM |
USB_OTG_DIEPMSK_XFRCM |
USB_OTG_DIEPMSK_EPDM;
}
else
{
USBx_DEVICE->DOEPMSK |= USB_OTG_DOEPMSK_STUPM |
USB_OTG_DOEPMSK_XFRCM |
USB_OTG_DOEPMSK_EPDM |
USB_OTG_DOEPMSK_OTEPSPRM |
USB_OTG_DOEPMSK_NAKM;
USBx_DEVICE->DIEPMSK |= USB_OTG_DIEPMSK_TOM |
USB_OTG_DIEPMSK_XFRCM |
USB_OTG_DIEPMSK_EPDM;
}
/* Set Default Address to 0 */
USBx_DEVICE->DCFG &= ~USB_OTG_DCFG_DAD;
/* setup EP0 to receive SETUP packets */
(void)USB_EP0_OutStart(hpcd->Instance, (uint8_t *)hpcd->Setup);
__HAL_PCD_CLEAR_FLAG(hpcd, USB_OTG_GINTSTS_USBRST);
}
/* Handle Enumeration done Interrupt */
if (__HAL_PCD_GET_FLAG(hpcd, USB_OTG_GINTSTS_ENUMDNE))
{
(void)USB_ActivateSetup(hpcd->Instance);
hpcd->Init.speed = USB_GetDevSpeed(hpcd->Instance);
/* Set USB Turnaround time */
(void)USB_SetTurnaroundTime(hpcd->Instance,
HAL_RCC_GetHCLKFreq(),
(uint8_t)hpcd->Init.speed);
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
hpcd->ResetCallback(hpcd);
#else
HAL_PCD_ResetCallback(hpcd);
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
__HAL_PCD_CLEAR_FLAG(hpcd, USB_OTG_GINTSTS_ENUMDNE);
}
/* Handle SOF Interrupt */
if (__HAL_PCD_GET_FLAG(hpcd, USB_OTG_GINTSTS_SOF))
{
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
hpcd->SOFCallback(hpcd);
#else
HAL_PCD_SOFCallback(hpcd);
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
__HAL_PCD_CLEAR_FLAG(hpcd, USB_OTG_GINTSTS_SOF);
}
/* Handle Global OUT NAK effective Interrupt */
if (__HAL_PCD_GET_FLAG(hpcd, USB_OTG_GINTSTS_BOUTNAKEFF))
{
USBx->GINTMSK &= ~USB_OTG_GINTMSK_GONAKEFFM;
for (epnum = 1U; epnum < hpcd->Init.dev_endpoints; epnum++)
{
if (hpcd->OUT_ep[epnum].is_iso_incomplete == 1U)
{
/* Abort current transaction and disable the EP */
(void)HAL_PCD_EP_Abort(hpcd, (uint8_t)epnum);
}
}
}
/* Handle Incomplete ISO IN Interrupt */
if (__HAL_PCD_GET_FLAG(hpcd, USB_OTG_GINTSTS_IISOIXFR))
{
for (epnum = 1U; epnum < hpcd->Init.dev_endpoints; epnum++)
{
RegVal = USBx_INEP(epnum)->DIEPCTL;
if ((hpcd->IN_ep[epnum].type == EP_TYPE_ISOC) &&
((RegVal & USB_OTG_DIEPCTL_EPENA) == USB_OTG_DIEPCTL_EPENA))
{
hpcd->IN_ep[epnum].is_iso_incomplete = 1U;
/* Abort current transaction and disable the EP */
(void)HAL_PCD_EP_Abort(hpcd, (uint8_t)(epnum | 0x80U));
}
}
__HAL_PCD_CLEAR_FLAG(hpcd, USB_OTG_GINTSTS_IISOIXFR);
}
/* Handle Incomplete ISO OUT Interrupt */
if (__HAL_PCD_GET_FLAG(hpcd, USB_OTG_GINTSTS_PXFR_INCOMPISOOUT))
{
for (epnum = 1U; epnum < hpcd->Init.dev_endpoints; epnum++)
{
RegVal = USBx_OUTEP(epnum)->DOEPCTL;
if ((hpcd->OUT_ep[epnum].type == EP_TYPE_ISOC) &&
((RegVal & USB_OTG_DOEPCTL_EPENA) == USB_OTG_DOEPCTL_EPENA) &&
((RegVal & (0x1U << 16)) == (hpcd->FrameNumber & 0x1U)))
{
hpcd->OUT_ep[epnum].is_iso_incomplete = 1U;
USBx->GINTMSK |= USB_OTG_GINTMSK_GONAKEFFM;
if ((USBx->GINTSTS & USB_OTG_GINTSTS_BOUTNAKEFF) == 0U)
{
USBx_DEVICE->DCTL |= USB_OTG_DCTL_SGONAK;
break;
}
}
}
__HAL_PCD_CLEAR_FLAG(hpcd, USB_OTG_GINTSTS_PXFR_INCOMPISOOUT);
}
/* Handle Connection event Interrupt */
if (__HAL_PCD_GET_FLAG(hpcd, USB_OTG_GINTSTS_SRQINT))
{
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
hpcd->ConnectCallback(hpcd);
#else
HAL_PCD_ConnectCallback(hpcd);
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
__HAL_PCD_CLEAR_FLAG(hpcd, USB_OTG_GINTSTS_SRQINT);
}
/* Handle Disconnection event Interrupt */
if (__HAL_PCD_GET_FLAG(hpcd, USB_OTG_GINTSTS_OTGINT))
{
RegVal = hpcd->Instance->GOTGINT;
if ((RegVal & USB_OTG_GOTGINT_SEDET) == USB_OTG_GOTGINT_SEDET)
{
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
hpcd->DisconnectCallback(hpcd);
#else
HAL_PCD_DisconnectCallback(hpcd);
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
}
hpcd->Instance->GOTGINT |= RegVal;
}
}
}
/**
* @brief Handles PCD Wakeup interrupt request.
* @param hpcd PCD handle
* @retval HAL status
*/
void HAL_PCD_WKUP_IRQHandler(PCD_HandleTypeDef *hpcd)
{
/* Clear EXTI pending Bit */
__HAL_USB_OTG_FS_WAKEUP_EXTI_CLEAR_FLAG();
}
#endif /* defined (USB_OTG_FS) */
#if defined (USB)
/**
* @brief This function handles PCD interrupt request.
* @param hpcd PCD handle
* @retval HAL status
*/
void HAL_PCD_IRQHandler(PCD_HandleTypeDef *hpcd)
{
uint32_t wIstr = USB_ReadInterrupts(hpcd->Instance);
uint16_t store_ep[8];
uint8_t i;
if ((wIstr & USB_ISTR_CTR) == USB_ISTR_CTR)
{
/* servicing of the endpoint correct transfer interrupt */
/* clear of the CTR flag into the sub */
(void)PCD_EP_ISR_Handler(hpcd);
return;
}
if ((wIstr & USB_ISTR_RESET) == USB_ISTR_RESET)
{
__HAL_PCD_CLEAR_FLAG(hpcd, USB_ISTR_RESET);
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
hpcd->ResetCallback(hpcd);
#else
HAL_PCD_ResetCallback(hpcd);
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
(void)HAL_PCD_SetAddress(hpcd, 0U);
return;
}
if ((wIstr & USB_ISTR_PMAOVR) == USB_ISTR_PMAOVR)
{
__HAL_PCD_CLEAR_FLAG(hpcd, USB_ISTR_PMAOVR);
return;
}
if ((wIstr & USB_ISTR_ERR) == USB_ISTR_ERR)
{
__HAL_PCD_CLEAR_FLAG(hpcd, USB_ISTR_ERR);
return;
}
if ((wIstr & USB_ISTR_WKUP) == USB_ISTR_WKUP)
{
hpcd->Instance->CNTR &= (uint16_t) ~(USB_CNTR_LP_MODE);
hpcd->Instance->CNTR &= (uint16_t) ~(USB_CNTR_FSUSP);
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
hpcd->ResumeCallback(hpcd);
#else
HAL_PCD_ResumeCallback(hpcd);
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
__HAL_PCD_CLEAR_FLAG(hpcd, USB_ISTR_WKUP);
return;
}
if ((wIstr & USB_ISTR_SUSP) == USB_ISTR_SUSP)
{
/* WA: To Clear Wakeup flag if raised with suspend signal */
/* Store Endpoint registers */
for (i = 0U; i < 8U; i++)
{
store_ep[i] = PCD_GET_ENDPOINT(hpcd->Instance, i);
}
/* FORCE RESET */
hpcd->Instance->CNTR |= (uint16_t)(USB_CNTR_FRES);
/* CLEAR RESET */
hpcd->Instance->CNTR &= (uint16_t)(~USB_CNTR_FRES);
/* wait for reset flag in ISTR */
while ((hpcd->Instance->ISTR & USB_ISTR_RESET) == 0U)
{
}
/* Clear Reset Flag */
__HAL_PCD_CLEAR_FLAG(hpcd, USB_ISTR_RESET);
/* Restore Registre */
for (i = 0U; i < 8U; i++)
{
PCD_SET_ENDPOINT(hpcd->Instance, i, store_ep[i]);
}
/* Force low-power mode in the macrocell */
hpcd->Instance->CNTR |= (uint16_t)USB_CNTR_FSUSP;
/* clear of the ISTR bit must be done after setting of CNTR_FSUSP */
__HAL_PCD_CLEAR_FLAG(hpcd, USB_ISTR_SUSP);
hpcd->Instance->CNTR |= (uint16_t)USB_CNTR_LP_MODE;
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
hpcd->SuspendCallback(hpcd);
#else
HAL_PCD_SuspendCallback(hpcd);
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
return;
}
if ((wIstr & USB_ISTR_SOF) == USB_ISTR_SOF)
{
__HAL_PCD_CLEAR_FLAG(hpcd, USB_ISTR_SOF);
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
hpcd->SOFCallback(hpcd);
#else
HAL_PCD_SOFCallback(hpcd);
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
return;
}
if ((wIstr & USB_ISTR_ESOF) == USB_ISTR_ESOF)
{
/* clear ESOF flag in ISTR */
__HAL_PCD_CLEAR_FLAG(hpcd, USB_ISTR_ESOF);
return;
}
}
/**
* @brief Handles PCD Wakeup interrupt request.
* @param hpcd PCD handle
* @retval HAL status
*/
void HAL_PCD_WKUP_IRQHandler(PCD_HandleTypeDef *hpcd)
{
/* Clear EXTI pending Bit */
__HAL_USB_WAKEUP_EXTI_CLEAR_FLAG();
}
#endif /* defined (USB) */
/**
* @brief Data OUT stage callback.
* @param hpcd PCD handle
* @param epnum endpoint number
* @retval None
*/
__weak void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hpcd);
UNUSED(epnum);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_PCD_DataOutStageCallback could be implemented in the user file
*/
}
/**
* @brief Data IN stage callback
* @param hpcd PCD handle
* @param epnum endpoint number
* @retval None
*/
__weak void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hpcd);
UNUSED(epnum);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_PCD_DataInStageCallback could be implemented in the user file
*/
}
/**
* @brief Setup stage callback
* @param hpcd PCD handle
* @retval None
*/
__weak void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hpcd);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_PCD_SetupStageCallback could be implemented in the user file
*/
}
/**
* @brief USB Start Of Frame callback.
* @param hpcd PCD handle
* @retval None
*/
__weak void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hpcd);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_PCD_SOFCallback could be implemented in the user file
*/
}
/**
* @brief USB Reset callback.
* @param hpcd PCD handle
* @retval None
*/
__weak void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hpcd);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_PCD_ResetCallback could be implemented in the user file
*/
}
/**
* @brief Suspend event callback.
* @param hpcd PCD handle
* @retval None
*/
__weak void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hpcd);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_PCD_SuspendCallback could be implemented in the user file
*/
}
/**
* @brief Resume event callback.
* @param hpcd PCD handle
* @retval None
*/
__weak void HAL_PCD_ResumeCallback(PCD_HandleTypeDef *hpcd)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hpcd);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_PCD_ResumeCallback could be implemented in the user file
*/
}
/**
* @brief Incomplete ISO OUT callback.
* @param hpcd PCD handle
* @param epnum endpoint number
* @retval None
*/
__weak void HAL_PCD_ISOOUTIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hpcd);
UNUSED(epnum);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_PCD_ISOOUTIncompleteCallback could be implemented in the user file
*/
}
/**
* @brief Incomplete ISO IN callback.
* @param hpcd PCD handle
* @param epnum endpoint number
* @retval None
*/
__weak void HAL_PCD_ISOINIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hpcd);
UNUSED(epnum);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_PCD_ISOINIncompleteCallback could be implemented in the user file
*/
}
/**
* @brief Connection event callback.
* @param hpcd PCD handle
* @retval None
*/
__weak void HAL_PCD_ConnectCallback(PCD_HandleTypeDef *hpcd)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hpcd);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_PCD_ConnectCallback could be implemented in the user file
*/
}
/**
* @brief Disconnection event callback.
* @param hpcd PCD handle
* @retval None
*/
__weak void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hpcd);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_PCD_DisconnectCallback could be implemented in the user file
*/
}
/**
* @}
*/
/** @defgroup PCD_Exported_Functions_Group3 Peripheral Control functions
* @brief management functions
*
@verbatim
===============================================================================
##### Peripheral Control functions #####
===============================================================================
[..]
This subsection provides a set of functions allowing to control the PCD data
transfers.
@endverbatim
* @{
*/
/**
* @brief Connect the USB device
* @param hpcd PCD handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCD_DevConnect(PCD_HandleTypeDef *hpcd)
{
__HAL_LOCK(hpcd);
#if defined (USB)
HAL_PCDEx_SetConnectionState(hpcd, 1U);
#endif /* defined (USB) */
(void)USB_DevConnect(hpcd->Instance);
__HAL_UNLOCK(hpcd);
return HAL_OK;
}
/**
* @brief Disconnect the USB device.
* @param hpcd PCD handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCD_DevDisconnect(PCD_HandleTypeDef *hpcd)
{
__HAL_LOCK(hpcd);
#if defined (USB)
HAL_PCDEx_SetConnectionState(hpcd, 0U);
#endif /* defined (USB) */
(void)USB_DevDisconnect(hpcd->Instance);
__HAL_UNLOCK(hpcd);
return HAL_OK;
}
/**
* @brief Set the USB Device address.
* @param hpcd PCD handle
* @param address new device address
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCD_SetAddress(PCD_HandleTypeDef *hpcd, uint8_t address)
{
__HAL_LOCK(hpcd);
hpcd->USB_Address = address;
(void)USB_SetDevAddress(hpcd->Instance, address);
__HAL_UNLOCK(hpcd);
return HAL_OK;
}
/**
* @brief Open and configure an endpoint.
* @param hpcd PCD handle
* @param ep_addr endpoint address
* @param ep_mps endpoint max packet size
* @param ep_type endpoint type
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCD_EP_Open(PCD_HandleTypeDef *hpcd, uint8_t ep_addr,
uint16_t ep_mps, uint8_t ep_type)
{
HAL_StatusTypeDef ret = HAL_OK;
PCD_EPTypeDef *ep;
if ((ep_addr & 0x80U) == 0x80U)
{
ep = &hpcd->IN_ep[ep_addr & EP_ADDR_MSK];
ep->is_in = 1U;
}
else
{
ep = &hpcd->OUT_ep[ep_addr & EP_ADDR_MSK];
ep->is_in = 0U;
}
ep->num = ep_addr & EP_ADDR_MSK;
ep->maxpacket = ep_mps;
ep->type = ep_type;
#if defined (USB_OTG_FS)
if (ep->is_in != 0U)
{
/* Assign a Tx FIFO */
ep->tx_fifo_num = ep->num;
}
#endif /* defined (USB_OTG_FS) */
/* Set initial data PID. */
if (ep_type == EP_TYPE_BULK)
{
ep->data_pid_start = 0U;
}
__HAL_LOCK(hpcd);
(void)USB_ActivateEndpoint(hpcd->Instance, ep);
__HAL_UNLOCK(hpcd);
return ret;
}
/**
* @brief Deactivate an endpoint.
* @param hpcd PCD handle
* @param ep_addr endpoint address
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCD_EP_Close(PCD_HandleTypeDef *hpcd, uint8_t ep_addr)
{
PCD_EPTypeDef *ep;
if ((ep_addr & 0x80U) == 0x80U)
{
ep = &hpcd->IN_ep[ep_addr & EP_ADDR_MSK];
ep->is_in = 1U;
}
else
{
ep = &hpcd->OUT_ep[ep_addr & EP_ADDR_MSK];
ep->is_in = 0U;
}
ep->num = ep_addr & EP_ADDR_MSK;
__HAL_LOCK(hpcd);
(void)USB_DeactivateEndpoint(hpcd->Instance, ep);
__HAL_UNLOCK(hpcd);
return HAL_OK;
}
/**
* @brief Receive an amount of data.
* @param hpcd PCD handle
* @param ep_addr endpoint address
* @param pBuf pointer to the reception buffer
* @param len amount of data to be received
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCD_EP_Receive(PCD_HandleTypeDef *hpcd, uint8_t ep_addr, uint8_t *pBuf, uint32_t len)
{
PCD_EPTypeDef *ep;
ep = &hpcd->OUT_ep[ep_addr & EP_ADDR_MSK];
/*setup and start the Xfer */
ep->xfer_buff = pBuf;
ep->xfer_len = len;
ep->xfer_count = 0U;
ep->is_in = 0U;
ep->num = ep_addr & EP_ADDR_MSK;
(void)USB_EPStartXfer(hpcd->Instance, ep);
return HAL_OK;
}
/**
* @brief Get Received Data Size
* @param hpcd PCD handle
* @param ep_addr endpoint address
* @retval Data Size
*/
uint32_t HAL_PCD_EP_GetRxCount(PCD_HandleTypeDef const *hpcd, uint8_t ep_addr)
{
return hpcd->OUT_ep[ep_addr & EP_ADDR_MSK].xfer_count;
}
/**
* @brief Send an amount of data
* @param hpcd PCD handle
* @param ep_addr endpoint address
* @param pBuf pointer to the transmission buffer
* @param len amount of data to be sent
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCD_EP_Transmit(PCD_HandleTypeDef *hpcd, uint8_t ep_addr, uint8_t *pBuf, uint32_t len)
{
PCD_EPTypeDef *ep;
ep = &hpcd->IN_ep[ep_addr & EP_ADDR_MSK];
/*setup and start the Xfer */
ep->xfer_buff = pBuf;
ep->xfer_len = len;
#if defined (USB)
ep->xfer_fill_db = 1U;
ep->xfer_len_db = len;
#endif /* defined (USB) */
ep->xfer_count = 0U;
ep->is_in = 1U;
ep->num = ep_addr & EP_ADDR_MSK;
(void)USB_EPStartXfer(hpcd->Instance, ep);
return HAL_OK;
}
/**
* @brief Set a STALL condition over an endpoint
* @param hpcd PCD handle
* @param ep_addr endpoint address
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCD_EP_SetStall(PCD_HandleTypeDef *hpcd, uint8_t ep_addr)
{
PCD_EPTypeDef *ep;
if (((uint32_t)ep_addr & EP_ADDR_MSK) > hpcd->Init.dev_endpoints)
{
return HAL_ERROR;
}
if ((0x80U & ep_addr) == 0x80U)
{
ep = &hpcd->IN_ep[ep_addr & EP_ADDR_MSK];
ep->is_in = 1U;
}
else
{
ep = &hpcd->OUT_ep[ep_addr];
ep->is_in = 0U;
}
ep->is_stall = 1U;
ep->num = ep_addr & EP_ADDR_MSK;
__HAL_LOCK(hpcd);
(void)USB_EPSetStall(hpcd->Instance, ep);
if ((ep_addr & EP_ADDR_MSK) == 0U)
{
(void)USB_EP0_OutStart(hpcd->Instance, (uint8_t *)hpcd->Setup);
}
__HAL_UNLOCK(hpcd);
return HAL_OK;
}
/**
* @brief Clear a STALL condition over in an endpoint
* @param hpcd PCD handle
* @param ep_addr endpoint address
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCD_EP_ClrStall(PCD_HandleTypeDef *hpcd, uint8_t ep_addr)
{
PCD_EPTypeDef *ep;
if (((uint32_t)ep_addr & 0x0FU) > hpcd->Init.dev_endpoints)
{
return HAL_ERROR;
}
if ((0x80U & ep_addr) == 0x80U)
{
ep = &hpcd->IN_ep[ep_addr & EP_ADDR_MSK];
ep->is_in = 1U;
}
else
{
ep = &hpcd->OUT_ep[ep_addr & EP_ADDR_MSK];
ep->is_in = 0U;
}
ep->is_stall = 0U;
ep->num = ep_addr & EP_ADDR_MSK;
__HAL_LOCK(hpcd);
(void)USB_EPClearStall(hpcd->Instance, ep);
__HAL_UNLOCK(hpcd);
return HAL_OK;
}
/**
* @brief Abort an USB EP transaction.
* @param hpcd PCD handle
* @param ep_addr endpoint address
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCD_EP_Abort(PCD_HandleTypeDef *hpcd, uint8_t ep_addr)
{
HAL_StatusTypeDef ret;
PCD_EPTypeDef *ep;
if ((0x80U & ep_addr) == 0x80U)
{
ep = &hpcd->IN_ep[ep_addr & EP_ADDR_MSK];
}
else
{
ep = &hpcd->OUT_ep[ep_addr & EP_ADDR_MSK];
}
/* Stop Xfer */
ret = USB_EPStopXfer(hpcd->Instance, ep);
return ret;
}
/**
* @brief Flush an endpoint
* @param hpcd PCD handle
* @param ep_addr endpoint address
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCD_EP_Flush(PCD_HandleTypeDef *hpcd, uint8_t ep_addr)
{
__HAL_LOCK(hpcd);
if ((ep_addr & 0x80U) == 0x80U)
{
(void)USB_FlushTxFifo(hpcd->Instance, (uint32_t)ep_addr & EP_ADDR_MSK);
}
else
{
(void)USB_FlushRxFifo(hpcd->Instance);
}
__HAL_UNLOCK(hpcd);
return HAL_OK;
}
/**
* @brief Activate remote wakeup signalling
* @param hpcd PCD handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCD_ActivateRemoteWakeup(PCD_HandleTypeDef *hpcd)
{
return (USB_ActivateRemoteWakeup(hpcd->Instance));
}
/**
* @brief De-activate remote wakeup signalling.
* @param hpcd PCD handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCD_DeActivateRemoteWakeup(PCD_HandleTypeDef *hpcd)
{
return (USB_DeActivateRemoteWakeup(hpcd->Instance));
}
/**
* @}
*/
/** @defgroup PCD_Exported_Functions_Group4 Peripheral State functions
* @brief Peripheral State functions
*
@verbatim
===============================================================================
##### Peripheral State functions #####
===============================================================================
[..]
This subsection permits to get in run-time the status of the peripheral
and the data flow.
@endverbatim
* @{
*/
/**
* @brief Return the PCD handle state.
* @param hpcd PCD handle
* @retval HAL state
*/
PCD_StateTypeDef HAL_PCD_GetState(PCD_HandleTypeDef const *hpcd)
{
return hpcd->State;
}
/**
* @}
*/
/**
* @}
*/
/* Private functions ---------------------------------------------------------*/
/** @addtogroup PCD_Private_Functions
* @{
*/
#if defined (USB_OTG_FS)
/**
* @brief Check FIFO for the next packet to be loaded.
* @param hpcd PCD handle
* @param epnum endpoint number
* @retval HAL status
*/
static HAL_StatusTypeDef PCD_WriteEmptyTxFifo(PCD_HandleTypeDef *hpcd, uint32_t epnum)
{
USB_OTG_GlobalTypeDef *USBx = hpcd->Instance;
uint32_t USBx_BASE = (uint32_t)USBx;
USB_OTG_EPTypeDef *ep;
uint32_t len;
uint32_t len32b;
uint32_t fifoemptymsk;
ep = &hpcd->IN_ep[epnum];
if (ep->xfer_count > ep->xfer_len)
{
return HAL_ERROR;
}
len = ep->xfer_len - ep->xfer_count;
if (len > ep->maxpacket)
{
len = ep->maxpacket;
}
len32b = (len + 3U) / 4U;
while (((USBx_INEP(epnum)->DTXFSTS & USB_OTG_DTXFSTS_INEPTFSAV) >= len32b) &&
(ep->xfer_count < ep->xfer_len) && (ep->xfer_len != 0U))
{
/* Write the FIFO */
len = ep->xfer_len - ep->xfer_count;
if (len > ep->maxpacket)
{
len = ep->maxpacket;
}
len32b = (len + 3U) / 4U;
(void)USB_WritePacket(USBx, ep->xfer_buff, (uint8_t)epnum, (uint16_t)len);
ep->xfer_buff += len;
ep->xfer_count += len;
}
if (ep->xfer_len <= ep->xfer_count)
{
fifoemptymsk = (uint32_t)(0x1UL << (epnum & EP_ADDR_MSK));
USBx_DEVICE->DIEPEMPMSK &= ~fifoemptymsk;
}
return HAL_OK;
}
/**
* @brief process EP OUT transfer complete interrupt.
* @param hpcd PCD handle
* @param epnum endpoint number
* @retval HAL status
*/
static HAL_StatusTypeDef PCD_EP_OutXfrComplete_int(PCD_HandleTypeDef *hpcd, uint32_t epnum)
{
const USB_OTG_GlobalTypeDef *USBx = hpcd->Instance;
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t gSNPSiD = *(__IO const uint32_t *)(&USBx->CID + 0x1U);
uint32_t DoepintReg = USBx_OUTEP(epnum)->DOEPINT;
if (gSNPSiD == USB_OTG_CORE_ID_310A)
{
/* StupPktRcvd = 1 this is a setup packet */
if ((DoepintReg & USB_OTG_DOEPINT_STPKTRX) == USB_OTG_DOEPINT_STPKTRX)
{
CLEAR_OUT_EP_INTR(epnum, USB_OTG_DOEPINT_STPKTRX);
}
else
{
if ((DoepintReg & USB_OTG_DOEPINT_OTEPSPR) == USB_OTG_DOEPINT_OTEPSPR)
{
CLEAR_OUT_EP_INTR(epnum, USB_OTG_DOEPINT_OTEPSPR);
}
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
hpcd->DataOutStageCallback(hpcd, (uint8_t)epnum);
#else
HAL_PCD_DataOutStageCallback(hpcd, (uint8_t)epnum);
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
}
}
else
{
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
hpcd->DataOutStageCallback(hpcd, (uint8_t)epnum);
#else
HAL_PCD_DataOutStageCallback(hpcd, (uint8_t)epnum);
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
}
return HAL_OK;
}
/**
* @brief process EP OUT setup packet received interrupt.
* @param hpcd PCD handle
* @param epnum endpoint number
* @retval HAL status
*/
static HAL_StatusTypeDef PCD_EP_OutSetupPacket_int(PCD_HandleTypeDef *hpcd, uint32_t epnum)
{
const USB_OTG_GlobalTypeDef *USBx = hpcd->Instance;
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t gSNPSiD = *(__IO const uint32_t *)(&USBx->CID + 0x1U);
uint32_t DoepintReg = USBx_OUTEP(epnum)->DOEPINT;
if ((gSNPSiD > USB_OTG_CORE_ID_300A) &&
((DoepintReg & USB_OTG_DOEPINT_STPKTRX) == USB_OTG_DOEPINT_STPKTRX))
{
CLEAR_OUT_EP_INTR(epnum, USB_OTG_DOEPINT_STPKTRX);
}
/* Inform the upper layer that a setup packet is available */
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
hpcd->SetupStageCallback(hpcd);
#else
HAL_PCD_SetupStageCallback(hpcd);
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
return HAL_OK;
}
#endif /* defined (USB_OTG_FS) */
#if defined (USB)
/**
* @brief This function handles PCD Endpoint interrupt request.
* @param hpcd PCD handle
* @retval HAL status
*/
static HAL_StatusTypeDef PCD_EP_ISR_Handler(PCD_HandleTypeDef *hpcd)
{
PCD_EPTypeDef *ep;
uint16_t count;
uint16_t wIstr;
uint16_t wEPVal;
uint16_t TxPctSize;
uint8_t epindex;
#if (USE_USB_DOUBLE_BUFFER != 1U)
count = 0U;
#endif /* USE_USB_DOUBLE_BUFFER */
/* stay in loop while pending interrupts */
while ((hpcd->Instance->ISTR & USB_ISTR_CTR) != 0U)
{
wIstr = hpcd->Instance->ISTR;
/* extract highest priority endpoint number */
epindex = (uint8_t)(wIstr & USB_ISTR_EP_ID);
if (epindex == 0U)
{
/* Decode and service control endpoint interrupt */
/* DIR bit = origin of the interrupt */
if ((wIstr & USB_ISTR_DIR) == 0U)
{
/* DIR = 0 */
/* DIR = 0 => IN int */
/* DIR = 0 implies that (EP_CTR_TX = 1) always */
PCD_CLEAR_TX_EP_CTR(hpcd->Instance, PCD_ENDP0);
ep = &hpcd->IN_ep[0];
ep->xfer_count = PCD_GET_EP_TX_CNT(hpcd->Instance, ep->num);
ep->xfer_buff += ep->xfer_count;
/* TX COMPLETE */
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
hpcd->DataInStageCallback(hpcd, 0U);
#else
HAL_PCD_DataInStageCallback(hpcd, 0U);
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
if ((hpcd->USB_Address > 0U) && (ep->xfer_len == 0U))
{
hpcd->Instance->DADDR = ((uint16_t)hpcd->USB_Address | USB_DADDR_EF);
hpcd->USB_Address = 0U;
}
}
else
{
/* DIR = 1 */
/* DIR = 1 & CTR_RX => SETUP or OUT int */
/* DIR = 1 & (CTR_TX | CTR_RX) => 2 int pending */
ep = &hpcd->OUT_ep[0];
wEPVal = PCD_GET_ENDPOINT(hpcd->Instance, PCD_ENDP0);
if ((wEPVal & USB_EP_SETUP) != 0U)
{
/* Get SETUP Packet */
ep->xfer_count = PCD_GET_EP_RX_CNT(hpcd->Instance, ep->num);
USB_ReadPMA(hpcd->Instance, (uint8_t *)hpcd->Setup,
ep->pmaadress, (uint16_t)ep->xfer_count);
/* SETUP bit kept frozen while CTR_RX = 1 */
PCD_CLEAR_RX_EP_CTR(hpcd->Instance, PCD_ENDP0);
/* Process SETUP Packet*/
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
hpcd->SetupStageCallback(hpcd);
#else
HAL_PCD_SetupStageCallback(hpcd);
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
}
else if ((wEPVal & USB_EP_CTR_RX) != 0U)
{
PCD_CLEAR_RX_EP_CTR(hpcd->Instance, PCD_ENDP0);
/* Get Control Data OUT Packet */
ep->xfer_count = PCD_GET_EP_RX_CNT(hpcd->Instance, ep->num);
if ((ep->xfer_count != 0U) && (ep->xfer_buff != 0U))
{
USB_ReadPMA(hpcd->Instance, ep->xfer_buff,
ep->pmaadress, (uint16_t)ep->xfer_count);
ep->xfer_buff += ep->xfer_count;
/* Process Control Data OUT Packet */
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
hpcd->DataOutStageCallback(hpcd, 0U);
#else
HAL_PCD_DataOutStageCallback(hpcd, 0U);
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
}
wEPVal = (uint16_t)PCD_GET_ENDPOINT(hpcd->Instance, PCD_ENDP0);
if (((wEPVal & USB_EP_SETUP) == 0U) && ((wEPVal & USB_EP_RX_STRX) != USB_EP_RX_VALID))
{
PCD_SET_EP_RX_CNT(hpcd->Instance, PCD_ENDP0, ep->maxpacket);
PCD_SET_EP_RX_STATUS(hpcd->Instance, PCD_ENDP0, USB_EP_RX_VALID);
}
}
}
}
else
{
/* Decode and service non control endpoints interrupt */
/* process related endpoint register */
wEPVal = PCD_GET_ENDPOINT(hpcd->Instance, epindex);
if ((wEPVal & USB_EP_CTR_RX) != 0U)
{
/* clear int flag */
PCD_CLEAR_RX_EP_CTR(hpcd->Instance, epindex);
ep = &hpcd->OUT_ep[epindex];
/* OUT Single Buffering */
if (ep->doublebuffer == 0U)
{
count = (uint16_t)PCD_GET_EP_RX_CNT(hpcd->Instance, ep->num);
if (count != 0U)
{
USB_ReadPMA(hpcd->Instance, ep->xfer_buff, ep->pmaadress, count);
}
}
#if (USE_USB_DOUBLE_BUFFER == 1U)
else
{
/* manage double buffer bulk out */
if (ep->type == EP_TYPE_BULK)
{
count = HAL_PCD_EP_DB_Receive(hpcd, ep, wEPVal);
}
else /* manage double buffer iso out */
{
/* free EP OUT Buffer */
PCD_FREE_USER_BUFFER(hpcd->Instance, ep->num, 0U);
if ((PCD_GET_ENDPOINT(hpcd->Instance, ep->num) & USB_EP_DTOG_RX) != 0U)
{
/* read from endpoint BUF0Addr buffer */
count = (uint16_t)PCD_GET_EP_DBUF0_CNT(hpcd->Instance, ep->num);
if (count != 0U)
{
USB_ReadPMA(hpcd->Instance, ep->xfer_buff, ep->pmaaddr0, count);
}
}
else
{
/* read from endpoint BUF1Addr buffer */
count = (uint16_t)PCD_GET_EP_DBUF1_CNT(hpcd->Instance, ep->num);
if (count != 0U)
{
USB_ReadPMA(hpcd->Instance, ep->xfer_buff, ep->pmaaddr1, count);
}
}
}
}
#endif /* (USE_USB_DOUBLE_BUFFER == 1U) */
/* multi-packet on the NON control OUT endpoint */
ep->xfer_count += count;
ep->xfer_buff += count;
if ((ep->xfer_len == 0U) || (count < ep->maxpacket))
{
/* RX COMPLETE */
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
hpcd->DataOutStageCallback(hpcd, ep->num);
#else
HAL_PCD_DataOutStageCallback(hpcd, ep->num);
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
}
else
{
(void)USB_EPStartXfer(hpcd->Instance, ep);
}
}
if ((wEPVal & USB_EP_CTR_TX) != 0U)
{
ep = &hpcd->IN_ep[epindex];
/* clear int flag */
PCD_CLEAR_TX_EP_CTR(hpcd->Instance, epindex);
if (ep->type == EP_TYPE_ISOC)
{
ep->xfer_len = 0U;
#if (USE_USB_DOUBLE_BUFFER == 1U)
if (ep->doublebuffer != 0U)
{
if ((wEPVal & USB_EP_DTOG_TX) != 0U)
{
PCD_SET_EP_DBUF0_CNT(hpcd->Instance, ep->num, ep->is_in, 0U);
}
else
{
PCD_SET_EP_DBUF1_CNT(hpcd->Instance, ep->num, ep->is_in, 0U);
}
}
#endif /* (USE_USB_DOUBLE_BUFFER == 1U) */
/* TX COMPLETE */
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
hpcd->DataInStageCallback(hpcd, ep->num);
#else
HAL_PCD_DataInStageCallback(hpcd, ep->num);
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
}
else
{
/* Manage Single Buffer Transaction */
if ((wEPVal & USB_EP_KIND) == 0U)
{
/* multi-packet on the NON control IN endpoint */
TxPctSize = (uint16_t)PCD_GET_EP_TX_CNT(hpcd->Instance, ep->num);
if (ep->xfer_len > TxPctSize)
{
ep->xfer_len -= TxPctSize;
}
else
{
ep->xfer_len = 0U;
}
/* Zero Length Packet? */
if (ep->xfer_len == 0U)
{
/* TX COMPLETE */
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
hpcd->DataInStageCallback(hpcd, ep->num);
#else
HAL_PCD_DataInStageCallback(hpcd, ep->num);
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
}
else
{
/* Transfer is not yet Done */
ep->xfer_buff += TxPctSize;
ep->xfer_count += TxPctSize;
(void)USB_EPStartXfer(hpcd->Instance, ep);
}
}
#if (USE_USB_DOUBLE_BUFFER == 1U)
/* Double Buffer bulk IN (bulk transfer Len > Ep_Mps) */
else
{
(void)HAL_PCD_EP_DB_Transmit(hpcd, ep, wEPVal);
}
#endif /* (USE_USB_DOUBLE_BUFFER == 1U) */
}
}
}
}
return HAL_OK;
}
#if (USE_USB_DOUBLE_BUFFER == 1U)
/**
* @brief Manage double buffer bulk out transaction from ISR
* @param hpcd PCD handle
* @param ep current endpoint handle
* @param wEPVal Last snapshot of EPRx register value taken in ISR
* @retval HAL status
*/
static uint16_t HAL_PCD_EP_DB_Receive(PCD_HandleTypeDef *hpcd,
PCD_EPTypeDef *ep, uint16_t wEPVal)
{
uint16_t count;
/* Manage Buffer0 OUT */
if ((wEPVal & USB_EP_DTOG_RX) != 0U)
{
/* Get count of received Data on buffer0 */
count = (uint16_t)PCD_GET_EP_DBUF0_CNT(hpcd->Instance, ep->num);
if (ep->xfer_len >= count)
{
ep->xfer_len -= count;
}
else
{
ep->xfer_len = 0U;
}
if (ep->xfer_len == 0U)
{
/* set NAK to OUT endpoint since double buffer is enabled */
PCD_SET_EP_RX_STATUS(hpcd->Instance, ep->num, USB_EP_RX_NAK);
}
/* Check if Buffer1 is in blocked state which requires to toggle */
if ((wEPVal & USB_EP_DTOG_TX) != 0U)
{
PCD_FREE_USER_BUFFER(hpcd->Instance, ep->num, 0U);
}
if (count != 0U)
{
USB_ReadPMA(hpcd->Instance, ep->xfer_buff, ep->pmaaddr0, count);
}
}
/* Manage Buffer 1 DTOG_RX=0 */
else
{
/* Get count of received data */
count = (uint16_t)PCD_GET_EP_DBUF1_CNT(hpcd->Instance, ep->num);
if (ep->xfer_len >= count)
{
ep->xfer_len -= count;
}
else
{
ep->xfer_len = 0U;
}
if (ep->xfer_len == 0U)
{
/* set NAK on the current endpoint */
PCD_SET_EP_RX_STATUS(hpcd->Instance, ep->num, USB_EP_RX_NAK);
}
/*Need to FreeUser Buffer*/
if ((wEPVal & USB_EP_DTOG_TX) == 0U)
{
PCD_FREE_USER_BUFFER(hpcd->Instance, ep->num, 0U);
}
if (count != 0U)
{
USB_ReadPMA(hpcd->Instance, ep->xfer_buff, ep->pmaaddr1, count);
}
}
return count;
}
/**
* @brief Manage double buffer bulk IN transaction from ISR
* @param hpcd PCD handle
* @param ep current endpoint handle
* @param wEPVal Last snapshot of EPRx register value taken in ISR
* @retval HAL status
*/
static HAL_StatusTypeDef HAL_PCD_EP_DB_Transmit(PCD_HandleTypeDef *hpcd,
PCD_EPTypeDef *ep, uint16_t wEPVal)
{
uint32_t len;
uint16_t TxPctSize;
/* Data Buffer0 ACK received */
if ((wEPVal & USB_EP_DTOG_TX) != 0U)
{
/* multi-packet on the NON control IN endpoint */
TxPctSize = (uint16_t)PCD_GET_EP_DBUF0_CNT(hpcd->Instance, ep->num);
if (ep->xfer_len > TxPctSize)
{
ep->xfer_len -= TxPctSize;
}
else
{
ep->xfer_len = 0U;
}
/* Transfer is completed */
if (ep->xfer_len == 0U)
{
PCD_SET_EP_DBUF0_CNT(hpcd->Instance, ep->num, ep->is_in, 0U);
PCD_SET_EP_DBUF1_CNT(hpcd->Instance, ep->num, ep->is_in, 0U);
/* TX COMPLETE */
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
hpcd->DataInStageCallback(hpcd, ep->num);
#else
HAL_PCD_DataInStageCallback(hpcd, ep->num);
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
if ((wEPVal & USB_EP_DTOG_RX) != 0U)
{
PCD_FREE_USER_BUFFER(hpcd->Instance, ep->num, 1U);
}
}
else /* Transfer is not yet Done */
{
/* need to Free USB Buff */
if ((wEPVal & USB_EP_DTOG_RX) != 0U)
{
PCD_FREE_USER_BUFFER(hpcd->Instance, ep->num, 1U);
}
/* Still there is data to Fill in the next Buffer */
if (ep->xfer_fill_db == 1U)
{
ep->xfer_buff += TxPctSize;
ep->xfer_count += TxPctSize;
/* Calculate the len of the new buffer to fill */
if (ep->xfer_len_db >= ep->maxpacket)
{
len = ep->maxpacket;
ep->xfer_len_db -= len;
}
else if (ep->xfer_len_db == 0U)
{
len = TxPctSize;
ep->xfer_fill_db = 0U;
}
else
{
ep->xfer_fill_db = 0U;
len = ep->xfer_len_db;
ep->xfer_len_db = 0U;
}
/* Write remaining Data to Buffer */
/* Set the Double buffer counter for pma buffer1 */
PCD_SET_EP_DBUF0_CNT(hpcd->Instance, ep->num, ep->is_in, len);
/* Copy user buffer to USB PMA */
USB_WritePMA(hpcd->Instance, ep->xfer_buff, ep->pmaaddr0, (uint16_t)len);
}
}
}
else /* Data Buffer1 ACK received */
{
/* multi-packet on the NON control IN endpoint */
TxPctSize = (uint16_t)PCD_GET_EP_DBUF1_CNT(hpcd->Instance, ep->num);
if (ep->xfer_len >= TxPctSize)
{
ep->xfer_len -= TxPctSize;
}
else
{
ep->xfer_len = 0U;
}
/* Transfer is completed */
if (ep->xfer_len == 0U)
{
PCD_SET_EP_DBUF0_CNT(hpcd->Instance, ep->num, ep->is_in, 0U);
PCD_SET_EP_DBUF1_CNT(hpcd->Instance, ep->num, ep->is_in, 0U);
/* TX COMPLETE */
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
hpcd->DataInStageCallback(hpcd, ep->num);
#else
HAL_PCD_DataInStageCallback(hpcd, ep->num);
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
/* need to Free USB Buff */
if ((wEPVal & USB_EP_DTOG_RX) == 0U)
{
PCD_FREE_USER_BUFFER(hpcd->Instance, ep->num, 1U);
}
}
else /* Transfer is not yet Done */
{
/* need to Free USB Buff */
if ((wEPVal & USB_EP_DTOG_RX) == 0U)
{
PCD_FREE_USER_BUFFER(hpcd->Instance, ep->num, 1U);
}
/* Still there is data to Fill in the next Buffer */
if (ep->xfer_fill_db == 1U)
{
ep->xfer_buff += TxPctSize;
ep->xfer_count += TxPctSize;
/* Calculate the len of the new buffer to fill */
if (ep->xfer_len_db >= ep->maxpacket)
{
len = ep->maxpacket;
ep->xfer_len_db -= len;
}
else if (ep->xfer_len_db == 0U)
{
len = TxPctSize;
ep->xfer_fill_db = 0U;
}
else
{
len = ep->xfer_len_db;
ep->xfer_len_db = 0U;
ep->xfer_fill_db = 0;
}
/* Set the Double buffer counter for pmabuffer1 */
PCD_SET_EP_DBUF1_CNT(hpcd->Instance, ep->num, ep->is_in, len);
/* Copy the user buffer to USB PMA */
USB_WritePMA(hpcd->Instance, ep->xfer_buff, ep->pmaaddr1, (uint16_t)len);
}
}
}
/*enable endpoint IN*/
PCD_SET_EP_TX_STATUS(hpcd->Instance, ep->num, USB_EP_TX_VALID);
return HAL_OK;
}
#endif /* (USE_USB_DOUBLE_BUFFER == 1U) */
#endif /* defined (USB) */
/**
* @}
*/
#endif /* defined (USB) || defined (USB_OTG_FS) */
#endif /* HAL_PCD_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/

View File

@@ -0,0 +1,243 @@
/**
******************************************************************************
* @file stm32f1xx_hal_pcd_ex.c
* @author MCD Application Team
* @brief PCD Extended HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of the USB Peripheral Controller:
* + Extended features functions
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
/** @defgroup PCDEx PCDEx
* @brief PCD Extended HAL module driver
* @{
*/
#ifdef HAL_PCD_MODULE_ENABLED
#if defined (USB) || defined (USB_OTG_FS)
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @defgroup PCDEx_Exported_Functions PCDEx Exported Functions
* @{
*/
/** @defgroup PCDEx_Exported_Functions_Group1 Peripheral Control functions
* @brief PCDEx control functions
*
@verbatim
===============================================================================
##### Extended features functions #####
===============================================================================
[..] This section provides functions allowing to:
(+) Update FIFO configuration
@endverbatim
* @{
*/
#if defined (USB_OTG_FS)
/**
* @brief Set Tx FIFO
* @param hpcd PCD handle
* @param fifo The number of Tx fifo
* @param size Fifo size
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCDEx_SetTxFiFo(PCD_HandleTypeDef *hpcd, uint8_t fifo, uint16_t size)
{
uint8_t i;
uint32_t Tx_Offset;
/* TXn min size = 16 words. (n : Transmit FIFO index)
When a TxFIFO is not used, the Configuration should be as follows:
case 1 : n > m and Txn is not used (n,m : Transmit FIFO indexes)
--> Txm can use the space allocated for Txn.
case2 : n < m and Txn is not used (n,m : Transmit FIFO indexes)
--> Txn should be configured with the minimum space of 16 words
The FIFO is used optimally when used TxFIFOs are allocated in the top
of the FIFO.Ex: use EP1 and EP2 as IN instead of EP1 and EP3 as IN ones.
When DMA is used 3n * FIFO locations should be reserved for internal DMA registers */
Tx_Offset = hpcd->Instance->GRXFSIZ;
if (fifo == 0U)
{
hpcd->Instance->DIEPTXF0_HNPTXFSIZ = ((uint32_t)size << 16) | Tx_Offset;
}
else
{
Tx_Offset += (hpcd->Instance->DIEPTXF0_HNPTXFSIZ) >> 16;
for (i = 0U; i < (fifo - 1U); i++)
{
Tx_Offset += (hpcd->Instance->DIEPTXF[i] >> 16);
}
/* Multiply Tx_Size by 2 to get higher performance */
hpcd->Instance->DIEPTXF[fifo - 1U] = ((uint32_t)size << 16) | Tx_Offset;
}
return HAL_OK;
}
/**
* @brief Set Rx FIFO
* @param hpcd PCD handle
* @param size Size of Rx fifo
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCDEx_SetRxFiFo(PCD_HandleTypeDef *hpcd, uint16_t size)
{
hpcd->Instance->GRXFSIZ = size;
return HAL_OK;
}
#endif /* defined (USB_OTG_FS) */
#if defined (USB)
/**
* @brief Configure PMA for EP
* @param hpcd Device instance
* @param ep_addr endpoint address
* @param ep_kind endpoint Kind
* USB_SNG_BUF: Single Buffer used
* USB_DBL_BUF: Double Buffer used
* @param pmaadress: EP address in The PMA: In case of single buffer endpoint
* this parameter is 16-bit value providing the address
* in PMA allocated to endpoint.
* In case of double buffer endpoint this parameter
* is a 32-bit value providing the endpoint buffer 0 address
* in the LSB part of 32-bit value and endpoint buffer 1 address
* in the MSB part of 32-bit value.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_PCDEx_PMAConfig(PCD_HandleTypeDef *hpcd, uint16_t ep_addr,
uint16_t ep_kind, uint32_t pmaadress)
{
PCD_EPTypeDef *ep;
/* initialize ep structure*/
if ((0x80U & ep_addr) == 0x80U)
{
ep = &hpcd->IN_ep[ep_addr & EP_ADDR_MSK];
}
else
{
ep = &hpcd->OUT_ep[ep_addr];
}
/* Here we check if the endpoint is single or double Buffer*/
if (ep_kind == PCD_SNG_BUF)
{
/* Single Buffer */
ep->doublebuffer = 0U;
/* Configure the PMA */
ep->pmaadress = (uint16_t)pmaadress;
}
#if (USE_USB_DOUBLE_BUFFER == 1U)
else /* USB_DBL_BUF */
{
/* Double Buffer Endpoint */
ep->doublebuffer = 1U;
/* Configure the PMA */
ep->pmaaddr0 = (uint16_t)(pmaadress & 0xFFFFU);
ep->pmaaddr1 = (uint16_t)((pmaadress & 0xFFFF0000U) >> 16);
}
#endif /* (USE_USB_DOUBLE_BUFFER == 1U) */
return HAL_OK;
}
/**
* @brief Software Device Connection,
* this function is not required by USB OTG FS peripheral, it is used
* only by USB Device FS peripheral.
* @param hpcd PCD handle
* @param state connection state (0 : disconnected / 1: connected)
* @retval None
*/
__weak void HAL_PCDEx_SetConnectionState(PCD_HandleTypeDef *hpcd, uint8_t state)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hpcd);
UNUSED(state);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_PCDEx_SetConnectionState could be implemented in the user file
*/
}
#endif /* defined (USB) */
/**
* @brief Send LPM message to user layer callback.
* @param hpcd PCD handle
* @param msg LPM message
* @retval HAL status
*/
__weak void HAL_PCDEx_LPM_Callback(PCD_HandleTypeDef *hpcd, PCD_LPM_MsgTypeDef msg)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hpcd);
UNUSED(msg);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_PCDEx_LPM_Callback could be implemented in the user file
*/
}
/**
* @brief Send BatteryCharging message to user layer callback.
* @param hpcd PCD handle
* @param msg LPM message
* @retval HAL status
*/
__weak void HAL_PCDEx_BCD_Callback(PCD_HandleTypeDef *hpcd, PCD_BCD_MsgTypeDef msg)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hpcd);
UNUSED(msg);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_PCDEx_BCD_Callback could be implemented in the user file
*/
}
/**
* @}
*/
/**
* @}
*/
#endif /* defined (USB) || defined (USB_OTG_FS) */
#endif /* HAL_PCD_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/

View File

@@ -0,0 +1,3215 @@
/**
******************************************************************************
* @file stm32f1xx_hal_sd.c
* @author MCD Application Team
* @brief SD card HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of the Secure Digital (SD) peripheral:
* + Initialization and de-initialization functions
* + IO operation functions
* + Peripheral Control functions
* + Peripheral State functions
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
==============================================================================
##### How to use this driver #####
==============================================================================
[..]
This driver implements a high level communication layer for read and write from/to
this memory. The needed STM32 hardware resources (SDIO and GPIO) are performed by
the user in HAL_SD_MspInit() function (MSP layer).
Basically, the MSP layer configuration should be the same as we provide in the
examples.
You can easily tailor this configuration according to hardware resources.
[..]
This driver is a generic layered driver for SDIO memories which uses the HAL
SDIO driver functions to interface with SD and uSD cards devices.
It is used as follows:
(#)Initialize the SDIO low level resources by implementing the HAL_SD_MspInit() API:
(##) Enable the SDIO interface clock using __HAL_RCC_SDIO_CLK_ENABLE();
(##) SDIO pins configuration for SD card
(+++) Enable the clock for the SDIO GPIOs using the functions __HAL_RCC_GPIOx_CLK_ENABLE();
(+++) Configure these SDIO pins as alternate function pull-up using HAL_GPIO_Init()
and according to your pin assignment;
(##) DMA configuration if you need to use DMA process (HAL_SD_ReadBlocks_DMA()
and HAL_SD_WriteBlocks_DMA() APIs).
(+++) Enable the DMAx interface clock using __HAL_RCC_DMAx_CLK_ENABLE();
(+++) Configure the DMA using the function HAL_DMA_Init() with predeclared and filled.
(##) NVIC configuration if you need to use interrupt process when using DMA transfer.
(+++) Configure the SDIO and DMA interrupt priorities using functions
HAL_NVIC_SetPriority(); DMA priority is superior to SDIO's priority
(+++) Enable the NVIC DMA and SDIO IRQs using function HAL_NVIC_EnableIRQ()
(+++) SDIO interrupts are managed using the macros __HAL_SD_ENABLE_IT()
and __HAL_SD_DISABLE_IT() inside the communication process.
(+++) SDIO interrupts pending bits are managed using the macros __HAL_SD_GET_IT()
and __HAL_SD_CLEAR_IT()
(##) NVIC configuration if you need to use interrupt process (HAL_SD_ReadBlocks_IT()
and HAL_SD_WriteBlocks_IT() APIs).
(+++) Configure the SDIO interrupt priorities using function HAL_NVIC_SetPriority();
(+++) Enable the NVIC SDIO IRQs using function HAL_NVIC_EnableIRQ()
(+++) SDIO interrupts are managed using the macros __HAL_SD_ENABLE_IT()
and __HAL_SD_DISABLE_IT() inside the communication process.
(+++) SDIO interrupts pending bits are managed using the macros __HAL_SD_GET_IT()
and __HAL_SD_CLEAR_IT()
(#) At this stage, you can perform SD read/write/erase operations after SD card initialization
*** SD Card Initialization and configuration ***
================================================
[..]
To initialize the SD Card, use the HAL_SD_Init() function. It Initializes
SDIO Peripheral(STM32 side) and the SD Card, and put it into StandBy State (Ready for data transfer).
This function provide the following operations:
(#) Apply the SD Card initialization process at 400KHz and check the SD Card
type (Standard Capacity or High Capacity). You can change or adapt this
frequency by adjusting the "ClockDiv" field.
The SD Card frequency (SDIO_CK) is computed as follows:
SDIO_CK = SDIOCLK / (ClockDiv + 2)
In initialization mode and according to the SD Card standard,
make sure that the SDIO_CK frequency doesn't exceed 400KHz.
This phase of initialization is done through SDIO_Init() and
SDIO_PowerState_ON() SDIO low level APIs.
(#) Initialize the SD card. The API used is HAL_SD_InitCard().
This phase allows the card initialization and identification
and check the SD Card type (Standard Capacity or High Capacity)
The initialization flow is compatible with SD standard.
This API (HAL_SD_InitCard()) could be used also to reinitialize the card in case
of plug-off plug-in.
(#) Configure the SD Card Data transfer frequency. You can change or adapt this
frequency by adjusting the "ClockDiv" field.
In transfer mode and according to the SD Card standard, make sure that the
SDIO_CK frequency doesn't exceed 25MHz and 50MHz in High-speed mode switch.
To be able to use a frequency higher than 24MHz, you should use the SDIO
peripheral in bypass mode. Refer to the corresponding reference manual
for more details.
(#) Select the corresponding SD Card according to the address read with the step 2.
(#) Configure the SD Card in wide bus mode: 4-bits data.
*** SD Card Read operation ***
==============================
[..]
(+) You can read from SD card in polling mode by using function HAL_SD_ReadBlocks().
This function support only 512-bytes block length (the block size should be
chosen as 512 bytes).
You can choose either one block read operation or multiple block read operation
by adjusting the "NumberOfBlocks" parameter.
After this, you have to ensure that the transfer is done correctly. The check is done
through HAL_SD_GetCardState() function for SD card state.
(+) You can read from SD card in DMA mode by using function HAL_SD_ReadBlocks_DMA().
This function support only 512-bytes block length (the block size should be
chosen as 512 bytes).
You can choose either one block read operation or multiple block read operation
by adjusting the "NumberOfBlocks" parameter.
After this, you have to ensure that the transfer is done correctly. The check is done
through HAL_SD_GetCardState() function for SD card state.
You could also check the DMA transfer process through the SD Rx interrupt event.
(+) You can read from SD card in Interrupt mode by using function HAL_SD_ReadBlocks_IT().
This function support only 512-bytes block length (the block size should be
chosen as 512 bytes).
You can choose either one block read operation or multiple block read operation
by adjusting the "NumberOfBlocks" parameter.
After this, you have to ensure that the transfer is done correctly. The check is done
through HAL_SD_GetCardState() function for SD card state.
You could also check the IT transfer process through the SD Rx interrupt event.
*** SD Card Write operation ***
===============================
[..]
(+) You can write to SD card in polling mode by using function HAL_SD_WriteBlocks().
This function support only 512-bytes block length (the block size should be
chosen as 512 bytes).
You can choose either one block read operation or multiple block read operation
by adjusting the "NumberOfBlocks" parameter.
After this, you have to ensure that the transfer is done correctly. The check is done
through HAL_SD_GetCardState() function for SD card state.
(+) You can write to SD card in DMA mode by using function HAL_SD_WriteBlocks_DMA().
This function support only 512-bytes block length (the block size should be
chosen as 512 bytes).
You can choose either one block read operation or multiple block read operation
by adjusting the "NumberOfBlocks" parameter.
After this, you have to ensure that the transfer is done correctly. The check is done
through HAL_SD_GetCardState() function for SD card state.
You could also check the DMA transfer process through the SD Tx interrupt event.
(+) You can write to SD card in Interrupt mode by using function HAL_SD_WriteBlocks_IT().
This function support only 512-bytes block length (the block size should be
chosen as 512 bytes).
You can choose either one block read operation or multiple block read operation
by adjusting the "NumberOfBlocks" parameter.
After this, you have to ensure that the transfer is done correctly. The check is done
through HAL_SD_GetCardState() function for SD card state.
You could also check the IT transfer process through the SD Tx interrupt event.
*** SD card status ***
======================
[..]
(+) The SD Status contains status bits that are related to the SD Memory
Card proprietary features. To get SD card status use the HAL_SD_GetCardStatus().
*** SD card information ***
===========================
[..]
(+) To get SD card information, you can use the function HAL_SD_GetCardInfo().
It returns useful information about the SD card such as block size, card type,
block number ...
*** SD card CSD register ***
============================
(+) The HAL_SD_GetCardCSD() API allows to get the parameters of the CSD register.
Some of the CSD parameters are useful for card initialization and identification.
*** SD card CID register ***
============================
(+) The HAL_SD_GetCardCID() API allows to get the parameters of the CID register.
Some of the CSD parameters are useful for card initialization and identification.
*** SD HAL driver macros list ***
==================================
[..]
Below the list of most used macros in SD HAL driver.
(+) __HAL_SD_ENABLE : Enable the SD device
(+) __HAL_SD_DISABLE : Disable the SD device
(+) __HAL_SD_DMA_ENABLE: Enable the SDIO DMA transfer
(+) __HAL_SD_DMA_DISABLE: Disable the SDIO DMA transfer
(+) __HAL_SD_ENABLE_IT: Enable the SD device interrupt
(+) __HAL_SD_DISABLE_IT: Disable the SD device interrupt
(+) __HAL_SD_GET_FLAG:Check whether the specified SD flag is set or not
(+) __HAL_SD_CLEAR_FLAG: Clear the SD's pending flags
(@) You can refer to the SD HAL driver header file for more useful macros
*** Callback registration ***
=============================================
[..]
The compilation define USE_HAL_SD_REGISTER_CALLBACKS when set to 1
allows the user to configure dynamically the driver callbacks.
Use Functions HAL_SD_RegisterCallback() to register a user callback,
it allows to register following callbacks:
(+) TxCpltCallback : callback when a transmission transfer is completed.
(+) RxCpltCallback : callback when a reception transfer is completed.
(+) ErrorCallback : callback when error occurs.
(+) AbortCpltCallback : callback when abort is completed.
(+) MspInitCallback : SD MspInit.
(+) MspDeInitCallback : SD MspDeInit.
This function takes as parameters the HAL peripheral handle, the Callback ID
and a pointer to the user callback function.
Use function HAL_SD_UnRegisterCallback() to reset a callback to the default
weak (surcharged) function. It allows to reset following callbacks:
(+) TxCpltCallback : callback when a transmission transfer is completed.
(+) RxCpltCallback : callback when a reception transfer is completed.
(+) ErrorCallback : callback when error occurs.
(+) AbortCpltCallback : callback when abort is completed.
(+) MspInitCallback : SD MspInit.
(+) MspDeInitCallback : SD MspDeInit.
This function) takes as parameters the HAL peripheral handle and the Callback ID.
By default, after the HAL_SD_Init and if the state is HAL_SD_STATE_RESET
all callbacks are reset to the corresponding legacy weak (surcharged) functions.
Exception done for MspInit and MspDeInit callbacks that are respectively
reset to the legacy weak (surcharged) functions in the HAL_SD_Init
and HAL_SD_DeInit only when these callbacks are null (not registered beforehand).
If not, MspInit or MspDeInit are not null, the HAL_SD_Init and HAL_SD_DeInit
keep and use the user MspInit/MspDeInit callbacks (registered beforehand)
Callbacks can be registered/unregistered in READY state only.
Exception done for MspInit/MspDeInit callbacks that can be registered/unregistered
in READY or RESET state, thus registered (user) MspInit/DeInit callbacks can be used
during the Init/DeInit.
In that case first register the MspInit/MspDeInit user callbacks
using HAL_SD_RegisterCallback before calling HAL_SD_DeInit
or HAL_SD_Init function.
When The compilation define USE_HAL_SD_REGISTER_CALLBACKS is set to 0 or
not defined, the callback registering feature is not available
and weak (surcharged) callbacks are used.
@endverbatim
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
#if defined(SDIO)
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
/** @addtogroup SD
* @{
*/
#ifdef HAL_SD_MODULE_ENABLED
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/** @addtogroup SD_Private_Defines
* @{
*/
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/** @defgroup SD_Private_Functions SD Private Functions
* @{
*/
static uint32_t SD_InitCard(SD_HandleTypeDef *hsd);
static uint32_t SD_PowerON(SD_HandleTypeDef *hsd);
static uint32_t SD_SendSDStatus(SD_HandleTypeDef *hsd, uint32_t *pSDstatus);
static uint32_t SD_SendStatus(SD_HandleTypeDef *hsd, uint32_t *pCardStatus);
static uint32_t SD_WideBus_Enable(SD_HandleTypeDef *hsd);
static uint32_t SD_WideBus_Disable(SD_HandleTypeDef *hsd);
static uint32_t SD_FindSCR(SD_HandleTypeDef *hsd, uint32_t *pSCR);
static void SD_PowerOFF(SD_HandleTypeDef *hsd);
static void SD_Write_IT(SD_HandleTypeDef *hsd);
static void SD_Read_IT(SD_HandleTypeDef *hsd);
static void SD_DMATransmitCplt(DMA_HandleTypeDef *hdma);
static void SD_DMAReceiveCplt(DMA_HandleTypeDef *hdma);
static void SD_DMAError(DMA_HandleTypeDef *hdma);
static void SD_DMATxAbort(DMA_HandleTypeDef *hdma);
static void SD_DMARxAbort(DMA_HandleTypeDef *hdma);
/**
* @}
*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup SD_Exported_Functions
* @{
*/
/** @addtogroup SD_Exported_Functions_Group1
* @brief Initialization and de-initialization functions
*
@verbatim
==============================================================================
##### Initialization and de-initialization functions #####
==============================================================================
[..]
This section provides functions allowing to initialize/de-initialize the SD
card device to be ready for use.
@endverbatim
* @{
*/
/**
* @brief Initializes the SD according to the specified parameters in the
SD_HandleTypeDef and create the associated handle.
* @param hsd: Pointer to the SD handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SD_Init(SD_HandleTypeDef *hsd)
{
/* Check the SD handle allocation */
if(hsd == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_SDIO_ALL_INSTANCE(hsd->Instance));
assert_param(IS_SDIO_CLOCK_EDGE(hsd->Init.ClockEdge));
assert_param(IS_SDIO_CLOCK_BYPASS(hsd->Init.ClockBypass));
assert_param(IS_SDIO_CLOCK_POWER_SAVE(hsd->Init.ClockPowerSave));
assert_param(IS_SDIO_BUS_WIDE(hsd->Init.BusWide));
assert_param(IS_SDIO_HARDWARE_FLOW_CONTROL(hsd->Init.HardwareFlowControl));
assert_param(IS_SDIO_CLKDIV(hsd->Init.ClockDiv));
if(hsd->State == HAL_SD_STATE_RESET)
{
/* Allocate lock resource and initialize it */
hsd->Lock = HAL_UNLOCKED;
#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U)
/* Reset Callback pointers in HAL_SD_STATE_RESET only */
hsd->TxCpltCallback = HAL_SD_TxCpltCallback;
hsd->RxCpltCallback = HAL_SD_RxCpltCallback;
hsd->ErrorCallback = HAL_SD_ErrorCallback;
hsd->AbortCpltCallback = HAL_SD_AbortCallback;
if(hsd->MspInitCallback == NULL)
{
hsd->MspInitCallback = HAL_SD_MspInit;
}
/* Init the low level hardware */
hsd->MspInitCallback(hsd);
#else
/* Init the low level hardware : GPIO, CLOCK, CORTEX...etc */
HAL_SD_MspInit(hsd);
#endif /* USE_HAL_SD_REGISTER_CALLBACKS */
}
hsd->State = HAL_SD_STATE_BUSY;
/* Initialize the Card parameters */
if (HAL_SD_InitCard(hsd) != HAL_OK)
{
return HAL_ERROR;
}
/* Initialize the error code */
hsd->ErrorCode = HAL_SD_ERROR_NONE;
/* Initialize the SD operation */
hsd->Context = SD_CONTEXT_NONE;
/* Initialize the SD state */
hsd->State = HAL_SD_STATE_READY;
return HAL_OK;
}
/**
* @brief Initializes the SD Card.
* @param hsd: Pointer to SD handle
* @note This function initializes the SD card. It could be used when a card
re-initialization is needed.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SD_InitCard(SD_HandleTypeDef *hsd)
{
uint32_t errorstate;
SD_InitTypeDef Init;
/* Default SDIO peripheral configuration for SD card initialization */
Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;
Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
Init.BusWide = SDIO_BUS_WIDE_1B;
Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
Init.ClockDiv = SDIO_INIT_CLK_DIV;
/* Initialize SDIO peripheral interface with default configuration */
SDIO_Init(hsd->Instance, Init);
/* Disable SDIO Clock */
__HAL_SD_DISABLE(hsd);
/* Set Power State to ON */
(void)SDIO_PowerState_ON(hsd->Instance);
/* Enable SDIO Clock */
__HAL_SD_ENABLE(hsd);
/* Required power up waiting time before starting the SD initialization sequence */
HAL_Delay(2);
/* Identify card operating voltage */
errorstate = SD_PowerON(hsd);
if(errorstate != HAL_SD_ERROR_NONE)
{
hsd->State = HAL_SD_STATE_READY;
hsd->ErrorCode |= errorstate;
return HAL_ERROR;
}
/* Card initialization */
errorstate = SD_InitCard(hsd);
if(errorstate != HAL_SD_ERROR_NONE)
{
hsd->State = HAL_SD_STATE_READY;
hsd->ErrorCode |= errorstate;
return HAL_ERROR;
}
/* Set Block Size for Card */
errorstate = SDMMC_CmdBlockLength(hsd->Instance, BLOCKSIZE);
if(errorstate != HAL_SD_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->ErrorCode |= errorstate;
hsd->State = HAL_SD_STATE_READY;
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief De-Initializes the SD card.
* @param hsd: Pointer to SD handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SD_DeInit(SD_HandleTypeDef *hsd)
{
/* Check the SD handle allocation */
if(hsd == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_SDIO_ALL_INSTANCE(hsd->Instance));
hsd->State = HAL_SD_STATE_BUSY;
/* Set SD power state to off */
SD_PowerOFF(hsd);
#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U)
if(hsd->MspDeInitCallback == NULL)
{
hsd->MspDeInitCallback = HAL_SD_MspDeInit;
}
/* DeInit the low level hardware */
hsd->MspDeInitCallback(hsd);
#else
/* De-Initialize the MSP layer */
HAL_SD_MspDeInit(hsd);
#endif /* USE_HAL_SD_REGISTER_CALLBACKS */
hsd->ErrorCode = HAL_SD_ERROR_NONE;
hsd->State = HAL_SD_STATE_RESET;
return HAL_OK;
}
/**
* @brief Initializes the SD MSP.
* @param hsd: Pointer to SD handle
* @retval None
*/
__weak void HAL_SD_MspInit(SD_HandleTypeDef *hsd)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hsd);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_SD_MspInit could be implemented in the user file
*/
}
/**
* @brief De-Initialize SD MSP.
* @param hsd: Pointer to SD handle
* @retval None
*/
__weak void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hsd);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_SD_MspDeInit could be implemented in the user file
*/
}
/**
* @}
*/
/** @addtogroup SD_Exported_Functions_Group2
* @brief Data transfer functions
*
@verbatim
==============================================================================
##### IO operation functions #####
==============================================================================
[..]
This subsection provides a set of functions allowing to manage the data
transfer from/to SD card.
@endverbatim
* @{
*/
/**
* @brief Reads block(s) from a specified address in a card. The Data transfer
* is managed by polling mode.
* @note This API should be followed by a check on the card state through
* HAL_SD_GetCardState().
* @param hsd: Pointer to SD handle
* @param pData: pointer to the buffer that will contain the received data
* @param BlockAdd: Block Address from where data is to be read
* @param NumberOfBlocks: Number of SD blocks to read
* @param Timeout: Specify timeout value
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks, uint32_t Timeout)
{
SDIO_DataInitTypeDef config;
uint32_t errorstate;
uint32_t tickstart = HAL_GetTick();
uint32_t count, data, dataremaining;
uint32_t add = BlockAdd;
uint8_t *tempbuff = pData;
if(NULL == pData)
{
hsd->ErrorCode |= HAL_SD_ERROR_PARAM;
return HAL_ERROR;
}
if(hsd->State == HAL_SD_STATE_READY)
{
hsd->ErrorCode = HAL_SD_ERROR_NONE;
if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr))
{
hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
return HAL_ERROR;
}
hsd->State = HAL_SD_STATE_BUSY;
/* Initialize data control register */
hsd->Instance->DCTRL = 0U;
if(hsd->SdCard.CardType != CARD_SDHC_SDXC)
{
add *= 512U;
}
/* Configure the SD DPSM (Data Path State Machine) */
config.DataTimeOut = SDMMC_DATATIMEOUT;
config.DataLength = NumberOfBlocks * BLOCKSIZE;
config.DataBlockSize = SDIO_DATABLOCK_SIZE_512B;
config.TransferDir = SDIO_TRANSFER_DIR_TO_SDIO;
config.TransferMode = SDIO_TRANSFER_MODE_BLOCK;
config.DPSM = SDIO_DPSM_ENABLE;
(void)SDIO_ConfigData(hsd->Instance, &config);
/* Read block(s) in polling mode */
if(NumberOfBlocks > 1U)
{
hsd->Context = SD_CONTEXT_READ_MULTIPLE_BLOCK;
/* Read Multi Block command */
errorstate = SDMMC_CmdReadMultiBlock(hsd->Instance, add);
}
else
{
hsd->Context = SD_CONTEXT_READ_SINGLE_BLOCK;
/* Read Single Block command */
errorstate = SDMMC_CmdReadSingleBlock(hsd->Instance, add);
}
if(errorstate != HAL_SD_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->ErrorCode |= errorstate;
hsd->State = HAL_SD_STATE_READY;
hsd->Context = SD_CONTEXT_NONE;
return HAL_ERROR;
}
/* Poll on SDIO flags */
dataremaining = config.DataLength;
while(!__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DATAEND | SDIO_FLAG_STBITERR))
{
if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_RXFIFOHF) && (dataremaining > 0U))
{
/* Read data from SDIO Rx FIFO */
for(count = 0U; count < 8U; count++)
{
data = SDIO_ReadFIFO(hsd->Instance);
*tempbuff = (uint8_t)(data & 0xFFU);
tempbuff++;
dataremaining--;
*tempbuff = (uint8_t)((data >> 8U) & 0xFFU);
tempbuff++;
dataremaining--;
*tempbuff = (uint8_t)((data >> 16U) & 0xFFU);
tempbuff++;
dataremaining--;
*tempbuff = (uint8_t)((data >> 24U) & 0xFFU);
tempbuff++;
dataremaining--;
}
}
if(((HAL_GetTick()-tickstart) >= Timeout) || (Timeout == 0U))
{
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->ErrorCode |= HAL_SD_ERROR_TIMEOUT;
hsd->State= HAL_SD_STATE_READY;
hsd->Context = SD_CONTEXT_NONE;
return HAL_TIMEOUT;
}
}
/* Send stop transmission command in case of multiblock read */
if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_DATAEND) && (NumberOfBlocks > 1U))
{
if(hsd->SdCard.CardType != CARD_SECURED)
{
/* Send stop transmission command */
errorstate = SDMMC_CmdStopTransfer(hsd->Instance);
if(errorstate != HAL_SD_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->ErrorCode |= errorstate;
hsd->State = HAL_SD_STATE_READY;
hsd->Context = SD_CONTEXT_NONE;
return HAL_ERROR;
}
}
}
/* Get error state */
if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_DTIMEOUT) || (__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_STBITERR)))
{
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->ErrorCode |= HAL_SD_ERROR_DATA_TIMEOUT;
hsd->State = HAL_SD_STATE_READY;
hsd->Context = SD_CONTEXT_NONE;
return HAL_ERROR;
}
else if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_DCRCFAIL))
{
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->ErrorCode |= HAL_SD_ERROR_DATA_CRC_FAIL;
hsd->State = HAL_SD_STATE_READY;
hsd->Context = SD_CONTEXT_NONE;
return HAL_ERROR;
}
else if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_RXOVERR))
{
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->ErrorCode |= HAL_SD_ERROR_RX_OVERRUN;
hsd->State = HAL_SD_STATE_READY;
hsd->Context = SD_CONTEXT_NONE;
return HAL_ERROR;
}
else
{
/* Nothing to do */
}
/* Empty FIFO if there is still any data */
while ((__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_RXDAVL)) && (dataremaining > 0U))
{
data = SDIO_ReadFIFO(hsd->Instance);
*tempbuff = (uint8_t)(data & 0xFFU);
tempbuff++;
dataremaining--;
*tempbuff = (uint8_t)((data >> 8U) & 0xFFU);
tempbuff++;
dataremaining--;
*tempbuff = (uint8_t)((data >> 16U) & 0xFFU);
tempbuff++;
dataremaining--;
*tempbuff = (uint8_t)((data >> 24U) & 0xFFU);
tempbuff++;
dataremaining--;
if(((HAL_GetTick()-tickstart) >= Timeout) || (Timeout == 0U))
{
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->ErrorCode |= HAL_SD_ERROR_TIMEOUT;
hsd->State= HAL_SD_STATE_READY;
hsd->Context = SD_CONTEXT_NONE;
return HAL_ERROR;
}
}
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_DATA_FLAGS);
hsd->State = HAL_SD_STATE_READY;
return HAL_OK;
}
else
{
hsd->ErrorCode |= HAL_SD_ERROR_BUSY;
return HAL_ERROR;
}
}
/**
* @brief Allows to write block(s) to a specified address in a card. The Data
* transfer is managed by polling mode.
* @note This API should be followed by a check on the card state through
* HAL_SD_GetCardState().
* @param hsd: Pointer to SD handle
* @param pData: pointer to the buffer that will contain the data to transmit
* @param BlockAdd: Block Address where data will be written
* @param NumberOfBlocks: Number of SD blocks to write
* @param Timeout: Specify timeout value
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SD_WriteBlocks(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks, uint32_t Timeout)
{
SDIO_DataInitTypeDef config;
uint32_t errorstate;
uint32_t tickstart = HAL_GetTick();
uint32_t count, data, dataremaining;
uint32_t add = BlockAdd;
uint8_t *tempbuff = pData;
if(NULL == pData)
{
hsd->ErrorCode |= HAL_SD_ERROR_PARAM;
return HAL_ERROR;
}
if(hsd->State == HAL_SD_STATE_READY)
{
hsd->ErrorCode = HAL_SD_ERROR_NONE;
if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr))
{
hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
return HAL_ERROR;
}
hsd->State = HAL_SD_STATE_BUSY;
/* Initialize data control register */
hsd->Instance->DCTRL = 0U;
if(hsd->SdCard.CardType != CARD_SDHC_SDXC)
{
add *= 512U;
}
/* Configure the SD DPSM (Data Path State Machine) */
config.DataTimeOut = SDMMC_DATATIMEOUT;
config.DataLength = NumberOfBlocks * BLOCKSIZE;
config.DataBlockSize = SDIO_DATABLOCK_SIZE_512B;
config.TransferDir = SDIO_TRANSFER_DIR_TO_CARD;
config.TransferMode = SDIO_TRANSFER_MODE_BLOCK;
config.DPSM = SDIO_DPSM_ENABLE;
(void)SDIO_ConfigData(hsd->Instance, &config);
/* Write Blocks in Polling mode */
if(NumberOfBlocks > 1U)
{
hsd->Context = SD_CONTEXT_WRITE_MULTIPLE_BLOCK;
/* Write Multi Block command */
errorstate = SDMMC_CmdWriteMultiBlock(hsd->Instance, add);
}
else
{
hsd->Context = SD_CONTEXT_WRITE_SINGLE_BLOCK;
/* Write Single Block command */
errorstate = SDMMC_CmdWriteSingleBlock(hsd->Instance, add);
}
if(errorstate != HAL_SD_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->ErrorCode |= errorstate;
hsd->State = HAL_SD_STATE_READY;
hsd->Context = SD_CONTEXT_NONE;
return HAL_ERROR;
}
/* Write block(s) in polling mode */
dataremaining = config.DataLength;
while(!__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_TXUNDERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DATAEND | SDIO_FLAG_STBITERR))
{
if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_TXFIFOHE) && (dataremaining > 0U))
{
/* Write data to SDIO Tx FIFO */
for(count = 0U; count < 8U; count++)
{
data = (uint32_t)(*tempbuff);
tempbuff++;
dataremaining--;
data |= ((uint32_t)(*tempbuff) << 8U);
tempbuff++;
dataremaining--;
data |= ((uint32_t)(*tempbuff) << 16U);
tempbuff++;
dataremaining--;
data |= ((uint32_t)(*tempbuff) << 24U);
tempbuff++;
dataremaining--;
(void)SDIO_WriteFIFO(hsd->Instance, &data);
}
}
if(((HAL_GetTick()-tickstart) >= Timeout) || (Timeout == 0U))
{
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->ErrorCode |= errorstate;
hsd->State = HAL_SD_STATE_READY;
hsd->Context = SD_CONTEXT_NONE;
return HAL_TIMEOUT;
}
}
/* Send stop transmission command in case of multiblock write */
if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_DATAEND) && (NumberOfBlocks > 1U))
{
if(hsd->SdCard.CardType != CARD_SECURED)
{
/* Send stop transmission command */
errorstate = SDMMC_CmdStopTransfer(hsd->Instance);
if(errorstate != HAL_SD_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->ErrorCode |= errorstate;
hsd->State = HAL_SD_STATE_READY;
hsd->Context = SD_CONTEXT_NONE;
return HAL_ERROR;
}
}
}
/* Get error state */
if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_DTIMEOUT) || (__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_STBITERR)))
{
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->ErrorCode |= HAL_SD_ERROR_DATA_TIMEOUT;
hsd->State = HAL_SD_STATE_READY;
hsd->Context = SD_CONTEXT_NONE;
return HAL_ERROR;
}
else if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_DCRCFAIL))
{
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->ErrorCode |= HAL_SD_ERROR_DATA_CRC_FAIL;
hsd->State = HAL_SD_STATE_READY;
hsd->Context = SD_CONTEXT_NONE;
return HAL_ERROR;
}
else if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_TXUNDERR))
{
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->ErrorCode |= HAL_SD_ERROR_TX_UNDERRUN;
hsd->State = HAL_SD_STATE_READY;
hsd->Context = SD_CONTEXT_NONE;
return HAL_ERROR;
}
else
{
/* Nothing to do */
}
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_DATA_FLAGS);
hsd->State = HAL_SD_STATE_READY;
return HAL_OK;
}
else
{
hsd->ErrorCode |= HAL_SD_ERROR_BUSY;
return HAL_ERROR;
}
}
/**
* @brief Reads block(s) from a specified address in a card. The Data transfer
* is managed in interrupt mode.
* @note This API should be followed by a check on the card state through
* HAL_SD_GetCardState().
* @note You could also check the IT transfer process through the SD Rx
* interrupt event.
* @param hsd: Pointer to SD handle
* @param pData: Pointer to the buffer that will contain the received data
* @param BlockAdd: Block Address from where data is to be read
* @param NumberOfBlocks: Number of blocks to read.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SD_ReadBlocks_IT(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks)
{
SDIO_DataInitTypeDef config;
uint32_t errorstate;
uint32_t add = BlockAdd;
if(NULL == pData)
{
hsd->ErrorCode |= HAL_SD_ERROR_PARAM;
return HAL_ERROR;
}
if(hsd->State == HAL_SD_STATE_READY)
{
hsd->ErrorCode = HAL_SD_ERROR_NONE;
if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr))
{
hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
return HAL_ERROR;
}
hsd->State = HAL_SD_STATE_BUSY;
/* Initialize data control register */
hsd->Instance->DCTRL = 0U;
hsd->pRxBuffPtr = pData;
hsd->RxXferSize = BLOCKSIZE * NumberOfBlocks;
__HAL_SD_ENABLE_IT(hsd, (SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_RXOVERR | SDIO_IT_DATAEND | SDIO_FLAG_RXFIFOHF));
if(hsd->SdCard.CardType != CARD_SDHC_SDXC)
{
add *= 512U;
}
/* Configure the SD DPSM (Data Path State Machine) */
config.DataTimeOut = SDMMC_DATATIMEOUT;
config.DataLength = BLOCKSIZE * NumberOfBlocks;
config.DataBlockSize = SDIO_DATABLOCK_SIZE_512B;
config.TransferDir = SDIO_TRANSFER_DIR_TO_SDIO;
config.TransferMode = SDIO_TRANSFER_MODE_BLOCK;
config.DPSM = SDIO_DPSM_ENABLE;
(void)SDIO_ConfigData(hsd->Instance, &config);
/* Read Blocks in IT mode */
if(NumberOfBlocks > 1U)
{
hsd->Context = (SD_CONTEXT_READ_MULTIPLE_BLOCK | SD_CONTEXT_IT);
/* Read Multi Block command */
errorstate = SDMMC_CmdReadMultiBlock(hsd->Instance, add);
}
else
{
hsd->Context = (SD_CONTEXT_READ_SINGLE_BLOCK | SD_CONTEXT_IT);
/* Read Single Block command */
errorstate = SDMMC_CmdReadSingleBlock(hsd->Instance, add);
}
if(errorstate != HAL_SD_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->ErrorCode |= errorstate;
hsd->State = HAL_SD_STATE_READY;
hsd->Context = SD_CONTEXT_NONE;
return HAL_ERROR;
}
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Writes block(s) to a specified address in a card. The Data transfer
* is managed in interrupt mode.
* @note This API should be followed by a check on the card state through
* HAL_SD_GetCardState().
* @note You could also check the IT transfer process through the SD Tx
* interrupt event.
* @param hsd: Pointer to SD handle
* @param pData: Pointer to the buffer that will contain the data to transmit
* @param BlockAdd: Block Address where data will be written
* @param NumberOfBlocks: Number of blocks to write
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SD_WriteBlocks_IT(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks)
{
SDIO_DataInitTypeDef config;
uint32_t errorstate;
uint32_t add = BlockAdd;
if(NULL == pData)
{
hsd->ErrorCode |= HAL_SD_ERROR_PARAM;
return HAL_ERROR;
}
if(hsd->State == HAL_SD_STATE_READY)
{
hsd->ErrorCode = HAL_SD_ERROR_NONE;
if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr))
{
hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
return HAL_ERROR;
}
hsd->State = HAL_SD_STATE_BUSY;
/* Initialize data control register */
hsd->Instance->DCTRL = 0U;
hsd->pTxBuffPtr = pData;
hsd->TxXferSize = BLOCKSIZE * NumberOfBlocks;
/* Enable transfer interrupts */
__HAL_SD_ENABLE_IT(hsd, (SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_TXUNDERR | SDIO_IT_DATAEND | SDIO_FLAG_TXFIFOHE));
if(hsd->SdCard.CardType != CARD_SDHC_SDXC)
{
add *= 512U;
}
/* Write Blocks in Polling mode */
if(NumberOfBlocks > 1U)
{
hsd->Context = (SD_CONTEXT_WRITE_MULTIPLE_BLOCK| SD_CONTEXT_IT);
/* Write Multi Block command */
errorstate = SDMMC_CmdWriteMultiBlock(hsd->Instance, add);
}
else
{
hsd->Context = (SD_CONTEXT_WRITE_SINGLE_BLOCK | SD_CONTEXT_IT);
/* Write Single Block command */
errorstate = SDMMC_CmdWriteSingleBlock(hsd->Instance, add);
}
if(errorstate != HAL_SD_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->ErrorCode |= errorstate;
hsd->State = HAL_SD_STATE_READY;
hsd->Context = SD_CONTEXT_NONE;
return HAL_ERROR;
}
/* Configure the SD DPSM (Data Path State Machine) */
config.DataTimeOut = SDMMC_DATATIMEOUT;
config.DataLength = BLOCKSIZE * NumberOfBlocks;
config.DataBlockSize = SDIO_DATABLOCK_SIZE_512B;
config.TransferDir = SDIO_TRANSFER_DIR_TO_CARD;
config.TransferMode = SDIO_TRANSFER_MODE_BLOCK;
config.DPSM = SDIO_DPSM_ENABLE;
(void)SDIO_ConfigData(hsd->Instance, &config);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Reads block(s) from a specified address in a card. The Data transfer
* is managed by DMA mode.
* @note This API should be followed by a check on the card state through
* HAL_SD_GetCardState().
* @note You could also check the DMA transfer process through the SD Rx
* interrupt event.
* @param hsd: Pointer SD handle
* @param pData: Pointer to the buffer that will contain the received data
* @param BlockAdd: Block Address from where data is to be read
* @param NumberOfBlocks: Number of blocks to read.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SD_ReadBlocks_DMA(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks)
{
SDIO_DataInitTypeDef config;
uint32_t errorstate;
uint32_t add = BlockAdd;
if(NULL == pData)
{
hsd->ErrorCode |= HAL_SD_ERROR_PARAM;
return HAL_ERROR;
}
if(hsd->State == HAL_SD_STATE_READY)
{
hsd->ErrorCode = HAL_SD_ERROR_NONE;
if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr))
{
hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
return HAL_ERROR;
}
hsd->State = HAL_SD_STATE_BUSY;
/* Initialize data control register */
hsd->Instance->DCTRL = 0U;
__HAL_SD_ENABLE_IT(hsd, (SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_RXOVERR | SDIO_IT_DATAEND));
/* Set the DMA transfer complete callback */
hsd->hdmarx->XferCpltCallback = SD_DMAReceiveCplt;
/* Set the DMA error callback */
hsd->hdmarx->XferErrorCallback = SD_DMAError;
/* Set the DMA Abort callback */
hsd->hdmarx->XferAbortCallback = NULL;
/* Force DMA Direction */
hsd->hdmarx->Init.Direction = DMA_PERIPH_TO_MEMORY;
MODIFY_REG(hsd->hdmarx->Instance->CCR, DMA_CCR_DIR, hsd->hdmarx->Init.Direction);
/* Enable the DMA Channel */
if(HAL_DMA_Start_IT(hsd->hdmarx, (uint32_t)&hsd->Instance->FIFO, (uint32_t)pData, (uint32_t)(BLOCKSIZE * NumberOfBlocks)/4U) != HAL_OK)
{
__HAL_SD_DISABLE_IT(hsd, (SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_RXOVERR | SDIO_IT_DATAEND));
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->ErrorCode |= HAL_SD_ERROR_DMA;
hsd->State = HAL_SD_STATE_READY;
return HAL_ERROR;
}
else
{
/* Enable SD DMA transfer */
__HAL_SD_DMA_ENABLE(hsd);
if(hsd->SdCard.CardType != CARD_SDHC_SDXC)
{
add *= 512U;
}
/* Configure the SD DPSM (Data Path State Machine) */
config.DataTimeOut = SDMMC_DATATIMEOUT;
config.DataLength = BLOCKSIZE * NumberOfBlocks;
config.DataBlockSize = SDIO_DATABLOCK_SIZE_512B;
config.TransferDir = SDIO_TRANSFER_DIR_TO_SDIO;
config.TransferMode = SDIO_TRANSFER_MODE_BLOCK;
config.DPSM = SDIO_DPSM_ENABLE;
(void)SDIO_ConfigData(hsd->Instance, &config);
/* Read Blocks in DMA mode */
if(NumberOfBlocks > 1U)
{
hsd->Context = (SD_CONTEXT_READ_MULTIPLE_BLOCK | SD_CONTEXT_DMA);
/* Read Multi Block command */
errorstate = SDMMC_CmdReadMultiBlock(hsd->Instance, add);
}
else
{
hsd->Context = (SD_CONTEXT_READ_SINGLE_BLOCK | SD_CONTEXT_DMA);
/* Read Single Block command */
errorstate = SDMMC_CmdReadSingleBlock(hsd->Instance, add);
}
if(errorstate != HAL_SD_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->ErrorCode |= errorstate;
hsd->State = HAL_SD_STATE_READY;
hsd->Context = SD_CONTEXT_NONE;
return HAL_ERROR;
}
return HAL_OK;
}
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Writes block(s) to a specified address in a card. The Data transfer
* is managed by DMA mode.
* @note This API should be followed by a check on the card state through
* HAL_SD_GetCardState().
* @note You could also check the DMA transfer process through the SD Tx
* interrupt event.
* @param hsd: Pointer to SD handle
* @param pData: Pointer to the buffer that will contain the data to transmit
* @param BlockAdd: Block Address where data will be written
* @param NumberOfBlocks: Number of blocks to write
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SD_WriteBlocks_DMA(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks)
{
SDIO_DataInitTypeDef config;
uint32_t errorstate;
uint32_t add = BlockAdd;
if(NULL == pData)
{
hsd->ErrorCode |= HAL_SD_ERROR_PARAM;
return HAL_ERROR;
}
if(hsd->State == HAL_SD_STATE_READY)
{
hsd->ErrorCode = HAL_SD_ERROR_NONE;
if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr))
{
hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
return HAL_ERROR;
}
hsd->State = HAL_SD_STATE_BUSY;
/* Initialize data control register */
hsd->Instance->DCTRL = 0U;
/* Enable SD Error interrupts */
__HAL_SD_ENABLE_IT(hsd, (SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_TXUNDERR));
/* Set the DMA transfer complete callback */
hsd->hdmatx->XferCpltCallback = SD_DMATransmitCplt;
/* Set the DMA error callback */
hsd->hdmatx->XferErrorCallback = SD_DMAError;
/* Set the DMA Abort callback */
hsd->hdmatx->XferAbortCallback = NULL;
if(hsd->SdCard.CardType != CARD_SDHC_SDXC)
{
add *= 512U;
}
/* Write Blocks in Polling mode */
if(NumberOfBlocks > 1U)
{
hsd->Context = (SD_CONTEXT_WRITE_MULTIPLE_BLOCK | SD_CONTEXT_DMA);
/* Write Multi Block command */
errorstate = SDMMC_CmdWriteMultiBlock(hsd->Instance, add);
}
else
{
hsd->Context = (SD_CONTEXT_WRITE_SINGLE_BLOCK | SD_CONTEXT_DMA);
/* Write Single Block command */
errorstate = SDMMC_CmdWriteSingleBlock(hsd->Instance, add);
}
if(errorstate != HAL_SD_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->ErrorCode |= errorstate;
hsd->State = HAL_SD_STATE_READY;
hsd->Context = SD_CONTEXT_NONE;
return HAL_ERROR;
}
/* Enable SDIO DMA transfer */
__HAL_SD_DMA_ENABLE(hsd);
/* Force DMA Direction */
hsd->hdmatx->Init.Direction = DMA_MEMORY_TO_PERIPH;
MODIFY_REG(hsd->hdmatx->Instance->CCR, DMA_CCR_DIR, hsd->hdmatx->Init.Direction);
/* Enable the DMA Channel */
if(HAL_DMA_Start_IT(hsd->hdmatx, (uint32_t)pData, (uint32_t)&hsd->Instance->FIFO, (uint32_t)(BLOCKSIZE * NumberOfBlocks)/4U) != HAL_OK)
{
__HAL_SD_DISABLE_IT(hsd, (SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_TXUNDERR));
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->ErrorCode |= HAL_SD_ERROR_DMA;
hsd->State = HAL_SD_STATE_READY;
hsd->Context = SD_CONTEXT_NONE;
return HAL_ERROR;
}
else
{
/* Configure the SD DPSM (Data Path State Machine) */
config.DataTimeOut = SDMMC_DATATIMEOUT;
config.DataLength = BLOCKSIZE * NumberOfBlocks;
config.DataBlockSize = SDIO_DATABLOCK_SIZE_512B;
config.TransferDir = SDIO_TRANSFER_DIR_TO_CARD;
config.TransferMode = SDIO_TRANSFER_MODE_BLOCK;
config.DPSM = SDIO_DPSM_ENABLE;
(void)SDIO_ConfigData(hsd->Instance, &config);
return HAL_OK;
}
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Erases the specified memory area of the given SD card.
* @note This API should be followed by a check on the card state through
* HAL_SD_GetCardState().
* @param hsd: Pointer to SD handle
* @param BlockStartAdd: Start Block address
* @param BlockEndAdd: End Block address
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SD_Erase(SD_HandleTypeDef *hsd, uint32_t BlockStartAdd, uint32_t BlockEndAdd)
{
uint32_t errorstate;
uint32_t start_add = BlockStartAdd;
uint32_t end_add = BlockEndAdd;
if(hsd->State == HAL_SD_STATE_READY)
{
hsd->ErrorCode = HAL_SD_ERROR_NONE;
if(end_add < start_add)
{
hsd->ErrorCode |= HAL_SD_ERROR_PARAM;
return HAL_ERROR;
}
if(end_add > (hsd->SdCard.LogBlockNbr))
{
hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
return HAL_ERROR;
}
hsd->State = HAL_SD_STATE_BUSY;
/* Check if the card command class supports erase command */
if(((hsd->SdCard.Class) & SDIO_CCCC_ERASE) == 0U)
{
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->ErrorCode |= HAL_SD_ERROR_REQUEST_NOT_APPLICABLE;
hsd->State = HAL_SD_STATE_READY;
return HAL_ERROR;
}
if((SDIO_GetResponse(hsd->Instance, SDIO_RESP1) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED)
{
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->ErrorCode |= HAL_SD_ERROR_LOCK_UNLOCK_FAILED;
hsd->State = HAL_SD_STATE_READY;
return HAL_ERROR;
}
/* Get start and end block for high capacity cards */
if(hsd->SdCard.CardType != CARD_SDHC_SDXC)
{
start_add *= 512U;
end_add *= 512U;
}
/* According to sd-card spec 1.0 ERASE_GROUP_START (CMD32) and erase_group_end(CMD33) */
if(hsd->SdCard.CardType != CARD_SECURED)
{
/* Send CMD32 SD_ERASE_GRP_START with argument as addr */
errorstate = SDMMC_CmdSDEraseStartAdd(hsd->Instance, start_add);
if(errorstate != HAL_SD_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->ErrorCode |= errorstate;
hsd->State = HAL_SD_STATE_READY;
return HAL_ERROR;
}
/* Send CMD33 SD_ERASE_GRP_END with argument as addr */
errorstate = SDMMC_CmdSDEraseEndAdd(hsd->Instance, end_add);
if(errorstate != HAL_SD_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->ErrorCode |= errorstate;
hsd->State = HAL_SD_STATE_READY;
return HAL_ERROR;
}
}
/* Send CMD38 ERASE */
errorstate = SDMMC_CmdErase(hsd->Instance);
if(errorstate != HAL_SD_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->ErrorCode |= errorstate;
hsd->State = HAL_SD_STATE_READY;
return HAL_ERROR;
}
hsd->State = HAL_SD_STATE_READY;
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief This function handles SD card interrupt request.
* @param hsd: Pointer to SD handle
* @retval None
*/
void HAL_SD_IRQHandler(SD_HandleTypeDef *hsd)
{
uint32_t errorstate;
uint32_t context = hsd->Context;
/* Check for SDIO interrupt flags */
if((__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_RXFIFOHF) != RESET) && ((context & SD_CONTEXT_IT) != 0U))
{
SD_Read_IT(hsd);
}
else if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_DATAEND) != RESET)
{
__HAL_SD_CLEAR_FLAG(hsd, SDIO_FLAG_DATAEND);
__HAL_SD_DISABLE_IT(hsd, SDIO_IT_DATAEND | SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT|\
SDIO_IT_TXUNDERR | SDIO_IT_RXOVERR | SDIO_IT_TXFIFOHE |\
SDIO_IT_RXFIFOHF);
hsd->Instance->DCTRL &= ~(SDIO_DCTRL_DTEN);
if((context & SD_CONTEXT_IT) != 0U)
{
if(((context & SD_CONTEXT_READ_MULTIPLE_BLOCK) != 0U) || ((context & SD_CONTEXT_WRITE_MULTIPLE_BLOCK) != 0U))
{
errorstate = SDMMC_CmdStopTransfer(hsd->Instance);
if(errorstate != HAL_SD_ERROR_NONE)
{
hsd->ErrorCode |= errorstate;
#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U)
hsd->ErrorCallback(hsd);
#else
HAL_SD_ErrorCallback(hsd);
#endif /* USE_HAL_SD_REGISTER_CALLBACKS */
}
}
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_DATA_FLAGS);
hsd->State = HAL_SD_STATE_READY;
hsd->Context = SD_CONTEXT_NONE;
if(((context & SD_CONTEXT_READ_SINGLE_BLOCK) != 0U) || ((context & SD_CONTEXT_READ_MULTIPLE_BLOCK) != 0U))
{
#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U)
hsd->RxCpltCallback(hsd);
#else
HAL_SD_RxCpltCallback(hsd);
#endif /* USE_HAL_SD_REGISTER_CALLBACKS */
}
else
{
#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U)
hsd->TxCpltCallback(hsd);
#else
HAL_SD_TxCpltCallback(hsd);
#endif /* USE_HAL_SD_REGISTER_CALLBACKS */
}
}
else if((context & SD_CONTEXT_DMA) != 0U)
{
if((context & SD_CONTEXT_WRITE_MULTIPLE_BLOCK) != 0U)
{
errorstate = SDMMC_CmdStopTransfer(hsd->Instance);
if(errorstate != HAL_SD_ERROR_NONE)
{
hsd->ErrorCode |= errorstate;
#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U)
hsd->ErrorCallback(hsd);
#else
HAL_SD_ErrorCallback(hsd);
#endif /* USE_HAL_SD_REGISTER_CALLBACKS */
}
}
if(((context & SD_CONTEXT_READ_SINGLE_BLOCK) == 0U) && ((context & SD_CONTEXT_READ_MULTIPLE_BLOCK) == 0U))
{
/* Disable the DMA transfer for transmit request by setting the DMAEN bit
in the SD DCTRL register */
hsd->Instance->DCTRL &= (uint32_t)~((uint32_t)SDIO_DCTRL_DMAEN);
hsd->State = HAL_SD_STATE_READY;
#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U)
hsd->TxCpltCallback(hsd);
#else
HAL_SD_TxCpltCallback(hsd);
#endif /* USE_HAL_SD_REGISTER_CALLBACKS */
}
}
else
{
/* Nothing to do */
}
}
else if((__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_TXFIFOHE) != RESET) && ((context & SD_CONTEXT_IT) != 0U))
{
SD_Write_IT(hsd);
}
else if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_RXOVERR | SDIO_FLAG_TXUNDERR) != RESET)
{
/* Set Error code */
if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_DCRCFAIL) != RESET)
{
hsd->ErrorCode |= HAL_SD_ERROR_DATA_CRC_FAIL;
}
if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_DTIMEOUT) != RESET)
{
hsd->ErrorCode |= HAL_SD_ERROR_DATA_TIMEOUT;
}
if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_RXOVERR) != RESET)
{
hsd->ErrorCode |= HAL_SD_ERROR_RX_OVERRUN;
}
if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_TXUNDERR) != RESET)
{
hsd->ErrorCode |= HAL_SD_ERROR_TX_UNDERRUN;
}
/* Clear All flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_DATA_FLAGS | SDIO_FLAG_STBITERR);
/* Disable all interrupts */
__HAL_SD_DISABLE_IT(hsd, SDIO_IT_DATAEND | SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT|\
SDIO_IT_TXUNDERR| SDIO_IT_RXOVERR | SDIO_IT_STBITERR);
hsd->ErrorCode |= SDMMC_CmdStopTransfer(hsd->Instance);
if((context & SD_CONTEXT_IT) != 0U)
{
/* Set the SD state to ready to be able to start again the process */
hsd->State = HAL_SD_STATE_READY;
hsd->Context = SD_CONTEXT_NONE;
#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U)
hsd->ErrorCallback(hsd);
#else
HAL_SD_ErrorCallback(hsd);
#endif /* USE_HAL_SD_REGISTER_CALLBACKS */
}
else if((context & SD_CONTEXT_DMA) != 0U)
{
/* Abort the SD DMA channel */
if(((context & SD_CONTEXT_WRITE_SINGLE_BLOCK) != 0U) || ((context & SD_CONTEXT_WRITE_MULTIPLE_BLOCK) != 0U))
{
/* Set the DMA Tx abort callback */
hsd->hdmatx->XferAbortCallback = SD_DMATxAbort;
/* Abort DMA in IT mode */
if(HAL_DMA_Abort_IT(hsd->hdmatx) != HAL_OK)
{
SD_DMATxAbort(hsd->hdmatx);
}
}
else if(((context & SD_CONTEXT_READ_SINGLE_BLOCK) != 0U) || ((context & SD_CONTEXT_READ_MULTIPLE_BLOCK) != 0U))
{
/* Set the DMA Rx abort callback */
hsd->hdmarx->XferAbortCallback = SD_DMARxAbort;
/* Abort DMA in IT mode */
if(HAL_DMA_Abort_IT(hsd->hdmarx) != HAL_OK)
{
SD_DMARxAbort(hsd->hdmarx);
}
}
else
{
hsd->ErrorCode = HAL_SD_ERROR_NONE;
hsd->State = HAL_SD_STATE_READY;
hsd->Context = SD_CONTEXT_NONE;
#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U)
hsd->AbortCpltCallback(hsd);
#else
HAL_SD_AbortCallback(hsd);
#endif /* USE_HAL_SD_REGISTER_CALLBACKS */
}
}
else
{
/* Nothing to do */
}
}
else
{
/* Nothing to do */
}
}
/**
* @brief return the SD state
* @param hsd: Pointer to sd handle
* @retval HAL state
*/
HAL_SD_StateTypeDef HAL_SD_GetState(SD_HandleTypeDef *hsd)
{
return hsd->State;
}
/**
* @brief Return the SD error code
* @param hsd : Pointer to a SD_HandleTypeDef structure that contains
* the configuration information.
* @retval SD Error Code
*/
uint32_t HAL_SD_GetError(SD_HandleTypeDef *hsd)
{
return hsd->ErrorCode;
}
/**
* @brief Tx Transfer completed callbacks
* @param hsd: Pointer to SD handle
* @retval None
*/
__weak void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hsd);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_SD_TxCpltCallback can be implemented in the user file
*/
}
/**
* @brief Rx Transfer completed callbacks
* @param hsd: Pointer SD handle
* @retval None
*/
__weak void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hsd);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_SD_RxCpltCallback can be implemented in the user file
*/
}
/**
* @brief SD error callbacks
* @param hsd: Pointer SD handle
* @retval None
*/
__weak void HAL_SD_ErrorCallback(SD_HandleTypeDef *hsd)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hsd);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_SD_ErrorCallback can be implemented in the user file
*/
}
/**
* @brief SD Abort callbacks
* @param hsd: Pointer SD handle
* @retval None
*/
__weak void HAL_SD_AbortCallback(SD_HandleTypeDef *hsd)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hsd);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_SD_AbortCallback can be implemented in the user file
*/
}
#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U)
/**
* @brief Register a User SD Callback
* To be used instead of the weak (surcharged) predefined callback
* @param hsd : SD handle
* @param CallbackID : ID of the callback to be registered
* This parameter can be one of the following values:
* @arg @ref HAL_SD_TX_CPLT_CB_ID SD Tx Complete Callback ID
* @arg @ref HAL_SD_RX_CPLT_CB_ID SD Rx Complete Callback ID
* @arg @ref HAL_SD_ERROR_CB_ID SD Error Callback ID
* @arg @ref HAL_SD_ABORT_CB_ID SD Abort Callback ID
* @arg @ref HAL_SD_MSP_INIT_CB_ID SD MspInit Callback ID
* @arg @ref HAL_SD_MSP_DEINIT_CB_ID SD MspDeInit Callback ID
* @param pCallback : pointer to the Callback function
* @retval status
*/
HAL_StatusTypeDef HAL_SD_RegisterCallback(SD_HandleTypeDef *hsd, HAL_SD_CallbackIDTypeDef CallbackID, pSD_CallbackTypeDef pCallback)
{
HAL_StatusTypeDef status = HAL_OK;
if(pCallback == NULL)
{
/* Update the error code */
hsd->ErrorCode |= HAL_SD_ERROR_INVALID_CALLBACK;
return HAL_ERROR;
}
/* Process locked */
__HAL_LOCK(hsd);
if(hsd->State == HAL_SD_STATE_READY)
{
switch (CallbackID)
{
case HAL_SD_TX_CPLT_CB_ID :
hsd->TxCpltCallback = pCallback;
break;
case HAL_SD_RX_CPLT_CB_ID :
hsd->RxCpltCallback = pCallback;
break;
case HAL_SD_ERROR_CB_ID :
hsd->ErrorCallback = pCallback;
break;
case HAL_SD_ABORT_CB_ID :
hsd->AbortCpltCallback = pCallback;
break;
case HAL_SD_MSP_INIT_CB_ID :
hsd->MspInitCallback = pCallback;
break;
case HAL_SD_MSP_DEINIT_CB_ID :
hsd->MspDeInitCallback = pCallback;
break;
default :
/* Update the error code */
hsd->ErrorCode |= HAL_SD_ERROR_INVALID_CALLBACK;
/* update return status */
status = HAL_ERROR;
break;
}
}
else if (hsd->State == HAL_SD_STATE_RESET)
{
switch (CallbackID)
{
case HAL_SD_MSP_INIT_CB_ID :
hsd->MspInitCallback = pCallback;
break;
case HAL_SD_MSP_DEINIT_CB_ID :
hsd->MspDeInitCallback = pCallback;
break;
default :
/* Update the error code */
hsd->ErrorCode |= HAL_SD_ERROR_INVALID_CALLBACK;
/* update return status */
status = HAL_ERROR;
break;
}
}
else
{
/* Update the error code */
hsd->ErrorCode |= HAL_SD_ERROR_INVALID_CALLBACK;
/* update return status */
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(hsd);
return status;
}
/**
* @brief Unregister a User SD Callback
* SD Callback is redirected to the weak (surcharged) predefined callback
* @param hsd : SD handle
* @param CallbackID : ID of the callback to be unregistered
* This parameter can be one of the following values:
* @arg @ref HAL_SD_TX_CPLT_CB_ID SD Tx Complete Callback ID
* @arg @ref HAL_SD_RX_CPLT_CB_ID SD Rx Complete Callback ID
* @arg @ref HAL_SD_ERROR_CB_ID SD Error Callback ID
* @arg @ref HAL_SD_ABORT_CB_ID SD Abort Callback ID
* @arg @ref HAL_SD_MSP_INIT_CB_ID SD MspInit Callback ID
* @arg @ref HAL_SD_MSP_DEINIT_CB_ID SD MspDeInit Callback ID
* @retval status
*/
HAL_StatusTypeDef HAL_SD_UnRegisterCallback(SD_HandleTypeDef *hsd, HAL_SD_CallbackIDTypeDef CallbackID)
{
HAL_StatusTypeDef status = HAL_OK;
/* Process locked */
__HAL_LOCK(hsd);
if(hsd->State == HAL_SD_STATE_READY)
{
switch (CallbackID)
{
case HAL_SD_TX_CPLT_CB_ID :
hsd->TxCpltCallback = HAL_SD_TxCpltCallback;
break;
case HAL_SD_RX_CPLT_CB_ID :
hsd->RxCpltCallback = HAL_SD_RxCpltCallback;
break;
case HAL_SD_ERROR_CB_ID :
hsd->ErrorCallback = HAL_SD_ErrorCallback;
break;
case HAL_SD_ABORT_CB_ID :
hsd->AbortCpltCallback = HAL_SD_AbortCallback;
break;
case HAL_SD_MSP_INIT_CB_ID :
hsd->MspInitCallback = HAL_SD_MspInit;
break;
case HAL_SD_MSP_DEINIT_CB_ID :
hsd->MspDeInitCallback = HAL_SD_MspDeInit;
break;
default :
/* Update the error code */
hsd->ErrorCode |= HAL_SD_ERROR_INVALID_CALLBACK;
/* update return status */
status = HAL_ERROR;
break;
}
}
else if (hsd->State == HAL_SD_STATE_RESET)
{
switch (CallbackID)
{
case HAL_SD_MSP_INIT_CB_ID :
hsd->MspInitCallback = HAL_SD_MspInit;
break;
case HAL_SD_MSP_DEINIT_CB_ID :
hsd->MspDeInitCallback = HAL_SD_MspDeInit;
break;
default :
/* Update the error code */
hsd->ErrorCode |= HAL_SD_ERROR_INVALID_CALLBACK;
/* update return status */
status = HAL_ERROR;
break;
}
}
else
{
/* Update the error code */
hsd->ErrorCode |= HAL_SD_ERROR_INVALID_CALLBACK;
/* update return status */
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(hsd);
return status;
}
#endif /* USE_HAL_SD_REGISTER_CALLBACKS */
/**
* @}
*/
/** @addtogroup SD_Exported_Functions_Group3
* @brief management functions
*
@verbatim
==============================================================================
##### Peripheral Control functions #####
==============================================================================
[..]
This subsection provides a set of functions allowing to control the SD card
operations and get the related information
@endverbatim
* @{
*/
/**
* @brief Returns information the information of the card which are stored on
* the CID register.
* @param hsd: Pointer to SD handle
* @param pCID: Pointer to a HAL_SD_CardCIDTypeDef structure that
* contains all CID register parameters
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SD_GetCardCID(SD_HandleTypeDef *hsd, HAL_SD_CardCIDTypeDef *pCID)
{
pCID->ManufacturerID = (uint8_t)((hsd->CID[0] & 0xFF000000U) >> 24U);
pCID->OEM_AppliID = (uint16_t)((hsd->CID[0] & 0x00FFFF00U) >> 8U);
pCID->ProdName1 = (((hsd->CID[0] & 0x000000FFU) << 24U) | ((hsd->CID[1] & 0xFFFFFF00U) >> 8U));
pCID->ProdName2 = (uint8_t)(hsd->CID[1] & 0x000000FFU);
pCID->ProdRev = (uint8_t)((hsd->CID[2] & 0xFF000000U) >> 24U);
pCID->ProdSN = (((hsd->CID[2] & 0x00FFFFFFU) << 8U) | ((hsd->CID[3] & 0xFF000000U) >> 24U));
pCID->Reserved1 = (uint8_t)((hsd->CID[3] & 0x00F00000U) >> 20U);
pCID->ManufactDate = (uint16_t)((hsd->CID[3] & 0x000FFF00U) >> 8U);
pCID->CID_CRC = (uint8_t)((hsd->CID[3] & 0x000000FEU) >> 1U);
pCID->Reserved2 = 1U;
return HAL_OK;
}
/**
* @brief Returns information the information of the card which are stored on
* the CSD register.
* @param hsd: Pointer to SD handle
* @param pCSD: Pointer to a HAL_SD_CardCSDTypeDef structure that
* contains all CSD register parameters
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SD_GetCardCSD(SD_HandleTypeDef *hsd, HAL_SD_CardCSDTypeDef *pCSD)
{
pCSD->CSDStruct = (uint8_t)((hsd->CSD[0] & 0xC0000000U) >> 30U);
pCSD->SysSpecVersion = (uint8_t)((hsd->CSD[0] & 0x3C000000U) >> 26U);
pCSD->Reserved1 = (uint8_t)((hsd->CSD[0] & 0x03000000U) >> 24U);
pCSD->TAAC = (uint8_t)((hsd->CSD[0] & 0x00FF0000U) >> 16U);
pCSD->NSAC = (uint8_t)((hsd->CSD[0] & 0x0000FF00U) >> 8U);
pCSD->MaxBusClkFrec = (uint8_t)(hsd->CSD[0] & 0x000000FFU);
pCSD->CardComdClasses = (uint16_t)((hsd->CSD[1] & 0xFFF00000U) >> 20U);
pCSD->RdBlockLen = (uint8_t)((hsd->CSD[1] & 0x000F0000U) >> 16U);
pCSD->PartBlockRead = (uint8_t)((hsd->CSD[1] & 0x00008000U) >> 15U);
pCSD->WrBlockMisalign = (uint8_t)((hsd->CSD[1] & 0x00004000U) >> 14U);
pCSD->RdBlockMisalign = (uint8_t)((hsd->CSD[1] & 0x00002000U) >> 13U);
pCSD->DSRImpl = (uint8_t)((hsd->CSD[1] & 0x00001000U) >> 12U);
pCSD->Reserved2 = 0U; /*!< Reserved */
if(hsd->SdCard.CardType == CARD_SDSC)
{
pCSD->DeviceSize = (((hsd->CSD[1] & 0x000003FFU) << 2U) | ((hsd->CSD[2] & 0xC0000000U) >> 30U));
pCSD->MaxRdCurrentVDDMin = (uint8_t)((hsd->CSD[2] & 0x38000000U) >> 27U);
pCSD->MaxRdCurrentVDDMax = (uint8_t)((hsd->CSD[2] & 0x07000000U) >> 24U);
pCSD->MaxWrCurrentVDDMin = (uint8_t)((hsd->CSD[2] & 0x00E00000U) >> 21U);
pCSD->MaxWrCurrentVDDMax = (uint8_t)((hsd->CSD[2] & 0x001C0000U) >> 18U);
pCSD->DeviceSizeMul = (uint8_t)((hsd->CSD[2] & 0x00038000U) >> 15U);
hsd->SdCard.BlockNbr = (pCSD->DeviceSize + 1U) ;
hsd->SdCard.BlockNbr *= (1UL << ((pCSD->DeviceSizeMul & 0x07U) + 2U));
hsd->SdCard.BlockSize = (1UL << (pCSD->RdBlockLen & 0x0FU));
hsd->SdCard.LogBlockNbr = (hsd->SdCard.BlockNbr) * ((hsd->SdCard.BlockSize) / 512U);
hsd->SdCard.LogBlockSize = 512U;
}
else if(hsd->SdCard.CardType == CARD_SDHC_SDXC)
{
/* Byte 7 */
pCSD->DeviceSize = (((hsd->CSD[1] & 0x0000003FU) << 16U) | ((hsd->CSD[2] & 0xFFFF0000U) >> 16U));
hsd->SdCard.BlockNbr = ((pCSD->DeviceSize + 1U) * 1024U);
hsd->SdCard.LogBlockNbr = hsd->SdCard.BlockNbr;
hsd->SdCard.BlockSize = 512U;
hsd->SdCard.LogBlockSize = hsd->SdCard.BlockSize;
}
else
{
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE;
hsd->State = HAL_SD_STATE_READY;
return HAL_ERROR;
}
pCSD->EraseGrSize = (uint8_t)((hsd->CSD[2] & 0x00004000U) >> 14U);
pCSD->EraseGrMul = (uint8_t)((hsd->CSD[2] & 0x00003F80U) >> 7U);
pCSD->WrProtectGrSize = (uint8_t)(hsd->CSD[2] & 0x0000007FU);
pCSD->WrProtectGrEnable = (uint8_t)((hsd->CSD[3] & 0x80000000U) >> 31U);
pCSD->ManDeflECC = (uint8_t)((hsd->CSD[3] & 0x60000000U) >> 29U);
pCSD->WrSpeedFact = (uint8_t)((hsd->CSD[3] & 0x1C000000U) >> 26U);
pCSD->MaxWrBlockLen= (uint8_t)((hsd->CSD[3] & 0x03C00000U) >> 22U);
pCSD->WriteBlockPaPartial = (uint8_t)((hsd->CSD[3] & 0x00200000U) >> 21U);
pCSD->Reserved3 = 0;
pCSD->ContentProtectAppli = (uint8_t)((hsd->CSD[3] & 0x00010000U) >> 16U);
pCSD->FileFormatGroup = (uint8_t)((hsd->CSD[3] & 0x00008000U) >> 15U);
pCSD->CopyFlag = (uint8_t)((hsd->CSD[3] & 0x00004000U) >> 14U);
pCSD->PermWrProtect = (uint8_t)((hsd->CSD[3] & 0x00002000U) >> 13U);
pCSD->TempWrProtect = (uint8_t)((hsd->CSD[3] & 0x00001000U) >> 12U);
pCSD->FileFormat = (uint8_t)((hsd->CSD[3] & 0x00000C00U) >> 10U);
pCSD->ECC= (uint8_t)((hsd->CSD[3] & 0x00000300U) >> 8U);
pCSD->CSD_CRC = (uint8_t)((hsd->CSD[3] & 0x000000FEU) >> 1U);
pCSD->Reserved4 = 1;
return HAL_OK;
}
/**
* @brief Gets the SD status info.
* @param hsd: Pointer to SD handle
* @param pStatus: Pointer to the HAL_SD_CardStatusTypeDef structure that
* will contain the SD card status information
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SD_GetCardStatus(SD_HandleTypeDef *hsd, HAL_SD_CardStatusTypeDef *pStatus)
{
uint32_t sd_status[16];
uint32_t errorstate;
HAL_StatusTypeDef status = HAL_OK;
errorstate = SD_SendSDStatus(hsd, sd_status);
if(errorstate != HAL_SD_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->ErrorCode |= errorstate;
hsd->State = HAL_SD_STATE_READY;
status = HAL_ERROR;
}
else
{
pStatus->DataBusWidth = (uint8_t)((sd_status[0] & 0xC0U) >> 6U);
pStatus->SecuredMode = (uint8_t)((sd_status[0] & 0x20U) >> 5U);
pStatus->CardType = (uint16_t)(((sd_status[0] & 0x00FF0000U) >> 8U) | ((sd_status[0] & 0xFF000000U) >> 24U));
pStatus->ProtectedAreaSize = (((sd_status[1] & 0xFFU) << 24U) | ((sd_status[1] & 0xFF00U) << 8U) |
((sd_status[1] & 0xFF0000U) >> 8U) | ((sd_status[1] & 0xFF000000U) >> 24U));
pStatus->SpeedClass = (uint8_t)(sd_status[2] & 0xFFU);
pStatus->PerformanceMove = (uint8_t)((sd_status[2] & 0xFF00U) >> 8U);
pStatus->AllocationUnitSize = (uint8_t)((sd_status[2] & 0xF00000U) >> 20U);
pStatus->EraseSize = (uint16_t)(((sd_status[2] & 0xFF000000U) >> 16U) | (sd_status[3] & 0xFFU));
pStatus->EraseTimeout = (uint8_t)((sd_status[3] & 0xFC00U) >> 10U);
pStatus->EraseOffset = (uint8_t)((sd_status[3] & 0x0300U) >> 8U);
}
/* Set Block Size for Card */
errorstate = SDMMC_CmdBlockLength(hsd->Instance, BLOCKSIZE);
if(errorstate != HAL_SD_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->ErrorCode = errorstate;
hsd->State = HAL_SD_STATE_READY;
status = HAL_ERROR;
}
return status;
}
/**
* @brief Gets the SD card info.
* @param hsd: Pointer to SD handle
* @param pCardInfo: Pointer to the HAL_SD_CardInfoTypeDef structure that
* will contain the SD card status information
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SD_GetCardInfo(SD_HandleTypeDef *hsd, HAL_SD_CardInfoTypeDef *pCardInfo)
{
pCardInfo->CardType = (uint32_t)(hsd->SdCard.CardType);
pCardInfo->CardVersion = (uint32_t)(hsd->SdCard.CardVersion);
pCardInfo->Class = (uint32_t)(hsd->SdCard.Class);
pCardInfo->RelCardAdd = (uint32_t)(hsd->SdCard.RelCardAdd);
pCardInfo->BlockNbr = (uint32_t)(hsd->SdCard.BlockNbr);
pCardInfo->BlockSize = (uint32_t)(hsd->SdCard.BlockSize);
pCardInfo->LogBlockNbr = (uint32_t)(hsd->SdCard.LogBlockNbr);
pCardInfo->LogBlockSize = (uint32_t)(hsd->SdCard.LogBlockSize);
return HAL_OK;
}
/**
* @brief Enables wide bus operation for the requested card if supported by
* card.
* @param hsd: Pointer to SD handle
* @param WideMode: Specifies the SD card wide bus mode
* This parameter can be one of the following values:
* @arg SDIO_BUS_WIDE_8B: 8-bit data transfer
* @arg SDIO_BUS_WIDE_4B: 4-bit data transfer
* @arg SDIO_BUS_WIDE_1B: 1-bit data transfer
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SD_ConfigWideBusOperation(SD_HandleTypeDef *hsd, uint32_t WideMode)
{
SDIO_InitTypeDef Init;
uint32_t errorstate;
HAL_StatusTypeDef status = HAL_OK;
/* Check the parameters */
assert_param(IS_SDIO_BUS_WIDE(WideMode));
/* Change State */
hsd->State = HAL_SD_STATE_BUSY;
if(hsd->SdCard.CardType != CARD_SECURED)
{
if(WideMode == SDIO_BUS_WIDE_8B)
{
hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE;
}
else if(WideMode == SDIO_BUS_WIDE_4B)
{
errorstate = SD_WideBus_Enable(hsd);
hsd->ErrorCode |= errorstate;
}
else if(WideMode == SDIO_BUS_WIDE_1B)
{
errorstate = SD_WideBus_Disable(hsd);
hsd->ErrorCode |= errorstate;
}
else
{
/* WideMode is not a valid argument*/
hsd->ErrorCode |= HAL_SD_ERROR_PARAM;
}
}
else
{
/* MMC Card does not support this feature */
hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE;
}
if(hsd->ErrorCode != HAL_SD_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->State = HAL_SD_STATE_READY;
status = HAL_ERROR;
}
else
{
/* Configure the SDIO peripheral */
Init.ClockEdge = hsd->Init.ClockEdge;
Init.ClockBypass = hsd->Init.ClockBypass;
Init.ClockPowerSave = hsd->Init.ClockPowerSave;
Init.BusWide = WideMode;
Init.HardwareFlowControl = hsd->Init.HardwareFlowControl;
Init.ClockDiv = hsd->Init.ClockDiv;
(void)SDIO_Init(hsd->Instance, Init);
}
/* Set Block Size for Card */
errorstate = SDMMC_CmdBlockLength(hsd->Instance, BLOCKSIZE);
if(errorstate != HAL_SD_ERROR_NONE)
{
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
hsd->ErrorCode |= errorstate;
status = HAL_ERROR;
}
/* Change State */
hsd->State = HAL_SD_STATE_READY;
return status;
}
/**
* @brief Gets the current sd card data state.
* @param hsd: pointer to SD handle
* @retval Card state
*/
HAL_SD_CardStateTypeDef HAL_SD_GetCardState(SD_HandleTypeDef *hsd)
{
uint32_t cardstate;
uint32_t errorstate;
uint32_t resp1 = 0;
errorstate = SD_SendStatus(hsd, &resp1);
if(errorstate != HAL_SD_ERROR_NONE)
{
hsd->ErrorCode |= errorstate;
}
cardstate = ((resp1 >> 9U) & 0x0FU);
return (HAL_SD_CardStateTypeDef)cardstate;
}
/**
* @brief Abort the current transfer and disable the SD.
* @param hsd: pointer to a SD_HandleTypeDef structure that contains
* the configuration information for SD module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SD_Abort(SD_HandleTypeDef *hsd)
{
HAL_SD_CardStateTypeDef CardState;
uint32_t context = hsd->Context;
/* DIsable All interrupts */
__HAL_SD_DISABLE_IT(hsd, SDIO_IT_DATAEND | SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT|\
SDIO_IT_TXUNDERR| SDIO_IT_RXOVERR);
/* Clear All flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_DATA_FLAGS);
CLEAR_BIT(hsd->Instance->DCTRL, SDIO_DCTRL_DTEN);
if ((context & SD_CONTEXT_DMA) != 0U)
{
/* Disable the SD DMA request */
hsd->Instance->DCTRL &= (uint32_t)~((uint32_t)SDIO_DCTRL_DMAEN);
/* Abort the SD DMA Tx channel */
if (((context & SD_CONTEXT_WRITE_SINGLE_BLOCK) != 0U) || ((context & SD_CONTEXT_WRITE_MULTIPLE_BLOCK) != 0U))
{
if(HAL_DMA_Abort(hsd->hdmatx) != HAL_OK)
{
hsd->ErrorCode |= HAL_SD_ERROR_DMA;
}
}
/* Abort the SD DMA Rx channel */
else if (((context & SD_CONTEXT_READ_SINGLE_BLOCK) != 0U) || ((context & SD_CONTEXT_READ_MULTIPLE_BLOCK) != 0U))
{
if(HAL_DMA_Abort(hsd->hdmarx) != HAL_OK)
{
hsd->ErrorCode |= HAL_SD_ERROR_DMA;
}
}
else
{
/* Nothing to do */
}
}
hsd->State = HAL_SD_STATE_READY;
/* Initialize the SD operation */
hsd->Context = SD_CONTEXT_NONE;
CardState = HAL_SD_GetCardState(hsd);
if((CardState == HAL_SD_CARD_RECEIVING) || (CardState == HAL_SD_CARD_SENDING))
{
hsd->ErrorCode = SDMMC_CmdStopTransfer(hsd->Instance);
}
if(hsd->ErrorCode != HAL_SD_ERROR_NONE)
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Abort the current transfer and disable the SD (IT mode).
* @param hsd: pointer to a SD_HandleTypeDef structure that contains
* the configuration information for SD module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SD_Abort_IT(SD_HandleTypeDef *hsd)
{
HAL_SD_CardStateTypeDef CardState;
uint32_t context = hsd->Context;
/* Disable All interrupts */
__HAL_SD_DISABLE_IT(hsd, SDIO_IT_DATAEND | SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT|\
SDIO_IT_TXUNDERR| SDIO_IT_RXOVERR);
CLEAR_BIT(hsd->Instance->DCTRL, SDIO_DCTRL_DTEN);
if ((context & SD_CONTEXT_DMA) != 0U)
{
/* Disable the SD DMA request */
hsd->Instance->DCTRL &= (uint32_t)~((uint32_t)SDIO_DCTRL_DMAEN);
/* Abort the SD DMA Tx channel */
if (((context & SD_CONTEXT_WRITE_SINGLE_BLOCK) != 0U) || ((context & SD_CONTEXT_WRITE_MULTIPLE_BLOCK) != 0U))
{
hsd->hdmatx->XferAbortCallback = SD_DMATxAbort;
if(HAL_DMA_Abort_IT(hsd->hdmatx) != HAL_OK)
{
hsd->hdmatx = NULL;
}
}
/* Abort the SD DMA Rx channel */
else if (((context & SD_CONTEXT_READ_SINGLE_BLOCK) != 0U) || ((context & SD_CONTEXT_READ_MULTIPLE_BLOCK) != 0U))
{
hsd->hdmarx->XferAbortCallback = SD_DMARxAbort;
if(HAL_DMA_Abort_IT(hsd->hdmarx) != HAL_OK)
{
hsd->hdmarx = NULL;
}
}
else
{
/* Nothing to do */
}
}
/* No transfer ongoing on both DMA channels*/
else
{
/* Clear All flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_DATA_FLAGS);
CardState = HAL_SD_GetCardState(hsd);
hsd->State = HAL_SD_STATE_READY;
hsd->Context = SD_CONTEXT_NONE;
if((CardState == HAL_SD_CARD_RECEIVING) || (CardState == HAL_SD_CARD_SENDING))
{
hsd->ErrorCode = SDMMC_CmdStopTransfer(hsd->Instance);
}
if(hsd->ErrorCode != HAL_SD_ERROR_NONE)
{
return HAL_ERROR;
}
else
{
#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U)
hsd->AbortCpltCallback(hsd);
#else
HAL_SD_AbortCallback(hsd);
#endif /* USE_HAL_SD_REGISTER_CALLBACKS */
}
}
return HAL_OK;
}
/**
* @}
*/
/**
* @}
*/
/* Private function ----------------------------------------------------------*/
/** @addtogroup SD_Private_Functions
* @{
*/
/**
* @brief DMA SD transmit process complete callback
* @param hdma: DMA handle
* @retval None
*/
static void SD_DMATransmitCplt(DMA_HandleTypeDef *hdma)
{
SD_HandleTypeDef* hsd = (SD_HandleTypeDef* )(hdma->Parent);
/* Enable DATAEND Interrupt */
__HAL_SD_ENABLE_IT(hsd, (SDIO_IT_DATAEND));
}
/**
* @brief DMA SD receive process complete callback
* @param hdma: DMA handle
* @retval None
*/
static void SD_DMAReceiveCplt(DMA_HandleTypeDef *hdma)
{
SD_HandleTypeDef* hsd = (SD_HandleTypeDef* )(hdma->Parent);
uint32_t errorstate;
/* Send stop command in multiblock write */
if(hsd->Context == (SD_CONTEXT_READ_MULTIPLE_BLOCK | SD_CONTEXT_DMA))
{
errorstate = SDMMC_CmdStopTransfer(hsd->Instance);
if(errorstate != HAL_SD_ERROR_NONE)
{
hsd->ErrorCode |= errorstate;
#if (USE_HAL_SD_REGISTER_CALLBACKS == 1)
hsd->ErrorCallback(hsd);
#else
HAL_SD_ErrorCallback(hsd);
#endif
}
}
/* Disable the DMA transfer for transmit request by setting the DMAEN bit
in the SD DCTRL register */
hsd->Instance->DCTRL &= (uint32_t)~((uint32_t)SDIO_DCTRL_DMAEN);
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_DATA_FLAGS);
hsd->State = HAL_SD_STATE_READY;
hsd->Context = SD_CONTEXT_NONE;
#if (USE_HAL_SD_REGISTER_CALLBACKS == 1)
hsd->RxCpltCallback(hsd);
#else
HAL_SD_RxCpltCallback(hsd);
#endif
}
/**
* @brief DMA SD communication error callback
* @param hdma: DMA handle
* @retval None
*/
static void SD_DMAError(DMA_HandleTypeDef *hdma)
{
SD_HandleTypeDef* hsd = (SD_HandleTypeDef* )(hdma->Parent);
HAL_SD_CardStateTypeDef CardState;
uint32_t RxErrorCode, TxErrorCode;
RxErrorCode = hsd->hdmarx->ErrorCode;
TxErrorCode = hsd->hdmatx->ErrorCode;
if((RxErrorCode == HAL_DMA_ERROR_TE) || (TxErrorCode == HAL_DMA_ERROR_TE))
{
/* Clear All flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
/* Disable All interrupts */
__HAL_SD_DISABLE_IT(hsd, SDIO_IT_DATAEND | SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT|\
SDIO_IT_TXUNDERR| SDIO_IT_RXOVERR);
hsd->ErrorCode |= HAL_SD_ERROR_DMA;
CardState = HAL_SD_GetCardState(hsd);
if((CardState == HAL_SD_CARD_RECEIVING) || (CardState == HAL_SD_CARD_SENDING))
{
hsd->ErrorCode |= SDMMC_CmdStopTransfer(hsd->Instance);
}
hsd->State= HAL_SD_STATE_READY;
hsd->Context = SD_CONTEXT_NONE;
}
#if (USE_HAL_SD_REGISTER_CALLBACKS == 1)
hsd->ErrorCallback(hsd);
#else
HAL_SD_ErrorCallback(hsd);
#endif
}
/**
* @brief DMA SD Tx Abort callback
* @param hdma: DMA handle
* @retval None
*/
static void SD_DMATxAbort(DMA_HandleTypeDef *hdma)
{
SD_HandleTypeDef* hsd = (SD_HandleTypeDef* )(hdma->Parent);
HAL_SD_CardStateTypeDef CardState;
/* Clear All flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_DATA_FLAGS);
CardState = HAL_SD_GetCardState(hsd);
hsd->State = HAL_SD_STATE_READY;
hsd->Context = SD_CONTEXT_NONE;
if((CardState == HAL_SD_CARD_RECEIVING) || (CardState == HAL_SD_CARD_SENDING))
{
hsd->ErrorCode |= SDMMC_CmdStopTransfer(hsd->Instance);
}
if(hsd->ErrorCode == HAL_SD_ERROR_NONE)
{
#if (USE_HAL_SD_REGISTER_CALLBACKS == 1)
hsd->AbortCpltCallback(hsd);
#else
HAL_SD_AbortCallback(hsd);
#endif
}
else
{
#if (USE_HAL_SD_REGISTER_CALLBACKS == 1)
hsd->ErrorCallback(hsd);
#else
HAL_SD_ErrorCallback(hsd);
#endif
}
}
/**
* @brief DMA SD Rx Abort callback
* @param hdma: DMA handle
* @retval None
*/
static void SD_DMARxAbort(DMA_HandleTypeDef *hdma)
{
SD_HandleTypeDef* hsd = (SD_HandleTypeDef* )(hdma->Parent);
HAL_SD_CardStateTypeDef CardState;
/* Clear All flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_DATA_FLAGS);
CardState = HAL_SD_GetCardState(hsd);
hsd->State = HAL_SD_STATE_READY;
hsd->Context = SD_CONTEXT_NONE;
if((CardState == HAL_SD_CARD_RECEIVING) || (CardState == HAL_SD_CARD_SENDING))
{
hsd->ErrorCode |= SDMMC_CmdStopTransfer(hsd->Instance);
}
if(hsd->ErrorCode == HAL_SD_ERROR_NONE)
{
#if (USE_HAL_SD_REGISTER_CALLBACKS == 1)
hsd->AbortCpltCallback(hsd);
#else
HAL_SD_AbortCallback(hsd);
#endif
}
else
{
#if (USE_HAL_SD_REGISTER_CALLBACKS == 1)
hsd->ErrorCallback(hsd);
#else
HAL_SD_ErrorCallback(hsd);
#endif
}
}
/**
* @brief Initializes the sd card.
* @param hsd: Pointer to SD handle
* @retval SD Card error state
*/
static uint32_t SD_InitCard(SD_HandleTypeDef *hsd)
{
HAL_SD_CardCSDTypeDef CSD;
uint32_t errorstate;
uint16_t sd_rca = 1U;
/* Check the power State */
if(SDIO_GetPowerState(hsd->Instance) == 0U)
{
/* Power off */
return HAL_SD_ERROR_REQUEST_NOT_APPLICABLE;
}
if(hsd->SdCard.CardType != CARD_SECURED)
{
/* Send CMD2 ALL_SEND_CID */
errorstate = SDMMC_CmdSendCID(hsd->Instance);
if(errorstate != HAL_SD_ERROR_NONE)
{
return errorstate;
}
else
{
/* Get Card identification number data */
hsd->CID[0U] = SDIO_GetResponse(hsd->Instance, SDIO_RESP1);
hsd->CID[1U] = SDIO_GetResponse(hsd->Instance, SDIO_RESP2);
hsd->CID[2U] = SDIO_GetResponse(hsd->Instance, SDIO_RESP3);
hsd->CID[3U] = SDIO_GetResponse(hsd->Instance, SDIO_RESP4);
}
}
if(hsd->SdCard.CardType != CARD_SECURED)
{
/* Send CMD3 SET_REL_ADDR with argument 0 */
/* SD Card publishes its RCA. */
errorstate = SDMMC_CmdSetRelAdd(hsd->Instance, &sd_rca);
if(errorstate != HAL_SD_ERROR_NONE)
{
return errorstate;
}
}
if(hsd->SdCard.CardType != CARD_SECURED)
{
/* Get the SD card RCA */
hsd->SdCard.RelCardAdd = sd_rca;
/* Send CMD9 SEND_CSD with argument as card's RCA */
errorstate = SDMMC_CmdSendCSD(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U));
if(errorstate != HAL_SD_ERROR_NONE)
{
return errorstate;
}
else
{
/* Get Card Specific Data */
hsd->CSD[0U] = SDIO_GetResponse(hsd->Instance, SDIO_RESP1);
hsd->CSD[1U] = SDIO_GetResponse(hsd->Instance, SDIO_RESP2);
hsd->CSD[2U] = SDIO_GetResponse(hsd->Instance, SDIO_RESP3);
hsd->CSD[3U] = SDIO_GetResponse(hsd->Instance, SDIO_RESP4);
}
}
/* Get the Card Class */
hsd->SdCard.Class = (SDIO_GetResponse(hsd->Instance, SDIO_RESP2) >> 20U);
/* Get CSD parameters */
if (HAL_SD_GetCardCSD(hsd, &CSD) != HAL_OK)
{
return HAL_SD_ERROR_UNSUPPORTED_FEATURE;
}
/* Select the Card */
errorstate = SDMMC_CmdSelDesel(hsd->Instance, (uint32_t)(((uint32_t)hsd->SdCard.RelCardAdd) << 16U));
if(errorstate != HAL_SD_ERROR_NONE)
{
return errorstate;
}
/* Configure SDIO peripheral interface */
(void)SDIO_Init(hsd->Instance, hsd->Init);
/* All cards are initialized */
return HAL_SD_ERROR_NONE;
}
/**
* @brief Enquires cards about their operating voltage and configures clock
* controls and stores SD information that will be needed in future
* in the SD handle.
* @param hsd: Pointer to SD handle
* @retval error state
*/
static uint32_t SD_PowerON(SD_HandleTypeDef *hsd)
{
__IO uint32_t count = 0U;
uint32_t response = 0U, validvoltage = 0U;
uint32_t errorstate;
/* CMD0: GO_IDLE_STATE */
errorstate = SDMMC_CmdGoIdleState(hsd->Instance);
if(errorstate != HAL_SD_ERROR_NONE)
{
return errorstate;
}
/* CMD8: SEND_IF_COND: Command available only on V2.0 cards */
errorstate = SDMMC_CmdOperCond(hsd->Instance);
if(errorstate != HAL_SD_ERROR_NONE)
{
hsd->SdCard.CardVersion = CARD_V1_X;
/* CMD0: GO_IDLE_STATE */
errorstate = SDMMC_CmdGoIdleState(hsd->Instance);
if(errorstate != HAL_SD_ERROR_NONE)
{
return errorstate;
}
}
else
{
hsd->SdCard.CardVersion = CARD_V2_X;
}
if( hsd->SdCard.CardVersion == CARD_V2_X)
{
/* SEND CMD55 APP_CMD with RCA as 0 */
errorstate = SDMMC_CmdAppCommand(hsd->Instance, 0);
if(errorstate != HAL_SD_ERROR_NONE)
{
return HAL_SD_ERROR_UNSUPPORTED_FEATURE;
}
}
/* SD CARD */
/* Send ACMD41 SD_APP_OP_COND with Argument 0x80100000 */
while((count < SDMMC_MAX_VOLT_TRIAL) && (validvoltage == 0U))
{
/* SEND CMD55 APP_CMD with RCA as 0 */
errorstate = SDMMC_CmdAppCommand(hsd->Instance, 0);
if(errorstate != HAL_SD_ERROR_NONE)
{
return errorstate;
}
/* Send CMD41 */
errorstate = SDMMC_CmdAppOperCommand(hsd->Instance, SDMMC_VOLTAGE_WINDOW_SD | SDMMC_HIGH_CAPACITY | SD_SWITCH_1_8V_CAPACITY);
if(errorstate != HAL_SD_ERROR_NONE)
{
return HAL_SD_ERROR_UNSUPPORTED_FEATURE;
}
/* Get command response */
response = SDIO_GetResponse(hsd->Instance, SDIO_RESP1);
/* Get operating voltage*/
validvoltage = (((response >> 31U) == 1U) ? 1U : 0U);
count++;
}
if(count >= SDMMC_MAX_VOLT_TRIAL)
{
return HAL_SD_ERROR_INVALID_VOLTRANGE;
}
if((response & SDMMC_HIGH_CAPACITY) == SDMMC_HIGH_CAPACITY) /* (response &= SD_HIGH_CAPACITY) */
{
hsd->SdCard.CardType = CARD_SDHC_SDXC;
}
else
{
hsd->SdCard.CardType = CARD_SDSC;
}
return HAL_SD_ERROR_NONE;
}
/**
* @brief Turns the SDIO output signals off.
* @param hsd: Pointer to SD handle
* @retval None
*/
static void SD_PowerOFF(SD_HandleTypeDef *hsd)
{
/* Set Power State to OFF */
(void)SDIO_PowerState_OFF(hsd->Instance);
}
/**
* @brief Send Status info command.
* @param hsd: pointer to SD handle
* @param pSDstatus: Pointer to the buffer that will contain the SD card status
* SD Status register)
* @retval error state
*/
static uint32_t SD_SendSDStatus(SD_HandleTypeDef *hsd, uint32_t *pSDstatus)
{
SDIO_DataInitTypeDef config;
uint32_t errorstate;
uint32_t tickstart = HAL_GetTick();
uint32_t count;
uint32_t *pData = pSDstatus;
/* Check SD response */
if((SDIO_GetResponse(hsd->Instance, SDIO_RESP1) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED)
{
return HAL_SD_ERROR_LOCK_UNLOCK_FAILED;
}
/* Set block size for card if it is not equal to current block size for card */
errorstate = SDMMC_CmdBlockLength(hsd->Instance, 64U);
if(errorstate != HAL_SD_ERROR_NONE)
{
hsd->ErrorCode |= HAL_SD_ERROR_NONE;
return errorstate;
}
/* Send CMD55 */
errorstate = SDMMC_CmdAppCommand(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U));
if(errorstate != HAL_SD_ERROR_NONE)
{
hsd->ErrorCode |= HAL_SD_ERROR_NONE;
return errorstate;
}
/* Configure the SD DPSM (Data Path State Machine) */
config.DataTimeOut = SDMMC_DATATIMEOUT;
config.DataLength = 64U;
config.DataBlockSize = SDIO_DATABLOCK_SIZE_64B;
config.TransferDir = SDIO_TRANSFER_DIR_TO_SDIO;
config.TransferMode = SDIO_TRANSFER_MODE_BLOCK;
config.DPSM = SDIO_DPSM_ENABLE;
(void)SDIO_ConfigData(hsd->Instance, &config);
/* Send ACMD13 (SD_APP_STAUS) with argument as card's RCA */
errorstate = SDMMC_CmdStatusRegister(hsd->Instance);
if(errorstate != HAL_SD_ERROR_NONE)
{
hsd->ErrorCode |= HAL_SD_ERROR_NONE;
return errorstate;
}
/* Get status data */
while(!__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DBCKEND))
{
if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_RXFIFOHF))
{
for(count = 0U; count < 8U; count++)
{
*pData = SDIO_ReadFIFO(hsd->Instance);
pData++;
}
}
if((HAL_GetTick() - tickstart) >= SDMMC_SWDATATIMEOUT)
{
return HAL_SD_ERROR_TIMEOUT;
}
}
if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_DTIMEOUT) || (__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_STBITERR)))
{
return HAL_SD_ERROR_DATA_TIMEOUT;
}
else if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_DCRCFAIL))
{
return HAL_SD_ERROR_DATA_CRC_FAIL;
}
else if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_RXOVERR))
{
return HAL_SD_ERROR_RX_OVERRUN;
}
else
{
/* Nothing to do */
}
while ((__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_RXDAVL)))
{
*pData = SDIO_ReadFIFO(hsd->Instance);
pData++;
if((HAL_GetTick() - tickstart) >= SDMMC_SWDATATIMEOUT)
{
return HAL_SD_ERROR_TIMEOUT;
}
}
/* Clear all the static status flags*/
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_DATA_FLAGS);
return HAL_SD_ERROR_NONE;
}
/**
* @brief Returns the current card's status.
* @param hsd: Pointer to SD handle
* @param pCardStatus: pointer to the buffer that will contain the SD card
* status (Card Status register)
* @retval error state
*/
static uint32_t SD_SendStatus(SD_HandleTypeDef *hsd, uint32_t *pCardStatus)
{
uint32_t errorstate;
if(pCardStatus == NULL)
{
return HAL_SD_ERROR_PARAM;
}
/* Send Status command */
errorstate = SDMMC_CmdSendStatus(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U));
if(errorstate != HAL_SD_ERROR_NONE)
{
return errorstate;
}
/* Get SD card status */
*pCardStatus = SDIO_GetResponse(hsd->Instance, SDIO_RESP1);
return HAL_SD_ERROR_NONE;
}
/**
* @brief Enables the SDIO wide bus mode.
* @param hsd: pointer to SD handle
* @retval error state
*/
static uint32_t SD_WideBus_Enable(SD_HandleTypeDef *hsd)
{
uint32_t scr[2U] = {0U, 0U};
uint32_t errorstate;
if((SDIO_GetResponse(hsd->Instance, SDIO_RESP1) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED)
{
return HAL_SD_ERROR_LOCK_UNLOCK_FAILED;
}
/* Get SCR Register */
errorstate = SD_FindSCR(hsd, scr);
if(errorstate != HAL_SD_ERROR_NONE)
{
return errorstate;
}
/* If requested card supports wide bus operation */
if((scr[1U] & SDMMC_WIDE_BUS_SUPPORT) != SDMMC_ALLZERO)
{
/* Send CMD55 APP_CMD with argument as card's RCA.*/
errorstate = SDMMC_CmdAppCommand(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U));
if(errorstate != HAL_SD_ERROR_NONE)
{
return errorstate;
}
/* Send ACMD6 APP_CMD with argument as 2 for wide bus mode */
errorstate = SDMMC_CmdBusWidth(hsd->Instance, 2U);
if(errorstate != HAL_SD_ERROR_NONE)
{
return errorstate;
}
return HAL_SD_ERROR_NONE;
}
else
{
return HAL_SD_ERROR_REQUEST_NOT_APPLICABLE;
}
}
/**
* @brief Disables the SDIO wide bus mode.
* @param hsd: Pointer to SD handle
* @retval error state
*/
static uint32_t SD_WideBus_Disable(SD_HandleTypeDef *hsd)
{
uint32_t scr[2U] = {0U, 0U};
uint32_t errorstate;
if((SDIO_GetResponse(hsd->Instance, SDIO_RESP1) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED)
{
return HAL_SD_ERROR_LOCK_UNLOCK_FAILED;
}
/* Get SCR Register */
errorstate = SD_FindSCR(hsd, scr);
if(errorstate != HAL_SD_ERROR_NONE)
{
return errorstate;
}
/* If requested card supports 1 bit mode operation */
if((scr[1U] & SDMMC_SINGLE_BUS_SUPPORT) != SDMMC_ALLZERO)
{
/* Send CMD55 APP_CMD with argument as card's RCA */
errorstate = SDMMC_CmdAppCommand(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U));
if(errorstate != HAL_SD_ERROR_NONE)
{
return errorstate;
}
/* Send ACMD6 APP_CMD with argument as 0 for single bus mode */
errorstate = SDMMC_CmdBusWidth(hsd->Instance, 0U);
if(errorstate != HAL_SD_ERROR_NONE)
{
return errorstate;
}
return HAL_SD_ERROR_NONE;
}
else
{
return HAL_SD_ERROR_REQUEST_NOT_APPLICABLE;
}
}
/**
* @brief Finds the SD card SCR register value.
* @param hsd: Pointer to SD handle
* @param pSCR: pointer to the buffer that will contain the SCR value
* @retval error state
*/
static uint32_t SD_FindSCR(SD_HandleTypeDef *hsd, uint32_t *pSCR)
{
SDIO_DataInitTypeDef config;
uint32_t errorstate;
uint32_t tickstart = HAL_GetTick();
uint32_t index = 0U;
uint32_t tempscr[2U] = {0U, 0U};
uint32_t *scr = pSCR;
/* Set Block Size To 8 Bytes */
errorstate = SDMMC_CmdBlockLength(hsd->Instance, 8U);
if(errorstate != HAL_SD_ERROR_NONE)
{
return errorstate;
}
/* Send CMD55 APP_CMD with argument as card's RCA */
errorstate = SDMMC_CmdAppCommand(hsd->Instance, (uint32_t)((hsd->SdCard.RelCardAdd) << 16U));
if(errorstate != HAL_SD_ERROR_NONE)
{
return errorstate;
}
config.DataTimeOut = SDMMC_DATATIMEOUT;
config.DataLength = 8U;
config.DataBlockSize = SDIO_DATABLOCK_SIZE_8B;
config.TransferDir = SDIO_TRANSFER_DIR_TO_SDIO;
config.TransferMode = SDIO_TRANSFER_MODE_BLOCK;
config.DPSM = SDIO_DPSM_ENABLE;
(void)SDIO_ConfigData(hsd->Instance, &config);
/* Send ACMD51 SD_APP_SEND_SCR with argument as 0 */
errorstate = SDMMC_CmdSendSCR(hsd->Instance);
if(errorstate != HAL_SD_ERROR_NONE)
{
return errorstate;
}
while(!__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT))
{
if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_RXDAVL))
{
*(tempscr + index) = SDIO_ReadFIFO(hsd->Instance);
index++;
}
else if(!__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_RXACT))
{
break;
}
if((HAL_GetTick() - tickstart) >= SDMMC_SWDATATIMEOUT)
{
return HAL_SD_ERROR_TIMEOUT;
}
}
if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_DTIMEOUT) || (__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_STBITERR)))
{
__HAL_SD_CLEAR_FLAG(hsd, SDIO_FLAG_DTIMEOUT);
return HAL_SD_ERROR_DATA_TIMEOUT;
}
else if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_DCRCFAIL))
{
__HAL_SD_CLEAR_FLAG(hsd, SDIO_FLAG_DCRCFAIL);
return HAL_SD_ERROR_DATA_CRC_FAIL;
}
else if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_RXOVERR))
{
__HAL_SD_CLEAR_FLAG(hsd, SDIO_FLAG_RXOVERR);
return HAL_SD_ERROR_RX_OVERRUN;
}
else
{
/* No error flag set */
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_DATA_FLAGS);
*scr = (((tempscr[1] & SDMMC_0TO7BITS) << 24) | ((tempscr[1] & SDMMC_8TO15BITS) << 8) |\
((tempscr[1] & SDMMC_16TO23BITS) >> 8) | ((tempscr[1] & SDMMC_24TO31BITS) >> 24));
scr++;
*scr = (((tempscr[0] & SDMMC_0TO7BITS) << 24) | ((tempscr[0] & SDMMC_8TO15BITS) << 8) |\
((tempscr[0] & SDMMC_16TO23BITS) >> 8) | ((tempscr[0] & SDMMC_24TO31BITS) >> 24));
}
return HAL_SD_ERROR_NONE;
}
/**
* @brief Wrap up reading in non-blocking mode.
* @param hsd: pointer to a SD_HandleTypeDef structure that contains
* the configuration information.
* @retval None
*/
static void SD_Read_IT(SD_HandleTypeDef *hsd)
{
uint32_t count, data, dataremaining;
uint8_t* tmp;
tmp = hsd->pRxBuffPtr;
dataremaining = hsd->RxXferSize;
if (dataremaining > 0U)
{
/* Read data from SDIO Rx FIFO */
for(count = 0U; count < 8U; count++)
{
data = SDIO_ReadFIFO(hsd->Instance);
*tmp = (uint8_t)(data & 0xFFU);
tmp++;
dataremaining--;
*tmp = (uint8_t)((data >> 8U) & 0xFFU);
tmp++;
dataremaining--;
*tmp = (uint8_t)((data >> 16U) & 0xFFU);
tmp++;
dataremaining--;
*tmp = (uint8_t)((data >> 24U) & 0xFFU);
tmp++;
dataremaining--;
}
hsd->pRxBuffPtr = tmp;
hsd->RxXferSize = dataremaining;
}
}
/**
* @brief Wrap up writing in non-blocking mode.
* @param hsd: pointer to a SD_HandleTypeDef structure that contains
* the configuration information.
* @retval None
*/
static void SD_Write_IT(SD_HandleTypeDef *hsd)
{
uint32_t count, data, dataremaining;
uint8_t* tmp;
tmp = hsd->pTxBuffPtr;
dataremaining = hsd->TxXferSize;
if (dataremaining > 0U)
{
/* Write data to SDIO Tx FIFO */
for(count = 0U; count < 8U; count++)
{
data = (uint32_t)(*tmp);
tmp++;
dataremaining--;
data |= ((uint32_t)(*tmp) << 8U);
tmp++;
dataremaining--;
data |= ((uint32_t)(*tmp) << 16U);
tmp++;
dataremaining--;
data |= ((uint32_t)(*tmp) << 24U);
tmp++;
dataremaining--;
(void)SDIO_WriteFIFO(hsd->Instance, &data);
}
hsd->pTxBuffPtr = tmp;
hsd->TxXferSize = dataremaining;
}
}
/**
* @}
*/
#endif /* HAL_SD_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/
#endif /* SDIO */

View File

@@ -0,0 +1,2348 @@
/**
******************************************************************************
* @file stm32f1xx_hal_smartcard.c
* @author MCD Application Team
* @brief SMARTCARD HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of the SMARTCARD peripheral:
* + Initialization and de-initialization functions
* + IO operation functions
* + Peripheral Control functions
* + Peripheral State and Error functions
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
==============================================================================
##### How to use this driver #####
==============================================================================
[..]
The SMARTCARD HAL driver can be used as follows:
(#) Declare a SMARTCARD_HandleTypeDef handle structure.
(#) Initialize the SMARTCARD low level resources by implementing the HAL_SMARTCARD_MspInit() API:
(##) Enable the interface clock of the USARTx associated to the SMARTCARD.
(##) SMARTCARD pins configuration:
(+++) Enable the clock for the SMARTCARD GPIOs.
(+++) Configure SMARTCARD pins as alternate function pull-up.
(##) NVIC configuration if you need to use interrupt process (HAL_SMARTCARD_Transmit_IT()
and HAL_SMARTCARD_Receive_IT() APIs):
(+++) Configure the USARTx interrupt priority.
(+++) Enable the NVIC USART IRQ handle.
(##) DMA Configuration if you need to use DMA process (HAL_SMARTCARD_Transmit_DMA()
and HAL_SMARTCARD_Receive_DMA() APIs):
(+++) Declare a DMA handle structure for the Tx/Rx channel.
(+++) Enable the DMAx interface clock.
(+++) Configure the declared DMA handle structure with the required Tx/Rx parameters.
(+++) Configure the DMA Tx/Rx channel.
(+++) Associate the initialized DMA handle to the SMARTCARD DMA Tx/Rx handle.
(+++) Configure the priority and enable the NVIC for the transfer complete interrupt on the DMA Tx/Rx channel.
(+++) Configure the USARTx interrupt priority and enable the NVIC USART IRQ handle
(used for last byte sending completion detection in DMA non circular mode)
(#) Program the Baud Rate, Word Length , Stop Bit, Parity, Hardware
flow control and Mode(Receiver/Transmitter) in the SMARTCARD Init structure.
(#) Initialize the SMARTCARD registers by calling the HAL_SMARTCARD_Init() API:
(++) These APIs configure also the low level Hardware GPIO, CLOCK, CORTEX...etc)
by calling the customized HAL_SMARTCARD_MspInit() API.
[..]
(@) The specific SMARTCARD interrupts (Transmission complete interrupt,
RXNE interrupt and Error Interrupts) will be managed using the macros
__HAL_SMARTCARD_ENABLE_IT() and __HAL_SMARTCARD_DISABLE_IT() inside the transmit and receive process.
[..]
Three operation modes are available within this driver :
*** Polling mode IO operation ***
=================================
[..]
(+) Send an amount of data in blocking mode using HAL_SMARTCARD_Transmit()
(+) Receive an amount of data in blocking mode using HAL_SMARTCARD_Receive()
*** Interrupt mode IO operation ***
===================================
[..]
(+) Send an amount of data in non blocking mode using HAL_SMARTCARD_Transmit_IT()
(+) At transmission end of transfer HAL_SMARTCARD_TxCpltCallback is executed and user can
add his own code by customization of function pointer HAL_SMARTCARD_TxCpltCallback
(+) Receive an amount of data in non blocking mode using HAL_SMARTCARD_Receive_IT()
(+) At reception end of transfer HAL_SMARTCARD_RxCpltCallback is executed and user can
add his own code by customization of function pointer HAL_SMARTCARD_RxCpltCallback
(+) In case of transfer Error, HAL_SMARTCARD_ErrorCallback() function is executed and user can
add his own code by customization of function pointer HAL_SMARTCARD_ErrorCallback
*** DMA mode IO operation ***
==============================
[..]
(+) Send an amount of data in non blocking mode (DMA) using HAL_SMARTCARD_Transmit_DMA()
(+) At transmission end of transfer HAL_SMARTCARD_TxCpltCallback is executed and user can
add his own code by customization of function pointer HAL_SMARTCARD_TxCpltCallback
(+) Receive an amount of data in non blocking mode (DMA) using HAL_SMARTCARD_Receive_DMA()
(+) At reception end of transfer HAL_SMARTCARD_RxCpltCallback is executed and user can
add his own code by customization of function pointer HAL_SMARTCARD_RxCpltCallback
(+) In case of transfer Error, HAL_SMARTCARD_ErrorCallback() function is executed and user can
add his own code by customization of function pointer HAL_SMARTCARD_ErrorCallback
*** SMARTCARD HAL driver macros list ***
========================================
[..]
Below the list of most used macros in SMARTCARD HAL driver.
(+) __HAL_SMARTCARD_ENABLE: Enable the SMARTCARD peripheral
(+) __HAL_SMARTCARD_DISABLE: Disable the SMARTCARD peripheral
(+) __HAL_SMARTCARD_GET_FLAG : Check whether the specified SMARTCARD flag is set or not
(+) __HAL_SMARTCARD_CLEAR_FLAG : Clear the specified SMARTCARD pending flag
(+) __HAL_SMARTCARD_ENABLE_IT: Enable the specified SMARTCARD interrupt
(+) __HAL_SMARTCARD_DISABLE_IT: Disable the specified SMARTCARD interrupt
[..]
(@) You can refer to the SMARTCARD HAL driver header file for more useful macros
##### Callback registration #####
==================================
[..]
The compilation define USE_HAL_SMARTCARD_REGISTER_CALLBACKS when set to 1
allows the user to configure dynamically the driver callbacks.
[..]
Use Function HAL_SMARTCARD_RegisterCallback() to register a user callback.
Function HAL_SMARTCARD_RegisterCallback() allows to register following callbacks:
(+) TxCpltCallback : Tx Complete Callback.
(+) RxCpltCallback : Rx Complete Callback.
(+) ErrorCallback : Error Callback.
(+) AbortCpltCallback : Abort Complete Callback.
(+) AbortTransmitCpltCallback : Abort Transmit Complete Callback.
(+) AbortReceiveCpltCallback : Abort Receive Complete Callback.
(+) MspInitCallback : SMARTCARD MspInit.
(+) MspDeInitCallback : SMARTCARD MspDeInit.
This function takes as parameters the HAL peripheral handle, the Callback ID
and a pointer to the user callback function.
[..]
Use function HAL_SMARTCARD_UnRegisterCallback() to reset a callback to the default
weak (surcharged) function.
HAL_SMARTCARD_UnRegisterCallback() takes as parameters the HAL peripheral handle,
and the Callback ID.
This function allows to reset following callbacks:
(+) TxCpltCallback : Tx Complete Callback.
(+) RxCpltCallback : Rx Complete Callback.
(+) ErrorCallback : Error Callback.
(+) AbortCpltCallback : Abort Complete Callback.
(+) AbortTransmitCpltCallback : Abort Transmit Complete Callback.
(+) AbortReceiveCpltCallback : Abort Receive Complete Callback.
(+) MspInitCallback : SMARTCARD MspInit.
(+) MspDeInitCallback : SMARTCARD MspDeInit.
[..]
By default, after the HAL_SMARTCARD_Init() and when the state is HAL_SMARTCARD_STATE_RESET
all callbacks are set to the corresponding weak (surcharged) functions:
examples HAL_SMARTCARD_TxCpltCallback(), HAL_SMARTCARD_RxCpltCallback().
Exception done for MspInit and MspDeInit functions that are respectively
reset to the legacy weak (surcharged) functions in the HAL_SMARTCARD_Init()
and HAL_SMARTCARD_DeInit() only when these callbacks are null (not registered beforehand).
If not, MspInit or MspDeInit are not null, the HAL_SMARTCARD_Init() and HAL_SMARTCARD_DeInit()
keep and use the user MspInit/MspDeInit callbacks (registered beforehand).
[..]
Callbacks can be registered/unregistered in HAL_SMARTCARD_STATE_READY state only.
Exception done MspInit/MspDeInit that can be registered/unregistered
in HAL_SMARTCARD_STATE_READY or HAL_SMARTCARD_STATE_RESET state, thus registered (user)
MspInit/DeInit callbacks can be used during the Init/DeInit.
In that case first register the MspInit/MspDeInit user callbacks
using HAL_SMARTCARD_RegisterCallback() before calling HAL_SMARTCARD_DeInit()
or HAL_SMARTCARD_Init() function.
[..]
When The compilation define USE_HAL_SMARTCARD_REGISTER_CALLBACKS is set to 0 or
not defined, the callback registration feature is not available
and weak (surcharged) callbacks are used.
@endverbatim
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
/** @defgroup SMARTCARD SMARTCARD
* @brief HAL SMARTCARD module driver
* @{
*/
#ifdef HAL_SMARTCARD_MODULE_ENABLED
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/** @addtogroup SMARTCARD_Private_Constants
* @{
*/
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/** @addtogroup SMARTCARD_Private_Functions
* @{
*/
#if (USE_HAL_SMARTCARD_REGISTER_CALLBACKS == 1)
void SMARTCARD_InitCallbacksToDefault(SMARTCARD_HandleTypeDef *hsc);
#endif /* USE_HAL_SMARTCARD_REGISTER_CALLBACKS */
static void SMARTCARD_EndTxTransfer(SMARTCARD_HandleTypeDef *hsc);
static void SMARTCARD_EndRxTransfer(SMARTCARD_HandleTypeDef *hsc);
static void SMARTCARD_SetConfig (SMARTCARD_HandleTypeDef *hsc);
static HAL_StatusTypeDef SMARTCARD_Transmit_IT(SMARTCARD_HandleTypeDef *hsc);
static HAL_StatusTypeDef SMARTCARD_EndTransmit_IT(SMARTCARD_HandleTypeDef *hsc);
static HAL_StatusTypeDef SMARTCARD_Receive_IT(SMARTCARD_HandleTypeDef *hsc);
static void SMARTCARD_DMATransmitCplt(DMA_HandleTypeDef *hdma);
static void SMARTCARD_DMAReceiveCplt(DMA_HandleTypeDef *hdma);
static void SMARTCARD_DMAError(DMA_HandleTypeDef *hdma);
static void SMARTCARD_DMAAbortOnError(DMA_HandleTypeDef *hdma);
static void SMARTCARD_DMATxAbortCallback(DMA_HandleTypeDef *hdma);
static void SMARTCARD_DMARxAbortCallback(DMA_HandleTypeDef *hdma);
static void SMARTCARD_DMATxOnlyAbortCallback(DMA_HandleTypeDef *hdma);
static void SMARTCARD_DMARxOnlyAbortCallback(DMA_HandleTypeDef *hdma);
static HAL_StatusTypeDef SMARTCARD_WaitOnFlagUntilTimeout(SMARTCARD_HandleTypeDef *hsc, uint32_t Flag, FlagStatus Status, uint32_t Tickstart, uint32_t Timeout);
/**
* @}
*/
/* Exported functions --------------------------------------------------------*/
/** @defgroup SMARTCARD_Exported_Functions SMARTCARD Exported Functions
* @{
*/
/** @defgroup SMARTCARD_Exported_Functions_Group1 SmartCard Initialization and de-initialization functions
* @brief Initialization and Configuration functions
*
@verbatim
==============================================================================
##### Initialization and Configuration functions #####
==============================================================================
[..]
This subsection provides a set of functions allowing to initialize the USART
in Smartcard mode.
[..]
The Smartcard interface is designed to support asynchronous protocol Smartcards as
defined in the ISO 7816-3 standard.
[..]
The USART can provide a clock to the smartcard through the SCLK output.
In smartcard mode, SCLK is not associated to the communication but is simply derived
from the internal peripheral input clock through a 5-bit prescaler.
[..]
(+) For the Smartcard mode only these parameters can be configured:
(++) Baud Rate
(++) Word Length => Should be 9 bits (8 bits + parity)
(++) Stop Bit
(++) Parity: => Should be enabled
(++) USART polarity
(++) USART phase
(++) USART LastBit
(++) Receiver/transmitter modes
(++) Prescaler
(++) GuardTime
(++) NACKState: The Smartcard NACK state
(+) Recommended SmartCard interface configuration to get the Answer to Reset from the Card:
(++) Word Length = 9 Bits
(++) 1.5 Stop Bit
(++) Even parity
(++) BaudRate = 12096 baud
(++) Tx and Rx enabled
[..]
Please refer to the ISO 7816-3 specification for more details.
[..]
(@) It is also possible to choose 0.5 stop bit for receiving but it is recommended
to use 1.5 stop bits for both transmitting and receiving to avoid switching
between the two configurations.
[..]
The HAL_SMARTCARD_Init() function follows the USART SmartCard configuration
procedures (details for the procedures are available in reference manuals
(RM0008 for STM32F10Xxx MCUs and RM0041 for STM32F100xx MCUs)).
@endverbatim
The SMARTCARD frame format is given in the following table:
+-------------------------------------------------------------+
| M bit | PCE bit | SMARTCARD frame |
|---------------------|---------------------------------------|
| 1 | 1 | | SB | 8 bit data | PB | STB | |
+-------------------------------------------------------------+
* @{
*/
/**
* @brief Initializes the SmartCard mode according to the specified
* parameters in the SMARTCARD_InitTypeDef and create the associated handle.
* @param hsc Pointer to a SMARTCARD_HandleTypeDef structure that contains
* the configuration information for SMARTCARD module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SMARTCARD_Init(SMARTCARD_HandleTypeDef *hsc)
{
/* Check the SMARTCARD handle allocation */
if(hsc == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_SMARTCARD_INSTANCE(hsc->Instance));
assert_param(IS_SMARTCARD_NACK_STATE(hsc->Init.NACKState));
if(hsc->gState == HAL_SMARTCARD_STATE_RESET)
{
/* Allocate lock resource and initialize it */
hsc->Lock = HAL_UNLOCKED;
#if USE_HAL_SMARTCARD_REGISTER_CALLBACKS == 1
SMARTCARD_InitCallbacksToDefault(hsc);
if (hsc->MspInitCallback == NULL)
{
hsc->MspInitCallback = HAL_SMARTCARD_MspInit;
}
/* Init the low level hardware */
hsc->MspInitCallback(hsc);
#else
/* Init the low level hardware : GPIO, CLOCK */
HAL_SMARTCARD_MspInit(hsc);
#endif /* USE_HAL_SMARTCARD_REGISTER_CALLBACKS */
}
hsc->gState = HAL_SMARTCARD_STATE_BUSY;
/* Set the Prescaler */
MODIFY_REG(hsc->Instance->GTPR, USART_GTPR_PSC, hsc->Init.Prescaler);
/* Set the Guard Time */
MODIFY_REG(hsc->Instance->GTPR, USART_GTPR_GT, ((hsc->Init.GuardTime)<<8U));
/* Set the Smartcard Communication parameters */
SMARTCARD_SetConfig(hsc);
/* In SmartCard mode, the following bits must be kept cleared:
- LINEN bit in the USART_CR2 register
- HDSEL and IREN bits in the USART_CR3 register.*/
CLEAR_BIT(hsc->Instance->CR2, USART_CR2_LINEN);
CLEAR_BIT(hsc->Instance->CR3, (USART_CR3_IREN | USART_CR3_HDSEL));
/* Enable the SMARTCARD Parity Error Interrupt */
SET_BIT(hsc->Instance->CR1, USART_CR1_PEIE);
/* Enable the SMARTCARD Framing Error Interrupt */
SET_BIT(hsc->Instance->CR3, USART_CR3_EIE);
/* Enable the Peripheral */
__HAL_SMARTCARD_ENABLE(hsc);
/* Configure the Smartcard NACK state */
MODIFY_REG(hsc->Instance->CR3, USART_CR3_NACK, hsc->Init.NACKState);
/* Enable the SC mode by setting the SCEN bit in the CR3 register */
hsc->Instance->CR3 |= (USART_CR3_SCEN);
/* Initialize the SMARTCARD state*/
hsc->ErrorCode = HAL_SMARTCARD_ERROR_NONE;
hsc->gState= HAL_SMARTCARD_STATE_READY;
hsc->RxState= HAL_SMARTCARD_STATE_READY;
return HAL_OK;
}
/**
* @brief DeInitializes the USART SmartCard peripheral
* @param hsc Pointer to a SMARTCARD_HandleTypeDef structure that contains
* the configuration information for SMARTCARD module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SMARTCARD_DeInit(SMARTCARD_HandleTypeDef *hsc)
{
/* Check the SMARTCARD handle allocation */
if(hsc == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_SMARTCARD_INSTANCE(hsc->Instance));
hsc->gState = HAL_SMARTCARD_STATE_BUSY;
/* Disable the Peripheral */
__HAL_SMARTCARD_DISABLE(hsc);
/* DeInit the low level hardware */
#if USE_HAL_SMARTCARD_REGISTER_CALLBACKS == 1
if (hsc->MspDeInitCallback == NULL)
{
hsc->MspDeInitCallback = HAL_SMARTCARD_MspDeInit;
}
/* DeInit the low level hardware */
hsc->MspDeInitCallback(hsc);
#else
HAL_SMARTCARD_MspDeInit(hsc);
#endif /* USE_HAL_SMARTCARD_REGISTER_CALLBACKS */
hsc->ErrorCode = HAL_SMARTCARD_ERROR_NONE;
hsc->gState = HAL_SMARTCARD_STATE_RESET;
hsc->RxState = HAL_SMARTCARD_STATE_RESET;
/* Release Lock */
__HAL_UNLOCK(hsc);
return HAL_OK;
}
/**
* @brief SMARTCARD MSP Init
* @param hsc Pointer to a SMARTCARD_HandleTypeDef structure that contains
* the configuration information for SMARTCARD module.
* @retval None
*/
__weak void HAL_SMARTCARD_MspInit(SMARTCARD_HandleTypeDef *hsc)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hsc);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_SMARTCARD_MspInit can be implemented in the user file
*/
}
/**
* @brief SMARTCARD MSP DeInit
* @param hsc Pointer to a SMARTCARD_HandleTypeDef structure that contains
* the configuration information for SMARTCARD module.
* @retval None
*/
__weak void HAL_SMARTCARD_MspDeInit(SMARTCARD_HandleTypeDef *hsc)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hsc);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_SMARTCARD_MspDeInit can be implemented in the user file
*/
}
#if (USE_HAL_SMARTCARD_REGISTER_CALLBACKS == 1)
/**
* @brief Register a User SMARTCARD Callback
* To be used instead of the weak predefined callback
* @note The HAL_SMARTCARD_RegisterCallback() may be called before HAL_SMARTCARD_Init()
* in HAL_SMARTCARD_STATE_RESET to register callbacks for HAL_SMARTCARD_MSPINIT_CB_ID
* and HAL_SMARTCARD_MSPDEINIT_CB_ID
* @param hsc smartcard handle
* @param CallbackID ID of the callback to be registered
* This parameter can be one of the following values:
* @arg @ref HAL_SMARTCARD_TX_COMPLETE_CB_ID Tx Complete Callback ID
* @arg @ref HAL_SMARTCARD_RX_COMPLETE_CB_ID Rx Complete Callback ID
* @arg @ref HAL_SMARTCARD_ERROR_CB_ID Error Callback ID
* @arg @ref HAL_SMARTCARD_ABORT_COMPLETE_CB_ID Abort Complete Callback ID
* @arg @ref HAL_SMARTCARD_ABORT_TRANSMIT_COMPLETE_CB_ID Abort Transmit Complete Callback ID
* @arg @ref HAL_SMARTCARD_ABORT_RECEIVE_COMPLETE_CB_ID Abort Receive Complete Callback ID
* @arg @ref HAL_SMARTCARD_MSPINIT_CB_ID MspInit Callback ID
* @arg @ref HAL_SMARTCARD_MSPDEINIT_CB_ID MspDeInit Callback ID
* @param pCallback pointer to the Callback function
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SMARTCARD_RegisterCallback(SMARTCARD_HandleTypeDef *hsc, HAL_SMARTCARD_CallbackIDTypeDef CallbackID, pSMARTCARD_CallbackTypeDef pCallback)
{
HAL_StatusTypeDef status = HAL_OK;
if (pCallback == NULL)
{
/* Update the error code */
hsc->ErrorCode |= HAL_SMARTCARD_ERROR_INVALID_CALLBACK;
return HAL_ERROR;
}
if (hsc->gState == HAL_SMARTCARD_STATE_READY)
{
switch (CallbackID)
{
case HAL_SMARTCARD_TX_COMPLETE_CB_ID :
hsc->TxCpltCallback = pCallback;
break;
case HAL_SMARTCARD_RX_COMPLETE_CB_ID :
hsc->RxCpltCallback = pCallback;
break;
case HAL_SMARTCARD_ERROR_CB_ID :
hsc->ErrorCallback = pCallback;
break;
case HAL_SMARTCARD_ABORT_COMPLETE_CB_ID :
hsc->AbortCpltCallback = pCallback;
break;
case HAL_SMARTCARD_ABORT_TRANSMIT_COMPLETE_CB_ID :
hsc->AbortTransmitCpltCallback = pCallback;
break;
case HAL_SMARTCARD_ABORT_RECEIVE_COMPLETE_CB_ID :
hsc->AbortReceiveCpltCallback = pCallback;
break;
case HAL_SMARTCARD_MSPINIT_CB_ID :
hsc->MspInitCallback = pCallback;
break;
case HAL_SMARTCARD_MSPDEINIT_CB_ID :
hsc->MspDeInitCallback = pCallback;
break;
default :
/* Update the error code */
hsc->ErrorCode |= HAL_SMARTCARD_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else if (hsc->gState == HAL_SMARTCARD_STATE_RESET)
{
switch (CallbackID)
{
case HAL_SMARTCARD_MSPINIT_CB_ID :
hsc->MspInitCallback = pCallback;
break;
case HAL_SMARTCARD_MSPDEINIT_CB_ID :
hsc->MspDeInitCallback = pCallback;
break;
default :
/* Update the error code */
hsc->ErrorCode |= HAL_SMARTCARD_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else
{
/* Update the error code */
hsc->ErrorCode |= HAL_SMARTCARD_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
}
return status;
}
/**
* @brief Unregister an SMARTCARD callback
* SMARTCARD callback is redirected to the weak predefined callback
* @note The HAL_SMARTCARD_UnRegisterCallback() may be called before HAL_SMARTCARD_Init()
* in HAL_SMARTCARD_STATE_RESET to un-register callbacks for HAL_SMARTCARD_MSPINIT_CB_ID
* and HAL_SMARTCARD_MSPDEINIT_CB_ID
* @param hsc smartcard handle
* @param CallbackID ID of the callback to be unregistered
* This parameter can be one of the following values:
* @arg @ref HAL_SMARTCARD_TX_COMPLETE_CB_ID Tx Complete Callback ID
* @arg @ref HAL_SMARTCARD_RX_COMPLETE_CB_ID Rx Complete Callback ID
* @arg @ref HAL_SMARTCARD_ERROR_CB_ID Error Callback ID
* @arg @ref HAL_SMARTCARD_ABORT_COMPLETE_CB_ID Abort Complete Callback ID
* @arg @ref HAL_SMARTCARD_ABORT_TRANSMIT_COMPLETE_CB_ID Abort Transmit Complete Callback ID
* @arg @ref HAL_SMARTCARD_ABORT_RECEIVE_COMPLETE_CB_ID Abort Receive Complete Callback ID
* @arg @ref HAL_SMARTCARD_MSPINIT_CB_ID MspInit Callback ID
* @arg @ref HAL_SMARTCARD_MSPDEINIT_CB_ID MspDeInit Callback ID
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SMARTCARD_UnRegisterCallback(SMARTCARD_HandleTypeDef *hsc, HAL_SMARTCARD_CallbackIDTypeDef CallbackID)
{
HAL_StatusTypeDef status = HAL_OK;
if (HAL_SMARTCARD_STATE_READY == hsc->gState)
{
switch (CallbackID)
{
case HAL_SMARTCARD_TX_COMPLETE_CB_ID :
hsc->TxCpltCallback = HAL_SMARTCARD_TxCpltCallback; /* Legacy weak TxCpltCallback */
break;
case HAL_SMARTCARD_RX_COMPLETE_CB_ID :
hsc->RxCpltCallback = HAL_SMARTCARD_RxCpltCallback; /* Legacy weak RxCpltCallback */
break;
case HAL_SMARTCARD_ERROR_CB_ID :
hsc->ErrorCallback = HAL_SMARTCARD_ErrorCallback; /* Legacy weak ErrorCallback */
break;
case HAL_SMARTCARD_ABORT_COMPLETE_CB_ID :
hsc->AbortCpltCallback = HAL_SMARTCARD_AbortCpltCallback; /* Legacy weak AbortCpltCallback */
break;
case HAL_SMARTCARD_ABORT_TRANSMIT_COMPLETE_CB_ID :
hsc->AbortTransmitCpltCallback = HAL_SMARTCARD_AbortTransmitCpltCallback; /* Legacy weak AbortTransmitCpltCallback */
break;
case HAL_SMARTCARD_ABORT_RECEIVE_COMPLETE_CB_ID :
hsc->AbortReceiveCpltCallback = HAL_SMARTCARD_AbortReceiveCpltCallback; /* Legacy weak AbortReceiveCpltCallback */
break;
case HAL_SMARTCARD_MSPINIT_CB_ID :
hsc->MspInitCallback = HAL_SMARTCARD_MspInit; /* Legacy weak MspInitCallback */
break;
case HAL_SMARTCARD_MSPDEINIT_CB_ID :
hsc->MspDeInitCallback = HAL_SMARTCARD_MspDeInit; /* Legacy weak MspDeInitCallback */
break;
default :
/* Update the error code */
hsc->ErrorCode |= HAL_SMARTCARD_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else if (HAL_SMARTCARD_STATE_RESET == hsc->gState)
{
switch (CallbackID)
{
case HAL_SMARTCARD_MSPINIT_CB_ID :
hsc->MspInitCallback = HAL_SMARTCARD_MspInit;
break;
case HAL_SMARTCARD_MSPDEINIT_CB_ID :
hsc->MspDeInitCallback = HAL_SMARTCARD_MspDeInit;
break;
default :
/* Update the error code */
hsc->ErrorCode |= HAL_SMARTCARD_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else
{
/* Update the error code */
hsc->ErrorCode |= HAL_SMARTCARD_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
}
return status;
}
#endif /* USE_HAL_SMARTCARD_REGISTER_CALLBACKS */
/**
* @}
*/
/** @defgroup SMARTCARD_Exported_Functions_Group2 IO operation functions
* @brief SMARTCARD Transmit and Receive functions
*
@verbatim
===============================================================================
##### IO operation functions #####
===============================================================================
[..]
This subsection provides a set of functions allowing to manage the SMARTCARD data transfers.
[..]
(#) Smartcard is a single wire half duplex communication protocol.
The Smartcard interface is designed to support asynchronous protocol Smartcards as
defined in the ISO 7816-3 standard.
(#) The USART should be configured as:
(++) 8 bits plus parity: where M=1 and PCE=1 in the USART_CR1 register
(++) 1.5 stop bits when transmitting and receiving: where STOP=11 in the USART_CR2 register.
(#) There are two modes of transfer:
(++) Blocking mode: The communication is performed in polling mode.
The HAL status of all data processing is returned by the same function
after finishing transfer.
(++) Non Blocking mode: The communication is performed using Interrupts
or DMA, These APIs return the HAL status.
The end of the data processing will be indicated through the
dedicated SMARTCARD IRQ when using Interrupt mode or the DMA IRQ when
using DMA mode.
The HAL_SMARTCARD_TxCpltCallback(), HAL_SMARTCARD_RxCpltCallback() user callbacks
will be executed respectively at the end of the Transmit or Receive process
The HAL_SMARTCARD_ErrorCallback() user callback will be executed when a communication error is detected
(#) Blocking mode APIs are :
(++) HAL_SMARTCARD_Transmit()
(++) HAL_SMARTCARD_Receive()
(#) Non Blocking mode APIs with Interrupt are :
(++) HAL_SMARTCARD_Transmit_IT()
(++) HAL_SMARTCARD_Receive_IT()
(++) HAL_SMARTCARD_IRQHandler()
(#) Non Blocking mode functions with DMA are :
(++) HAL_SMARTCARD_Transmit_DMA()
(++) HAL_SMARTCARD_Receive_DMA()
(#) A set of Transfer Complete Callbacks are provided in non Blocking mode:
(++) HAL_SMARTCARD_TxCpltCallback()
(++) HAL_SMARTCARD_RxCpltCallback()
(++) HAL_SMARTCARD_ErrorCallback()
(#) Non-Blocking mode transfers could be aborted using Abort API's :
(+) HAL_SMARTCARD_Abort()
(+) HAL_SMARTCARD_AbortTransmit()
(+) HAL_SMARTCARD_AbortReceive()
(+) HAL_SMARTCARD_Abort_IT()
(+) HAL_SMARTCARD_AbortTransmit_IT()
(+) HAL_SMARTCARD_AbortReceive_IT()
(#) For Abort services based on interrupts (HAL_SMARTCARD_Abortxxx_IT), a set of Abort Complete Callbacks are provided:
(+) HAL_SMARTCARD_AbortCpltCallback()
(+) HAL_SMARTCARD_AbortTransmitCpltCallback()
(+) HAL_SMARTCARD_AbortReceiveCpltCallback()
(#) In Non-Blocking mode transfers, possible errors are split into 2 categories.
Errors are handled as follows :
(+) Error is considered as Recoverable and non blocking : Transfer could go till end, but error severity is
to be evaluated by user : this concerns Frame Error, Parity Error or Noise Error in Interrupt mode reception .
Received character is then retrieved and stored in Rx buffer, Error code is set to allow user to identify error type,
and HAL_SMARTCARD_ErrorCallback() user callback is executed. Transfer is kept ongoing on SMARTCARD side.
If user wants to abort it, Abort services should be called by user.
(+) Error is considered as Blocking : Transfer could not be completed properly and is aborted.
This concerns Frame Error in Interrupt mode transmission, Overrun Error in Interrupt mode reception and all errors in DMA mode.
Error code is set to allow user to identify error type, and HAL_SMARTCARD_ErrorCallback() user callback is executed.
@endverbatim
* @{
*/
/**
* @brief Send an amount of data in blocking mode
* @param hsc Pointer to a SMARTCARD_HandleTypeDef structure that contains
* the configuration information for SMARTCARD module.
* @param pData Pointer to data buffer
* @param Size Amount of data to be sent
* @param Timeout Timeout duration
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SMARTCARD_Transmit(SMARTCARD_HandleTypeDef *hsc, const uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
const uint8_t *tmp = pData;
uint32_t tickstart = 0U;
if(hsc->gState == HAL_SMARTCARD_STATE_READY)
{
if((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(hsc);
hsc->ErrorCode = HAL_SMARTCARD_ERROR_NONE;
hsc->gState = HAL_SMARTCARD_STATE_BUSY_TX;
/* Init tickstart for timeout management */
tickstart = HAL_GetTick();
hsc->TxXferSize = Size;
hsc->TxXferCount = Size;
while(hsc->TxXferCount > 0U)
{
hsc->TxXferCount--;
if(SMARTCARD_WaitOnFlagUntilTimeout(hsc, SMARTCARD_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK)
{
return HAL_TIMEOUT;
}
hsc->Instance->DR = (uint8_t)(*tmp & 0xFFU);
tmp++;
}
if(SMARTCARD_WaitOnFlagUntilTimeout(hsc, SMARTCARD_FLAG_TC, RESET, tickstart, Timeout) != HAL_OK)
{
return HAL_TIMEOUT;
}
/* At end of Tx process, restore hsc->gState to Ready */
hsc->gState = HAL_SMARTCARD_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(hsc);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Receive an amount of data in blocking mode
* @param hsc Pointer to a SMARTCARD_HandleTypeDef structure that contains
* the configuration information for SMARTCARD module.
* @param pData Pointer to data buffer
* @param Size Amount of data to be received
* @param Timeout Timeout duration
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SMARTCARD_Receive(SMARTCARD_HandleTypeDef *hsc, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
uint8_t *tmp = pData;
uint32_t tickstart = 0U;
if(hsc->RxState == HAL_SMARTCARD_STATE_READY)
{
if((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(hsc);
hsc->ErrorCode = HAL_SMARTCARD_ERROR_NONE;
hsc->RxState = HAL_SMARTCARD_STATE_BUSY_RX;
/* Init tickstart for timeout management */
tickstart = HAL_GetTick();
hsc->RxXferSize = Size;
hsc->RxXferCount = Size;
/* Check the remain data to be received */
while(hsc->RxXferCount > 0U)
{
hsc->RxXferCount--;
if(SMARTCARD_WaitOnFlagUntilTimeout(hsc, SMARTCARD_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
{
return HAL_TIMEOUT;
}
*tmp = (uint8_t)(hsc->Instance->DR & (uint8_t)0xFFU);
tmp++;
}
/* At end of Rx process, restore hsc->RxState to Ready */
hsc->RxState = HAL_SMARTCARD_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(hsc);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Send an amount of data in non blocking mode
* @param hsc Pointer to a SMARTCARD_HandleTypeDef structure that contains
* the configuration information for SMARTCARD module.
* @param pData Pointer to data buffer
* @param Size Amount of data to be sent
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SMARTCARD_Transmit_IT(SMARTCARD_HandleTypeDef *hsc, const uint8_t *pData, uint16_t Size)
{
/* Check that a Tx process is not already ongoing */
if(hsc->gState == HAL_SMARTCARD_STATE_READY)
{
if((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(hsc);
hsc->pTxBuffPtr = pData;
hsc->TxXferSize = Size;
hsc->TxXferCount = Size;
hsc->ErrorCode = HAL_SMARTCARD_ERROR_NONE;
hsc->gState = HAL_SMARTCARD_STATE_BUSY_TX;
/* Process Unlocked */
__HAL_UNLOCK(hsc);
/* Enable the SMARTCARD Parity Error Interrupt */
SET_BIT(hsc->Instance->CR1, USART_CR1_PEIE);
/* Disable the SMARTCARD Error Interrupt: (Frame error, noise error, overrun error) */
CLEAR_BIT(hsc->Instance->CR3, USART_CR3_EIE);
/* Enable the SMARTCARD Transmit data register empty Interrupt */
SET_BIT(hsc->Instance->CR1, USART_CR1_TXEIE);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Receive an amount of data in non blocking mode
* @param hsc Pointer to a SMARTCARD_HandleTypeDef structure that contains
* the configuration information for SMARTCARD module.
* @param pData Pointer to data buffer
* @param Size Amount of data to be received
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SMARTCARD_Receive_IT(SMARTCARD_HandleTypeDef *hsc, uint8_t *pData, uint16_t Size)
{
/* Check that a Rx process is not already ongoing */
if(hsc->RxState == HAL_SMARTCARD_STATE_READY)
{
if((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(hsc);
hsc->pRxBuffPtr = pData;
hsc->RxXferSize = Size;
hsc->RxXferCount = Size;
hsc->ErrorCode = HAL_SMARTCARD_ERROR_NONE;
hsc->RxState = HAL_SMARTCARD_STATE_BUSY_RX;
/* Process Unlocked */
__HAL_UNLOCK(hsc);
/* Enable the SMARTCARD Parity Error and Data Register not empty Interrupts */
SET_BIT(hsc->Instance->CR1, USART_CR1_PEIE| USART_CR1_RXNEIE);
/* Enable the SMARTCARD Error Interrupt: (Frame error, noise error, overrun error) */
SET_BIT(hsc->Instance->CR3, USART_CR3_EIE);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Send an amount of data in non blocking mode
* @param hsc Pointer to a SMARTCARD_HandleTypeDef structure that contains
* the configuration information for SMARTCARD module.
* @param pData Pointer to data buffer
* @param Size Amount of data to be sent
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SMARTCARD_Transmit_DMA(SMARTCARD_HandleTypeDef *hsc, const uint8_t *pData, uint16_t Size)
{
const uint32_t *tmp;
/* Check that a Tx process is not already ongoing */
if(hsc->gState == HAL_SMARTCARD_STATE_READY)
{
if((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(hsc);
hsc->pTxBuffPtr = pData;
hsc->TxXferSize = Size;
hsc->TxXferCount = Size;
hsc->ErrorCode = HAL_SMARTCARD_ERROR_NONE;
hsc->gState = HAL_SMARTCARD_STATE_BUSY_TX;
/* Set the SMARTCARD DMA transfer complete callback */
hsc->hdmatx->XferCpltCallback = SMARTCARD_DMATransmitCplt;
/* Set the DMA error callback */
hsc->hdmatx->XferErrorCallback = SMARTCARD_DMAError;
/* Set the DMA abort callback */
hsc->hdmatx->XferAbortCallback = NULL;
/* Enable the SMARTCARD transmit DMA channel */
tmp = (const uint32_t*)&pData;
HAL_DMA_Start_IT(hsc->hdmatx, *(const uint32_t*)tmp, (uint32_t)&hsc->Instance->DR, Size);
/* Clear the TC flag in the SR register by writing 0 to it */
__HAL_SMARTCARD_CLEAR_FLAG(hsc, SMARTCARD_FLAG_TC);
/* Process Unlocked */
__HAL_UNLOCK(hsc);
/* Enable the DMA transfer for transmit request by setting the DMAT bit
in the SMARTCARD CR3 register */
SET_BIT(hsc->Instance->CR3, USART_CR3_DMAT);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Receive an amount of data in non blocking mode
* @param hsc Pointer to a SMARTCARD_HandleTypeDef structure that contains
* the configuration information for SMARTCARD module.
* @param pData Pointer to data buffer
* @param Size Amount of data to be received
* @note When the SMARTCARD parity is enabled (PCE = 1) the data received contain the parity bit.s
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SMARTCARD_Receive_DMA(SMARTCARD_HandleTypeDef *hsc, uint8_t *pData, uint16_t Size)
{
uint32_t *tmp;
/* Check that a Rx process is not already ongoing */
if(hsc->RxState == HAL_SMARTCARD_STATE_READY)
{
if((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(hsc);
hsc->pRxBuffPtr = pData;
hsc->RxXferSize = Size;
hsc->ErrorCode = HAL_SMARTCARD_ERROR_NONE;
hsc->RxState = HAL_SMARTCARD_STATE_BUSY_RX;
/* Set the SMARTCARD DMA transfer complete callback */
hsc->hdmarx->XferCpltCallback = SMARTCARD_DMAReceiveCplt;
/* Set the DMA error callback */
hsc->hdmarx->XferErrorCallback = SMARTCARD_DMAError;
/* Set the DMA abort callback */
hsc->hdmatx->XferAbortCallback = NULL;
/* Enable the DMA channel */
tmp = (uint32_t*)&pData;
HAL_DMA_Start_IT(hsc->hdmarx, (uint32_t)&hsc->Instance->DR, *(uint32_t*)tmp, Size);
/* Clear the Overrun flag just before enabling the DMA Rx request: can be mandatory for the second transfer */
__HAL_SMARTCARD_CLEAR_OREFLAG(hsc);
/* Process Unlocked */
__HAL_UNLOCK(hsc);
/* Enable the SMARTCARD Parity Error Interrupt */
SET_BIT(hsc->Instance->CR1, USART_CR1_PEIE);
/* Enable the SMARTCARD Error Interrupt: (Frame error, noise error, overrun error) */
SET_BIT(hsc->Instance->CR3, USART_CR3_EIE);
/* Enable the DMA transfer for the receiver request by setting the DMAR bit
in the SMARTCARD CR3 register */
SET_BIT(hsc->Instance->CR3, USART_CR3_DMAR);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Abort ongoing transfers (blocking mode).
* @param hsc SMARTCARD handle.
* @note This procedure could be used for aborting any ongoing transfer started in Interrupt or DMA mode.
* This procedure performs following operations :
* - Disable PPP Interrupts
* - Disable the DMA transfer in the peripheral register (if enabled)
* - Abort DMA transfer by calling HAL_DMA_Abort (in case of transfer in DMA mode)
* - Set handle State to READY
* @note This procedure is executed in blocking mode : when exiting function, Abort is considered as completed.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SMARTCARD_Abort(SMARTCARD_HandleTypeDef *hsc)
{
/* Disable TXEIE, TCIE, RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
CLEAR_BIT(hsc->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE | USART_CR1_TXEIE | USART_CR1_TCIE));
CLEAR_BIT(hsc->Instance->CR3, USART_CR3_EIE);
/* Disable the SMARTCARD DMA Tx request if enabled */
if(HAL_IS_BIT_SET(hsc->Instance->CR3, USART_CR3_DMAT))
{
CLEAR_BIT(hsc->Instance->CR3, USART_CR3_DMAT);
/* Abort the SMARTCARD DMA Tx channel : use blocking DMA Abort API (no callback) */
if(hsc->hdmatx != NULL)
{
/* Set the SMARTCARD DMA Abort callback to Null.
No call back execution at end of DMA abort procedure */
hsc->hdmatx->XferAbortCallback = NULL;
HAL_DMA_Abort(hsc->hdmatx);
}
}
/* Disable the SMARTCARD DMA Rx request if enabled */
if(HAL_IS_BIT_SET(hsc->Instance->CR3, USART_CR3_DMAR))
{
CLEAR_BIT(hsc->Instance->CR3, USART_CR3_DMAR);
/* Abort the SMARTCARD DMA Rx channel : use blocking DMA Abort API (no callback) */
if(hsc->hdmarx != NULL)
{
/* Set the SMARTCARD DMA Abort callback to Null.
No call back execution at end of DMA abort procedure */
hsc->hdmarx->XferAbortCallback = NULL;
HAL_DMA_Abort(hsc->hdmarx);
}
}
/* Reset Tx and Rx transfer counters */
hsc->TxXferCount = 0x00U;
hsc->RxXferCount = 0x00U;
/* Reset ErrorCode */
hsc->ErrorCode = HAL_SMARTCARD_ERROR_NONE;
/* Restore hsc->RxState and hsc->gState to Ready */
hsc->RxState = HAL_SMARTCARD_STATE_READY;
hsc->gState = HAL_SMARTCARD_STATE_READY;
return HAL_OK;
}
/**
* @brief Abort ongoing Transmit transfer (blocking mode).
* @param hsc SMARTCARD handle.
* @note This procedure could be used for aborting any ongoing transfer started in Interrupt or DMA mode.
* This procedure performs following operations :
* - Disable SMARTCARD Interrupts (Tx)
* - Disable the DMA transfer in the peripheral register (if enabled)
* - Abort DMA transfer by calling HAL_DMA_Abort (in case of transfer in DMA mode)
* - Set handle State to READY
* @note This procedure is executed in blocking mode : when exiting function, Abort is considered as completed.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SMARTCARD_AbortTransmit(SMARTCARD_HandleTypeDef *hsc)
{
/* Disable TXEIE and TCIE interrupts */
CLEAR_BIT(hsc->Instance->CR1, (USART_CR1_TXEIE | USART_CR1_TCIE));
/* Disable the SMARTCARD DMA Tx request if enabled */
if(HAL_IS_BIT_SET(hsc->Instance->CR3, USART_CR3_DMAT))
{
CLEAR_BIT(hsc->Instance->CR3, USART_CR3_DMAT);
/* Abort the SMARTCARD DMA Tx channel : use blocking DMA Abort API (no callback) */
if(hsc->hdmatx != NULL)
{
/* Set the SMARTCARD DMA Abort callback to Null.
No call back execution at end of DMA abort procedure */
hsc->hdmatx->XferAbortCallback = NULL;
HAL_DMA_Abort(hsc->hdmatx);
}
}
/* Reset Tx transfer counter */
hsc->TxXferCount = 0x00U;
/* Restore hsc->gState to Ready */
hsc->gState = HAL_SMARTCARD_STATE_READY;
return HAL_OK;
}
/**
* @brief Abort ongoing Receive transfer (blocking mode).
* @param hsc SMARTCARD handle.
* @note This procedure could be used for aborting any ongoing transfer started in Interrupt or DMA mode.
* This procedure performs following operations :
* - Disable PPP Interrupts
* - Disable the DMA transfer in the peripheral register (if enabled)
* - Abort DMA transfer by calling HAL_DMA_Abort (in case of transfer in DMA mode)
* - Set handle State to READY
* @note This procedure is executed in blocking mode : when exiting function, Abort is considered as completed.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SMARTCARD_AbortReceive(SMARTCARD_HandleTypeDef *hsc)
{
/* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
CLEAR_BIT(hsc->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
CLEAR_BIT(hsc->Instance->CR3, USART_CR3_EIE);
/* Disable the SMARTCARD DMA Rx request if enabled */
if(HAL_IS_BIT_SET(hsc->Instance->CR3, USART_CR3_DMAR))
{
CLEAR_BIT(hsc->Instance->CR3, USART_CR3_DMAR);
/* Abort the SMARTCARD DMA Rx channel : use blocking DMA Abort API (no callback) */
if(hsc->hdmarx != NULL)
{
/* Set the SMARTCARD DMA Abort callback to Null.
No call back execution at end of DMA abort procedure */
hsc->hdmarx->XferAbortCallback = NULL;
HAL_DMA_Abort(hsc->hdmarx);
}
}
/* Reset Rx transfer counter */
hsc->RxXferCount = 0x00U;
/* Restore hsc->RxState to Ready */
hsc->RxState = HAL_SMARTCARD_STATE_READY;
return HAL_OK;
}
/**
* @brief Abort ongoing transfers (Interrupt mode).
* @param hsc SMARTCARD handle.
* @note This procedure could be used for aborting any ongoing transfer started in Interrupt or DMA mode.
* This procedure performs following operations :
* - Disable PPP Interrupts
* - Disable the DMA transfer in the peripheral register (if enabled)
* - Abort DMA transfer by calling HAL_DMA_Abort_IT (in case of transfer in DMA mode)
* - Set handle State to READY
* - At abort completion, call user abort complete callback
* @note This procedure is executed in Interrupt mode, meaning that abort procedure could be
* considered as completed only when user abort complete callback is executed (not when exiting function).
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SMARTCARD_Abort_IT(SMARTCARD_HandleTypeDef *hsc)
{
uint32_t AbortCplt = 0x01U;
/* Disable TXEIE, TCIE, RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
CLEAR_BIT(hsc->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE | USART_CR1_TXEIE | USART_CR1_TCIE));
CLEAR_BIT(hsc->Instance->CR3, USART_CR3_EIE);
/* If DMA Tx and/or DMA Rx Handles are associated to SMARTCARD Handle, DMA Abort complete callbacks should be initialised
before any call to DMA Abort functions */
/* DMA Tx Handle is valid */
if(hsc->hdmatx != NULL)
{
/* Set DMA Abort Complete callback if SMARTCARD DMA Tx request if enabled.
Otherwise, set it to NULL */
if(HAL_IS_BIT_SET(hsc->Instance->CR3, USART_CR3_DMAT))
{
hsc->hdmatx->XferAbortCallback = SMARTCARD_DMATxAbortCallback;
}
else
{
hsc->hdmatx->XferAbortCallback = NULL;
}
}
/* DMA Rx Handle is valid */
if(hsc->hdmarx != NULL)
{
/* Set DMA Abort Complete callback if SMARTCARD DMA Rx request if enabled.
Otherwise, set it to NULL */
if(HAL_IS_BIT_SET(hsc->Instance->CR3, USART_CR3_DMAR))
{
hsc->hdmarx->XferAbortCallback = SMARTCARD_DMARxAbortCallback;
}
else
{
hsc->hdmarx->XferAbortCallback = NULL;
}
}
/* Disable the SMARTCARD DMA Tx request if enabled */
if(HAL_IS_BIT_SET(hsc->Instance->CR3, USART_CR3_DMAT))
{
/* Disable DMA Tx at SMARTCARD level */
CLEAR_BIT(hsc->Instance->CR3, USART_CR3_DMAT);
/* Abort the SMARTCARD DMA Tx channel : use non blocking DMA Abort API (callback) */
if(hsc->hdmatx != NULL)
{
/* SMARTCARD Tx DMA Abort callback has already been initialised :
will lead to call HAL_SMARTCARD_AbortCpltCallback() at end of DMA abort procedure */
/* Abort DMA TX */
if(HAL_DMA_Abort_IT(hsc->hdmatx) != HAL_OK)
{
hsc->hdmatx->XferAbortCallback = NULL;
}
else
{
AbortCplt = 0x00U;
}
}
}
/* Disable the SMARTCARD DMA Rx request if enabled */
if(HAL_IS_BIT_SET(hsc->Instance->CR3, USART_CR3_DMAR))
{
CLEAR_BIT(hsc->Instance->CR3, USART_CR3_DMAR);
/* Abort the SMARTCARD DMA Rx channel : use non blocking DMA Abort API (callback) */
if(hsc->hdmarx != NULL)
{
/* SMARTCARD Rx DMA Abort callback has already been initialised :
will lead to call HAL_SMARTCARD_AbortCpltCallback() at end of DMA abort procedure */
/* Abort DMA RX */
if(HAL_DMA_Abort_IT(hsc->hdmarx) != HAL_OK)
{
hsc->hdmarx->XferAbortCallback = NULL;
AbortCplt = 0x01U;
}
else
{
AbortCplt = 0x00U;
}
}
}
/* if no DMA abort complete callback execution is required => call user Abort Complete callback */
if(AbortCplt == 0x01U)
{
/* Reset Tx and Rx transfer counters */
hsc->TxXferCount = 0x00U;
hsc->RxXferCount = 0x00U;
/* Reset ErrorCode */
hsc->ErrorCode = HAL_SMARTCARD_ERROR_NONE;
/* Restore hsc->gState and hsc->RxState to Ready */
hsc->gState = HAL_SMARTCARD_STATE_READY;
hsc->RxState = HAL_SMARTCARD_STATE_READY;
/* As no DMA to be aborted, call directly user Abort complete callback */
#if (USE_HAL_SMARTCARD_REGISTER_CALLBACKS == 1)
/* Call registered Abort complete callback */
hsc->AbortCpltCallback(hsc);
#else
/* Call legacy weak Abort complete callback */
HAL_SMARTCARD_AbortCpltCallback(hsc);
#endif /* USE_HAL_SMARTCARD_REGISTER_CALLBACK */
}
return HAL_OK;
}
/**
* @brief Abort ongoing Transmit transfer (Interrupt mode).
* @param hsc SMARTCARD handle.
* @note This procedure could be used for aborting any ongoing transfer started in Interrupt or DMA mode.
* This procedure performs following operations :
* - Disable SMARTCARD Interrupts (Tx)
* - Disable the DMA transfer in the peripheral register (if enabled)
* - Abort DMA transfer by calling HAL_DMA_Abort_IT (in case of transfer in DMA mode)
* - Set handle State to READY
* - At abort completion, call user abort complete callback
* @note This procedure is executed in Interrupt mode, meaning that abort procedure could be
* considered as completed only when user abort complete callback is executed (not when exiting function).
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SMARTCARD_AbortTransmit_IT(SMARTCARD_HandleTypeDef *hsc)
{
/* Disable TXEIE and TCIE interrupts */
CLEAR_BIT(hsc->Instance->CR1, (USART_CR1_TXEIE | USART_CR1_TCIE));
/* Disable the SMARTCARD DMA Tx request if enabled */
if(HAL_IS_BIT_SET(hsc->Instance->CR3, USART_CR3_DMAT))
{
CLEAR_BIT(hsc->Instance->CR3, USART_CR3_DMAT);
/* Abort the SMARTCARD DMA Tx channel : use blocking DMA Abort API (no callback) */
if(hsc->hdmatx != NULL)
{
/* Set the SMARTCARD DMA Abort callback :
will lead to call HAL_SMARTCARD_AbortCpltCallback() at end of DMA abort procedure */
hsc->hdmatx->XferAbortCallback = SMARTCARD_DMATxOnlyAbortCallback;
/* Abort DMA TX */
if(HAL_DMA_Abort_IT(hsc->hdmatx) != HAL_OK)
{
/* Call Directly hsc->hdmatx->XferAbortCallback function in case of error */
hsc->hdmatx->XferAbortCallback(hsc->hdmatx);
}
}
else
{
/* Reset Tx transfer counter */
hsc->TxXferCount = 0x00U;
/* Restore hsc->gState to Ready */
hsc->gState = HAL_SMARTCARD_STATE_READY;
/* As no DMA to be aborted, call directly user Abort complete callback */
#if (USE_HAL_SMARTCARD_REGISTER_CALLBACKS == 1)
/* Call registered Abort Transmit Complete Callback */
hsc->AbortTransmitCpltCallback(hsc);
#else
/* Call legacy weak Abort Transmit Complete Callback */
HAL_SMARTCARD_AbortTransmitCpltCallback(hsc);
#endif /* USE_HAL_SMARTCARD_REGISTER_CALLBACK */
}
}
else
{
/* Reset Tx transfer counter */
hsc->TxXferCount = 0x00U;
/* Restore hsc->gState to Ready */
hsc->gState = HAL_SMARTCARD_STATE_READY;
/* As no DMA to be aborted, call directly user Abort complete callback */
#if (USE_HAL_SMARTCARD_REGISTER_CALLBACKS == 1)
/* Call registered Abort Transmit Complete Callback */
hsc->AbortTransmitCpltCallback(hsc);
#else
/* Call legacy weak Abort Transmit Complete Callback */
HAL_SMARTCARD_AbortTransmitCpltCallback(hsc);
#endif /* USE_HAL_SMARTCARD_REGISTER_CALLBACK */
}
return HAL_OK;
}
/**
* @brief Abort ongoing Receive transfer (Interrupt mode).
* @param hsc SMARTCARD handle.
* @note This procedure could be used for aborting any ongoing transfer started in Interrupt or DMA mode.
* This procedure performs following operations :
* - Disable SMARTCARD Interrupts (Rx)
* - Disable the DMA transfer in the peripheral register (if enabled)
* - Abort DMA transfer by calling HAL_DMA_Abort_IT (in case of transfer in DMA mode)
* - Set handle State to READY
* - At abort completion, call user abort complete callback
* @note This procedure is executed in Interrupt mode, meaning that abort procedure could be
* considered as completed only when user abort complete callback is executed (not when exiting function).
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SMARTCARD_AbortReceive_IT(SMARTCARD_HandleTypeDef *hsc)
{
/* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
CLEAR_BIT(hsc->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
CLEAR_BIT(hsc->Instance->CR3, USART_CR3_EIE);
/* Disable the SMARTCARD DMA Rx request if enabled */
if(HAL_IS_BIT_SET(hsc->Instance->CR3, USART_CR3_DMAR))
{
CLEAR_BIT(hsc->Instance->CR3, USART_CR3_DMAR);
/* Abort the SMARTCARD DMA Rx channel : use blocking DMA Abort API (no callback) */
if(hsc->hdmarx != NULL)
{
/* Set the SMARTCARD DMA Abort callback :
will lead to call HAL_SMARTCARD_AbortCpltCallback() at end of DMA abort procedure */
hsc->hdmarx->XferAbortCallback = SMARTCARD_DMARxOnlyAbortCallback;
/* Abort DMA RX */
if(HAL_DMA_Abort_IT(hsc->hdmarx) != HAL_OK)
{
/* Call Directly hsc->hdmarx->XferAbortCallback function in case of error */
hsc->hdmarx->XferAbortCallback(hsc->hdmarx);
}
}
else
{
/* Reset Rx transfer counter */
hsc->RxXferCount = 0x00U;
/* Restore hsc->RxState to Ready */
hsc->RxState = HAL_SMARTCARD_STATE_READY;
/* As no DMA to be aborted, call directly user Abort complete callback */
#if (USE_HAL_SMARTCARD_REGISTER_CALLBACKS == 1)
/* Call registered Abort Receive Complete Callback */
hsc->AbortReceiveCpltCallback(hsc);
#else
/* Call legacy weak Abort Receive Complete Callback */
HAL_SMARTCARD_AbortReceiveCpltCallback(hsc);
#endif /* USE_HAL_SMARTCARD_REGISTER_CALLBACK */
}
}
else
{
/* Reset Rx transfer counter */
hsc->RxXferCount = 0x00U;
/* Restore hsc->RxState to Ready */
hsc->RxState = HAL_SMARTCARD_STATE_READY;
/* As no DMA to be aborted, call directly user Abort complete callback */
#if (USE_HAL_SMARTCARD_REGISTER_CALLBACKS == 1)
/* Call registered Abort Receive Complete Callback */
hsc->AbortReceiveCpltCallback(hsc);
#else
/* Call legacy weak Abort Receive Complete Callback */
HAL_SMARTCARD_AbortReceiveCpltCallback(hsc);
#endif /* USE_HAL_SMARTCARD_REGISTER_CALLBACK */
}
return HAL_OK;
}
/**
* @brief This function handles SMARTCARD interrupt request.
* @param hsc Pointer to a SMARTCARD_HandleTypeDef structure that contains
* the configuration information for SMARTCARD module.
* @retval None
*/
void HAL_SMARTCARD_IRQHandler(SMARTCARD_HandleTypeDef *hsc)
{
uint32_t isrflags = READ_REG(hsc->Instance->SR);
uint32_t cr1its = READ_REG(hsc->Instance->CR1);
uint32_t cr3its = READ_REG(hsc->Instance->CR3);
uint32_t dmarequest = 0x00U;
uint32_t errorflags = 0x00U;
/* If no error occurs */
errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
if(errorflags == RESET)
{
/* SMARTCARD in mode Receiver -------------------------------------------------*/
if(((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
{
SMARTCARD_Receive_IT(hsc);
return;
}
}
/* If some errors occur */
if((errorflags != RESET) && (((cr3its & USART_CR3_EIE) != RESET) || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET)))
{
/* SMARTCARD parity error interrupt occurred ---------------------------*/
if(((isrflags & SMARTCARD_FLAG_PE) != RESET) && ((cr1its & USART_CR1_PEIE) != RESET))
{
hsc->ErrorCode |= HAL_SMARTCARD_ERROR_PE;
}
/* SMARTCARD frame error interrupt occurred ----------------------------*/
if(((isrflags & SMARTCARD_FLAG_FE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
{
hsc->ErrorCode |= HAL_SMARTCARD_ERROR_FE;
}
/* SMARTCARD noise error interrupt occurred ----------------------------*/
if(((isrflags & SMARTCARD_FLAG_NE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
{
hsc->ErrorCode |= HAL_SMARTCARD_ERROR_NE;
}
/* SMARTCARD Over-Run interrupt occurred -------------------------------*/
if(((isrflags & SMARTCARD_FLAG_ORE) != RESET) && (((cr1its & USART_CR1_RXNEIE) != RESET) || ((cr3its & USART_CR3_EIE) != RESET)))
{
hsc->ErrorCode |= HAL_SMARTCARD_ERROR_ORE;
}
/* Call the Error call Back in case of Errors --------------------------*/
if(hsc->ErrorCode != HAL_SMARTCARD_ERROR_NONE)
{
/* SMARTCARD in mode Receiver ----------------------------------------*/
if(((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
{
SMARTCARD_Receive_IT(hsc);
}
/* If Overrun error occurs, or if any error occurs in DMA mode reception,
consider error as blocking */
dmarequest = HAL_IS_BIT_SET(hsc->Instance->CR3, USART_CR3_DMAR);
if(((hsc->ErrorCode & HAL_SMARTCARD_ERROR_ORE) != RESET) || dmarequest)
{
/* Blocking error : transfer is aborted
Set the SMARTCARD state ready to be able to start again the process,
Disable Rx Interrupts, and disable Rx DMA request, if ongoing */
SMARTCARD_EndRxTransfer(hsc);
/* Disable the SMARTCARD DMA Rx request if enabled */
if(HAL_IS_BIT_SET(hsc->Instance->CR3, USART_CR3_DMAR))
{
CLEAR_BIT(hsc->Instance->CR3, USART_CR3_DMAR);
/* Abort the SMARTCARD DMA Rx channel */
if(hsc->hdmarx != NULL)
{
/* Set the SMARTCARD DMA Abort callback :
will lead to call HAL_SMARTCARD_ErrorCallback() at end of DMA abort procedure */
hsc->hdmarx->XferAbortCallback = SMARTCARD_DMAAbortOnError;
if(HAL_DMA_Abort_IT(hsc->hdmarx) != HAL_OK)
{
/* Call Directly XferAbortCallback function in case of error */
hsc->hdmarx->XferAbortCallback(hsc->hdmarx);
}
}
else
{
#if (USE_HAL_SMARTCARD_REGISTER_CALLBACKS == 1)
/* Call registered user error callback */
hsc->ErrorCallback(hsc);
#else
/* Call legacy weak user error callback */
HAL_SMARTCARD_ErrorCallback(hsc);
#endif /* USE_HAL_SMARTCARD_REGISTER_CALLBACK */
}
}
else
{
#if (USE_HAL_SMARTCARD_REGISTER_CALLBACKS == 1)
/* Call registered user error callback */
hsc->ErrorCallback(hsc);
#else
/* Call legacy weak user error callback */
HAL_SMARTCARD_ErrorCallback(hsc);
#endif /* USE_HAL_SMARTCARD_REGISTER_CALLBACK */
}
}
else
{
/* Non Blocking error : transfer could go on.
Error is notified to user through user error callback */
#if (USE_HAL_SMARTCARD_REGISTER_CALLBACKS == 1)
/* Call registered user error callback */
hsc->ErrorCallback(hsc);
#else
/* Call legacy weak user error callback */
HAL_SMARTCARD_ErrorCallback(hsc);
#endif /* USE_HAL_SMARTCARD_REGISTER_CALLBACK */
hsc->ErrorCode = HAL_SMARTCARD_ERROR_NONE;
}
}
return;
} /* End if some error occurs */
/* SMARTCARD in mode Transmitter ------------------------------------------*/
if(((isrflags & SMARTCARD_FLAG_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
{
SMARTCARD_Transmit_IT(hsc);
return;
}
/* SMARTCARD in mode Transmitter (transmission end) -----------------------*/
if(((isrflags & SMARTCARD_FLAG_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))
{
SMARTCARD_EndTransmit_IT(hsc);
return;
}
}
/**
* @brief Tx Transfer completed callbacks
* @param hsc Pointer to a SMARTCARD_HandleTypeDef structure that contains
* the configuration information for SMARTCARD module.
* @retval None
*/
__weak void HAL_SMARTCARD_TxCpltCallback(SMARTCARD_HandleTypeDef *hsc)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hsc);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_SMARTCARD_TxCpltCallback can be implemented in the user file.
*/
}
/**
* @brief Rx Transfer completed callback
* @param hsc Pointer to a SMARTCARD_HandleTypeDef structure that contains
* the configuration information for SMARTCARD module.
* @retval None
*/
__weak void HAL_SMARTCARD_RxCpltCallback(SMARTCARD_HandleTypeDef *hsc)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hsc);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_SMARTCARD_RxCpltCallback can be implemented in the user file.
*/
}
/**
* @brief SMARTCARD error callback
* @param hsc Pointer to a SMARTCARD_HandleTypeDef structure that contains
* the configuration information for SMARTCARD module.
* @retval None
*/
__weak void HAL_SMARTCARD_ErrorCallback(SMARTCARD_HandleTypeDef *hsc)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hsc);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_SMARTCARD_ErrorCallback can be implemented in the user file.
*/
}
/**
* @brief SMARTCARD Abort Complete callback.
* @param hsc SMARTCARD handle.
* @retval None
*/
__weak void HAL_SMARTCARD_AbortCpltCallback (SMARTCARD_HandleTypeDef *hsc)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hsc);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_SMARTCARD_AbortCpltCallback can be implemented in the user file.
*/
}
/**
* @brief SMARTCARD Abort Transmit Complete callback.
* @param hsc SMARTCARD handle.
* @retval None
*/
__weak void HAL_SMARTCARD_AbortTransmitCpltCallback (SMARTCARD_HandleTypeDef *hsc)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hsc);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_SMARTCARD_AbortTransmitCpltCallback can be implemented in the user file.
*/
}
/**
* @brief SMARTCARD Abort Receive Complete callback.
* @param hsc SMARTCARD handle.
* @retval None
*/
__weak void HAL_SMARTCARD_AbortReceiveCpltCallback (SMARTCARD_HandleTypeDef *hsc)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hsc);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_SMARTCARD_AbortReceiveCpltCallback can be implemented in the user file.
*/
}
/**
* @}
*/
/** @defgroup SMARTCARD_Exported_Functions_Group3 Peripheral State and Errors functions
* @brief SMARTCARD State and Errors functions
*
@verbatim
===============================================================================
##### Peripheral State and Errors functions #####
===============================================================================
[..]
This subsection provides a set of functions allowing to control the SmartCard.
(+) HAL_SMARTCARD_GetState() API can be helpful to check in run-time the state of the SmartCard peripheral.
(+) HAL_SMARTCARD_GetError() check in run-time errors that could be occurred during communication.
@endverbatim
* @{
*/
/**
* @brief Return the SMARTCARD handle state
* @param hsc Pointer to a SMARTCARD_HandleTypeDef structure that contains
* the configuration information for SMARTCARD module.
* @retval HAL state
*/
HAL_SMARTCARD_StateTypeDef HAL_SMARTCARD_GetState(const SMARTCARD_HandleTypeDef *hsc)
{
uint32_t temp1= 0x00U, temp2 = 0x00U;
temp1 = hsc->gState;
temp2 = hsc->RxState;
return (HAL_SMARTCARD_StateTypeDef)(temp1 | temp2);
}
/**
* @brief Return the SMARTCARD error code
* @param hsc Pointer to a SMARTCARD_HandleTypeDef structure that contains
* the configuration information for the specified SMARTCARD.
* @retval SMARTCARD Error Code
*/
uint32_t HAL_SMARTCARD_GetError(const SMARTCARD_HandleTypeDef *hsc)
{
return hsc->ErrorCode;
}
/**
* @}
*/
/**
* @}
*/
/** @defgroup SMARTCARD_Private_Functions SMARTCARD Private Functions
* @{
*/
#if (USE_HAL_SMARTCARD_REGISTER_CALLBACKS == 1)
/**
* @brief Initialize the callbacks to their default values.
* @param hsc SMARTCARD handle.
* @retval none
*/
void SMARTCARD_InitCallbacksToDefault(SMARTCARD_HandleTypeDef *hsc)
{
/* Init the SMARTCARD Callback settings */
hsc->TxCpltCallback = HAL_SMARTCARD_TxCpltCallback; /* Legacy weak TxCpltCallback */
hsc->RxCpltCallback = HAL_SMARTCARD_RxCpltCallback; /* Legacy weak RxCpltCallback */
hsc->ErrorCallback = HAL_SMARTCARD_ErrorCallback; /* Legacy weak ErrorCallback */
hsc->AbortCpltCallback = HAL_SMARTCARD_AbortCpltCallback; /* Legacy weak AbortCpltCallback */
hsc->AbortTransmitCpltCallback = HAL_SMARTCARD_AbortTransmitCpltCallback; /* Legacy weak AbortTransmitCpltCallback */
hsc->AbortReceiveCpltCallback = HAL_SMARTCARD_AbortReceiveCpltCallback; /* Legacy weak AbortReceiveCpltCallback */
}
#endif /* USE_HAL_SMARTCARD_REGISTER_CALLBACKS */
/**
* @brief DMA SMARTCARD transmit process complete callback
* @param hdma Pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
static void SMARTCARD_DMATransmitCplt(DMA_HandleTypeDef *hdma)
{
SMARTCARD_HandleTypeDef* hsc = ( SMARTCARD_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;
hsc->TxXferCount = 0U;
/* Disable the DMA transfer for transmit request by setting the DMAT bit
in the USART CR3 register */
CLEAR_BIT(hsc->Instance->CR3, USART_CR3_DMAT);
/* Enable the SMARTCARD Transmit Complete Interrupt */
SET_BIT(hsc->Instance->CR1, USART_CR1_TCIE);
}
/**
* @brief DMA SMARTCARD receive process complete callback
* @param hdma Pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
static void SMARTCARD_DMAReceiveCplt(DMA_HandleTypeDef *hdma)
{
SMARTCARD_HandleTypeDef* hsc = ( SMARTCARD_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;
hsc->RxXferCount = 0U;
/* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
CLEAR_BIT(hsc->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
CLEAR_BIT(hsc->Instance->CR3, USART_CR3_EIE);
/* Disable the DMA transfer for the receiver request by setting the DMAR bit
in the USART CR3 register */
CLEAR_BIT(hsc->Instance->CR3, USART_CR3_DMAR);
/* At end of Rx process, restore hsc->RxState to Ready */
hsc->RxState = HAL_SMARTCARD_STATE_READY;
#if (USE_HAL_SMARTCARD_REGISTER_CALLBACKS == 1)
/* Call registered Rx complete callback */
hsc->RxCpltCallback(hsc);
#else
/* Call legacy weak Rx complete callback */
HAL_SMARTCARD_RxCpltCallback(hsc);
#endif /* USE_HAL_SMARTCARD_REGISTER_CALLBACK */
}
/**
* @brief DMA SMARTCARD communication error callback
* @param hdma Pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
static void SMARTCARD_DMAError(DMA_HandleTypeDef *hdma)
{
uint32_t dmarequest = 0x00U;
SMARTCARD_HandleTypeDef* hsc = ( SMARTCARD_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;
hsc->RxXferCount = 0U;
hsc->TxXferCount = 0U;
hsc->ErrorCode = HAL_SMARTCARD_ERROR_DMA;
/* Stop SMARTCARD DMA Tx request if ongoing */
dmarequest = HAL_IS_BIT_SET(hsc->Instance->CR3, USART_CR3_DMAT);
if((hsc->gState == HAL_SMARTCARD_STATE_BUSY_TX) && dmarequest)
{
SMARTCARD_EndTxTransfer(hsc);
}
/* Stop SMARTCARD DMA Rx request if ongoing */
dmarequest = HAL_IS_BIT_SET(hsc->Instance->CR3, USART_CR3_DMAR);
if((hsc->RxState == HAL_SMARTCARD_STATE_BUSY_RX) && dmarequest)
{
SMARTCARD_EndRxTransfer(hsc);
}
#if (USE_HAL_SMARTCARD_REGISTER_CALLBACKS == 1)
/* Call registered user error callback */
hsc->ErrorCallback(hsc);
#else
/* Call legacy weak user error callback */
HAL_SMARTCARD_ErrorCallback(hsc);
#endif /* USE_HAL_SMARTCARD_REGISTER_CALLBACK */
}
/**
* @brief This function handles SMARTCARD Communication Timeout. It waits
* until a flag is no longer in the specified status.
* @param hsc Pointer to a SMARTCARD_HandleTypeDef structure that contains
* the configuration information for SMARTCARD module.
* @param Flag Specifies the SMARTCARD flag to check.
* @param Status The actual Flag status (SET or RESET).
* @param Timeout Timeout duration
* @param Tickstart Tick start value
* @retval HAL status
*/
static HAL_StatusTypeDef SMARTCARD_WaitOnFlagUntilTimeout(SMARTCARD_HandleTypeDef *hsc, uint32_t Flag, FlagStatus Status, uint32_t Tickstart, uint32_t Timeout)
{
/* Wait until flag is set */
while((__HAL_SMARTCARD_GET_FLAG(hsc, Flag) ? SET : RESET) == Status)
{
/* Check for the Timeout */
if(Timeout != HAL_MAX_DELAY)
{
if((Timeout == 0U)||((HAL_GetTick() - Tickstart ) > Timeout))
{
/* Disable TXE and RXNE interrupts for the interrupt process */
CLEAR_BIT(hsc->Instance->CR1, USART_CR1_TXEIE);
CLEAR_BIT(hsc->Instance->CR1, USART_CR1_RXNEIE);
hsc->gState= HAL_SMARTCARD_STATE_READY;
hsc->RxState= HAL_SMARTCARD_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(hsc);
return HAL_TIMEOUT;
}
}
}
return HAL_OK;
}
/**
* @brief End ongoing Tx transfer on SMARTCARD peripheral (following error detection or Transmit completion).
* @param hsc Pointer to a SMARTCARD_HandleTypeDef structure that contains
* the configuration information for SMARTCARD module.
* @retval None
*/
static void SMARTCARD_EndTxTransfer(SMARTCARD_HandleTypeDef *hsc)
{
/* At end of Tx process, restore hsc->gState to Ready */
hsc->gState = HAL_SMARTCARD_STATE_READY;
/* Disable TXEIE and TCIE interrupts */
CLEAR_BIT(hsc->Instance->CR1, (USART_CR1_TXEIE | USART_CR1_TCIE));
}
/**
* @brief End ongoing Rx transfer on SMARTCARD peripheral (following error detection or Reception completion).
* @param hsc Pointer to a SMARTCARD_HandleTypeDef structure that contains
* the configuration information for SMARTCARD module.
* @retval None
*/
static void SMARTCARD_EndRxTransfer(SMARTCARD_HandleTypeDef *hsc)
{
/* At end of Rx process, restore hsc->RxState to Ready */
hsc->RxState = HAL_SMARTCARD_STATE_READY;
/* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
CLEAR_BIT(hsc->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
CLEAR_BIT(hsc->Instance->CR3, USART_CR3_EIE);
}
/**
* @brief Send an amount of data in non blocking mode
* @param hsc Pointer to a SMARTCARD_HandleTypeDef structure that contains
* the configuration information for SMARTCARD module.
* @retval HAL status
*/
static HAL_StatusTypeDef SMARTCARD_Transmit_IT(SMARTCARD_HandleTypeDef *hsc)
{
/* Check that a Tx process is ongoing */
if(hsc->gState == HAL_SMARTCARD_STATE_BUSY_TX)
{
hsc->Instance->DR = (uint8_t)(*hsc->pTxBuffPtr & 0xFFU);
hsc->pTxBuffPtr++;
if(--hsc->TxXferCount == 0U)
{
/* Disable the SMARTCARD Transmit data register empty Interrupt */
CLEAR_BIT(hsc->Instance->CR1, USART_CR1_TXEIE);
/* Enable the SMARTCARD Transmit Complete Interrupt */
SET_BIT(hsc->Instance->CR1, USART_CR1_TCIE);
}
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Wraps up transmission in non blocking mode.
* @param hsc Pointer to a SMARTCARD_HandleTypeDef structure that contains
* the configuration information for the specified SMARTCARD module.
* @retval HAL status
*/
static HAL_StatusTypeDef SMARTCARD_EndTransmit_IT(SMARTCARD_HandleTypeDef *hsc)
{
/* Disable the SMARTCARD Transmit Complete Interrupt */
CLEAR_BIT(hsc->Instance->CR1, USART_CR1_TCIE);
/* Disable the SMARTCARD Error Interrupt: (Frame error, noise error, overrun error) */
CLEAR_BIT(hsc->Instance->CR3, USART_CR3_EIE);
/* Tx process is ended, restore hsc->gState to Ready */
hsc->gState = HAL_SMARTCARD_STATE_READY;
#if (USE_HAL_SMARTCARD_REGISTER_CALLBACKS == 1)
/* Call registered Tx complete callback */
hsc->TxCpltCallback(hsc);
#else
/* Call legacy weak Tx complete callback */
HAL_SMARTCARD_TxCpltCallback(hsc);
#endif /* USE_HAL_SMARTCARD_REGISTER_CALLBACK */
return HAL_OK;
}
/**
* @brief Receive an amount of data in non blocking mode
* @param hsc Pointer to a SMARTCARD_HandleTypeDef structure that contains
* the configuration information for SMARTCARD module.
* @retval HAL status
*/
static HAL_StatusTypeDef SMARTCARD_Receive_IT(SMARTCARD_HandleTypeDef *hsc)
{
/* Check that a Rx process is ongoing */
if(hsc->RxState == HAL_SMARTCARD_STATE_BUSY_RX)
{
*hsc->pRxBuffPtr = (uint8_t)(hsc->Instance->DR & (uint8_t)0xFFU);
hsc->pRxBuffPtr++;
if(--hsc->RxXferCount == 0U)
{
CLEAR_BIT(hsc->Instance->CR1, USART_CR1_RXNEIE);
/* Disable the SMARTCARD Parity Error Interrupt */
CLEAR_BIT(hsc->Instance->CR1, USART_CR1_PEIE);
/* Disable the SMARTCARD Error Interrupt: (Frame error, noise error, overrun error) */
CLEAR_BIT(hsc->Instance->CR3, USART_CR3_EIE);
/* Rx process is completed, restore hsc->RxState to Ready */
hsc->RxState = HAL_SMARTCARD_STATE_READY;
#if (USE_HAL_SMARTCARD_REGISTER_CALLBACKS == 1)
/* Call registered Rx complete callback */
hsc->RxCpltCallback(hsc);
#else
/* Call legacy weak Rx complete callback */
HAL_SMARTCARD_RxCpltCallback(hsc);
#endif /* USE_HAL_SMARTCARD_REGISTER_CALLBACK */
return HAL_OK;
}
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief DMA SMARTCARD communication abort callback, when initiated by HAL services on Error
* (To be called at end of DMA Abort procedure following error occurrence).
* @param hdma DMA handle.
* @retval None
*/
static void SMARTCARD_DMAAbortOnError(DMA_HandleTypeDef *hdma)
{
SMARTCARD_HandleTypeDef* hsc = (SMARTCARD_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;
hsc->RxXferCount = 0x00U;
hsc->TxXferCount = 0x00U;
#if (USE_HAL_SMARTCARD_REGISTER_CALLBACKS == 1)
/* Call registered user error callback */
hsc->ErrorCallback(hsc);
#else
/* Call legacy weak user error callback */
HAL_SMARTCARD_ErrorCallback(hsc);
#endif /* USE_HAL_SMARTCARD_REGISTER_CALLBACK */
}
/**
* @brief DMA SMARTCARD Tx communication abort callback, when initiated by user
* (To be called at end of DMA Tx Abort procedure following user abort request).
* @note When this callback is executed, User Abort complete call back is called only if no
* Abort still ongoing for Rx DMA Handle.
* @param hdma DMA handle.
* @retval None
*/
static void SMARTCARD_DMATxAbortCallback(DMA_HandleTypeDef *hdma)
{
SMARTCARD_HandleTypeDef* hsc = ( SMARTCARD_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;
hsc->hdmatx->XferAbortCallback = NULL;
/* Check if an Abort process is still ongoing */
if(hsc->hdmarx != NULL)
{
if(hsc->hdmarx->XferAbortCallback != NULL)
{
return;
}
}
/* No Abort process still ongoing : All DMA channels are aborted, call user Abort Complete callback */
hsc->TxXferCount = 0x00U;
hsc->RxXferCount = 0x00U;
/* Reset ErrorCode */
hsc->ErrorCode = HAL_SMARTCARD_ERROR_NONE;
/* Restore hsc->gState and hsc->RxState to Ready */
hsc->gState = HAL_SMARTCARD_STATE_READY;
hsc->RxState = HAL_SMARTCARD_STATE_READY;
#if (USE_HAL_SMARTCARD_REGISTER_CALLBACKS == 1)
/* Call registered Abort complete callback */
hsc->AbortCpltCallback(hsc);
#else
/* Call legacy weak Abort complete callback */
HAL_SMARTCARD_AbortCpltCallback(hsc);
#endif /* USE_HAL_SMARTCARD_REGISTER_CALLBACK */
}
/**
* @brief DMA SMARTCARD Rx communication abort callback, when initiated by user
* (To be called at end of DMA Rx Abort procedure following user abort request).
* @note When this callback is executed, User Abort complete call back is called only if no
* Abort still ongoing for Tx DMA Handle.
* @param hdma DMA handle.
* @retval None
*/
static void SMARTCARD_DMARxAbortCallback(DMA_HandleTypeDef *hdma)
{
SMARTCARD_HandleTypeDef* hsc = ( SMARTCARD_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;
hsc->hdmarx->XferAbortCallback = NULL;
/* Check if an Abort process is still ongoing */
if(hsc->hdmatx != NULL)
{
if(hsc->hdmatx->XferAbortCallback != NULL)
{
return;
}
}
/* No Abort process still ongoing : All DMA channels are aborted, call user Abort Complete callback */
hsc->TxXferCount = 0x00U;
hsc->RxXferCount = 0x00U;
/* Reset ErrorCode */
hsc->ErrorCode = HAL_SMARTCARD_ERROR_NONE;
/* Restore hsc->gState and hsc->RxState to Ready */
hsc->gState = HAL_SMARTCARD_STATE_READY;
hsc->RxState = HAL_SMARTCARD_STATE_READY;
#if (USE_HAL_SMARTCARD_REGISTER_CALLBACKS == 1)
/* Call registered Abort complete callback */
hsc->AbortCpltCallback(hsc);
#else
/* Call legacy weak Abort complete callback */
HAL_SMARTCARD_AbortCpltCallback(hsc);
#endif /* USE_HAL_SMARTCARD_REGISTER_CALLBACK */
}
/**
* @brief DMA SMARTCARD Tx communication abort callback, when initiated by user by a call to
* HAL_SMARTCARD_AbortTransmit_IT API (Abort only Tx transfer)
* (This callback is executed at end of DMA Tx Abort procedure following user abort request,
* and leads to user Tx Abort Complete callback execution).
* @param hdma DMA handle.
* @retval None
*/
static void SMARTCARD_DMATxOnlyAbortCallback(DMA_HandleTypeDef *hdma)
{
SMARTCARD_HandleTypeDef* hsc = ( SMARTCARD_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;
hsc->TxXferCount = 0x00U;
/* Restore hsc->gState to Ready */
hsc->gState = HAL_SMARTCARD_STATE_READY;
#if (USE_HAL_SMARTCARD_REGISTER_CALLBACKS == 1)
/* Call registered Abort Transmit Complete Callback */
hsc->AbortTransmitCpltCallback(hsc);
#else
/* Call legacy weak Abort Transmit Complete Callback */
HAL_SMARTCARD_AbortTransmitCpltCallback(hsc);
#endif /* USE_HAL_SMARTCARD_REGISTER_CALLBACK */
}
/**
* @brief DMA SMARTCARD Rx communication abort callback, when initiated by user by a call to
* HAL_SMARTCARD_AbortReceive_IT API (Abort only Rx transfer)
* (This callback is executed at end of DMA Rx Abort procedure following user abort request,
* and leads to user Rx Abort Complete callback execution).
* @param hdma DMA handle.
* @retval None
*/
static void SMARTCARD_DMARxOnlyAbortCallback(DMA_HandleTypeDef *hdma)
{
SMARTCARD_HandleTypeDef* hsc = ( SMARTCARD_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;
hsc->RxXferCount = 0x00U;
/* Restore hsc->RxState to Ready */
hsc->RxState = HAL_SMARTCARD_STATE_READY;
#if (USE_HAL_SMARTCARD_REGISTER_CALLBACKS == 1)
/* Call registered Abort Receive Complete Callback */
hsc->AbortReceiveCpltCallback(hsc);
#else
/* Call legacy weak Abort Receive Complete Callback */
HAL_SMARTCARD_AbortReceiveCpltCallback(hsc);
#endif /* USE_HAL_SMARTCARD_REGISTER_CALLBACK */
}
/**
* @brief Configure the SMARTCARD peripheral
* @param hsc Pointer to a SMARTCARD_HandleTypeDef structure that contains
* the configuration information for SMARTCARD module.
* @retval None
*/
static void SMARTCARD_SetConfig(SMARTCARD_HandleTypeDef *hsc)
{
uint32_t tmpreg = 0x00U;
uint32_t pclk;
/* Check the parameters */
assert_param(IS_SMARTCARD_INSTANCE(hsc->Instance));
assert_param(IS_SMARTCARD_POLARITY(hsc->Init.CLKPolarity));
assert_param(IS_SMARTCARD_PHASE(hsc->Init.CLKPhase));
assert_param(IS_SMARTCARD_LASTBIT(hsc->Init.CLKLastBit));
assert_param(IS_SMARTCARD_BAUDRATE(hsc->Init.BaudRate));
assert_param(IS_SMARTCARD_WORD_LENGTH(hsc->Init.WordLength));
assert_param(IS_SMARTCARD_STOPBITS(hsc->Init.StopBits));
assert_param(IS_SMARTCARD_PARITY(hsc->Init.Parity));
assert_param(IS_SMARTCARD_MODE(hsc->Init.Mode));
assert_param(IS_SMARTCARD_NACK_STATE(hsc->Init.NACKState));
/* The LBCL, CPOL and CPHA bits have to be selected when both the transmitter and the
receiver are disabled (TE=RE=0) to ensure that the clock pulses function correctly. */
CLEAR_BIT(hsc->Instance->CR1, (USART_CR1_TE | USART_CR1_RE));
/*---------------------------- USART CR2 Configuration ---------------------*/
tmpreg = hsc->Instance->CR2;
/* Clear CLKEN, CPOL, CPHA and LBCL bits */
tmpreg &= (uint32_t)~((uint32_t)(USART_CR2_CPHA | USART_CR2_CPOL | USART_CR2_CLKEN | USART_CR2_LBCL));
/* Configure the SMARTCARD Clock, CPOL, CPHA and LastBit -----------------------*/
/* Set CPOL bit according to hsc->Init.CLKPolarity value */
/* Set CPHA bit according to hsc->Init.CLKPhase value */
/* Set LBCL bit according to hsc->Init.CLKLastBit value */
/* Set Stop Bits: Set STOP[13:12] bits according to hsc->Init.StopBits value */
tmpreg |= (uint32_t)(USART_CR2_CLKEN | hsc->Init.CLKPolarity |
hsc->Init.CLKPhase| hsc->Init.CLKLastBit | hsc->Init.StopBits);
/* Write to USART CR2 */
WRITE_REG(hsc->Instance->CR2, (uint32_t)tmpreg);
tmpreg = hsc->Instance->CR2;
/* Clear STOP[13:12] bits */
tmpreg &= (uint32_t)~((uint32_t)USART_CR2_STOP);
/* Set Stop Bits: Set STOP[13:12] bits according to hsc->Init.StopBits value */
tmpreg |= (uint32_t)(hsc->Init.StopBits);
/* Write to USART CR2 */
WRITE_REG(hsc->Instance->CR2, (uint32_t)tmpreg);
/*-------------------------- USART CR1 Configuration -----------------------*/
tmpreg = hsc->Instance->CR1;
/* Clear M, PCE, PS, TE and RE bits */
tmpreg &= (uint32_t)~((uint32_t)(USART_CR1_M | USART_CR1_PCE | USART_CR1_PS | USART_CR1_TE | \
USART_CR1_RE));
/* Configure the SMARTCARD Word Length, Parity and mode:
Set the M bits according to hsc->Init.WordLength value
Set PCE and PS bits according to hsc->Init.Parity value
Set TE and RE bits according to hsc->Init.Mode value */
tmpreg |= (uint32_t)hsc->Init.WordLength | hsc->Init.Parity | hsc->Init.Mode;
/* Write to USART CR1 */
WRITE_REG(hsc->Instance->CR1, (uint32_t)tmpreg);
/*-------------------------- USART CR3 Configuration -----------------------*/
/* Clear CTSE and RTSE bits */
CLEAR_BIT(hsc->Instance->CR3, (USART_CR3_RTSE | USART_CR3_CTSE));
/*-------------------------- USART BRR Configuration -----------------------*/
if(hsc->Instance == USART1)
{
pclk = HAL_RCC_GetPCLK2Freq();
hsc->Instance->BRR = SMARTCARD_BRR(pclk, hsc->Init.BaudRate);
}
else
{
pclk = HAL_RCC_GetPCLK1Freq();
hsc->Instance->BRR = SMARTCARD_BRR(pclk, hsc->Init.BaudRate);
}
}
/**
* @}
*/
#endif /* HAL_SMARTCARD_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/

View File

@@ -0,0 +1,1117 @@
/**
******************************************************************************
* @file stm32f1xx_hal_sram.c
* @author MCD Application Team
* @brief SRAM HAL module driver.
* This file provides a generic firmware to drive SRAM memories
* mounted as external device.
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
==============================================================================
##### How to use this driver #####
==============================================================================
[..]
This driver is a generic layered driver which contains a set of APIs used to
control SRAM memories. It uses the FSMC layer functions to interface
with SRAM devices.
The following sequence should be followed to configure the FSMC to interface
with SRAM/PSRAM memories:
(#) Declare a SRAM_HandleTypeDef handle structure, for example:
SRAM_HandleTypeDef hsram; and:
(++) Fill the SRAM_HandleTypeDef handle "Init" field with the allowed
values of the structure member.
(++) Fill the SRAM_HandleTypeDef handle "Instance" field with a predefined
base register instance for NOR or SRAM device
(++) Fill the SRAM_HandleTypeDef handle "Extended" field with a predefined
base register instance for NOR or SRAM extended mode
(#) Declare two FSMC_NORSRAM_TimingTypeDef structures, for both normal and extended
mode timings; for example:
FSMC_NORSRAM_TimingTypeDef Timing and FSMC_NORSRAM_TimingTypeDef ExTiming;
and fill its fields with the allowed values of the structure member.
(#) Initialize the SRAM Controller by calling the function HAL_SRAM_Init(). This function
performs the following sequence:
(##) MSP hardware layer configuration using the function HAL_SRAM_MspInit()
(##) Control register configuration using the FSMC NORSRAM interface function
FSMC_NORSRAM_Init()
(##) Timing register configuration using the FSMC NORSRAM interface function
FSMC_NORSRAM_Timing_Init()
(##) Extended mode Timing register configuration using the FSMC NORSRAM interface function
FSMC_NORSRAM_Extended_Timing_Init()
(##) Enable the SRAM device using the macro __FSMC_NORSRAM_ENABLE()
(#) At this stage you can perform read/write accesses from/to the memory connected
to the NOR/SRAM Bank. You can perform either polling or DMA transfer using the
following APIs:
(++) HAL_SRAM_Read()/HAL_SRAM_Write() for polling read/write access
(++) HAL_SRAM_Read_DMA()/HAL_SRAM_Write_DMA() for DMA read/write transfer
(#) You can also control the SRAM device by calling the control APIs HAL_SRAM_WriteOperation_Enable()/
HAL_SRAM_WriteOperation_Disable() to respectively enable/disable the SRAM write operation
(#) You can continuously monitor the SRAM device HAL state by calling the function
HAL_SRAM_GetState()
*** Callback registration ***
=============================================
[..]
The compilation define USE_HAL_SRAM_REGISTER_CALLBACKS when set to 1
allows the user to configure dynamically the driver callbacks.
Use Functions HAL_SRAM_RegisterCallback() to register a user callback,
it allows to register following callbacks:
(+) MspInitCallback : SRAM MspInit.
(+) MspDeInitCallback : SRAM MspDeInit.
This function takes as parameters the HAL peripheral handle, the Callback ID
and a pointer to the user callback function.
Use function HAL_SRAM_UnRegisterCallback() to reset a callback to the default
weak (overridden) function. It allows to reset following callbacks:
(+) MspInitCallback : SRAM MspInit.
(+) MspDeInitCallback : SRAM MspDeInit.
This function) takes as parameters the HAL peripheral handle and the Callback ID.
By default, after the HAL_SRAM_Init and if the state is HAL_SRAM_STATE_RESET
all callbacks are reset to the corresponding legacy weak (overridden) functions.
Exception done for MspInit and MspDeInit callbacks that are respectively
reset to the legacy weak (overridden) functions in the HAL_SRAM_Init
and HAL_SRAM_DeInit only when these callbacks are null (not registered beforehand).
If not, MspInit or MspDeInit are not null, the HAL_SRAM_Init and HAL_SRAM_DeInit
keep and use the user MspInit/MspDeInit callbacks (registered beforehand)
Callbacks can be registered/unregistered in READY state only.
Exception done for MspInit/MspDeInit callbacks that can be registered/unregistered
in READY or RESET state, thus registered (user) MspInit/DeInit callbacks can be used
during the Init/DeInit.
In that case first register the MspInit/MspDeInit user callbacks
using HAL_SRAM_RegisterCallback before calling HAL_SRAM_DeInit
or HAL_SRAM_Init function.
When The compilation define USE_HAL_SRAM_REGISTER_CALLBACKS is set to 0 or
not defined, the callback registering feature is not available
and weak (overridden) callbacks are used.
@endverbatim
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
#if defined(FSMC_BANK1)
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
#ifdef HAL_SRAM_MODULE_ENABLED
/** @defgroup SRAM SRAM
* @brief SRAM driver modules
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/** @addtogroup SRAM_Private_Functions SRAM Private Functions
* @{
*/
static void SRAM_DMACplt(DMA_HandleTypeDef *hdma);
static void SRAM_DMACpltProt(DMA_HandleTypeDef *hdma);
static void SRAM_DMAError(DMA_HandleTypeDef *hdma);
/**
* @}
*/
/* Exported functions --------------------------------------------------------*/
/** @defgroup SRAM_Exported_Functions SRAM Exported Functions
* @{
*/
/** @defgroup SRAM_Exported_Functions_Group1 Initialization and de-initialization functions
* @brief Initialization and Configuration functions.
*
@verbatim
==============================================================================
##### SRAM Initialization and de_initialization functions #####
==============================================================================
[..] This section provides functions allowing to initialize/de-initialize
the SRAM memory
@endverbatim
* @{
*/
/**
* @brief Performs the SRAM device initialization sequence
* @param hsram pointer to a SRAM_HandleTypeDef structure that contains
* the configuration information for SRAM module.
* @param Timing Pointer to SRAM control timing structure
* @param ExtTiming Pointer to SRAM extended mode timing structure
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SRAM_Init(SRAM_HandleTypeDef *hsram, FSMC_NORSRAM_TimingTypeDef *Timing,
FSMC_NORSRAM_TimingTypeDef *ExtTiming)
{
/* Check the SRAM handle parameter */
if ((hsram == NULL) || (hsram->Init.BurstAccessMode == FSMC_BURST_ACCESS_MODE_ENABLE))
{
return HAL_ERROR;
}
if (hsram->State == HAL_SRAM_STATE_RESET)
{
/* Allocate lock resource and initialize it */
hsram->Lock = HAL_UNLOCKED;
#if (USE_HAL_SRAM_REGISTER_CALLBACKS == 1)
if (hsram->MspInitCallback == NULL)
{
hsram->MspInitCallback = HAL_SRAM_MspInit;
}
hsram->DmaXferCpltCallback = HAL_SRAM_DMA_XferCpltCallback;
hsram->DmaXferErrorCallback = HAL_SRAM_DMA_XferErrorCallback;
/* Init the low level hardware */
hsram->MspInitCallback(hsram);
#else
/* Initialize the low level hardware (MSP) */
HAL_SRAM_MspInit(hsram);
#endif /* USE_HAL_SRAM_REGISTER_CALLBACKS */
}
/* Initialize SRAM control Interface */
(void)FSMC_NORSRAM_Init(hsram->Instance, &(hsram->Init));
/* Initialize SRAM timing Interface */
(void)FSMC_NORSRAM_Timing_Init(hsram->Instance, Timing, hsram->Init.NSBank);
/* Initialize SRAM extended mode timing Interface */
(void)FSMC_NORSRAM_Extended_Timing_Init(hsram->Extended, ExtTiming, hsram->Init.NSBank,
hsram->Init.ExtendedMode);
/* Enable the NORSRAM device */
__FSMC_NORSRAM_ENABLE(hsram->Instance, hsram->Init.NSBank);
/* Initialize the SRAM controller state */
hsram->State = HAL_SRAM_STATE_READY;
return HAL_OK;
}
/**
* @brief Performs the SRAM device De-initialization sequence.
* @param hsram pointer to a SRAM_HandleTypeDef structure that contains
* the configuration information for SRAM module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SRAM_DeInit(SRAM_HandleTypeDef *hsram)
{
#if (USE_HAL_SRAM_REGISTER_CALLBACKS == 1)
if (hsram->MspDeInitCallback == NULL)
{
hsram->MspDeInitCallback = HAL_SRAM_MspDeInit;
}
/* DeInit the low level hardware */
hsram->MspDeInitCallback(hsram);
#else
/* De-Initialize the low level hardware (MSP) */
HAL_SRAM_MspDeInit(hsram);
#endif /* USE_HAL_SRAM_REGISTER_CALLBACKS */
/* Configure the SRAM registers with their reset values */
(void)FSMC_NORSRAM_DeInit(hsram->Instance, hsram->Extended, hsram->Init.NSBank);
/* Reset the SRAM controller state */
hsram->State = HAL_SRAM_STATE_RESET;
/* Release Lock */
__HAL_UNLOCK(hsram);
return HAL_OK;
}
/**
* @brief SRAM MSP Init.
* @param hsram pointer to a SRAM_HandleTypeDef structure that contains
* the configuration information for SRAM module.
* @retval None
*/
__weak void HAL_SRAM_MspInit(SRAM_HandleTypeDef *hsram)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hsram);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_SRAM_MspInit could be implemented in the user file
*/
}
/**
* @brief SRAM MSP DeInit.
* @param hsram pointer to a SRAM_HandleTypeDef structure that contains
* the configuration information for SRAM module.
* @retval None
*/
__weak void HAL_SRAM_MspDeInit(SRAM_HandleTypeDef *hsram)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hsram);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_SRAM_MspDeInit could be implemented in the user file
*/
}
/**
* @brief DMA transfer complete callback.
* @param hdma pointer to a SRAM_HandleTypeDef structure that contains
* the configuration information for SRAM module.
* @retval None
*/
__weak void HAL_SRAM_DMA_XferCpltCallback(DMA_HandleTypeDef *hdma)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hdma);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_SRAM_DMA_XferCpltCallback could be implemented in the user file
*/
}
/**
* @brief DMA transfer complete error callback.
* @param hdma pointer to a SRAM_HandleTypeDef structure that contains
* the configuration information for SRAM module.
* @retval None
*/
__weak void HAL_SRAM_DMA_XferErrorCallback(DMA_HandleTypeDef *hdma)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hdma);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_SRAM_DMA_XferErrorCallback could be implemented in the user file
*/
}
/**
* @}
*/
/** @defgroup SRAM_Exported_Functions_Group2 Input Output and memory control functions
* @brief Input Output and memory control functions
*
@verbatim
==============================================================================
##### SRAM Input and Output functions #####
==============================================================================
[..]
This section provides functions allowing to use and control the SRAM memory
@endverbatim
* @{
*/
/**
* @brief Reads 8-bit buffer from SRAM memory.
* @param hsram pointer to a SRAM_HandleTypeDef structure that contains
* the configuration information for SRAM module.
* @param pAddress Pointer to read start address
* @param pDstBuffer Pointer to destination buffer
* @param BufferSize Size of the buffer to read from memory
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SRAM_Read_8b(SRAM_HandleTypeDef *hsram, uint32_t *pAddress, uint8_t *pDstBuffer,
uint32_t BufferSize)
{
uint32_t size;
__IO uint8_t *psramaddress = (uint8_t *)pAddress;
uint8_t *pdestbuff = pDstBuffer;
HAL_SRAM_StateTypeDef state = hsram->State;
/* Check the SRAM controller state */
if ((state == HAL_SRAM_STATE_READY) || (state == HAL_SRAM_STATE_PROTECTED))
{
/* Process Locked */
__HAL_LOCK(hsram);
/* Update the SRAM controller state */
hsram->State = HAL_SRAM_STATE_BUSY;
/* Read data from memory */
for (size = BufferSize; size != 0U; size--)
{
*pdestbuff = *psramaddress;
pdestbuff++;
psramaddress++;
}
/* Update the SRAM controller state */
hsram->State = state;
/* Process unlocked */
__HAL_UNLOCK(hsram);
}
else
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Writes 8-bit buffer to SRAM memory.
* @param hsram pointer to a SRAM_HandleTypeDef structure that contains
* the configuration information for SRAM module.
* @param pAddress Pointer to write start address
* @param pSrcBuffer Pointer to source buffer to write
* @param BufferSize Size of the buffer to write to memory
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SRAM_Write_8b(SRAM_HandleTypeDef *hsram, uint32_t *pAddress, uint8_t *pSrcBuffer,
uint32_t BufferSize)
{
uint32_t size;
__IO uint8_t *psramaddress = (uint8_t *)pAddress;
uint8_t *psrcbuff = pSrcBuffer;
/* Check the SRAM controller state */
if (hsram->State == HAL_SRAM_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(hsram);
/* Update the SRAM controller state */
hsram->State = HAL_SRAM_STATE_BUSY;
/* Write data to memory */
for (size = BufferSize; size != 0U; size--)
{
*psramaddress = *psrcbuff;
psrcbuff++;
psramaddress++;
}
/* Update the SRAM controller state */
hsram->State = HAL_SRAM_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hsram);
}
else
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Reads 16-bit buffer from SRAM memory.
* @param hsram pointer to a SRAM_HandleTypeDef structure that contains
* the configuration information for SRAM module.
* @param pAddress Pointer to read start address
* @param pDstBuffer Pointer to destination buffer
* @param BufferSize Size of the buffer to read from memory
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SRAM_Read_16b(SRAM_HandleTypeDef *hsram, uint32_t *pAddress, uint16_t *pDstBuffer,
uint32_t BufferSize)
{
uint32_t size;
__IO uint32_t *psramaddress = pAddress;
uint16_t *pdestbuff = pDstBuffer;
uint8_t limit;
HAL_SRAM_StateTypeDef state = hsram->State;
/* Check the SRAM controller state */
if ((state == HAL_SRAM_STATE_READY) || (state == HAL_SRAM_STATE_PROTECTED))
{
/* Process Locked */
__HAL_LOCK(hsram);
/* Update the SRAM controller state */
hsram->State = HAL_SRAM_STATE_BUSY;
/* Check if the size is a 32-bits multiple */
limit = (((BufferSize % 2U) != 0U) ? 1U : 0U);
/* Read data from memory */
for (size = BufferSize; size != limit; size -= 2U)
{
*pdestbuff = (uint16_t)((*psramaddress) & 0x0000FFFFU);
pdestbuff++;
*pdestbuff = (uint16_t)(((*psramaddress) & 0xFFFF0000U) >> 16U);
pdestbuff++;
psramaddress++;
}
/* Read last 16-bits if size is not 32-bits multiple */
if (limit != 0U)
{
*pdestbuff = (uint16_t)((*psramaddress) & 0x0000FFFFU);
}
/* Update the SRAM controller state */
hsram->State = state;
/* Process unlocked */
__HAL_UNLOCK(hsram);
}
else
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Writes 16-bit buffer to SRAM memory.
* @param hsram pointer to a SRAM_HandleTypeDef structure that contains
* the configuration information for SRAM module.
* @param pAddress Pointer to write start address
* @param pSrcBuffer Pointer to source buffer to write
* @param BufferSize Size of the buffer to write to memory
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SRAM_Write_16b(SRAM_HandleTypeDef *hsram, uint32_t *pAddress, uint16_t *pSrcBuffer,
uint32_t BufferSize)
{
uint32_t size;
__IO uint32_t *psramaddress = pAddress;
uint16_t *psrcbuff = pSrcBuffer;
uint8_t limit;
/* Check the SRAM controller state */
if (hsram->State == HAL_SRAM_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(hsram);
/* Update the SRAM controller state */
hsram->State = HAL_SRAM_STATE_BUSY;
/* Check if the size is a 32-bits multiple */
limit = (((BufferSize % 2U) != 0U) ? 1U : 0U);
/* Write data to memory */
for (size = BufferSize; size != limit; size -= 2U)
{
*psramaddress = (uint32_t)(*psrcbuff);
psrcbuff++;
*psramaddress |= ((uint32_t)(*psrcbuff) << 16U);
psrcbuff++;
psramaddress++;
}
/* Write last 16-bits if size is not 32-bits multiple */
if (limit != 0U)
{
*psramaddress = ((uint32_t)(*psrcbuff) & 0x0000FFFFU) | ((*psramaddress) & 0xFFFF0000U);
}
/* Update the SRAM controller state */
hsram->State = HAL_SRAM_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hsram);
}
else
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Reads 32-bit buffer from SRAM memory.
* @param hsram pointer to a SRAM_HandleTypeDef structure that contains
* the configuration information for SRAM module.
* @param pAddress Pointer to read start address
* @param pDstBuffer Pointer to destination buffer
* @param BufferSize Size of the buffer to read from memory
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SRAM_Read_32b(SRAM_HandleTypeDef *hsram, uint32_t *pAddress, uint32_t *pDstBuffer,
uint32_t BufferSize)
{
uint32_t size;
__IO uint32_t *psramaddress = pAddress;
uint32_t *pdestbuff = pDstBuffer;
HAL_SRAM_StateTypeDef state = hsram->State;
/* Check the SRAM controller state */
if ((state == HAL_SRAM_STATE_READY) || (state == HAL_SRAM_STATE_PROTECTED))
{
/* Process Locked */
__HAL_LOCK(hsram);
/* Update the SRAM controller state */
hsram->State = HAL_SRAM_STATE_BUSY;
/* Read data from memory */
for (size = BufferSize; size != 0U; size--)
{
*pdestbuff = *psramaddress;
pdestbuff++;
psramaddress++;
}
/* Update the SRAM controller state */
hsram->State = state;
/* Process unlocked */
__HAL_UNLOCK(hsram);
}
else
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Writes 32-bit buffer to SRAM memory.
* @param hsram pointer to a SRAM_HandleTypeDef structure that contains
* the configuration information for SRAM module.
* @param pAddress Pointer to write start address
* @param pSrcBuffer Pointer to source buffer to write
* @param BufferSize Size of the buffer to write to memory
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SRAM_Write_32b(SRAM_HandleTypeDef *hsram, uint32_t *pAddress, uint32_t *pSrcBuffer,
uint32_t BufferSize)
{
uint32_t size;
__IO uint32_t *psramaddress = pAddress;
uint32_t *psrcbuff = pSrcBuffer;
/* Check the SRAM controller state */
if (hsram->State == HAL_SRAM_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(hsram);
/* Update the SRAM controller state */
hsram->State = HAL_SRAM_STATE_BUSY;
/* Write data to memory */
for (size = BufferSize; size != 0U; size--)
{
*psramaddress = *psrcbuff;
psrcbuff++;
psramaddress++;
}
/* Update the SRAM controller state */
hsram->State = HAL_SRAM_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hsram);
}
else
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Reads a Words data from the SRAM memory using DMA transfer.
* @param hsram pointer to a SRAM_HandleTypeDef structure that contains
* the configuration information for SRAM module.
* @param pAddress Pointer to read start address
* @param pDstBuffer Pointer to destination buffer
* @param BufferSize Size of the buffer to read from memory
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SRAM_Read_DMA(SRAM_HandleTypeDef *hsram, uint32_t *pAddress, uint32_t *pDstBuffer,
uint32_t BufferSize)
{
HAL_StatusTypeDef status;
HAL_SRAM_StateTypeDef state = hsram->State;
/* Check the SRAM controller state */
if ((state == HAL_SRAM_STATE_READY) || (state == HAL_SRAM_STATE_PROTECTED))
{
/* Process Locked */
__HAL_LOCK(hsram);
/* Update the SRAM controller state */
hsram->State = HAL_SRAM_STATE_BUSY;
/* Configure DMA user callbacks */
if (state == HAL_SRAM_STATE_READY)
{
hsram->hdma->XferCpltCallback = SRAM_DMACplt;
}
else
{
hsram->hdma->XferCpltCallback = SRAM_DMACpltProt;
}
hsram->hdma->XferErrorCallback = SRAM_DMAError;
/* Enable the DMA Stream */
status = HAL_DMA_Start_IT(hsram->hdma, (uint32_t)pAddress, (uint32_t)pDstBuffer, (uint32_t)BufferSize);
/* Process unlocked */
__HAL_UNLOCK(hsram);
}
else
{
status = HAL_ERROR;
}
return status;
}
/**
* @brief Writes a Words data buffer to SRAM memory using DMA transfer.
* @param hsram pointer to a SRAM_HandleTypeDef structure that contains
* the configuration information for SRAM module.
* @param pAddress Pointer to write start address
* @param pSrcBuffer Pointer to source buffer to write
* @param BufferSize Size of the buffer to write to memory
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SRAM_Write_DMA(SRAM_HandleTypeDef *hsram, uint32_t *pAddress, uint32_t *pSrcBuffer,
uint32_t BufferSize)
{
HAL_StatusTypeDef status;
/* Check the SRAM controller state */
if (hsram->State == HAL_SRAM_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(hsram);
/* Update the SRAM controller state */
hsram->State = HAL_SRAM_STATE_BUSY;
/* Configure DMA user callbacks */
hsram->hdma->XferCpltCallback = SRAM_DMACplt;
hsram->hdma->XferErrorCallback = SRAM_DMAError;
/* Enable the DMA Stream */
status = HAL_DMA_Start_IT(hsram->hdma, (uint32_t)pSrcBuffer, (uint32_t)pAddress, (uint32_t)BufferSize);
/* Process unlocked */
__HAL_UNLOCK(hsram);
}
else
{
status = HAL_ERROR;
}
return status;
}
#if (USE_HAL_SRAM_REGISTER_CALLBACKS == 1)
/**
* @brief Register a User SRAM Callback
* To be used to override the weak predefined callback
* @param hsram : SRAM handle
* @param CallbackId : ID of the callback to be registered
* This parameter can be one of the following values:
* @arg @ref HAL_SRAM_MSP_INIT_CB_ID SRAM MspInit callback ID
* @arg @ref HAL_SRAM_MSP_DEINIT_CB_ID SRAM MspDeInit callback ID
* @param pCallback : pointer to the Callback function
* @retval status
*/
HAL_StatusTypeDef HAL_SRAM_RegisterCallback(SRAM_HandleTypeDef *hsram, HAL_SRAM_CallbackIDTypeDef CallbackId,
pSRAM_CallbackTypeDef pCallback)
{
HAL_StatusTypeDef status = HAL_OK;
HAL_SRAM_StateTypeDef state;
if (pCallback == NULL)
{
return HAL_ERROR;
}
state = hsram->State;
if ((state == HAL_SRAM_STATE_READY) || (state == HAL_SRAM_STATE_RESET) || (state == HAL_SRAM_STATE_PROTECTED))
{
switch (CallbackId)
{
case HAL_SRAM_MSP_INIT_CB_ID :
hsram->MspInitCallback = pCallback;
break;
case HAL_SRAM_MSP_DEINIT_CB_ID :
hsram->MspDeInitCallback = pCallback;
break;
default :
/* update return status */
status = HAL_ERROR;
break;
}
}
else
{
/* update return status */
status = HAL_ERROR;
}
return status;
}
/**
* @brief Unregister a User SRAM Callback
* SRAM Callback is redirected to the weak predefined callback
* @param hsram : SRAM handle
* @param CallbackId : ID of the callback to be unregistered
* This parameter can be one of the following values:
* @arg @ref HAL_SRAM_MSP_INIT_CB_ID SRAM MspInit callback ID
* @arg @ref HAL_SRAM_MSP_DEINIT_CB_ID SRAM MspDeInit callback ID
* @arg @ref HAL_SRAM_DMA_XFER_CPLT_CB_ID SRAM DMA Xfer Complete callback ID
* @arg @ref HAL_SRAM_DMA_XFER_ERR_CB_ID SRAM DMA Xfer Error callback ID
* @retval status
*/
HAL_StatusTypeDef HAL_SRAM_UnRegisterCallback(SRAM_HandleTypeDef *hsram, HAL_SRAM_CallbackIDTypeDef CallbackId)
{
HAL_StatusTypeDef status = HAL_OK;
HAL_SRAM_StateTypeDef state;
state = hsram->State;
if ((state == HAL_SRAM_STATE_READY) || (state == HAL_SRAM_STATE_PROTECTED))
{
switch (CallbackId)
{
case HAL_SRAM_MSP_INIT_CB_ID :
hsram->MspInitCallback = HAL_SRAM_MspInit;
break;
case HAL_SRAM_MSP_DEINIT_CB_ID :
hsram->MspDeInitCallback = HAL_SRAM_MspDeInit;
break;
case HAL_SRAM_DMA_XFER_CPLT_CB_ID :
hsram->DmaXferCpltCallback = HAL_SRAM_DMA_XferCpltCallback;
break;
case HAL_SRAM_DMA_XFER_ERR_CB_ID :
hsram->DmaXferErrorCallback = HAL_SRAM_DMA_XferErrorCallback;
break;
default :
/* update return status */
status = HAL_ERROR;
break;
}
}
else if (state == HAL_SRAM_STATE_RESET)
{
switch (CallbackId)
{
case HAL_SRAM_MSP_INIT_CB_ID :
hsram->MspInitCallback = HAL_SRAM_MspInit;
break;
case HAL_SRAM_MSP_DEINIT_CB_ID :
hsram->MspDeInitCallback = HAL_SRAM_MspDeInit;
break;
default :
/* update return status */
status = HAL_ERROR;
break;
}
}
else
{
/* update return status */
status = HAL_ERROR;
}
return status;
}
/**
* @brief Register a User SRAM Callback for DMA transfers
* To be used to override the weak predefined callback
* @param hsram : SRAM handle
* @param CallbackId : ID of the callback to be registered
* This parameter can be one of the following values:
* @arg @ref HAL_SRAM_DMA_XFER_CPLT_CB_ID SRAM DMA Xfer Complete callback ID
* @arg @ref HAL_SRAM_DMA_XFER_ERR_CB_ID SRAM DMA Xfer Error callback ID
* @param pCallback : pointer to the Callback function
* @retval status
*/
HAL_StatusTypeDef HAL_SRAM_RegisterDmaCallback(SRAM_HandleTypeDef *hsram, HAL_SRAM_CallbackIDTypeDef CallbackId,
pSRAM_DmaCallbackTypeDef pCallback)
{
HAL_StatusTypeDef status = HAL_OK;
HAL_SRAM_StateTypeDef state;
if (pCallback == NULL)
{
return HAL_ERROR;
}
/* Process locked */
__HAL_LOCK(hsram);
state = hsram->State;
if ((state == HAL_SRAM_STATE_READY) || (state == HAL_SRAM_STATE_PROTECTED))
{
switch (CallbackId)
{
case HAL_SRAM_DMA_XFER_CPLT_CB_ID :
hsram->DmaXferCpltCallback = pCallback;
break;
case HAL_SRAM_DMA_XFER_ERR_CB_ID :
hsram->DmaXferErrorCallback = pCallback;
break;
default :
/* update return status */
status = HAL_ERROR;
break;
}
}
else
{
/* update return status */
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(hsram);
return status;
}
#endif /* USE_HAL_SRAM_REGISTER_CALLBACKS */
/**
* @}
*/
/** @defgroup SRAM_Exported_Functions_Group3 Control functions
* @brief Control functions
*
@verbatim
==============================================================================
##### SRAM Control functions #####
==============================================================================
[..]
This subsection provides a set of functions allowing to control dynamically
the SRAM interface.
@endverbatim
* @{
*/
/**
* @brief Enables dynamically SRAM write operation.
* @param hsram pointer to a SRAM_HandleTypeDef structure that contains
* the configuration information for SRAM module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SRAM_WriteOperation_Enable(SRAM_HandleTypeDef *hsram)
{
/* Check the SRAM controller state */
if (hsram->State == HAL_SRAM_STATE_PROTECTED)
{
/* Process Locked */
__HAL_LOCK(hsram);
/* Update the SRAM controller state */
hsram->State = HAL_SRAM_STATE_BUSY;
/* Enable write operation */
(void)FSMC_NORSRAM_WriteOperation_Enable(hsram->Instance, hsram->Init.NSBank);
/* Update the SRAM controller state */
hsram->State = HAL_SRAM_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(hsram);
}
else
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Disables dynamically SRAM write operation.
* @param hsram pointer to a SRAM_HandleTypeDef structure that contains
* the configuration information for SRAM module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SRAM_WriteOperation_Disable(SRAM_HandleTypeDef *hsram)
{
/* Check the SRAM controller state */
if (hsram->State == HAL_SRAM_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(hsram);
/* Update the SRAM controller state */
hsram->State = HAL_SRAM_STATE_BUSY;
/* Disable write operation */
(void)FSMC_NORSRAM_WriteOperation_Disable(hsram->Instance, hsram->Init.NSBank);
/* Update the SRAM controller state */
hsram->State = HAL_SRAM_STATE_PROTECTED;
/* Process unlocked */
__HAL_UNLOCK(hsram);
}
else
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @}
*/
/** @defgroup SRAM_Exported_Functions_Group4 Peripheral State functions
* @brief Peripheral State functions
*
@verbatim
==============================================================================
##### SRAM State functions #####
==============================================================================
[..]
This subsection permits to get in run-time the status of the SRAM controller
and the data flow.
@endverbatim
* @{
*/
/**
* @brief Returns the SRAM controller state
* @param hsram pointer to a SRAM_HandleTypeDef structure that contains
* the configuration information for SRAM module.
* @retval HAL state
*/
HAL_SRAM_StateTypeDef HAL_SRAM_GetState(const SRAM_HandleTypeDef *hsram)
{
return hsram->State;
}
/**
* @}
*/
/**
* @}
*/
/** @addtogroup SRAM_Private_Functions SRAM Private Functions
* @{
*/
/**
* @brief DMA SRAM process complete callback.
* @param hdma : DMA handle
* @retval None
*/
static void SRAM_DMACplt(DMA_HandleTypeDef *hdma)
{
/* Derogation MISRAC2012-Rule-11.5 */
SRAM_HandleTypeDef *hsram = (SRAM_HandleTypeDef *)(hdma->Parent);
/* Disable the DMA channel */
__HAL_DMA_DISABLE(hdma);
/* Update the SRAM controller state */
hsram->State = HAL_SRAM_STATE_READY;
#if (USE_HAL_SRAM_REGISTER_CALLBACKS == 1)
hsram->DmaXferCpltCallback(hdma);
#else
HAL_SRAM_DMA_XferCpltCallback(hdma);
#endif /* USE_HAL_SRAM_REGISTER_CALLBACKS */
}
/**
* @brief DMA SRAM process complete callback.
* @param hdma : DMA handle
* @retval None
*/
static void SRAM_DMACpltProt(DMA_HandleTypeDef *hdma)
{
/* Derogation MISRAC2012-Rule-11.5 */
SRAM_HandleTypeDef *hsram = (SRAM_HandleTypeDef *)(hdma->Parent);
/* Disable the DMA channel */
__HAL_DMA_DISABLE(hdma);
/* Update the SRAM controller state */
hsram->State = HAL_SRAM_STATE_PROTECTED;
#if (USE_HAL_SRAM_REGISTER_CALLBACKS == 1)
hsram->DmaXferCpltCallback(hdma);
#else
HAL_SRAM_DMA_XferCpltCallback(hdma);
#endif /* USE_HAL_SRAM_REGISTER_CALLBACKS */
}
/**
* @brief DMA SRAM error callback.
* @param hdma : DMA handle
* @retval None
*/
static void SRAM_DMAError(DMA_HandleTypeDef *hdma)
{
/* Derogation MISRAC2012-Rule-11.5 */
SRAM_HandleTypeDef *hsram = (SRAM_HandleTypeDef *)(hdma->Parent);
/* Disable the DMA channel */
__HAL_DMA_DISABLE(hdma);
/* Update the SRAM controller state */
hsram->State = HAL_SRAM_STATE_ERROR;
#if (USE_HAL_SRAM_REGISTER_CALLBACKS == 1)
hsram->DmaXferErrorCallback(hdma);
#else
HAL_SRAM_DMA_XferErrorCallback(hdma);
#endif /* USE_HAL_SRAM_REGISTER_CALLBACKS */
}
/**
* @}
*/
/**
* @}
*/
#endif /* HAL_SRAM_MODULE_ENABLED */
/**
* @}
*/
#endif /* FSMC_BANK1 */

View File

@@ -0,0 +1,309 @@
/**
******************************************************************************
* @file stm32f1xx_hal_timebase_rtc_alarm_template.c
* @author MCD Application Team
* @brief HAL time base based on the hardware RTC_ALARM.
*
* This file override the native HAL time base functions (defined as weak)
* to use the RTC ALARM for time base generation:
* + Intializes the RTC peripheral to increment the seconds registers each 1ms
* + The alarm is configured to assert an interrupt when the RTC reaches 1ms
* + HAL_IncTick is called at each Alarm event and the time is reset to 00:00:00
* + HSE (default), LSE or LSI can be selected as RTC clock source
*
******************************************************************************
* @attention
*
* Copyright (c) 2017 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
==============================================================================
##### How to use this driver #####
==============================================================================
[..]
This file must be copied to the application folder and modified as follows:
(#) Rename it to 'stm32f1xx_hal_timebase_rtc_alarm.c'
(#) Add this file and the RTC HAL drivers to your project and uncomment
HAL_RTC_MODULE_ENABLED define in stm32f1xx_hal_conf.h
[..]
(@) HAL RTC alarm and HAL RTC wakeup drivers cant be used with low power modes:
The wake up capability of the RTC may be intrusive in case of prior low power mode
configuration requiring different wake up sources.
Application/Example behavior is no more guaranteed
(@) The stm32f1xx_hal_timebase_tim use is recommended for the Applications/Examples
requiring low power modes
@endverbatim
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
/** @defgroup HAL_TimeBase_RTC_Alarm_Template HAL TimeBase RTC Alarm Template
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Uncomment the line below to select the appropriate RTC Clock source for your application:
+ RTC_CLOCK_SOURCE_HSE: can be selected for applications requiring timing precision.
+ RTC_CLOCK_SOURCE_LSE: can be selected for applications with low constraint on timing
precision.
+ RTC_CLOCK_SOURCE_LSI: can be selected for applications with low constraint on timing
precision.
*/
#define RTC_CLOCK_SOURCE_HSE
/* #define RTC_CLOCK_SOURCE_LSE */
/* #define RTC_CLOCK_SOURCE_LSI */
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
RTC_HandleTypeDef hRTC_Handle;
/* Private function prototypes -----------------------------------------------*/
void RTC_Alarm_IRQHandler(void);
/* Private functions ---------------------------------------------------------*/
/**
* @brief This function configures the RTC_ALARMA as a time base source.
* The time source is configured to have 1ms time base with a dedicated
* Tick interrupt priority.
* @note This function is called automatically at the beginning of program after
* reset by HAL_Init() or at any time when clock is configured, by HAL_RCC_ClockConfig().
* @param TickPriority Tick interrupt priority.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
__IO uint32_t counter = 0U;
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
HAL_StatusTypeDef status;
#ifdef RTC_CLOCK_SOURCE_LSE
/* Configue LSE as RTC clock soucre */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
#elif defined (RTC_CLOCK_SOURCE_LSI)
/* Configue LSI as RTC clock soucre */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
RCC_OscInitStruct.LSIState = RCC_LSI_ON;
PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
#elif defined (RTC_CLOCK_SOURCE_HSE)
/* Configue HSE as RTC clock soucre */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_HSE_DIV128;
#else
#error Please select the RTC Clock source
#endif /* RTC_CLOCK_SOURCE_LSE */
status = HAL_RCC_OscConfig(&RCC_OscInitStruct);
if (status == HAL_OK)
{
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;
status = HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
if (status == HAL_OK)
{
/* Enable RTC Clock */
__HAL_RCC_RTC_ENABLE();
/* Configure RTC time base to 10Khz */
hRTC_Handle.Instance = RTC;
hRTC_Handle.Init.AsynchPrediv = (HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_RTC) / 10000) - 1;
hRTC_Handle.Init.OutPut = RTC_OUTPUTSOURCE_NONE;
status = HAL_RTC_Init(&hRTC_Handle);
}
}
if (status == HAL_OK)
{
/* Disable the write protection for RTC registers */
__HAL_RTC_WRITEPROTECTION_DISABLE(&hRTC_Handle);
/* Clear flag alarm A */
__HAL_RTC_ALARM_CLEAR_FLAG(&hRTC_Handle, RTC_FLAG_ALRAF);
counter = 0U;
/* Wait till RTC ALRAF flag is set and if Time out is reached exit */
while (__HAL_RTC_ALARM_GET_FLAG(&hRTC_Handle, RTC_FLAG_ALRAF) != RESET)
{
if (counter++ == SystemCoreClock / 48U) /* Timeout = ~ 1s */
{
status = HAL_ERROR;
}
}
}
if (status == HAL_OK)
{
/* Set RTC COUNTER MSB word */
hRTC_Handle.Instance->ALRH = 0x00U;
/* Set RTC COUNTER LSB word */
hRTC_Handle.Instance->ALRL = 0x09U;
/* RTC Alarm Interrupt Configuration: EXTI configuration */
__HAL_RTC_ALARM_EXTI_ENABLE_IT();
__HAL_RTC_ALARM_EXTI_ENABLE_RISING_EDGE();
/* Clear Second and overflow flags */
CLEAR_BIT(hRTC_Handle.Instance->CRL, (RTC_FLAG_SEC | RTC_FLAG_OW));
/* Set RTC COUNTER MSB word */
hRTC_Handle.Instance->CNTH = 0x00U;
/* Set RTC COUNTER LSB word */
hRTC_Handle.Instance->CNTL = 0x00U;
/* Configure the Alarm interrupt */
__HAL_RTC_ALARM_ENABLE_IT(&hRTC_Handle, RTC_IT_ALRA);
/* Enable the write protection for RTC registers */
__HAL_RTC_WRITEPROTECTION_ENABLE(&hRTC_Handle);
/* Wait till RTC is in INIT state and if Time out is reached exit */
counter = 0U;
while ((hRTC_Handle.Instance->CRL & RTC_CRL_RTOFF) == (uint32_t)RESET)
{
if (counter++ == SystemCoreClock / 48U) /* Timeout = ~ 1s */
{
status = HAL_ERROR;
}
}
}
if (status == HAL_OK)
{
/* Enable the RTC global Interrupt */
HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn);
/* Configure the SysTick IRQ priority */
if (TickPriority < (1UL << __NVIC_PRIO_BITS))
{
HAL_NVIC_SetPriority(RTC_Alarm_IRQn, TickPriority ,0U);
uwTickPrio = TickPriority;
}
else
{
status = HAL_ERROR;
}
}
return status;
}
/**
* @brief Suspend Tick increment.
* @note Disable the tick increment by disabling RTC ALARM interrupt.
* @param None
* @retval None
*/
void HAL_SuspendTick(void)
{
/* Disable RTC ALARM update Interrupt */
__HAL_RTC_ALARM_DISABLE_IT(&hRTC_Handle, RTC_IT_ALRA);
}
/**
* @brief Resume Tick increment.
* @note Enable the tick increment by Enabling RTC ALARM interrupt.
* @param None
* @retval None
*/
void HAL_ResumeTick(void)
{
__IO uint32_t counter = 0U;
/* Disable the write protection for RTC registers */
__HAL_RTC_WRITEPROTECTION_DISABLE(&hRTC_Handle);
/* Set RTC COUNTER MSB word */
hRTC_Handle.Instance->CNTH = 0x00U;
/* Set RTC COUNTER LSB word */
hRTC_Handle.Instance->CNTL = 0x00U;
/* Clear Second and overflow flags */
CLEAR_BIT(hRTC_Handle.Instance->CRL, (RTC_FLAG_SEC | RTC_FLAG_OW | RTC_FLAG_ALRAF));
/* Enable RTC ALARM Update interrupt */
__HAL_RTC_ALARM_ENABLE_IT(&hRTC_Handle, RTC_IT_ALRA);
/* Enable the write protection for RTC registers */
__HAL_RTC_WRITEPROTECTION_ENABLE(&hRTC_Handle);
/* Wait till RTC is in INIT state and if Time out is reached exit */
while ((hRTC_Handle.Instance->CRL & RTC_CRL_RTOFF) == (uint32_t)RESET)
{
if (counter++ == SystemCoreClock / 48U) /* Timeout = ~ 1s */
{
break;
}
}
}
/**
* @brief ALARM A Event Callback in non blocking mode
* @note This function is called when RTC_ALARM interrupt took place, inside
* RTC_ALARM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
* a global variable "uwTick" used as application time base.
* @param hrtc RTC handle
* @retval None
*/
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
__IO uint32_t counter = 0U;
HAL_IncTick();
__HAL_RTC_WRITEPROTECTION_DISABLE(hrtc);
/* Set RTC COUNTER MSB word */
WRITE_REG(hrtc->Instance->CNTH, 0x00U);
/* Set RTC COUNTER LSB word */
WRITE_REG(hrtc->Instance->CNTL, 0x00U);
/* Clear Second and overflow flags */
CLEAR_BIT(hrtc->Instance->CRL, (RTC_FLAG_SEC | RTC_FLAG_OW));
/* Enable the write protection for RTC registers */
__HAL_RTC_WRITEPROTECTION_ENABLE(hrtc);
/* Wait till RTC is in INIT state and if Time out is reached exit */
while ((hrtc->Instance->CRL & RTC_CRL_RTOFF) == (uint32_t)RESET)
{
if (counter++ == SystemCoreClock / 48U) /* Timeout = ~ 1s */
{
break;
}
}
}
/**
* @brief This function handles RTC ALARM interrupt request.
* @retval None
*/
void RTC_Alarm_IRQHandler(void)
{
HAL_RTC_AlarmIRQHandler(&hRTC_Handle);
}
/**
* @}
*/
/**
* @}
*/

View File

@@ -0,0 +1,178 @@
/**
******************************************************************************
* @file stm32f1xx_hal_timebase_tim_template.c
* @author MCD Application Team
* @brief HAL time base based on the hardware TIM Template.
*
* This file overrides the native HAL time base functions (defined as weak)
* the TIM time base:
* + Initializes the TIM peripheral generate a Period elapsed Event each 1ms
* + HAL_IncTick is called inside HAL_TIM_PeriodElapsedCallback ie each 1ms
*
******************************************************************************
* @attention
*
* Copyright (c) 2017 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
/** @addtogroup HAL_TimeBase_TIM
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
TIM_HandleTypeDef TimHandle;
/* Private function prototypes -----------------------------------------------*/
void TIM2_IRQHandler(void);
/* Private functions ---------------------------------------------------------*/
/**
* @brief This function configures the TIM2 as a time base source.
* The time source is configured to have 1ms time base with a dedicated
* Tick interrupt priority.
* @note This function is called automatically at the beginning of program after
* reset by HAL_Init() or at any time when clock is configured, by HAL_RCC_ClockConfig().
* @param TickPriority Tick interrupt priority.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
RCC_ClkInitTypeDef clkconfig;
uint32_t uwTimclock, uwAPB1Prescaler = 0U;
uint32_t uwPrescalerValue = 0U;
uint32_t pFLatency;
HAL_StatusTypeDef status = HAL_OK;
/* Enable TIM2 clock */
__HAL_RCC_TIM2_CLK_ENABLE();
/* Get clock configuration */
HAL_RCC_GetClockConfig(&clkconfig, &pFLatency);
/* Get APB1 prescaler */
uwAPB1Prescaler = clkconfig.APB1CLKDivider;
/* Compute TIM2 clock */
if (uwAPB1Prescaler == RCC_HCLK_DIV1)
{
uwTimclock = HAL_RCC_GetPCLK1Freq();
}
else
{
uwTimclock = 2 * HAL_RCC_GetPCLK1Freq();
}
/* Compute the prescaler value to have TIM2 counter clock equal to 1MHz */
uwPrescalerValue = (uint32_t)((uwTimclock / 1000000U) - 1U);
/* Initialize TIM2 */
TimHandle.Instance = TIM2;
/* Initialize TIMx peripheral as follow:
+ Period = [(TIM2CLK/1000) - 1]. to have a (1/1000) s time base.
+ Prescaler = (uwTimclock/1000000 - 1) to have a 1MHz counter clock.
+ ClockDivision = 0
+ Counter direction = Up
*/
TimHandle.Init.Period = (1000000U / 1000U) - 1U;
TimHandle.Init.Prescaler = uwPrescalerValue;
TimHandle.Init.ClockDivision = 0U;
TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
status = HAL_TIM_Base_Init(&TimHandle);
if (status == HAL_OK)
{
/* Start the TIM time Base generation in interrupt mode */
status = HAL_TIM_Base_Start_IT(&TimHandle);
if (status == HAL_OK)
{
/* Enable the TIM2 global Interrupt */
HAL_NVIC_EnableIRQ(TIM2_IRQn);
if (TickPriority < (1UL << __NVIC_PRIO_BITS))
{
/*Configure the TIM2 IRQ priority */
HAL_NVIC_SetPriority(TIM2_IRQn, TickPriority ,0);
uwTickPrio = TickPriority;
}
else
{
status = HAL_ERROR;
}
}
}
/* Return function status */
return status;
}
/**
* @brief Suspend Tick increment.
* @note Disable the tick increment by disabling TIM2 update interrupt.
* @retval None
*/
void HAL_SuspendTick(void)
{
/* Disable TIM2 update Interrupt */
__HAL_TIM_DISABLE_IT(&TimHandle, TIM_IT_UPDATE);
}
/**
* @brief Resume Tick increment.
* @note Enable the tick increment by Enabling TIM2 update interrupt.
* @retval None
*/
void HAL_ResumeTick(void)
{
/* Enable TIM2 Update interrupt */
__HAL_TIM_ENABLE_IT(&TimHandle, TIM_IT_UPDATE);
}
/**
* @brief Period elapsed callback in non blocking mode
* @note This function is called when TIM2 interrupt took place, inside
* HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
* a global variable "uwTick" used as application time base.
* @param htim TIM handle
* @retval None
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
HAL_IncTick();
}
/**
* @brief This function handles TIM interrupt request.
* @retval None
*/
void TIM2_IRQHandler(void)
{
HAL_TIM_IRQHandler(&TimHandle);
}
/**
* @}
*/
/**
* @}
*/

View File

@@ -0,0 +1,2812 @@
/**
******************************************************************************
* @file stm32f1xx_hal_usart.c
* @author MCD Application Team
* @brief USART HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of the Universal Synchronous/Asynchronous Receiver Transmitter
* Peripheral (USART).
* + Initialization and de-initialization functions
* + IO operation functions
* + Peripheral Control functions
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
==============================================================================
##### How to use this driver #####
==============================================================================
[..]
The USART HAL driver can be used as follows:
(#) Declare a USART_HandleTypeDef handle structure (eg. USART_HandleTypeDef husart).
(#) Initialize the USART low level resources by implementing the HAL_USART_MspInit() API:
(##) Enable the USARTx interface clock.
(##) USART pins configuration:
(+++) Enable the clock for the USART GPIOs.
(+++) Configure the USART pins as alternate function pull-up.
(##) NVIC configuration if you need to use interrupt process (HAL_USART_Transmit_IT(),
HAL_USART_Receive_IT() and HAL_USART_TransmitReceive_IT() APIs):
(+++) Configure the USARTx interrupt priority.
(+++) Enable the NVIC USART IRQ handle.
(##) DMA Configuration if you need to use DMA process (HAL_USART_Transmit_DMA()
HAL_USART_Receive_DMA() and HAL_USART_TransmitReceive_DMA() APIs):
(+++) Declare a DMA handle structure for the Tx/Rx channel.
(+++) Enable the DMAx interface clock.
(+++) Configure the declared DMA handle structure with the required Tx/Rx parameters.
(+++) Configure the DMA Tx/Rx channel.
(+++) Associate the initialized DMA handle to the USART DMA Tx/Rx handle.
(+++) Configure the priority and enable the NVIC for the transfer complete interrupt on the DMA Tx/Rx channel.
(+++) Configure the USARTx interrupt priority and enable the NVIC USART IRQ handle
(used for last byte sending completion detection in DMA non circular mode)
(#) Program the Baud Rate, Word Length, Stop Bit, Parity, Hardware
flow control and Mode(Receiver/Transmitter) in the husart Init structure.
(#) Initialize the USART registers by calling the HAL_USART_Init() API:
(++) These APIs configures also the low level Hardware GPIO, CLOCK, CORTEX...etc)
by calling the customized HAL_USART_MspInit(&husart) API.
-@@- The specific USART interrupts (Transmission complete interrupt,
RXNE interrupt and Error Interrupts) will be managed using the macros
__HAL_USART_ENABLE_IT() and __HAL_USART_DISABLE_IT() inside the transmit and receive process.
(#) Three operation modes are available within this driver :
*** Polling mode IO operation ***
=================================
[..]
(+) Send an amount of data in blocking mode using HAL_USART_Transmit()
(+) Receive an amount of data in blocking mode using HAL_USART_Receive()
*** Interrupt mode IO operation ***
===================================
[..]
(+) Send an amount of data in non blocking mode using HAL_USART_Transmit_IT()
(+) At transmission end of transfer HAL_USART_TxHalfCpltCallback is executed and user can
add his own code by customization of function pointer HAL_USART_TxCpltCallback
(+) Receive an amount of data in non blocking mode using HAL_USART_Receive_IT()
(+) At reception end of transfer HAL_USART_RxCpltCallback is executed and user can
add his own code by customization of function pointer HAL_USART_RxCpltCallback
(+) In case of transfer Error, HAL_USART_ErrorCallback() function is executed and user can
add his own code by customization of function pointer HAL_USART_ErrorCallback
*** DMA mode IO operation ***
==============================
[..]
(+) Send an amount of data in non blocking mode (DMA) using HAL_USART_Transmit_DMA()
(+) At transmission end of half transfer HAL_USART_TxHalfCpltCallback is executed and user can
add his own code by customization of function pointer HAL_USART_TxHalfCpltCallback
(+) At transmission end of transfer HAL_USART_TxCpltCallback is executed and user can
add his own code by customization of function pointer HAL_USART_TxCpltCallback
(+) Receive an amount of data in non blocking mode (DMA) using HAL_USART_Receive_DMA()
(+) At reception end of half transfer HAL_USART_RxHalfCpltCallback is executed and user can
add his own code by customization of function pointer HAL_USART_RxHalfCpltCallback
(+) At reception end of transfer HAL_USART_RxCpltCallback is executed and user can
add his own code by customization of function pointer HAL_USART_RxCpltCallback
(+) In case of transfer Error, HAL_USART_ErrorCallback() function is executed and user can
add his own code by customization of function pointer HAL_USART_ErrorCallback
(+) Pause the DMA Transfer using HAL_USART_DMAPause()
(+) Resume the DMA Transfer using HAL_USART_DMAResume()
(+) Stop the DMA Transfer using HAL_USART_DMAStop()
*** USART HAL driver macros list ***
=============================================
[..]
Below the list of most used macros in USART HAL driver.
(+) __HAL_USART_ENABLE: Enable the USART peripheral
(+) __HAL_USART_DISABLE: Disable the USART peripheral
(+) __HAL_USART_GET_FLAG : Check whether the specified USART flag is set or not
(+) __HAL_USART_CLEAR_FLAG : Clear the specified USART pending flag
(+) __HAL_USART_ENABLE_IT: Enable the specified USART interrupt
(+) __HAL_USART_DISABLE_IT: Disable the specified USART interrupt
[..]
(@) You can refer to the USART HAL driver header file for more useful macros
##### Callback registration #####
==================================
[..]
The compilation define USE_HAL_USART_REGISTER_CALLBACKS when set to 1
allows the user to configure dynamically the driver callbacks.
[..]
Use Function @ref HAL_USART_RegisterCallback() to register a user callback.
Function @ref HAL_USART_RegisterCallback() allows to register following callbacks:
(+) TxHalfCpltCallback : Tx Half Complete Callback.
(+) TxCpltCallback : Tx Complete Callback.
(+) RxHalfCpltCallback : Rx Half Complete Callback.
(+) RxCpltCallback : Rx Complete Callback.
(+) TxRxCpltCallback : Tx Rx Complete Callback.
(+) ErrorCallback : Error Callback.
(+) AbortCpltCallback : Abort Complete Callback.
(+) MspInitCallback : USART MspInit.
(+) MspDeInitCallback : USART MspDeInit.
This function takes as parameters the HAL peripheral handle, the Callback ID
and a pointer to the user callback function.
[..]
Use function @ref HAL_USART_UnRegisterCallback() to reset a callback to the default
weak (surcharged) function.
@ref HAL_USART_UnRegisterCallback() takes as parameters the HAL peripheral handle,
and the Callback ID.
This function allows to reset following callbacks:
(+) TxHalfCpltCallback : Tx Half Complete Callback.
(+) TxCpltCallback : Tx Complete Callback.
(+) RxHalfCpltCallback : Rx Half Complete Callback.
(+) RxCpltCallback : Rx Complete Callback.
(+) TxRxCpltCallback : Tx Rx Complete Callback.
(+) ErrorCallback : Error Callback.
(+) AbortCpltCallback : Abort Complete Callback.
(+) MspInitCallback : USART MspInit.
(+) MspDeInitCallback : USART MspDeInit.
[..]
By default, after the @ref HAL_USART_Init() and when the state is HAL_USART_STATE_RESET
all callbacks are set to the corresponding weak (surcharged) functions:
examples @ref HAL_USART_TxCpltCallback(), @ref HAL_USART_RxHalfCpltCallback().
Exception done for MspInit and MspDeInit functions that are respectively
reset to the legacy weak (surcharged) functions in the @ref HAL_USART_Init()
and @ref HAL_USART_DeInit() only when these callbacks are null (not registered beforehand).
If not, MspInit or MspDeInit are not null, the @ref HAL_USART_Init() and @ref HAL_USART_DeInit()
keep and use the user MspInit/MspDeInit callbacks (registered beforehand).
[..]
Callbacks can be registered/unregistered in HAL_USART_STATE_READY state only.
Exception done MspInit/MspDeInit that can be registered/unregistered
in HAL_USART_STATE_READY or HAL_USART_STATE_RESET state, thus registered (user)
MspInit/DeInit callbacks can be used during the Init/DeInit.
In that case first register the MspInit/MspDeInit user callbacks
using @ref HAL_USART_RegisterCallback() before calling @ref HAL_USART_DeInit()
or @ref HAL_USART_Init() function.
[..]
When The compilation define USE_HAL_USART_REGISTER_CALLBACKS is set to 0 or
not defined, the callback registration feature is not available
and weak (surcharged) callbacks are used.
@endverbatim
[..]
(@) Additional remark: If the parity is enabled, then the MSB bit of the data written
in the data register is transmitted but is changed by the parity bit.
Depending on the frame length defined by the M bit (8-bits or 9-bits),
the possible USART frame formats are as listed in the following table:
+-------------------------------------------------------------+
| M bit | PCE bit | USART frame |
|---------------------|---------------------------------------|
| 0 | 0 | | SB | 8 bit data | STB | |
|---------|-----------|---------------------------------------|
| 0 | 1 | | SB | 7 bit data | PB | STB | |
|---------|-----------|---------------------------------------|
| 1 | 0 | | SB | 9 bit data | STB | |
|---------|-----------|---------------------------------------|
| 1 | 1 | | SB | 8 bit data | PB | STB | |
+-------------------------------------------------------------+
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
/** @defgroup USART USART
* @brief HAL USART Synchronous module driver
* @{
*/
#ifdef HAL_USART_MODULE_ENABLED
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/** @addtogroup USART_Private_Constants
* @{
*/
#define DUMMY_DATA 0xFFFFU
#define USART_TIMEOUT_VALUE 22000U
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/** @addtogroup USART_Private_Functions
* @{
*/
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
void USART_InitCallbacksToDefault(USART_HandleTypeDef *husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
static void USART_EndTxTransfer(USART_HandleTypeDef *husart);
static void USART_EndRxTransfer(USART_HandleTypeDef *husart);
static HAL_StatusTypeDef USART_Transmit_IT(USART_HandleTypeDef *husart);
static HAL_StatusTypeDef USART_EndTransmit_IT(USART_HandleTypeDef *husart);
static HAL_StatusTypeDef USART_Receive_IT(USART_HandleTypeDef *husart);
static HAL_StatusTypeDef USART_TransmitReceive_IT(USART_HandleTypeDef *husart);
static void USART_SetConfig(USART_HandleTypeDef *husart);
static void USART_DMATransmitCplt(DMA_HandleTypeDef *hdma);
static void USART_DMATxHalfCplt(DMA_HandleTypeDef *hdma);
static void USART_DMAReceiveCplt(DMA_HandleTypeDef *hdma);
static void USART_DMARxHalfCplt(DMA_HandleTypeDef *hdma);
static void USART_DMAError(DMA_HandleTypeDef *hdma);
static void USART_DMAAbortOnError(DMA_HandleTypeDef *hdma);
static void USART_DMATxAbortCallback(DMA_HandleTypeDef *hdma);
static void USART_DMARxAbortCallback(DMA_HandleTypeDef *hdma);
static HAL_StatusTypeDef USART_WaitOnFlagUntilTimeout(USART_HandleTypeDef *husart, uint32_t Flag, FlagStatus Status,
uint32_t Tickstart, uint32_t Timeout);
/**
* @}
*/
/* Exported functions --------------------------------------------------------*/
/** @defgroup USART_Exported_Functions USART Exported Functions
* @{
*/
/** @defgroup USART_Exported_Functions_Group1 USART Initialization and de-initialization functions
* @brief Initialization and Configuration functions
*
@verbatim
==============================================================================
##### Initialization and Configuration functions #####
==============================================================================
[..]
This subsection provides a set of functions allowing to initialize the USART
in asynchronous and in synchronous modes.
(+) For the asynchronous mode only these parameters can be configured:
(++) Baud Rate
(++) Word Length
(++) Stop Bit
(++) Parity: If the parity is enabled, then the MSB bit of the data written
in the data register is transmitted but is changed by the parity bit.
Depending on the frame length defined by the M bit (8-bits or 9-bits),
please refer to Reference manual for possible USART frame formats.
(++) USART polarity
(++) USART phase
(++) USART LastBit
(++) Receiver/transmitter modes
[..]
The HAL_USART_Init() function follows the USART synchronous configuration
procedures (details for the procedures are available in reference manuals
(RM0008 for STM32F10Xxx MCUs and RM0041 for STM32F100xx MCUs)).
@endverbatim
* @{
*/
/**
* @brief Initialize the USART mode according to the specified
* parameters in the USART_InitTypeDef and initialize the associated handle.
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_USART_Init(USART_HandleTypeDef *husart)
{
/* Check the USART handle allocation */
if (husart == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_USART_INSTANCE(husart->Instance));
if (husart->State == HAL_USART_STATE_RESET)
{
/* Allocate lock resource and initialize it */
husart->Lock = HAL_UNLOCKED;
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
USART_InitCallbacksToDefault(husart);
if (husart->MspInitCallback == NULL)
{
husart->MspInitCallback = HAL_USART_MspInit;
}
/* Init the low level hardware */
husart->MspInitCallback(husart);
#else
/* Init the low level hardware : GPIO, CLOCK */
HAL_USART_MspInit(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
}
husart->State = HAL_USART_STATE_BUSY;
/* Set the USART Communication parameters */
USART_SetConfig(husart);
/* In USART mode, the following bits must be kept cleared:
- LINEN bit in the USART_CR2 register
- HDSEL, SCEN and IREN bits in the USART_CR3 register */
CLEAR_BIT(husart->Instance->CR2, USART_CR2_LINEN);
CLEAR_BIT(husart->Instance->CR3, (USART_CR3_SCEN | USART_CR3_HDSEL | USART_CR3_IREN));
/* Enable the Peripheral */
__HAL_USART_ENABLE(husart);
/* Initialize the USART state */
husart->ErrorCode = HAL_USART_ERROR_NONE;
husart->State = HAL_USART_STATE_READY;
return HAL_OK;
}
/**
* @brief DeInitializes the USART peripheral.
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_USART_DeInit(USART_HandleTypeDef *husart)
{
/* Check the USART handle allocation */
if (husart == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_USART_INSTANCE(husart->Instance));
husart->State = HAL_USART_STATE_BUSY;
/* Disable the Peripheral */
__HAL_USART_DISABLE(husart);
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
if (husart->MspDeInitCallback == NULL)
{
husart->MspDeInitCallback = HAL_USART_MspDeInit;
}
/* DeInit the low level hardware */
husart->MspDeInitCallback(husart);
#else
/* DeInit the low level hardware */
HAL_USART_MspDeInit(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
husart->ErrorCode = HAL_USART_ERROR_NONE;
husart->State = HAL_USART_STATE_RESET;
/* Release Lock */
__HAL_UNLOCK(husart);
return HAL_OK;
}
/**
* @brief USART MSP Init.
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @retval None
*/
__weak void HAL_USART_MspInit(USART_HandleTypeDef *husart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(husart);
/* NOTE: This function should not be modified, when the callback is needed,
the HAL_USART_MspInit could be implemented in the user file
*/
}
/**
* @brief USART MSP DeInit.
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @retval None
*/
__weak void HAL_USART_MspDeInit(USART_HandleTypeDef *husart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(husart);
/* NOTE: This function should not be modified, when the callback is needed,
the HAL_USART_MspDeInit could be implemented in the user file
*/
}
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
/**
* @brief Register a User USART Callback
* To be used instead of the weak predefined callback
* @note The HAL_USART_RegisterCallback() may be called before HAL_USART_Init() in HAL_USART_STATE_RESET
* to register callbacks for HAL_USART_MSPINIT_CB_ID and HAL_USART_MSPDEINIT_CB_ID
* @param husart usart handle
* @param CallbackID ID of the callback to be registered
* This parameter can be one of the following values:
* @arg @ref HAL_USART_TX_HALFCOMPLETE_CB_ID Tx Half Complete Callback ID
* @arg @ref HAL_USART_TX_COMPLETE_CB_ID Tx Complete Callback ID
* @arg @ref HAL_USART_RX_HALFCOMPLETE_CB_ID Rx Half Complete Callback ID
* @arg @ref HAL_USART_RX_COMPLETE_CB_ID Rx Complete Callback ID
* @arg @ref HAL_USART_TX_RX_COMPLETE_CB_ID Rx Complete Callback ID
* @arg @ref HAL_USART_ERROR_CB_ID Error Callback ID
* @arg @ref HAL_USART_ABORT_COMPLETE_CB_ID Abort Complete Callback ID
* @arg @ref HAL_USART_MSPINIT_CB_ID MspInit Callback ID
* @arg @ref HAL_USART_MSPDEINIT_CB_ID MspDeInit Callback ID
* @param pCallback pointer to the Callback function
* @retval HAL status
+ */
HAL_StatusTypeDef HAL_USART_RegisterCallback(USART_HandleTypeDef *husart, HAL_USART_CallbackIDTypeDef CallbackID,
pUSART_CallbackTypeDef pCallback)
{
HAL_StatusTypeDef status = HAL_OK;
if (pCallback == NULL)
{
/* Update the error code */
husart->ErrorCode |= HAL_USART_ERROR_INVALID_CALLBACK;
return HAL_ERROR;
}
if (husart->State == HAL_USART_STATE_READY)
{
switch (CallbackID)
{
case HAL_USART_TX_HALFCOMPLETE_CB_ID :
husart->TxHalfCpltCallback = pCallback;
break;
case HAL_USART_TX_COMPLETE_CB_ID :
husart->TxCpltCallback = pCallback;
break;
case HAL_USART_RX_HALFCOMPLETE_CB_ID :
husart->RxHalfCpltCallback = pCallback;
break;
case HAL_USART_RX_COMPLETE_CB_ID :
husart->RxCpltCallback = pCallback;
break;
case HAL_USART_TX_RX_COMPLETE_CB_ID :
husart->TxRxCpltCallback = pCallback;
break;
case HAL_USART_ERROR_CB_ID :
husart->ErrorCallback = pCallback;
break;
case HAL_USART_ABORT_COMPLETE_CB_ID :
husart->AbortCpltCallback = pCallback;
break;
case HAL_USART_MSPINIT_CB_ID :
husart->MspInitCallback = pCallback;
break;
case HAL_USART_MSPDEINIT_CB_ID :
husart->MspDeInitCallback = pCallback;
break;
default :
/* Update the error code */
husart->ErrorCode |= HAL_USART_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else if (husart->State == HAL_USART_STATE_RESET)
{
switch (CallbackID)
{
case HAL_USART_MSPINIT_CB_ID :
husart->MspInitCallback = pCallback;
break;
case HAL_USART_MSPDEINIT_CB_ID :
husart->MspDeInitCallback = pCallback;
break;
default :
/* Update the error code */
husart->ErrorCode |= HAL_USART_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else
{
/* Update the error code */
husart->ErrorCode |= HAL_USART_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
}
return status;
}
/**
* @brief Unregister an USART Callback
* USART callaback is redirected to the weak predefined callback
* @note The HAL_USART_UnRegisterCallback() may be called before HAL_USART_Init() in HAL_USART_STATE_RESET
* to un-register callbacks for HAL_USART_MSPINIT_CB_ID and HAL_USART_MSPDEINIT_CB_ID
* @param husart usart handle
* @param CallbackID ID of the callback to be unregistered
* This parameter can be one of the following values:
* @arg @ref HAL_USART_TX_HALFCOMPLETE_CB_ID Tx Half Complete Callback ID
* @arg @ref HAL_USART_TX_COMPLETE_CB_ID Tx Complete Callback ID
* @arg @ref HAL_USART_RX_HALFCOMPLETE_CB_ID Rx Half Complete Callback ID
* @arg @ref HAL_USART_RX_COMPLETE_CB_ID Rx Complete Callback ID
* @arg @ref HAL_USART_TX_RX_COMPLETE_CB_ID Rx Complete Callback ID
* @arg @ref HAL_USART_ERROR_CB_ID Error Callback ID
* @arg @ref HAL_USART_ABORT_COMPLETE_CB_ID Abort Complete Callback ID
* @arg @ref HAL_USART_MSPINIT_CB_ID MspInit Callback ID
* @arg @ref HAL_USART_MSPDEINIT_CB_ID MspDeInit Callback ID
* @retval HAL status
*/
HAL_StatusTypeDef HAL_USART_UnRegisterCallback(USART_HandleTypeDef *husart, HAL_USART_CallbackIDTypeDef CallbackID)
{
HAL_StatusTypeDef status = HAL_OK;
if (husart->State == HAL_USART_STATE_READY)
{
switch (CallbackID)
{
case HAL_USART_TX_HALFCOMPLETE_CB_ID :
husart->TxHalfCpltCallback = HAL_USART_TxHalfCpltCallback; /* Legacy weak TxHalfCpltCallback */
break;
case HAL_USART_TX_COMPLETE_CB_ID :
husart->TxCpltCallback = HAL_USART_TxCpltCallback; /* Legacy weak TxCpltCallback */
break;
case HAL_USART_RX_HALFCOMPLETE_CB_ID :
husart->RxHalfCpltCallback = HAL_USART_RxHalfCpltCallback; /* Legacy weak RxHalfCpltCallback */
break;
case HAL_USART_RX_COMPLETE_CB_ID :
husart->RxCpltCallback = HAL_USART_RxCpltCallback; /* Legacy weak RxCpltCallback */
break;
case HAL_USART_TX_RX_COMPLETE_CB_ID :
husart->TxRxCpltCallback = HAL_USART_TxRxCpltCallback; /* Legacy weak TxRxCpltCallback */
break;
case HAL_USART_ERROR_CB_ID :
husart->ErrorCallback = HAL_USART_ErrorCallback; /* Legacy weak ErrorCallback */
break;
case HAL_USART_ABORT_COMPLETE_CB_ID :
husart->AbortCpltCallback = HAL_USART_AbortCpltCallback; /* Legacy weak AbortCpltCallback */
break;
case HAL_USART_MSPINIT_CB_ID :
husart->MspInitCallback = HAL_USART_MspInit; /* Legacy weak MspInitCallback */
break;
case HAL_USART_MSPDEINIT_CB_ID :
husart->MspDeInitCallback = HAL_USART_MspDeInit; /* Legacy weak MspDeInitCallback */
break;
default :
/* Update the error code */
husart->ErrorCode |= HAL_USART_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else if (husart->State == HAL_USART_STATE_RESET)
{
switch (CallbackID)
{
case HAL_USART_MSPINIT_CB_ID :
husart->MspInitCallback = HAL_USART_MspInit;
break;
case HAL_USART_MSPDEINIT_CB_ID :
husart->MspDeInitCallback = HAL_USART_MspDeInit;
break;
default :
/* Update the error code */
husart->ErrorCode |= HAL_USART_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else
{
/* Update the error code */
husart->ErrorCode |= HAL_USART_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
}
return status;
}
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
/**
* @}
*/
/** @defgroup USART_Exported_Functions_Group2 IO operation functions
* @brief USART Transmit and Receive functions
*
@verbatim
==============================================================================
##### IO operation functions #####
==============================================================================
[..]
This subsection provides a set of functions allowing to manage the USART synchronous
data transfers.
[..]
The USART supports master mode only: it cannot receive or send data related to an input
clock (SCLK is always an output).
(#) There are two modes of transfer:
(++) Blocking mode: The communication is performed in polling mode.
The HAL status of all data processing is returned by the same function
after finishing transfer.
(++) No-Blocking mode: The communication is performed using Interrupts
or DMA, These API's return the HAL status.
The end of the data processing will be indicated through the
dedicated USART IRQ when using Interrupt mode or the DMA IRQ when
using DMA mode.
The HAL_USART_TxCpltCallback(), HAL_USART_RxCpltCallback() and HAL_USART_TxRxCpltCallback()
user callbacks
will be executed respectively at the end of the transmit or Receive process
The HAL_USART_ErrorCallback() user callback will be executed when a communication
error is detected
(#) Blocking mode APIs are :
(++) HAL_USART_Transmit() in simplex mode
(++) HAL_USART_Receive() in full duplex receive only
(++) HAL_USART_TransmitReceive() in full duplex mode
(#) Non Blocking mode APIs with Interrupt are :
(++) HAL_USART_Transmit_IT()in simplex mode
(++) HAL_USART_Receive_IT() in full duplex receive only
(++) HAL_USART_TransmitReceive_IT() in full duplex mode
(++) HAL_USART_IRQHandler()
(#) Non Blocking mode functions with DMA are :
(++) HAL_USART_Transmit_DMA()in simplex mode
(++) HAL_USART_Receive_DMA() in full duplex receive only
(++) HAL_USART_TransmitReceive_DMA() in full duplex mode
(++) HAL_USART_DMAPause()
(++) HAL_USART_DMAResume()
(++) HAL_USART_DMAStop()
(#) A set of Transfer Complete Callbacks are provided in non Blocking mode:
(++) HAL_USART_TxHalfCpltCallback()
(++) HAL_USART_TxCpltCallback()
(++) HAL_USART_RxHalfCpltCallback()
(++) HAL_USART_RxCpltCallback()
(++) HAL_USART_ErrorCallback()
(++) HAL_USART_TxRxCpltCallback()
(#) Non-Blocking mode transfers could be aborted using Abort API's :
(++) HAL_USART_Abort()
(++) HAL_USART_Abort_IT()
(#) For Abort services based on interrupts (HAL_USART_Abort_IT), a Abort Complete Callbacks is provided:
(++) HAL_USART_AbortCpltCallback()
(#) In Non-Blocking mode transfers, possible errors are split into 2 categories.
Errors are handled as follows :
(++) Error is considered as Recoverable and non blocking : Transfer could go till end, but error severity is
to be evaluated by user : this concerns Frame Error, Parity Error or Noise Error in Interrupt mode reception .
Received character is then retrieved and stored in Rx buffer, Error code is set to allow user to identify error type,
and HAL_USART_ErrorCallback() user callback is executed. Transfer is kept ongoing on USART side.
If user wants to abort it, Abort services should be called by user.
(++) Error is considered as Blocking : Transfer could not be completed properly and is aborted.
This concerns Overrun Error In Interrupt mode reception and all errors in DMA mode.
Error code is set to allow user to identify error type, and HAL_USART_ErrorCallback() user callback is executed.
@endverbatim
* @{
*/
/**
* @brief Simplex Send an amount of data in blocking mode.
* @note When USART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the sent data is handled as a set of u16. In this case, Size must indicate the number
* of u16 provided through pTxData.
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @param pTxData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be sent.
* @param Timeout Timeout duration.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_USART_Transmit(USART_HandleTypeDef *husart, const uint8_t *pTxData, uint16_t Size, uint32_t Timeout)
{
const uint8_t *ptxdata8bits;
const uint16_t *ptxdata16bits;
uint32_t tickstart;
if (husart->State == HAL_USART_STATE_READY)
{
if ((pTxData == NULL) || (Size == 0))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(husart);
husart->ErrorCode = HAL_USART_ERROR_NONE;
husart->State = HAL_USART_STATE_BUSY_TX;
/* Init tickstart for timeout management */
tickstart = HAL_GetTick();
husart->TxXferSize = Size;
husart->TxXferCount = Size;
/* In case of 9bits/No Parity transfer, pTxData needs to be handled as a uint16_t pointer */
if ((husart->Init.WordLength == USART_WORDLENGTH_9B) && (husart->Init.Parity == USART_PARITY_NONE))
{
ptxdata8bits = NULL;
ptxdata16bits = (const uint16_t *) pTxData;
}
else
{
ptxdata8bits = pTxData;
ptxdata16bits = NULL;
}
while (husart->TxXferCount > 0U)
{
/* Wait for TXE flag in order to write data in DR */
if (USART_WaitOnFlagUntilTimeout(husart, USART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK)
{
return HAL_TIMEOUT;
}
if (ptxdata8bits == NULL)
{
husart->Instance->DR = (uint16_t)(*ptxdata16bits & (uint16_t)0x01FF);
ptxdata16bits++;
}
else
{
husart->Instance->DR = (uint8_t)(*ptxdata8bits & (uint8_t)0xFF);
ptxdata8bits++;
}
husart->TxXferCount--;
}
if (USART_WaitOnFlagUntilTimeout(husart, USART_FLAG_TC, RESET, tickstart, Timeout) != HAL_OK)
{
return HAL_TIMEOUT;
}
husart->State = HAL_USART_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(husart);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Full-Duplex Receive an amount of data in blocking mode.
* @note To receive synchronous data, dummy data are simultaneously transmitted.
* @note When USART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the received data is handled as a set of u16. In this case, Size must indicate the number
* of u16 available through pRxData.
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @param pRxData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be received.
* @param Timeout Timeout duration.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_USART_Receive(USART_HandleTypeDef *husart, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)
{
uint8_t *prxdata8bits;
uint16_t *prxdata16bits;
uint32_t tickstart;
if (husart->State == HAL_USART_STATE_READY)
{
if ((pRxData == NULL) || (Size == 0))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(husart);
husart->ErrorCode = HAL_USART_ERROR_NONE;
husart->State = HAL_USART_STATE_BUSY_RX;
/* Init tickstart for timeout management */
tickstart = HAL_GetTick();
husart->RxXferSize = Size;
husart->RxXferCount = Size;
/* In case of 9bits/No Parity transfer, pRxData needs to be handled as a uint16_t pointer */
if ((husart->Init.WordLength == USART_WORDLENGTH_9B) && (husart->Init.Parity == USART_PARITY_NONE))
{
prxdata8bits = NULL;
prxdata16bits = (uint16_t *) pRxData;
}
else
{
prxdata8bits = pRxData;
prxdata16bits = NULL;
}
/* Check the remain data to be received */
while (husart->RxXferCount > 0U)
{
/* Wait until TXE flag is set to send dummy byte in order to generate the
* clock for the slave to send data.
* Whatever the frame length (7, 8 or 9-bit long), the same dummy value
* can be written for all the cases. */
if (USART_WaitOnFlagUntilTimeout(husart, USART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK)
{
return HAL_TIMEOUT;
}
husart->Instance->DR = (DUMMY_DATA & (uint16_t)0x0FF);
/* Wait until RXNE flag is set to receive the byte */
if (USART_WaitOnFlagUntilTimeout(husart, USART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
{
return HAL_TIMEOUT;
}
if (prxdata8bits == NULL)
{
*prxdata16bits = (uint16_t)(husart->Instance->DR & (uint16_t)0x01FF);
prxdata16bits++;
}
else
{
if ((husart->Init.WordLength == USART_WORDLENGTH_9B) || ((husart->Init.WordLength == USART_WORDLENGTH_8B) && (husart->Init.Parity == USART_PARITY_NONE)))
{
*prxdata8bits = (uint8_t)(husart->Instance->DR & (uint8_t)0x0FF);
}
else
{
*prxdata8bits = (uint8_t)(husart->Instance->DR & (uint8_t)0x07F);
}
prxdata8bits++;
}
husart->RxXferCount--;
}
husart->State = HAL_USART_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(husart);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Full-Duplex Send and Receive an amount of data in full-duplex mode (blocking mode).
* @note When USART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the sent data and the received data are handled as sets of u16. In this case, Size must indicate the number
* of u16 available through pTxData and through pRxData.
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @param pTxData Pointer to TX data buffer (u8 or u16 data elements).
* @param pRxData Pointer to RX data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be sent (same amount to be received).
* @param Timeout Timeout duration
* @retval HAL status
*/
HAL_StatusTypeDef HAL_USART_TransmitReceive(USART_HandleTypeDef *husart, const uint8_t *pTxData, uint8_t *pRxData,
uint16_t Size, uint32_t Timeout)
{
uint8_t *prxdata8bits;
uint16_t *prxdata16bits;
const uint8_t *ptxdata8bits;
const uint16_t *ptxdata16bits;
uint16_t rxdatacount;
uint32_t tickstart;
if (husart->State == HAL_USART_STATE_READY)
{
if ((pTxData == NULL) || (pRxData == NULL) || (Size == 0))
{
return HAL_ERROR;
}
/* In case of 9bits/No Parity transfer, pTxData and pRxData buffers provided as input parameter
should be aligned on a u16 frontier, as data to be filled into TDR/retrieved from RDR will be
handled through a u16 cast. */
if ((husart->Init.WordLength == USART_WORDLENGTH_9B) && (husart->Init.Parity == USART_PARITY_NONE))
{
if (((((uint32_t)pTxData) & 1U) != 0U) || ((((uint32_t)pRxData) & 1U) != 0U))
{
return HAL_ERROR;
}
}
/* Process Locked */
__HAL_LOCK(husart);
husart->ErrorCode = HAL_USART_ERROR_NONE;
husart->State = HAL_USART_STATE_BUSY_RX;
/* Init tickstart for timeout management */
tickstart = HAL_GetTick();
husart->RxXferSize = Size;
husart->TxXferSize = Size;
husart->TxXferCount = Size;
husart->RxXferCount = Size;
/* In case of 9bits/No Parity transfer, pRxData needs to be handled as a uint16_t pointer */
if ((husart->Init.WordLength == USART_WORDLENGTH_9B) && (husart->Init.Parity == USART_PARITY_NONE))
{
prxdata8bits = NULL;
ptxdata8bits = NULL;
ptxdata16bits = (const uint16_t *) pTxData;
prxdata16bits = (uint16_t *) pRxData;
}
else
{
prxdata8bits = pRxData;
ptxdata8bits = pTxData;
ptxdata16bits = NULL;
prxdata16bits = NULL;
}
/* Check the remain data to be received */
/* rxdatacount is a temporary variable for MISRAC2012-Rule-13.5 */
rxdatacount = husart->RxXferCount;
while ((husart->TxXferCount > 0U) || (rxdatacount > 0U))
{
if (husart->TxXferCount > 0U)
{
/* Wait for TXE flag in order to write data in DR */
if (USART_WaitOnFlagUntilTimeout(husart, USART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK)
{
return HAL_TIMEOUT;
}
if (ptxdata8bits == NULL)
{
husart->Instance->DR = (uint16_t)(*ptxdata16bits & (uint16_t)0x01FF);
ptxdata16bits++;
}
else
{
husart->Instance->DR = (uint8_t)(*ptxdata8bits & (uint8_t)0xFF);
ptxdata8bits++;
}
husart->TxXferCount--;
}
if (husart->RxXferCount > 0U)
{
/* Wait for RXNE Flag */
if (USART_WaitOnFlagUntilTimeout(husart, USART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
{
return HAL_TIMEOUT;
}
if (prxdata8bits == NULL)
{
*prxdata16bits = (uint16_t)(husart->Instance->DR & (uint16_t)0x01FF);
prxdata16bits++;
}
else
{
if ((husart->Init.WordLength == USART_WORDLENGTH_9B) || ((husart->Init.WordLength == USART_WORDLENGTH_8B) && (husart->Init.Parity == USART_PARITY_NONE)))
{
*prxdata8bits = (uint8_t)(husart->Instance->DR & (uint8_t)0x0FF);
}
else
{
*prxdata8bits = (uint8_t)(husart->Instance->DR & (uint8_t)0x07F);
}
prxdata8bits++;
}
husart->RxXferCount--;
}
rxdatacount = husart->RxXferCount;
}
husart->State = HAL_USART_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(husart);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Simplex Send an amount of data in non-blocking mode.
* @note When USART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the sent data is handled as a set of u16. In this case, Size must indicate the number
* of u16 provided through pTxData.
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @param pTxData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be sent.
* @retval HAL status
* @note The USART errors are not managed to avoid the overrun error.
*/
HAL_StatusTypeDef HAL_USART_Transmit_IT(USART_HandleTypeDef *husart, const uint8_t *pTxData, uint16_t Size)
{
if (husart->State == HAL_USART_STATE_READY)
{
if ((pTxData == NULL) || (Size == 0))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(husart);
husart->pTxBuffPtr = pTxData;
husart->TxXferSize = Size;
husart->TxXferCount = Size;
husart->ErrorCode = HAL_USART_ERROR_NONE;
husart->State = HAL_USART_STATE_BUSY_TX;
/* The USART Error Interrupts: (Frame error, Noise error, Overrun error)
are not managed by the USART transmit process to avoid the overrun interrupt
when the USART mode is configured for transmit and receive "USART_MODE_TX_RX"
to benefit for the frame error and noise interrupts the USART mode should be
configured only for transmit "USART_MODE_TX"
The __HAL_USART_ENABLE_IT(husart, USART_IT_ERR) can be used to enable the Frame error,
Noise error interrupt */
/* Process Unlocked */
__HAL_UNLOCK(husart);
/* Enable the USART Transmit Data Register Empty Interrupt */
SET_BIT(husart->Instance->CR1, USART_CR1_TXEIE);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Simplex Receive an amount of data in non-blocking mode.
* @note To receive synchronous data, dummy data are simultaneously transmitted.
* @note When USART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the received data is handled as a set of u16. In this case, Size must indicate the number
* of u16 available through pRxData.
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @param pRxData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be received.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_USART_Receive_IT(USART_HandleTypeDef *husart, uint8_t *pRxData, uint16_t Size)
{
if (husart->State == HAL_USART_STATE_READY)
{
if ((pRxData == NULL) || (Size == 0))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(husart);
husart->pRxBuffPtr = pRxData;
husart->RxXferSize = Size;
husart->RxXferCount = Size;
husart->ErrorCode = HAL_USART_ERROR_NONE;
husart->State = HAL_USART_STATE_BUSY_RX;
/* Process Unlocked */
__HAL_UNLOCK(husart);
if (husart->Init.Parity != USART_PARITY_NONE)
{
/* Enable the USART Parity Error and Data Register not empty Interrupts */
SET_BIT(husart->Instance->CR1, USART_CR1_PEIE | USART_CR1_RXNEIE);
}
else
{
/* Enable the USART Data Register not empty Interrupts */
SET_BIT(husart->Instance->CR1, USART_CR1_RXNEIE);
}
/* Enable the USART Error Interrupt: (Frame error, noise error, overrun error) */
SET_BIT(husart->Instance->CR3, USART_CR3_EIE);
/* Send dummy byte in order to generate the clock for the slave to send data */
husart->Instance->DR = (DUMMY_DATA & (uint16_t)0x01FF);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Full-Duplex Send and Receive an amount of data in full-duplex mode (non-blocking).
* @note When USART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the sent data and the received data are handled as sets of u16. In this case, Size must indicate the number
* of u16 available through pTxData and through pRxData.
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @param pTxData Pointer to TX data buffer (u8 or u16 data elements).
* @param pRxData Pointer to RX data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be sent (same amount to be received).
* @retval HAL status
*/
HAL_StatusTypeDef HAL_USART_TransmitReceive_IT(USART_HandleTypeDef *husart, const uint8_t *pTxData, uint8_t *pRxData,
uint16_t Size)
{
if (husart->State == HAL_USART_STATE_READY)
{
if ((pTxData == NULL) || (pRxData == NULL) || (Size == 0))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(husart);
husart->pRxBuffPtr = pRxData;
husart->RxXferSize = Size;
husart->RxXferCount = Size;
husart->pTxBuffPtr = pTxData;
husart->TxXferSize = Size;
husart->TxXferCount = Size;
husart->ErrorCode = HAL_USART_ERROR_NONE;
husart->State = HAL_USART_STATE_BUSY_TX_RX;
/* Process Unlocked */
__HAL_UNLOCK(husart);
/* Enable the USART Data Register not empty Interrupt */
SET_BIT(husart->Instance->CR1, USART_CR1_RXNEIE);
if (husart->Init.Parity != USART_PARITY_NONE)
{
/* Enable the USART Parity Error Interrupt */
SET_BIT(husart->Instance->CR1, USART_CR1_PEIE);
}
/* Enable the USART Error Interrupt: (Frame error, noise error, overrun error) */
SET_BIT(husart->Instance->CR3, USART_CR3_EIE);
/* Enable the USART Transmit Data Register Empty Interrupt */
SET_BIT(husart->Instance->CR1, USART_CR1_TXEIE);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Simplex Send an amount of data in DMA mode.
* @note When USART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the sent data is handled as a set of u16. In this case, Size must indicate the number
* of u16 provided through pTxData.
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @param pTxData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be sent.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_USART_Transmit_DMA(USART_HandleTypeDef *husart, const uint8_t *pTxData, uint16_t Size)
{
const uint32_t *tmp;
if (husart->State == HAL_USART_STATE_READY)
{
if ((pTxData == NULL) || (Size == 0))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(husart);
husart->pTxBuffPtr = pTxData;
husart->TxXferSize = Size;
husart->TxXferCount = Size;
husart->ErrorCode = HAL_USART_ERROR_NONE;
husart->State = HAL_USART_STATE_BUSY_TX;
/* Set the USART DMA transfer complete callback */
husart->hdmatx->XferCpltCallback = USART_DMATransmitCplt;
/* Set the USART DMA Half transfer complete callback */
husart->hdmatx->XferHalfCpltCallback = USART_DMATxHalfCplt;
/* Set the DMA error callback */
husart->hdmatx->XferErrorCallback = USART_DMAError;
/* Set the DMA abort callback */
husart->hdmatx->XferAbortCallback = NULL;
/* Enable the USART transmit DMA channel */
tmp = (const uint32_t *)&pTxData;
HAL_DMA_Start_IT(husart->hdmatx, *(const uint32_t *)tmp, (uint32_t)&husart->Instance->DR, Size);
/* Clear the TC flag in the SR register by writing 0 to it */
__HAL_USART_CLEAR_FLAG(husart, USART_FLAG_TC);
/* Process Unlocked */
__HAL_UNLOCK(husart);
/* Enable the DMA transfer for transmit request by setting the DMAT bit
in the USART CR3 register */
SET_BIT(husart->Instance->CR3, USART_CR3_DMAT);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Full-Duplex Receive an amount of data in DMA mode.
* @note When USART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the received data is handled as a set of u16. In this case, Size must indicate the number
* of u16 available through pRxData.
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @param pRxData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be received.
* @retval HAL status
* @note The USART DMA transmit channel must be configured in order to generate the clock for the slave.
* @note When the USART parity is enabled (PCE = 1) the data received contain the parity bit.
*/
HAL_StatusTypeDef HAL_USART_Receive_DMA(USART_HandleTypeDef *husart, uint8_t *pRxData, uint16_t Size)
{
uint32_t *tmp;
if (husart->State == HAL_USART_STATE_READY)
{
if ((pRxData == NULL) || (Size == 0))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(husart);
husart->pRxBuffPtr = pRxData;
husart->RxXferSize = Size;
husart->pTxBuffPtr = pRxData;
husart->TxXferSize = Size;
husart->ErrorCode = HAL_USART_ERROR_NONE;
husart->State = HAL_USART_STATE_BUSY_RX;
/* Set the USART DMA Rx transfer complete callback */
husart->hdmarx->XferCpltCallback = USART_DMAReceiveCplt;
/* Set the USART DMA Half transfer complete callback */
husart->hdmarx->XferHalfCpltCallback = USART_DMARxHalfCplt;
/* Set the USART DMA Rx transfer error callback */
husart->hdmarx->XferErrorCallback = USART_DMAError;
/* Set the DMA abort callback */
husart->hdmarx->XferAbortCallback = NULL;
/* Set the USART Tx DMA transfer complete callback as NULL because the communication closing
is performed in DMA reception complete callback */
husart->hdmatx->XferHalfCpltCallback = NULL;
husart->hdmatx->XferCpltCallback = NULL;
/* Set the DMA error callback */
husart->hdmatx->XferErrorCallback = USART_DMAError;
/* Set the DMA AbortCpltCallback */
husart->hdmatx->XferAbortCallback = NULL;
/* Enable the USART receive DMA channel */
tmp = (uint32_t *)&pRxData;
HAL_DMA_Start_IT(husart->hdmarx, (uint32_t)&husart->Instance->DR, *(uint32_t *)tmp, Size);
/* Enable the USART transmit DMA channel: the transmit channel is used in order
to generate in the non-blocking mode the clock to the slave device,
this mode isn't a simplex receive mode but a full-duplex receive one */
HAL_DMA_Start_IT(husart->hdmatx, *(uint32_t *)tmp, (uint32_t)&husart->Instance->DR, Size);
/* Clear the Overrun flag just before enabling the DMA Rx request: mandatory for the second transfer */
__HAL_USART_CLEAR_OREFLAG(husart);
/* Process Unlocked */
__HAL_UNLOCK(husart);
if (husart->Init.Parity != USART_PARITY_NONE)
{
/* Enable the USART Parity Error Interrupt */
SET_BIT(husart->Instance->CR1, USART_CR1_PEIE);
}
/* Enable the USART Error Interrupt: (Frame error, noise error, overrun error) */
SET_BIT(husart->Instance->CR3, USART_CR3_EIE);
/* Enable the DMA transfer for the receiver request by setting the DMAR bit
in the USART CR3 register */
SET_BIT(husart->Instance->CR3, USART_CR3_DMAR);
/* Enable the DMA transfer for transmit request by setting the DMAT bit
in the USART CR3 register */
SET_BIT(husart->Instance->CR3, USART_CR3_DMAT);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Full-Duplex Transmit Receive an amount of data in DMA mode.
* @note When USART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the sent data and the received data are handled as sets of u16. In this case, Size must indicate the number
* of u16 available through pTxData and through pRxData.
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @param pTxData Pointer to TX data buffer (u8 or u16 data elements).
* @param pRxData Pointer to RX data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be received/sent.
* @note When the USART parity is enabled (PCE = 1) the data received contain the parity bit.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_USART_TransmitReceive_DMA(USART_HandleTypeDef *husart, const uint8_t *pTxData, uint8_t *pRxData,
uint16_t Size)
{
const uint32_t *tmp;
if (husart->State == HAL_USART_STATE_READY)
{
if ((pTxData == NULL) || (pRxData == NULL) || (Size == 0))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(husart);
husart->pRxBuffPtr = pRxData;
husart->RxXferSize = Size;
husart->pTxBuffPtr = pTxData;
husart->TxXferSize = Size;
husart->ErrorCode = HAL_USART_ERROR_NONE;
husart->State = HAL_USART_STATE_BUSY_TX_RX;
/* Set the USART DMA Rx transfer complete callback */
husart->hdmarx->XferCpltCallback = USART_DMAReceiveCplt;
/* Set the USART DMA Half transfer complete callback */
husart->hdmarx->XferHalfCpltCallback = USART_DMARxHalfCplt;
/* Set the USART DMA Tx transfer complete callback */
husart->hdmatx->XferCpltCallback = USART_DMATransmitCplt;
/* Set the USART DMA Half transfer complete callback */
husart->hdmatx->XferHalfCpltCallback = USART_DMATxHalfCplt;
/* Set the USART DMA Tx transfer error callback */
husart->hdmatx->XferErrorCallback = USART_DMAError;
/* Set the USART DMA Rx transfer error callback */
husart->hdmarx->XferErrorCallback = USART_DMAError;
/* Set the DMA abort callback */
husart->hdmarx->XferAbortCallback = NULL;
/* Enable the USART receive DMA channel */
tmp = (uint32_t *)&pRxData;
HAL_DMA_Start_IT(husart->hdmarx, (uint32_t)&husart->Instance->DR, *(const uint32_t *)tmp, Size);
/* Enable the USART transmit DMA channel */
tmp = (const uint32_t *)&pTxData;
HAL_DMA_Start_IT(husart->hdmatx, *(const uint32_t *)tmp, (uint32_t)&husart->Instance->DR, Size);
/* Clear the TC flag in the SR register by writing 0 to it */
__HAL_USART_CLEAR_FLAG(husart, USART_FLAG_TC);
/* Clear the Overrun flag: mandatory for the second transfer in circular mode */
__HAL_USART_CLEAR_OREFLAG(husart);
/* Process Unlocked */
__HAL_UNLOCK(husart);
if (husart->Init.Parity != USART_PARITY_NONE)
{
/* Enable the USART Parity Error Interrupt */
SET_BIT(husart->Instance->CR1, USART_CR1_PEIE);
}
/* Enable the USART Error Interrupt: (Frame error, noise error, overrun error) */
SET_BIT(husart->Instance->CR3, USART_CR3_EIE);
/* Enable the DMA transfer for the receiver request by setting the DMAR bit
in the USART CR3 register */
SET_BIT(husart->Instance->CR3, USART_CR3_DMAR);
/* Enable the DMA transfer for transmit request by setting the DMAT bit
in the USART CR3 register */
SET_BIT(husart->Instance->CR3, USART_CR3_DMAT);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Pauses the DMA Transfer.
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_USART_DMAPause(USART_HandleTypeDef *husart)
{
/* Process Locked */
__HAL_LOCK(husart);
/* Disable the USART DMA Tx request */
CLEAR_BIT(husart->Instance->CR3, USART_CR3_DMAT);
/* Process Unlocked */
__HAL_UNLOCK(husart);
return HAL_OK;
}
/**
* @brief Resumes the DMA Transfer.
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_USART_DMAResume(USART_HandleTypeDef *husart)
{
/* Process Locked */
__HAL_LOCK(husart);
/* Enable the USART DMA Tx request */
SET_BIT(husart->Instance->CR3, USART_CR3_DMAT);
/* Process Unlocked */
__HAL_UNLOCK(husart);
return HAL_OK;
}
/**
* @brief Stops the DMA Transfer.
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_USART_DMAStop(USART_HandleTypeDef *husart)
{
uint32_t dmarequest = 0x00U;
/* The Lock is not implemented on this API to allow the user application
to call the HAL USART API under callbacks HAL_USART_TxCpltCallback() / HAL_USART_RxCpltCallback():
when calling HAL_DMA_Abort() API the DMA TX/RX Transfer complete interrupt is generated
and the correspond call back is executed HAL_USART_TxCpltCallback() / HAL_USART_RxCpltCallback()
*/
/* Stop USART DMA Tx request if ongoing */
dmarequest = HAL_IS_BIT_SET(husart->Instance->CR3, USART_CR3_DMAT);
if ((husart->State == HAL_USART_STATE_BUSY_TX) && dmarequest)
{
USART_EndTxTransfer(husart);
/* Abort the USART DMA Tx channel */
if (husart->hdmatx != NULL)
{
HAL_DMA_Abort(husart->hdmatx);
}
/* Disable the USART Tx DMA request */
CLEAR_BIT(husart->Instance->CR3, USART_CR3_DMAT);
}
/* Stop USART DMA Rx request if ongoing */
dmarequest = HAL_IS_BIT_SET(husart->Instance->CR3, USART_CR3_DMAR);
if ((husart->State == HAL_USART_STATE_BUSY_RX) && dmarequest)
{
USART_EndRxTransfer(husart);
/* Abort the USART DMA Rx channel */
if (husart->hdmarx != NULL)
{
HAL_DMA_Abort(husart->hdmarx);
}
/* Disable the USART Rx DMA request */
CLEAR_BIT(husart->Instance->CR3, USART_CR3_DMAR);
}
return HAL_OK;
}
/**
* @brief Abort ongoing transfer (blocking mode).
* @param husart USART handle.
* @note This procedure could be used for aborting any ongoing transfer (either Tx or Rx,
* as described by TransferType parameter) started in Interrupt or DMA mode.
* This procedure performs following operations :
* - Disable PPP Interrupts (depending of transfer direction)
* - Disable the DMA transfer in the peripheral register (if enabled)
* - Abort DMA transfer by calling HAL_DMA_Abort (in case of transfer in DMA mode)
* - Set handle State to READY
* @note This procedure is executed in blocking mode : when exiting function, Abort is considered as completed.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_USART_Abort(USART_HandleTypeDef *husart)
{
/* Disable TXEIE, TCIE, RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
CLEAR_BIT(husart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE | USART_CR1_TXEIE | USART_CR1_TCIE));
CLEAR_BIT(husart->Instance->CR3, USART_CR3_EIE);
/* Disable the USART DMA Tx request if enabled */
if (HAL_IS_BIT_SET(husart->Instance->CR3, USART_CR3_DMAT))
{
CLEAR_BIT(husart->Instance->CR3, USART_CR3_DMAT);
/* Abort the USART DMA Tx channel : use blocking DMA Abort API (no callback) */
if (husart->hdmatx != NULL)
{
/* Set the USART DMA Abort callback to Null.
No call back execution at end of DMA abort procedure */
husart->hdmatx->XferAbortCallback = NULL;
HAL_DMA_Abort(husart->hdmatx);
}
}
/* Disable the USART DMA Rx request if enabled */
if (HAL_IS_BIT_SET(husart->Instance->CR3, USART_CR3_DMAR))
{
CLEAR_BIT(husart->Instance->CR3, USART_CR3_DMAR);
/* Abort the USART DMA Rx channel : use blocking DMA Abort API (no callback) */
if (husart->hdmarx != NULL)
{
/* Set the USART DMA Abort callback to Null.
No call back execution at end of DMA abort procedure */
husart->hdmarx->XferAbortCallback = NULL;
HAL_DMA_Abort(husart->hdmarx);
}
}
/* Reset Tx and Rx transfer counters */
husart->TxXferCount = 0x00U;
husart->RxXferCount = 0x00U;
/* Restore husart->State to Ready */
husart->State = HAL_USART_STATE_READY;
/* Reset Handle ErrorCode to No Error */
husart->ErrorCode = HAL_USART_ERROR_NONE;
return HAL_OK;
}
/**
* @brief Abort ongoing transfer (Interrupt mode).
* @param husart USART handle.
* @note This procedure could be used for aborting any ongoing transfer (either Tx or Rx,
* as described by TransferType parameter) started in Interrupt or DMA mode.
* This procedure performs following operations :
* - Disable PPP Interrupts (depending of transfer direction)
* - Disable the DMA transfer in the peripheral register (if enabled)
* - Abort DMA transfer by calling HAL_DMA_Abort_IT (in case of transfer in DMA mode)
* - Set handle State to READY
* - At abort completion, call user abort complete callback
* @note This procedure is executed in Interrupt mode, meaning that abort procedure could be
* considered as completed only when user abort complete callback is executed (not when exiting function).
* @retval HAL status
*/
HAL_StatusTypeDef HAL_USART_Abort_IT(USART_HandleTypeDef *husart)
{
uint32_t AbortCplt = 0x01U;
/* Disable TXEIE, TCIE, RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
CLEAR_BIT(husart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE | USART_CR1_TXEIE | USART_CR1_TCIE));
CLEAR_BIT(husart->Instance->CR3, USART_CR3_EIE);
/* If DMA Tx and/or DMA Rx Handles are associated to USART Handle, DMA Abort complete callbacks should be initialised
before any call to DMA Abort functions */
/* DMA Tx Handle is valid */
if (husart->hdmatx != NULL)
{
/* Set DMA Abort Complete callback if USART DMA Tx request if enabled.
Otherwise, set it to NULL */
if (HAL_IS_BIT_SET(husart->Instance->CR3, USART_CR3_DMAT))
{
husart->hdmatx->XferAbortCallback = USART_DMATxAbortCallback;
}
else
{
husart->hdmatx->XferAbortCallback = NULL;
}
}
/* DMA Rx Handle is valid */
if (husart->hdmarx != NULL)
{
/* Set DMA Abort Complete callback if USART DMA Rx request if enabled.
Otherwise, set it to NULL */
if (HAL_IS_BIT_SET(husart->Instance->CR3, USART_CR3_DMAR))
{
husart->hdmarx->XferAbortCallback = USART_DMARxAbortCallback;
}
else
{
husart->hdmarx->XferAbortCallback = NULL;
}
}
/* Disable the USART DMA Tx request if enabled */
if (HAL_IS_BIT_SET(husart->Instance->CR3, USART_CR3_DMAT))
{
/* Disable DMA Tx at USART level */
CLEAR_BIT(husart->Instance->CR3, USART_CR3_DMAT);
/* Abort the USART DMA Tx channel : use non blocking DMA Abort API (callback) */
if (husart->hdmatx != NULL)
{
/* USART Tx DMA Abort callback has already been initialised :
will lead to call HAL_USART_AbortCpltCallback() at end of DMA abort procedure */
/* Abort DMA TX */
if (HAL_DMA_Abort_IT(husart->hdmatx) != HAL_OK)
{
husart->hdmatx->XferAbortCallback = NULL;
}
else
{
AbortCplt = 0x00U;
}
}
}
/* Disable the USART DMA Rx request if enabled */
if (HAL_IS_BIT_SET(husart->Instance->CR3, USART_CR3_DMAR))
{
CLEAR_BIT(husart->Instance->CR3, USART_CR3_DMAR);
/* Abort the USART DMA Rx channel : use non blocking DMA Abort API (callback) */
if (husart->hdmarx != NULL)
{
/* USART Rx DMA Abort callback has already been initialised :
will lead to call HAL_USART_AbortCpltCallback() at end of DMA abort procedure */
/* Abort DMA RX */
if (HAL_DMA_Abort_IT(husart->hdmarx) != HAL_OK)
{
husart->hdmarx->XferAbortCallback = NULL;
AbortCplt = 0x01U;
}
else
{
AbortCplt = 0x00U;
}
}
}
/* if no DMA abort complete callback execution is required => call user Abort Complete callback */
if (AbortCplt == 0x01U)
{
/* Reset Tx and Rx transfer counters */
husart->TxXferCount = 0x00U;
husart->RxXferCount = 0x00U;
/* Reset errorCode */
husart->ErrorCode = HAL_USART_ERROR_NONE;
/* Restore husart->State to Ready */
husart->State = HAL_USART_STATE_READY;
/* As no DMA to be aborted, call directly user Abort complete callback */
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
/* Call registered Abort Complete Callback */
husart->AbortCpltCallback(husart);
#else
/* Call legacy weak Abort Complete Callback */
HAL_USART_AbortCpltCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
}
return HAL_OK;
}
/**
* @brief This function handles USART interrupt request.
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @retval None
*/
void HAL_USART_IRQHandler(USART_HandleTypeDef *husart)
{
uint32_t isrflags = READ_REG(husart->Instance->SR);
uint32_t cr1its = READ_REG(husart->Instance->CR1);
uint32_t cr3its = READ_REG(husart->Instance->CR3);
uint32_t errorflags = 0x00U;
uint32_t dmarequest = 0x00U;
/* If no error occurs */
errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
if (errorflags == RESET)
{
/* USART in mode Receiver -------------------------------------------------*/
if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
{
if (husart->State == HAL_USART_STATE_BUSY_RX)
{
USART_Receive_IT(husart);
}
else
{
USART_TransmitReceive_IT(husart);
}
return;
}
}
/* If some errors occur */
if ((errorflags != RESET) && (((cr3its & USART_CR3_EIE) != RESET) || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET)))
{
/* USART parity error interrupt occurred ----------------------------------*/
if (((isrflags & USART_SR_PE) != RESET) && ((cr1its & USART_CR1_PEIE) != RESET))
{
husart->ErrorCode |= HAL_USART_ERROR_PE;
}
/* USART noise error interrupt occurred --------------------------------*/
if (((isrflags & USART_SR_NE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
{
husart->ErrorCode |= HAL_USART_ERROR_NE;
}
/* USART frame error interrupt occurred --------------------------------*/
if (((isrflags & USART_SR_FE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
{
husart->ErrorCode |= HAL_USART_ERROR_FE;
}
/* USART Over-Run interrupt occurred -----------------------------------*/
if (((isrflags & USART_SR_ORE) != RESET) && (((cr1its & USART_CR1_RXNEIE) != RESET) || ((cr3its & USART_CR3_EIE) != RESET)))
{
husart->ErrorCode |= HAL_USART_ERROR_ORE;
}
if (husart->ErrorCode != HAL_USART_ERROR_NONE)
{
/* USART in mode Receiver -----------------------------------------------*/
if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
{
if (husart->State == HAL_USART_STATE_BUSY_RX)
{
USART_Receive_IT(husart);
}
else
{
USART_TransmitReceive_IT(husart);
}
}
/* If Overrun error occurs, or if any error occurs in DMA mode reception,
consider error as blocking */
dmarequest = HAL_IS_BIT_SET(husart->Instance->CR3, USART_CR3_DMAR);
if (((husart->ErrorCode & HAL_USART_ERROR_ORE) != RESET) || dmarequest)
{
/* Set the USART state ready to be able to start again the process,
Disable Rx Interrupts, and disable Rx DMA request, if ongoing */
USART_EndRxTransfer(husart);
/* Disable the USART DMA Rx request if enabled */
if (HAL_IS_BIT_SET(husart->Instance->CR3, USART_CR3_DMAR))
{
CLEAR_BIT(husart->Instance->CR3, USART_CR3_DMAR);
/* Abort the USART DMA Rx channel */
if (husart->hdmarx != NULL)
{
/* Set the USART DMA Abort callback :
will lead to call HAL_USART_ErrorCallback() at end of DMA abort procedure */
husart->hdmarx->XferAbortCallback = USART_DMAAbortOnError;
if (HAL_DMA_Abort_IT(husart->hdmarx) != HAL_OK)
{
/* Call Directly XferAbortCallback function in case of error */
husart->hdmarx->XferAbortCallback(husart->hdmarx);
}
}
else
{
/* Call user error callback */
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
/* Call registered Error Callback */
husart->ErrorCallback(husart);
#else
/* Call legacy weak Error Callback */
HAL_USART_ErrorCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
}
}
else
{
/* Call user error callback */
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
/* Call registered Error Callback */
husart->ErrorCallback(husart);
#else
/* Call legacy weak Error Callback */
HAL_USART_ErrorCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
}
}
else
{
/* Call user error callback */
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
/* Call registered Error Callback */
husart->ErrorCallback(husart);
#else
/* Call legacy weak Error Callback */
HAL_USART_ErrorCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
husart->ErrorCode = HAL_USART_ERROR_NONE;
}
}
return;
}
/* USART in mode Transmitter -----------------------------------------------*/
if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
{
if (husart->State == HAL_USART_STATE_BUSY_TX)
{
USART_Transmit_IT(husart);
}
else
{
USART_TransmitReceive_IT(husart);
}
return;
}
/* USART in mode Transmitter (transmission end) ----------------------------*/
if (((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))
{
USART_EndTransmit_IT(husart);
return;
}
}
/**
* @brief Tx Transfer completed callbacks.
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @retval None
*/
__weak void HAL_USART_TxCpltCallback(USART_HandleTypeDef *husart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(husart);
/* NOTE: This function should not be modified, when the callback is needed,
the HAL_USART_TxCpltCallback could be implemented in the user file
*/
}
/**
* @brief Tx Half Transfer completed callbacks.
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @retval None
*/
__weak void HAL_USART_TxHalfCpltCallback(USART_HandleTypeDef *husart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(husart);
/* NOTE: This function should not be modified, when the callback is needed,
the HAL_USART_TxHalfCpltCallback could be implemented in the user file
*/
}
/**
* @brief Rx Transfer completed callbacks.
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @retval None
*/
__weak void HAL_USART_RxCpltCallback(USART_HandleTypeDef *husart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(husart);
/* NOTE: This function should not be modified, when the callback is needed,
the HAL_USART_RxCpltCallback could be implemented in the user file
*/
}
/**
* @brief Rx Half Transfer completed callbacks.
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @retval None
*/
__weak void HAL_USART_RxHalfCpltCallback(USART_HandleTypeDef *husart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(husart);
/* NOTE: This function should not be modified, when the callback is needed,
the HAL_USART_RxHalfCpltCallback could be implemented in the user file
*/
}
/**
* @brief Tx/Rx Transfers completed callback for the non-blocking process.
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @retval None
*/
__weak void HAL_USART_TxRxCpltCallback(USART_HandleTypeDef *husart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(husart);
/* NOTE: This function should not be modified, when the callback is needed,
the HAL_USART_TxRxCpltCallback could be implemented in the user file
*/
}
/**
* @brief USART error callbacks.
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @retval None
*/
__weak void HAL_USART_ErrorCallback(USART_HandleTypeDef *husart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(husart);
/* NOTE: This function should not be modified, when the callback is needed,
the HAL_USART_ErrorCallback could be implemented in the user file
*/
}
/**
* @brief USART Abort Complete callback.
* @param husart USART handle.
* @retval None
*/
__weak void HAL_USART_AbortCpltCallback(USART_HandleTypeDef *husart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(husart);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_USART_AbortCpltCallback can be implemented in the user file.
*/
}
/**
* @}
*/
/** @defgroup USART_Exported_Functions_Group3 Peripheral State and Errors functions
* @brief USART State and Errors functions
*
@verbatim
==============================================================================
##### Peripheral State and Errors functions #####
==============================================================================
[..]
This subsection provides a set of functions allowing to return the State of
USART communication
process, return Peripheral Errors occurred during communication process
(+) HAL_USART_GetState() API can be helpful to check in run-time the state
of the USART peripheral.
(+) HAL_USART_GetError() check in run-time errors that could be occurred during
communication.
@endverbatim
* @{
*/
/**
* @brief Returns the USART state.
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @retval HAL state
*/
HAL_USART_StateTypeDef HAL_USART_GetState(const USART_HandleTypeDef *husart)
{
return husart->State;
}
/**
* @brief Return the USART error code
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART.
* @retval USART Error Code
*/
uint32_t HAL_USART_GetError(const USART_HandleTypeDef *husart)
{
return husart->ErrorCode;
}
/**
* @}
*/
/**
* @}
*/
/** @defgroup USART_Private_Functions USART Private Functions
* @{
*/
/**
* @brief Initialize the callbacks to their default values.
* @param husart USART handle.
* @retval none
*/
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
void USART_InitCallbacksToDefault(USART_HandleTypeDef *husart)
{
/* Init the USART Callback settings */
husart->TxHalfCpltCallback = HAL_USART_TxHalfCpltCallback; /* Legacy weak TxHalfCpltCallback */
husart->TxCpltCallback = HAL_USART_TxCpltCallback; /* Legacy weak TxCpltCallback */
husart->RxHalfCpltCallback = HAL_USART_RxHalfCpltCallback; /* Legacy weak RxHalfCpltCallback */
husart->RxCpltCallback = HAL_USART_RxCpltCallback; /* Legacy weak RxCpltCallback */
husart->TxRxCpltCallback = HAL_USART_TxRxCpltCallback; /* Legacy weak TxRxCpltCallback */
husart->ErrorCallback = HAL_USART_ErrorCallback; /* Legacy weak ErrorCallback */
husart->AbortCpltCallback = HAL_USART_AbortCpltCallback; /* Legacy weak AbortCpltCallback */
}
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
/**
* @brief DMA USART transmit process complete callback.
* @param hdma Pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
static void USART_DMATransmitCplt(DMA_HandleTypeDef *hdma)
{
USART_HandleTypeDef *husart = (USART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
/* DMA Normal mode */
if ((hdma->Instance->CCR & DMA_CCR_CIRC) == 0U)
{
husart->TxXferCount = 0U;
if (husart->State == HAL_USART_STATE_BUSY_TX)
{
/* Disable the DMA transfer for transmit request by resetting the DMAT bit
in the USART CR3 register */
CLEAR_BIT(husart->Instance->CR3, USART_CR3_DMAT);
/* Enable the USART Transmit Complete Interrupt */
SET_BIT(husart->Instance->CR1, USART_CR1_TCIE);
}
}
/* DMA Circular mode */
else
{
if (husart->State == HAL_USART_STATE_BUSY_TX)
{
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
/* Call registered Tx Complete Callback */
husart->TxCpltCallback(husart);
#else
/* Call legacy weak Tx Complete Callback */
HAL_USART_TxCpltCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
}
}
}
/**
* @brief DMA USART transmit process half complete callback
* @param hdma Pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
static void USART_DMATxHalfCplt(DMA_HandleTypeDef *hdma)
{
USART_HandleTypeDef *husart = (USART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
/* Call registered Tx Half Complete Callback */
husart->TxHalfCpltCallback(husart);
#else
/* Call legacy weak Tx Half Complete Callback */
HAL_USART_TxHalfCpltCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
}
/**
* @brief DMA USART receive process complete callback.
* @param hdma Pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
static void USART_DMAReceiveCplt(DMA_HandleTypeDef *hdma)
{
USART_HandleTypeDef *husart = (USART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
/* DMA Normal mode */
if ((hdma->Instance->CCR & DMA_CCR_CIRC) == 0U)
{
husart->RxXferCount = 0x00U;
/* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
CLEAR_BIT(husart->Instance->CR1, USART_CR1_PEIE);
CLEAR_BIT(husart->Instance->CR3, USART_CR3_EIE);
/* Disable the DMA transfer for the Transmit/receiver request by clearing the DMAT/DMAR bit
in the USART CR3 register */
CLEAR_BIT(husart->Instance->CR3, USART_CR3_DMAR);
CLEAR_BIT(husart->Instance->CR3, USART_CR3_DMAT);
/* The USART state is HAL_USART_STATE_BUSY_RX */
if (husart->State == HAL_USART_STATE_BUSY_RX)
{
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
/* Call registered Rx Complete Callback */
husart->RxCpltCallback(husart);
#else
/* Call legacy weak Rx Complete Callback */
HAL_USART_RxCpltCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
}
/* The USART state is HAL_USART_STATE_BUSY_TX_RX */
else
{
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
/* Call registered Tx Rx Complete Callback */
husart->TxRxCpltCallback(husart);
#else
/* Call legacy weak Tx Rx Complete Callback */
HAL_USART_TxRxCpltCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
}
husart->State = HAL_USART_STATE_READY;
}
/* DMA circular mode */
else
{
if (husart->State == HAL_USART_STATE_BUSY_RX)
{
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
/* Call registered Rx Complete Callback */
husart->RxCpltCallback(husart);
#else
/* Call legacy weak Rx Complete Callback */
HAL_USART_RxCpltCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
}
/* The USART state is HAL_USART_STATE_BUSY_TX_RX */
else
{
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
/* Call registered Tx Rx Complete Callback */
husart->TxRxCpltCallback(husart);
#else
/* Call legacy weak Tx Rx Complete Callback */
HAL_USART_TxRxCpltCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
}
}
}
/**
* @brief DMA USART receive process half complete callback
* @param hdma Pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
static void USART_DMARxHalfCplt(DMA_HandleTypeDef *hdma)
{
USART_HandleTypeDef *husart = (USART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
/* Call registered Rx Half Complete Callback */
husart->RxHalfCpltCallback(husart);
#else
/* Call legacy weak Rx Half Complete Callback */
HAL_USART_RxHalfCpltCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
}
/**
* @brief DMA USART communication error callback.
* @param hdma Pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
static void USART_DMAError(DMA_HandleTypeDef *hdma)
{
uint32_t dmarequest = 0x00U;
USART_HandleTypeDef *husart = (USART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
husart->RxXferCount = 0x00U;
husart->TxXferCount = 0x00U;
/* Stop USART DMA Tx request if ongoing */
dmarequest = HAL_IS_BIT_SET(husart->Instance->CR3, USART_CR3_DMAT);
if ((husart->State == HAL_USART_STATE_BUSY_TX) && dmarequest)
{
USART_EndTxTransfer(husart);
}
/* Stop USART DMA Rx request if ongoing */
dmarequest = HAL_IS_BIT_SET(husart->Instance->CR3, USART_CR3_DMAR);
if ((husart->State == HAL_USART_STATE_BUSY_RX) && dmarequest)
{
USART_EndRxTransfer(husart);
}
husart->ErrorCode |= HAL_USART_ERROR_DMA;
husart->State = HAL_USART_STATE_READY;
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
/* Call registered Error Callback */
husart->ErrorCallback(husart);
#else
/* Call legacy weak Error Callback */
HAL_USART_ErrorCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
}
/**
* @brief This function handles USART Communication Timeout. It waits
* until a flag is no longer in the specified status.
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @param Flag specifies the USART flag to check.
* @param Status The actual Flag status (SET or RESET).
* @param Tickstart Tick start value.
* @param Timeout Timeout duration.
* @retval HAL status
*/
static HAL_StatusTypeDef USART_WaitOnFlagUntilTimeout(USART_HandleTypeDef *husart, uint32_t Flag, FlagStatus Status,
uint32_t Tickstart, uint32_t Timeout)
{
/* Wait until flag is set */
while ((__HAL_USART_GET_FLAG(husart, Flag) ? SET : RESET) == Status)
{
/* Check for the Timeout */
if (Timeout != HAL_MAX_DELAY)
{
if ((Timeout == 0U) || ((HAL_GetTick() - Tickstart) > Timeout))
{
/* Disable the USART Transmit Complete Interrupt */
CLEAR_BIT(husart->Instance->CR1, USART_CR1_TXEIE);
/* Disable the USART RXNE Interrupt */
CLEAR_BIT(husart->Instance->CR1, USART_CR1_RXNEIE);
/* Disable the USART Parity Error Interrupt */
CLEAR_BIT(husart->Instance->CR1, USART_CR1_PEIE);
/* Disable the USART Error Interrupt: (Frame error, noise error, overrun error) */
CLEAR_BIT(husart->Instance->CR3, USART_CR3_EIE);
husart->State = HAL_USART_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(husart);
return HAL_TIMEOUT;
}
}
}
return HAL_OK;
}
/**
* @brief End ongoing Tx transfer on USART peripheral (following error detection or Transmit completion).
* @param husart USART handle.
* @retval None
*/
static void USART_EndTxTransfer(USART_HandleTypeDef *husart)
{
/* Disable TXEIE and TCIE interrupts */
CLEAR_BIT(husart->Instance->CR1, (USART_CR1_TXEIE | USART_CR1_TCIE));
/* At end of Tx process, restore husart->State to Ready */
husart->State = HAL_USART_STATE_READY;
}
/**
* @brief End ongoing Rx transfer on USART peripheral (following error detection or Reception completion).
* @param husart USART handle.
* @retval None
*/
static void USART_EndRxTransfer(USART_HandleTypeDef *husart)
{
/* Disable RXNE, PE and ERR interrupts */
CLEAR_BIT(husart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
CLEAR_BIT(husart->Instance->CR3, USART_CR3_EIE);
/* At end of Rx process, restore husart->State to Ready */
husart->State = HAL_USART_STATE_READY;
}
/**
* @brief DMA USART communication abort callback, when initiated by HAL services on Error
* (To be called at end of DMA Abort procedure following error occurrence).
* @param hdma DMA handle.
* @retval None
*/
static void USART_DMAAbortOnError(DMA_HandleTypeDef *hdma)
{
USART_HandleTypeDef *husart = (USART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
husart->RxXferCount = 0x00U;
husart->TxXferCount = 0x00U;
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
/* Call registered Error Callback */
husart->ErrorCallback(husart);
#else
/* Call legacy weak Error Callback */
HAL_USART_ErrorCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
}
/**
* @brief DMA USART Tx communication abort callback, when initiated by user
* (To be called at end of DMA Tx Abort procedure following user abort request).
* @note When this callback is executed, User Abort complete call back is called only if no
* Abort still ongoing for Rx DMA Handle.
* @param hdma DMA handle.
* @retval None
*/
static void USART_DMATxAbortCallback(DMA_HandleTypeDef *hdma)
{
USART_HandleTypeDef *husart = (USART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
husart->hdmatx->XferAbortCallback = NULL;
/* Check if an Abort process is still ongoing */
if (husart->hdmarx != NULL)
{
if (husart->hdmarx->XferAbortCallback != NULL)
{
return;
}
}
/* No Abort process still ongoing : All DMA channels are aborted, call user Abort Complete callback */
husart->TxXferCount = 0x00U;
husart->RxXferCount = 0x00U;
/* Reset errorCode */
husart->ErrorCode = HAL_USART_ERROR_NONE;
/* Restore husart->State to Ready */
husart->State = HAL_USART_STATE_READY;
/* Call user Abort complete callback */
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
/* Call registered Abort Complete Callback */
husart->AbortCpltCallback(husart);
#else
/* Call legacy weak Abort Complete Callback */
HAL_USART_AbortCpltCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
}
/**
* @brief DMA USART Rx communication abort callback, when initiated by user
* (To be called at end of DMA Rx Abort procedure following user abort request).
* @note When this callback is executed, User Abort complete call back is called only if no
* Abort still ongoing for Tx DMA Handle.
* @param hdma DMA handle.
* @retval None
*/
static void USART_DMARxAbortCallback(DMA_HandleTypeDef *hdma)
{
USART_HandleTypeDef *husart = (USART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
husart->hdmarx->XferAbortCallback = NULL;
/* Check if an Abort process is still ongoing */
if (husart->hdmatx != NULL)
{
if (husart->hdmatx->XferAbortCallback != NULL)
{
return;
}
}
/* No Abort process still ongoing : All DMA channels are aborted, call user Abort Complete callback */
husart->TxXferCount = 0x00U;
husart->RxXferCount = 0x00U;
/* Reset errorCode */
husart->ErrorCode = HAL_USART_ERROR_NONE;
/* Restore husart->State to Ready */
husart->State = HAL_USART_STATE_READY;
/* Call user Abort complete callback */
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
/* Call registered Abort Complete Callback */
husart->AbortCpltCallback(husart);
#else
/* Call legacy weak Abort Complete Callback */
HAL_USART_AbortCpltCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
}
/**
* @brief Simplex Send an amount of data in non-blocking mode.
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @retval HAL status
* @note The USART errors are not managed to avoid the overrun error.
*/
static HAL_StatusTypeDef USART_Transmit_IT(USART_HandleTypeDef *husart)
{
const uint16_t *tmp;
if (husart->State == HAL_USART_STATE_BUSY_TX)
{
if ((husart->Init.WordLength == USART_WORDLENGTH_9B) && (husart->Init.Parity == USART_PARITY_NONE))
{
tmp = (const uint16_t *) husart->pTxBuffPtr;
husart->Instance->DR = (uint16_t)(*tmp & (uint16_t)0x01FF);
husart->pTxBuffPtr += 2U;
}
else
{
husart->Instance->DR = (uint8_t)(*husart->pTxBuffPtr++ & (uint8_t)0x00FF);
}
if (--husart->TxXferCount == 0U)
{
/* Disable the USART Transmit data register empty Interrupt */
CLEAR_BIT(husart->Instance->CR1, USART_CR1_TXEIE);
/* Enable the USART Transmit Complete Interrupt */
SET_BIT(husart->Instance->CR1, USART_CR1_TCIE);
}
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Wraps up transmission in non blocking mode.
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @retval HAL status
*/
static HAL_StatusTypeDef USART_EndTransmit_IT(USART_HandleTypeDef *husart)
{
/* Disable the USART Transmit Complete Interrupt */
CLEAR_BIT(husart->Instance->CR1, USART_CR1_TCIE);
/* Disable the USART Error Interrupt: (Frame error, noise error, overrun error) */
CLEAR_BIT(husart->Instance->CR3, USART_CR3_EIE);
husart->State = HAL_USART_STATE_READY;
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
/* Call registered Tx Complete Callback */
husart->TxCpltCallback(husart);
#else
/* Call legacy weak Tx Complete Callback */
HAL_USART_TxCpltCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
return HAL_OK;
}
/**
* @brief Simplex Receive an amount of data in non-blocking mode.
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @retval HAL status
*/
static HAL_StatusTypeDef USART_Receive_IT(USART_HandleTypeDef *husart)
{
uint8_t *pdata8bits;
uint16_t *pdata16bits;
if (husart->State == HAL_USART_STATE_BUSY_RX)
{
if ((husart->Init.WordLength == USART_WORDLENGTH_9B) && (husart->Init.Parity == USART_PARITY_NONE))
{
pdata8bits = NULL;
pdata16bits = (uint16_t *) husart->pRxBuffPtr;
*pdata16bits = (uint16_t)(husart->Instance->DR & (uint16_t)0x01FF);
husart->pRxBuffPtr += 2U;
}
else
{
pdata8bits = (uint8_t *) husart->pRxBuffPtr;
pdata16bits = NULL;
if ((husart->Init.WordLength == USART_WORDLENGTH_9B) || ((husart->Init.WordLength == USART_WORDLENGTH_8B) && (husart->Init.Parity == USART_PARITY_NONE)))
{
*pdata8bits = (uint8_t)(husart->Instance->DR & (uint8_t)0x00FF);
}
else
{
*pdata8bits = (uint8_t)(husart->Instance->DR & (uint8_t)0x007F);
}
husart->pRxBuffPtr += 1U;
}
husart->RxXferCount--;
if (husart->RxXferCount == 0U)
{
/* Disable the USART RXNE Interrupt */
CLEAR_BIT(husart->Instance->CR1, USART_CR1_RXNEIE);
/* Disable the USART Parity Error Interrupt */
CLEAR_BIT(husart->Instance->CR1, USART_CR1_PEIE);
/* Disable the USART Error Interrupt: (Frame error, noise error, overrun error) */
CLEAR_BIT(husart->Instance->CR3, USART_CR3_EIE);
husart->State = HAL_USART_STATE_READY;
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
/* Call registered Rx Complete Callback */
husart->RxCpltCallback(husart);
#else
/* Call legacy weak Rx Complete Callback */
HAL_USART_RxCpltCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
return HAL_OK;
}
else
{
/* Send dummy byte in order to generate the clock for the slave to send the next data.
* Whatever the frame length (7, 8 or 9-bit long), the same dummy value
* can be written for all the cases. */
husart->Instance->DR = (DUMMY_DATA & (uint16_t)0x0FF);
}
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Full-Duplex Send receive an amount of data in full-duplex mode (non-blocking).
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @retval HAL status
*/
static HAL_StatusTypeDef USART_TransmitReceive_IT(USART_HandleTypeDef *husart)
{
const uint16_t *pdatatx16bits;
uint16_t *pdatarx16bits;
if (husart->State == HAL_USART_STATE_BUSY_TX_RX)
{
if (husart->TxXferCount != 0x00U)
{
if (__HAL_USART_GET_FLAG(husart, USART_FLAG_TXE) != RESET)
{
if ((husart->Init.WordLength == USART_WORDLENGTH_9B) && (husart->Init.Parity == USART_PARITY_NONE))
{
pdatatx16bits = (const uint16_t *) husart->pTxBuffPtr;
husart->Instance->DR = (uint16_t)(*pdatatx16bits & (uint16_t)0x01FF);
husart->pTxBuffPtr += 2U;
}
else
{
husart->Instance->DR = (uint8_t)(*husart->pTxBuffPtr++ & (uint8_t)0x00FF);
}
husart->TxXferCount--;
/* Check the latest data transmitted */
if (husart->TxXferCount == 0U)
{
CLEAR_BIT(husart->Instance->CR1, USART_CR1_TXEIE);
}
}
}
if (husart->RxXferCount != 0x00U)
{
if (__HAL_USART_GET_FLAG(husart, USART_FLAG_RXNE) != RESET)
{
if ((husart->Init.WordLength == USART_WORDLENGTH_9B) && (husart->Init.Parity == USART_PARITY_NONE))
{
pdatarx16bits = (uint16_t *) husart->pRxBuffPtr;
*pdatarx16bits = (uint16_t)(husart->Instance->DR & (uint16_t)0x01FF);
husart->pRxBuffPtr += 2U;
}
else
{
if ((husart->Init.WordLength == USART_WORDLENGTH_9B) || ((husart->Init.WordLength == USART_WORDLENGTH_8B) && (husart->Init.Parity == USART_PARITY_NONE)))
{
*husart->pRxBuffPtr = (uint8_t)(husart->Instance->DR & (uint8_t)0x00FF);
}
else
{
*husart->pRxBuffPtr = (uint8_t)(husart->Instance->DR & (uint8_t)0x007F);
}
husart->pRxBuffPtr += 1U;
}
husart->RxXferCount--;
}
}
/* Check the latest data received */
if (husart->RxXferCount == 0U)
{
/* Disable the USART RXNE Interrupt */
CLEAR_BIT(husart->Instance->CR1, USART_CR1_RXNEIE);
/* Disable the USART Parity Error Interrupt */
CLEAR_BIT(husart->Instance->CR1, USART_CR1_PEIE);
/* Disable the USART Error Interrupt: (Frame error, noise error, overrun error) */
CLEAR_BIT(husart->Instance->CR3, USART_CR3_EIE);
husart->State = HAL_USART_STATE_READY;
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
/* Call registered Tx Rx Complete Callback */
husart->TxRxCpltCallback(husart);
#else
/* Call legacy weak Tx Rx Complete Callback */
HAL_USART_TxRxCpltCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
return HAL_OK;
}
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Configures the USART peripheral.
* @param husart Pointer to a USART_HandleTypeDef structure that contains
* the configuration information for the specified USART module.
* @retval None
*/
static void USART_SetConfig(USART_HandleTypeDef *husart)
{
uint32_t tmpreg = 0x00U;
uint32_t pclk;
/* Check the parameters */
assert_param(IS_USART_INSTANCE(husart->Instance));
assert_param(IS_USART_POLARITY(husart->Init.CLKPolarity));
assert_param(IS_USART_PHASE(husart->Init.CLKPhase));
assert_param(IS_USART_LASTBIT(husart->Init.CLKLastBit));
assert_param(IS_USART_BAUDRATE(husart->Init.BaudRate));
assert_param(IS_USART_WORD_LENGTH(husart->Init.WordLength));
assert_param(IS_USART_STOPBITS(husart->Init.StopBits));
assert_param(IS_USART_PARITY(husart->Init.Parity));
assert_param(IS_USART_MODE(husart->Init.Mode));
/* The LBCL, CPOL and CPHA bits have to be selected when both the transmitter and the
receiver are disabled (TE=RE=0) to ensure that the clock pulses function correctly. */
CLEAR_BIT(husart->Instance->CR1, (USART_CR1_TE | USART_CR1_RE));
/*---------------------------- USART CR2 Configuration ---------------------*/
tmpreg = husart->Instance->CR2;
/* Clear CLKEN, CPOL, CPHA and LBCL bits */
tmpreg &= (uint32_t)~((uint32_t)(USART_CR2_CPHA | USART_CR2_CPOL | USART_CR2_CLKEN | USART_CR2_LBCL | USART_CR2_STOP));
/* Configure the USART Clock, CPOL, CPHA and LastBit -----------------------*/
/* Set CPOL bit according to husart->Init.CLKPolarity value */
/* Set CPHA bit according to husart->Init.CLKPhase value */
/* Set LBCL bit according to husart->Init.CLKLastBit value */
/* Set Stop Bits: Set STOP[13:12] bits according to husart->Init.StopBits value */
tmpreg |= (uint32_t)(USART_CLOCK_ENABLE | husart->Init.CLKPolarity |
husart->Init.CLKPhase | husart->Init.CLKLastBit | husart->Init.StopBits);
/* Write to USART CR2 */
WRITE_REG(husart->Instance->CR2, (uint32_t)tmpreg);
/*-------------------------- USART CR1 Configuration -----------------------*/
tmpreg = husart->Instance->CR1;
/* Clear M, PCE, PS, TE and RE bits */
tmpreg &= (uint32_t)~((uint32_t)(USART_CR1_M | USART_CR1_PCE | USART_CR1_PS | USART_CR1_TE | USART_CR1_RE));
/* Configure the USART Word Length, Parity and mode:
Set the M bits according to husart->Init.WordLength value
Set PCE and PS bits according to husart->Init.Parity value
Set TE and RE bits according to husart->Init.Mode value
*/
tmpreg |= (uint32_t)husart->Init.WordLength | husart->Init.Parity | husart->Init.Mode;
/* Write to USART CR1 */
WRITE_REG(husart->Instance->CR1, (uint32_t)tmpreg);
/*-------------------------- USART CR3 Configuration -----------------------*/
/* Clear CTSE and RTSE bits */
CLEAR_BIT(husart->Instance->CR3, (USART_CR3_RTSE | USART_CR3_CTSE));
/*-------------------------- USART BRR Configuration -----------------------*/
if (husart->Instance == USART1)
{
pclk = HAL_RCC_GetPCLK2Freq();
husart->Instance->BRR = USART_BRR(pclk, husart->Init.BaudRate);
}
else
{
pclk = HAL_RCC_GetPCLK1Freq();
husart->Instance->BRR = USART_BRR(pclk, husart->Init.BaudRate);
}
}
/**
* @}
*/
#endif /* HAL_USART_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/

View File

@@ -0,0 +1,420 @@
/**
******************************************************************************
* @file stm32f1xx_hal_wwdg.c
* @author MCD Application Team
* @brief WWDG HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of the Window Watchdog (WWDG) peripheral:
* + Initialization and Configuration functions
* + IO operation functions
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
==============================================================================
##### WWDG Specific features #####
==============================================================================
[..]
Once enabled the WWDG generates a system reset on expiry of a programmed
time period, unless the program refreshes the counter (T[6;0] downcounter)
before reaching 0x3F value (i.e. a reset is generated when the counter
value rolls down from 0x40 to 0x3F).
(+) An MCU reset is also generated if the counter value is refreshed
before the counter has reached the refresh window value. This
implies that the counter must be refreshed in a limited window.
(+) Once enabled the WWDG cannot be disabled except by a system reset.
(+) If required by application, an Early Wakeup Interrupt can be triggered
in order to be warned before WWDG expiration. The Early Wakeup Interrupt
(EWI) can be used if specific safety operations or data logging must
be performed before the actual reset is generated. When the downcounter
reaches 0x40, interrupt occurs. This mechanism requires WWDG interrupt
line to be enabled in NVIC. Once enabled, EWI interrupt cannot be
disabled except by a system reset.
(+) WWDGRST flag in RCC CSR register can be used to inform when a WWDG
reset occurs.
(+) The WWDG counter input clock is derived from the APB clock divided
by a programmable prescaler.
(+) WWDG clock (Hz) = PCLK1 / (4096 * Prescaler)
(+) WWDG timeout (mS) = 1000 * (T[5;0] + 1) / WWDG clock (Hz)
where T[5;0] are the lowest 6 bits of Counter.
(+) WWDG Counter refresh is allowed between the following limits :
(++) min time (mS) = 1000 * (Counter - Window) / WWDG clock
(++) max time (mS) = 1000 * (Counter - 0x40) / WWDG clock
(+) Typical values:
(++) Counter min (T[5;0] = 0x00) at 36MHz (PCLK1) with zero prescaler:
max timeout before reset: approximately 910us
(++) Counter max (T[5;0] = 0x3F) at 36MHz (PCLK1) with prescaler
dividing by 8:
max timeout before reset: approximately 58.25ms
##### How to use this driver #####
==============================================================================
*** Common driver usage ***
===========================
[..]
(+) Enable WWDG APB1 clock using __HAL_RCC_WWDG_CLK_ENABLE().
(+) Configure the WWDG prescaler, refresh window value, counter value and early
interrupt status using HAL_WWDG_Init() function. This will automatically
enable WWDG and start its downcounter. Time reference can be taken from
function exit. Care must be taken to provide a counter value
greater than 0x40 to prevent generation of immediate reset.
(+) If the Early Wakeup Interrupt (EWI) feature is enabled, an interrupt is
generated when the counter reaches 0x40. When HAL_WWDG_IRQHandler is
triggered by the interrupt service routine, flag will be automatically
cleared and HAL_WWDG_WakeupCallback user callback will be executed. User
can add his own code by customization of callback HAL_WWDG_WakeupCallback.
(+) Then the application program must refresh the WWDG counter at regular
intervals during normal operation to prevent an MCU reset, using
HAL_WWDG_Refresh() function. This operation must occur only when
the counter is lower than the refresh window value already programmed.
*** Callback registration ***
=============================
[..]
The compilation define USE_HAL_WWDG_REGISTER_CALLBACKS when set to 1 allows
the user to configure dynamically the driver callbacks. Use Functions
HAL_WWDG_RegisterCallback() to register a user callback.
(+) Function HAL_WWDG_RegisterCallback() allows to register following
callbacks:
(++) EwiCallback : callback for Early WakeUp Interrupt.
(++) MspInitCallback : WWDG MspInit.
This function takes as parameters the HAL peripheral handle, the Callback ID
and a pointer to the user callback function.
(+) Use function HAL_WWDG_UnRegisterCallback() to reset a callback to
the default weak (surcharged) function. HAL_WWDG_UnRegisterCallback()
takes as parameters the HAL peripheral handle and the Callback ID.
This function allows to reset following callbacks:
(++) EwiCallback : callback for Early WakeUp Interrupt.
(++) MspInitCallback : WWDG MspInit.
[..]
When calling HAL_WWDG_Init function, callbacks are reset to the
corresponding legacy weak (surcharged) functions:
HAL_WWDG_EarlyWakeupCallback() and HAL_WWDG_MspInit() only if they have
not been registered before.
[..]
When compilation define USE_HAL_WWDG_REGISTER_CALLBACKS is set to 0 or
not defined, the callback registering feature is not available
and weak (surcharged) callbacks are used.
*** WWDG HAL driver macros list ***
===================================
[..]
Below the list of available macros in WWDG HAL driver.
(+) __HAL_WWDG_ENABLE: Enable the WWDG peripheral
(+) __HAL_WWDG_GET_FLAG: Get the selected WWDG's flag status
(+) __HAL_WWDG_CLEAR_FLAG: Clear the WWDG's pending flags
(+) __HAL_WWDG_ENABLE_IT: Enable the WWDG early wakeup interrupt
@endverbatim
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
#ifdef HAL_WWDG_MODULE_ENABLED
/** @defgroup WWDG WWDG
* @brief WWDG HAL module driver.
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @defgroup WWDG_Exported_Functions WWDG Exported Functions
* @{
*/
/** @defgroup WWDG_Exported_Functions_Group1 Initialization and Configuration functions
* @brief Initialization and Configuration functions.
*
@verbatim
==============================================================================
##### Initialization and Configuration functions #####
==============================================================================
[..]
This section provides functions allowing to:
(+) Initialize and start the WWDG according to the specified parameters
in the WWDG_InitTypeDef of associated handle.
(+) Initialize the WWDG MSP.
@endverbatim
* @{
*/
/**
* @brief Initialize the WWDG according to the specified.
* parameters in the WWDG_InitTypeDef of associated handle.
* @param hwwdg pointer to a WWDG_HandleTypeDef structure that contains
* the configuration information for the specified WWDG module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_WWDG_Init(WWDG_HandleTypeDef *hwwdg)
{
/* Check the WWDG handle allocation */
if (hwwdg == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_WWDG_ALL_INSTANCE(hwwdg->Instance));
assert_param(IS_WWDG_PRESCALER(hwwdg->Init.Prescaler));
assert_param(IS_WWDG_WINDOW(hwwdg->Init.Window));
assert_param(IS_WWDG_COUNTER(hwwdg->Init.Counter));
assert_param(IS_WWDG_EWI_MODE(hwwdg->Init.EWIMode));
#if (USE_HAL_WWDG_REGISTER_CALLBACKS == 1)
/* Reset Callback pointers */
if (hwwdg->EwiCallback == NULL)
{
hwwdg->EwiCallback = HAL_WWDG_EarlyWakeupCallback;
}
if (hwwdg->MspInitCallback == NULL)
{
hwwdg->MspInitCallback = HAL_WWDG_MspInit;
}
/* Init the low level hardware */
hwwdg->MspInitCallback(hwwdg);
#else
/* Init the low level hardware */
HAL_WWDG_MspInit(hwwdg);
#endif /* USE_HAL_WWDG_REGISTER_CALLBACKS */
/* Set WWDG Counter */
WRITE_REG(hwwdg->Instance->CR, (WWDG_CR_WDGA | hwwdg->Init.Counter));
/* Set WWDG Prescaler and Window */
WRITE_REG(hwwdg->Instance->CFR, (hwwdg->Init.EWIMode | hwwdg->Init.Prescaler | hwwdg->Init.Window));
/* Return function status */
return HAL_OK;
}
/**
* @brief Initialize the WWDG MSP.
* @param hwwdg pointer to a WWDG_HandleTypeDef structure that contains
* the configuration information for the specified WWDG module.
* @note When rewriting this function in user file, mechanism may be added
* to avoid multiple initialize when HAL_WWDG_Init function is called
* again to change parameters.
* @retval None
*/
__weak void HAL_WWDG_MspInit(WWDG_HandleTypeDef *hwwdg)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hwwdg);
/* NOTE: This function should not be modified, when the callback is needed,
the HAL_WWDG_MspInit could be implemented in the user file
*/
}
#if (USE_HAL_WWDG_REGISTER_CALLBACKS == 1)
/**
* @brief Register a User WWDG Callback
* To be used instead of the weak (surcharged) predefined callback
* @param hwwdg WWDG handle
* @param CallbackID ID of the callback to be registered
* This parameter can be one of the following values:
* @arg @ref HAL_WWDG_EWI_CB_ID Early WakeUp Interrupt Callback ID
* @arg @ref HAL_WWDG_MSPINIT_CB_ID MspInit callback ID
* @param pCallback pointer to the Callback function
* @retval status
*/
HAL_StatusTypeDef HAL_WWDG_RegisterCallback(WWDG_HandleTypeDef *hwwdg, HAL_WWDG_CallbackIDTypeDef CallbackID,
pWWDG_CallbackTypeDef pCallback)
{
HAL_StatusTypeDef status = HAL_OK;
if (pCallback == NULL)
{
status = HAL_ERROR;
}
else
{
switch (CallbackID)
{
case HAL_WWDG_EWI_CB_ID:
hwwdg->EwiCallback = pCallback;
break;
case HAL_WWDG_MSPINIT_CB_ID:
hwwdg->MspInitCallback = pCallback;
break;
default:
status = HAL_ERROR;
break;
}
}
return status;
}
/**
* @brief Unregister a WWDG Callback
* WWDG Callback is redirected to the weak (surcharged) predefined callback
* @param hwwdg WWDG handle
* @param CallbackID ID of the callback to be registered
* This parameter can be one of the following values:
* @arg @ref HAL_WWDG_EWI_CB_ID Early WakeUp Interrupt Callback ID
* @arg @ref HAL_WWDG_MSPINIT_CB_ID MspInit callback ID
* @retval status
*/
HAL_StatusTypeDef HAL_WWDG_UnRegisterCallback(WWDG_HandleTypeDef *hwwdg, HAL_WWDG_CallbackIDTypeDef CallbackID)
{
HAL_StatusTypeDef status = HAL_OK;
switch (CallbackID)
{
case HAL_WWDG_EWI_CB_ID:
hwwdg->EwiCallback = HAL_WWDG_EarlyWakeupCallback;
break;
case HAL_WWDG_MSPINIT_CB_ID:
hwwdg->MspInitCallback = HAL_WWDG_MspInit;
break;
default:
status = HAL_ERROR;
break;
}
return status;
}
#endif /* USE_HAL_WWDG_REGISTER_CALLBACKS */
/**
* @}
*/
/** @defgroup WWDG_Exported_Functions_Group2 IO operation functions
* @brief IO operation functions
*
@verbatim
==============================================================================
##### IO operation functions #####
==============================================================================
[..]
This section provides functions allowing to:
(+) Refresh the WWDG.
(+) Handle WWDG interrupt request and associated function callback.
@endverbatim
* @{
*/
/**
* @brief Refresh the WWDG.
* @param hwwdg pointer to a WWDG_HandleTypeDef structure that contains
* the configuration information for the specified WWDG module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_WWDG_Refresh(WWDG_HandleTypeDef *hwwdg)
{
/* Write to WWDG CR the WWDG Counter value to refresh with */
WRITE_REG(hwwdg->Instance->CR, (hwwdg->Init.Counter));
/* Return function status */
return HAL_OK;
}
/**
* @brief Handle WWDG interrupt request.
* @note The Early Wakeup Interrupt (EWI) can be used if specific safety operations
* or data logging must be performed before the actual reset is generated.
* The EWI interrupt is enabled by calling HAL_WWDG_Init function with
* EWIMode set to WWDG_EWI_ENABLE.
* When the downcounter reaches the value 0x40, and EWI interrupt is
* generated and the corresponding Interrupt Service Routine (ISR) can
* be used to trigger specific actions (such as communications or data
* logging), before resetting the device.
* @param hwwdg pointer to a WWDG_HandleTypeDef structure that contains
* the configuration information for the specified WWDG module.
* @retval None
*/
void HAL_WWDG_IRQHandler(WWDG_HandleTypeDef *hwwdg)
{
/* Check if Early Wakeup Interrupt is enable */
if (__HAL_WWDG_GET_IT_SOURCE(hwwdg, WWDG_IT_EWI) != RESET)
{
/* Check if WWDG Early Wakeup Interrupt occurred */
if (__HAL_WWDG_GET_FLAG(hwwdg, WWDG_FLAG_EWIF) != RESET)
{
/* Clear the WWDG Early Wakeup flag */
__HAL_WWDG_CLEAR_FLAG(hwwdg, WWDG_FLAG_EWIF);
#if (USE_HAL_WWDG_REGISTER_CALLBACKS == 1)
/* Early Wakeup registered callback */
hwwdg->EwiCallback(hwwdg);
#else
/* Early Wakeup callback */
HAL_WWDG_EarlyWakeupCallback(hwwdg);
#endif /* USE_HAL_WWDG_REGISTER_CALLBACKS */
}
}
}
/**
* @brief WWDG Early Wakeup callback.
* @param hwwdg pointer to a WWDG_HandleTypeDef structure that contains
* the configuration information for the specified WWDG module.
* @retval None
*/
__weak void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hwwdg);
/* NOTE: This function should not be modified, when the callback is needed,
the HAL_WWDG_EarlyWakeupCallback could be implemented in the user file
*/
}
/**
* @}
*/
/**
* @}
*/
#endif /* HAL_WWDG_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/

View File

@@ -0,0 +1,893 @@
/**
******************************************************************************
* @file stm32f1xx_ll_adc.c
* @author MCD Application Team
* @brief ADC LL module driver
******************************************************************************
* @attention
*
* Copyright (c) 2017 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#if defined(USE_FULL_LL_DRIVER)
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_ll_adc.h"
#include "stm32f1xx_ll_bus.h"
#ifdef USE_FULL_ASSERT
#include "stm32_assert.h"
#else
#define assert_param(expr) ((void)0U)
#endif
/** @addtogroup STM32F1xx_LL_Driver
* @{
*/
#if defined (ADC1) || defined (ADC2) || defined (ADC3)
/** @addtogroup ADC_LL ADC
* @{
*/
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/** @addtogroup ADC_LL_Private_Macros
* @{
*/
/* Check of parameters for configuration of ADC hierarchical scope: */
/* common to several ADC instances. */
/* Check of parameters for configuration of ADC hierarchical scope: */
/* ADC instance. */
#define IS_LL_ADC_DATA_ALIGN(__DATA_ALIGN__) \
( ((__DATA_ALIGN__) == LL_ADC_DATA_ALIGN_RIGHT) \
|| ((__DATA_ALIGN__) == LL_ADC_DATA_ALIGN_LEFT) \
)
#define IS_LL_ADC_SCAN_SELECTION(__SCAN_SELECTION__) \
( ((__SCAN_SELECTION__) == LL_ADC_SEQ_SCAN_DISABLE) \
|| ((__SCAN_SELECTION__) == LL_ADC_SEQ_SCAN_ENABLE) \
)
#define IS_LL_ADC_SEQ_SCAN_MODE(__SEQ_SCAN_MODE__) \
( ((__SCAN_MODE__) == LL_ADC_SEQ_SCAN_DISABLE) \
|| ((__SCAN_MODE__) == LL_ADC_SEQ_SCAN_ENABLE) \
)
/* Check of parameters for configuration of ADC hierarchical scope: */
/* ADC group regular */
#if defined(ADC3)
#define IS_LL_ADC_REG_TRIG_SOURCE(__ADC_INSTANCE__, __REG_TRIG_SOURCE__) \
((((__ADC_INSTANCE__) == ADC1) || ((__ADC_INSTANCE__) == ADC2)) \
? ( ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_SOFTWARE) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_TIM1_CH3) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_TIM1_CH1) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_TIM1_CH2) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_TIM2_CH2) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_TIM3_TRGO) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_TIM4_CH4) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_EXTI_LINE11) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_TIM8_TRGO) \
) \
: \
( ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_SOFTWARE) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_TIM1_CH3) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_TIM3_CH1) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_TIM2_CH3) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_TIM8_CH1) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_TIM8_TRGO_ADC3) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_TIM5_CH1) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_TIM5_CH3) \
) \
)
#else
#if defined (STM32F101xE) || defined (STM32F105xC) || defined (STM32F107xC)
#define IS_LL_ADC_REG_TRIG_SOURCE(__REG_TRIG_SOURCE__) \
( ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_SOFTWARE) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_TIM1_CH3) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_TIM1_CH1) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_TIM1_CH2) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_TIM2_CH2) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_TIM3_TRGO) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_TIM4_CH4) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_EXTI_LINE11) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_TIM8_TRGO) \
)
#else
#define IS_LL_ADC_REG_TRIG_SOURCE(__REG_TRIG_SOURCE__) \
( ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_SOFTWARE) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_TIM1_CH3) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_TIM1_CH1) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_TIM1_CH2) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_TIM2_CH2) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_TIM3_TRGO) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_TIM4_CH4) \
|| ((__REG_TRIG_SOURCE__) == LL_ADC_REG_TRIG_EXT_EXTI_LINE11) \
)
#endif
#endif
#define IS_LL_ADC_REG_CONTINUOUS_MODE(__REG_CONTINUOUS_MODE__) \
( ((__REG_CONTINUOUS_MODE__) == LL_ADC_REG_CONV_SINGLE) \
|| ((__REG_CONTINUOUS_MODE__) == LL_ADC_REG_CONV_CONTINUOUS) \
)
#define IS_LL_ADC_REG_DMA_TRANSFER(__REG_DMA_TRANSFER__) \
( ((__REG_DMA_TRANSFER__) == LL_ADC_REG_DMA_TRANSFER_NONE) \
|| ((__REG_DMA_TRANSFER__) == LL_ADC_REG_DMA_TRANSFER_UNLIMITED) \
)
#define IS_LL_ADC_REG_SEQ_SCAN_LENGTH(__REG_SEQ_SCAN_LENGTH__) \
( ((__REG_SEQ_SCAN_LENGTH__) == LL_ADC_REG_SEQ_SCAN_DISABLE) \
|| ((__REG_SEQ_SCAN_LENGTH__) == LL_ADC_REG_SEQ_SCAN_ENABLE_2RANKS) \
|| ((__REG_SEQ_SCAN_LENGTH__) == LL_ADC_REG_SEQ_SCAN_ENABLE_3RANKS) \
|| ((__REG_SEQ_SCAN_LENGTH__) == LL_ADC_REG_SEQ_SCAN_ENABLE_4RANKS) \
|| ((__REG_SEQ_SCAN_LENGTH__) == LL_ADC_REG_SEQ_SCAN_ENABLE_5RANKS) \
|| ((__REG_SEQ_SCAN_LENGTH__) == LL_ADC_REG_SEQ_SCAN_ENABLE_6RANKS) \
|| ((__REG_SEQ_SCAN_LENGTH__) == LL_ADC_REG_SEQ_SCAN_ENABLE_7RANKS) \
|| ((__REG_SEQ_SCAN_LENGTH__) == LL_ADC_REG_SEQ_SCAN_ENABLE_8RANKS) \
|| ((__REG_SEQ_SCAN_LENGTH__) == LL_ADC_REG_SEQ_SCAN_ENABLE_9RANKS) \
|| ((__REG_SEQ_SCAN_LENGTH__) == LL_ADC_REG_SEQ_SCAN_ENABLE_10RANKS) \
|| ((__REG_SEQ_SCAN_LENGTH__) == LL_ADC_REG_SEQ_SCAN_ENABLE_11RANKS) \
|| ((__REG_SEQ_SCAN_LENGTH__) == LL_ADC_REG_SEQ_SCAN_ENABLE_12RANKS) \
|| ((__REG_SEQ_SCAN_LENGTH__) == LL_ADC_REG_SEQ_SCAN_ENABLE_13RANKS) \
|| ((__REG_SEQ_SCAN_LENGTH__) == LL_ADC_REG_SEQ_SCAN_ENABLE_14RANKS) \
|| ((__REG_SEQ_SCAN_LENGTH__) == LL_ADC_REG_SEQ_SCAN_ENABLE_15RANKS) \
|| ((__REG_SEQ_SCAN_LENGTH__) == LL_ADC_REG_SEQ_SCAN_ENABLE_16RANKS) \
)
#define IS_LL_ADC_REG_SEQ_SCAN_DISCONT_MODE(__REG_SEQ_DISCONT_MODE__) \
( ((__REG_SEQ_DISCONT_MODE__) == LL_ADC_REG_SEQ_DISCONT_DISABLE) \
|| ((__REG_SEQ_DISCONT_MODE__) == LL_ADC_REG_SEQ_DISCONT_1RANK) \
|| ((__REG_SEQ_DISCONT_MODE__) == LL_ADC_REG_SEQ_DISCONT_2RANKS) \
|| ((__REG_SEQ_DISCONT_MODE__) == LL_ADC_REG_SEQ_DISCONT_3RANKS) \
|| ((__REG_SEQ_DISCONT_MODE__) == LL_ADC_REG_SEQ_DISCONT_4RANKS) \
|| ((__REG_SEQ_DISCONT_MODE__) == LL_ADC_REG_SEQ_DISCONT_5RANKS) \
|| ((__REG_SEQ_DISCONT_MODE__) == LL_ADC_REG_SEQ_DISCONT_6RANKS) \
|| ((__REG_SEQ_DISCONT_MODE__) == LL_ADC_REG_SEQ_DISCONT_7RANKS) \
|| ((__REG_SEQ_DISCONT_MODE__) == LL_ADC_REG_SEQ_DISCONT_8RANKS) \
)
/* Check of parameters for configuration of ADC hierarchical scope: */
/* ADC group injected */
#if defined(ADC3)
#define IS_LL_ADC_INJ_TRIG_SOURCE(__ADC_INSTANCE__, __INJ_TRIG_SOURCE__) \
((((__ADC_INSTANCE__) == ADC1) || ((__ADC_INSTANCE__) == ADC2)) \
? ( ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_SOFTWARE) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_TIM1_TRGO) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_TIM1_CH4) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_TIM2_TRGO) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_TIM2_CH1) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_TIM3_CH4) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_TIM4_TRGO) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_EXTI_LINE15) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_TIM8_CH4) \
) \
: \
( ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_SOFTWARE) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_TIM1_TRGO) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_TIM1_CH4) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_TIM4_CH3) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_TIM8_CH2) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_TIM8_CH4_ADC3) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_TIM5_TRGO) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_TIM5_CH4) \
) \
)
#else
#if defined (STM32F101xE) || defined (STM32F105xC) || defined (STM32F107xC)
#define IS_LL_ADC_INJ_TRIG_SOURCE(__INJ_TRIG_SOURCE__) \
( ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_SOFTWARE) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_TIM1_TRGO) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_TIM1_CH4) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_TIM2_TRGO) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_TIM2_CH1) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_TIM3_CH4) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_TIM4_TRGO) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_EXTI_LINE15) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_TIM8_CH4) \
)
#else
#define IS_LL_ADC_INJ_TRIG_SOURCE(__INJ_TRIG_SOURCE__) \
( ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_SOFTWARE) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_TIM1_TRGO) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_TIM1_CH4) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_TIM2_TRGO) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_TIM2_CH1) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_TIM3_CH4) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_TIM4_TRGO) \
|| ((__INJ_TRIG_SOURCE__) == LL_ADC_INJ_TRIG_EXT_EXTI_LINE15) \
)
#endif
#endif
#define IS_LL_ADC_INJ_TRIG_AUTO(__INJ_TRIG_AUTO__) \
( ((__INJ_TRIG_AUTO__) == LL_ADC_INJ_TRIG_INDEPENDENT) \
|| ((__INJ_TRIG_AUTO__) == LL_ADC_INJ_TRIG_FROM_GRP_REGULAR) \
)
#define IS_LL_ADC_INJ_SEQ_SCAN_LENGTH(__INJ_SEQ_SCAN_LENGTH__) \
( ((__INJ_SEQ_SCAN_LENGTH__) == LL_ADC_INJ_SEQ_SCAN_DISABLE) \
|| ((__INJ_SEQ_SCAN_LENGTH__) == LL_ADC_INJ_SEQ_SCAN_ENABLE_2RANKS) \
|| ((__INJ_SEQ_SCAN_LENGTH__) == LL_ADC_INJ_SEQ_SCAN_ENABLE_3RANKS) \
|| ((__INJ_SEQ_SCAN_LENGTH__) == LL_ADC_INJ_SEQ_SCAN_ENABLE_4RANKS) \
)
#define IS_LL_ADC_INJ_SEQ_SCAN_DISCONT_MODE(__INJ_SEQ_DISCONT_MODE__) \
( ((__INJ_SEQ_DISCONT_MODE__) == LL_ADC_INJ_SEQ_DISCONT_DISABLE) \
|| ((__INJ_SEQ_DISCONT_MODE__) == LL_ADC_INJ_SEQ_DISCONT_1RANK) \
)
#if defined(ADC_MULTIMODE_SUPPORT)
/* Check of parameters for configuration of ADC hierarchical scope: */
/* multimode. */
#define IS_LL_ADC_MULTI_MODE(__MULTI_MODE__) \
( ((__MULTI_MODE__) == LL_ADC_MULTI_INDEPENDENT) \
|| ((__MULTI_MODE__) == LL_ADC_MULTI_DUAL_REG_SIMULT) \
|| ((__MULTI_MODE__) == LL_ADC_MULTI_DUAL_REG_INTERL_FAST) \
|| ((__MULTI_MODE__) == LL_ADC_MULTI_DUAL_REG_INTERL_SLOW) \
|| ((__MULTI_MODE__) == LL_ADC_MULTI_DUAL_INJ_SIMULT) \
|| ((__MULTI_MODE__) == LL_ADC_MULTI_DUAL_INJ_ALTERN) \
|| ((__MULTI_MODE__) == LL_ADC_MULTI_DUAL_REG_SIM_INJ_SIM) \
|| ((__MULTI_MODE__) == LL_ADC_MULTI_DUAL_REG_SIM_INJ_ALT) \
|| ((__MULTI_MODE__) == LL_ADC_MULTI_DUAL_REG_INTFAST_INJ_SIM) \
|| ((__MULTI_MODE__) == LL_ADC_MULTI_DUAL_REG_INTSLOW_INJ_SIM) \
)
#define IS_LL_ADC_MULTI_MASTER_SLAVE(__MULTI_MASTER_SLAVE__) \
( ((__MULTI_MASTER_SLAVE__) == LL_ADC_MULTI_MASTER) \
|| ((__MULTI_MASTER_SLAVE__) == LL_ADC_MULTI_SLAVE) \
|| ((__MULTI_MASTER_SLAVE__) == LL_ADC_MULTI_MASTER_SLAVE) \
)
#endif /* ADC_MULTIMODE_SUPPORT */
/**
* @}
*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup ADC_LL_Exported_Functions
* @{
*/
/** @addtogroup ADC_LL_EF_Init
* @{
*/
/**
* @brief De-initialize registers of all ADC instances belonging to
* the same ADC common instance to their default reset values.
* @param ADCxy_COMMON ADC common instance
* (can be set directly from CMSIS definition or by using helper macro @ref __LL_ADC_COMMON_INSTANCE() )
* @retval An ErrorStatus enumeration value:
* - SUCCESS: ADC common registers are de-initialized
* - ERROR: not applicable
*/
ErrorStatus LL_ADC_CommonDeInit(ADC_Common_TypeDef *ADCxy_COMMON)
{
/* Check the parameters */
assert_param(IS_ADC_COMMON_INSTANCE(ADCxy_COMMON));
/* Force reset of ADC clock (core clock) */
LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_ADC1);
/* Release reset of ADC clock (core clock) */
LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_ADC1);
return SUCCESS;
}
/**
* @brief Initialize some features of ADC common parameters
* (all ADC instances belonging to the same ADC common instance)
* and multimode (for devices with several ADC instances available).
* @note The setting of ADC common parameters is conditioned to
* ADC instances state:
* All ADC instances belonging to the same ADC common instance
* must be disabled.
* @param ADCxy_COMMON ADC common instance
* (can be set directly from CMSIS definition or by using helper macro @ref __LL_ADC_COMMON_INSTANCE() )
* @param ADC_CommonInitStruct Pointer to a @ref LL_ADC_CommonInitTypeDef structure
* @retval An ErrorStatus enumeration value:
* - SUCCESS: ADC common registers are initialized
* - ERROR: ADC common registers are not initialized
*/
ErrorStatus LL_ADC_CommonInit(ADC_Common_TypeDef *ADCxy_COMMON, LL_ADC_CommonInitTypeDef *ADC_CommonInitStruct)
{
ErrorStatus status = SUCCESS;
/* Check the parameters */
assert_param(IS_ADC_COMMON_INSTANCE(ADCxy_COMMON));
#if defined(ADC_MULTIMODE_SUPPORT)
assert_param(IS_LL_ADC_MULTI_MODE(ADC_CommonInitStruct->Multimode));
#endif /* ADC_MULTIMODE_SUPPORT */
/* Note: Hardware constraint (refer to description of functions */
/* "LL_ADC_SetCommonXXX()" and "LL_ADC_SetMultiXXX()"): */
/* On this STM32 series, setting of these features is conditioned to */
/* ADC state: */
/* All ADC instances of the ADC common group must be disabled. */
if(__LL_ADC_IS_ENABLED_ALL_COMMON_INSTANCE(ADCxy_COMMON) == 0U)
{
/* Configuration of ADC hierarchical scope: */
/* - common to several ADC */
/* (all ADC instances belonging to the same ADC common instance) */
/* - multimode (if several ADC instances available on the */
/* selected device) */
/* - Set ADC multimode configuration */
/* - Set ADC multimode DMA transfer */
/* - Set ADC multimode: delay between 2 sampling phases */
#if defined(ADC_MULTIMODE_SUPPORT)
if(ADC_CommonInitStruct->Multimode != LL_ADC_MULTI_INDEPENDENT)
{
MODIFY_REG(ADCxy_COMMON->CR1,
ADC_CR1_DUALMOD,
ADC_CommonInitStruct->Multimode
);
}
else
{
MODIFY_REG(ADCxy_COMMON->CR1,
ADC_CR1_DUALMOD,
LL_ADC_MULTI_INDEPENDENT
);
}
#endif
}
else
{
/* Initialization error: One or several ADC instances belonging to */
/* the same ADC common instance are not disabled. */
status = ERROR;
}
return status;
}
/**
* @brief Set each @ref LL_ADC_CommonInitTypeDef field to default value.
* @param ADC_CommonInitStruct Pointer to a @ref LL_ADC_CommonInitTypeDef structure
* whose fields will be set to default values.
* @retval None
*/
void LL_ADC_CommonStructInit(LL_ADC_CommonInitTypeDef *ADC_CommonInitStruct)
{
/* Set ADC_CommonInitStruct fields to default values */
/* Set fields of ADC common */
/* (all ADC instances belonging to the same ADC common instance) */
#if defined(ADC_MULTIMODE_SUPPORT)
/* Set fields of ADC multimode */
ADC_CommonInitStruct->Multimode = LL_ADC_MULTI_INDEPENDENT;
#endif /* ADC_MULTIMODE_SUPPORT */
}
/**
* @brief De-initialize registers of the selected ADC instance
* to their default reset values.
* @note To reset all ADC instances quickly (perform a hard reset),
* use function @ref LL_ADC_CommonDeInit().
* @param ADCx ADC instance
* @retval An ErrorStatus enumeration value:
* - SUCCESS: ADC registers are de-initialized
* - ERROR: ADC registers are not de-initialized
*/
ErrorStatus LL_ADC_DeInit(ADC_TypeDef *ADCx)
{
ErrorStatus status = SUCCESS;
/* Check the parameters */
assert_param(IS_ADC_ALL_INSTANCE(ADCx));
/* Disable ADC instance if not already disabled. */
if(LL_ADC_IsEnabled(ADCx) == 1U)
{
/* Set ADC group regular trigger source to SW start to ensure to not */
/* have an external trigger event occurring during the conversion stop */
/* ADC disable process. */
LL_ADC_REG_SetTriggerSource(ADCx, LL_ADC_REG_TRIG_SOFTWARE);
/* Set ADC group injected trigger source to SW start to ensure to not */
/* have an external trigger event occurring during the conversion stop */
/* ADC disable process. */
LL_ADC_INJ_SetTriggerSource(ADCx, LL_ADC_INJ_TRIG_SOFTWARE);
/* Disable the ADC instance */
LL_ADC_Disable(ADCx);
}
/* Check whether ADC state is compliant with expected state */
/* (hardware requirements of bits state to reset registers below) */
if(READ_BIT(ADCx->CR2, ADC_CR2_ADON) == 0U)
{
/* ========== Reset ADC registers ========== */
/* Reset register SR */
CLEAR_BIT(ADCx->SR,
( LL_ADC_FLAG_STRT
| LL_ADC_FLAG_JSTRT
| LL_ADC_FLAG_EOS
| LL_ADC_FLAG_JEOS
| LL_ADC_FLAG_AWD1 )
);
/* Reset register CR1 */
#if defined (STM32F103x6) || defined (STM32F103xB) || defined (STM32F105xC) || defined (STM32F107xC) || defined (STM32F103xE) || defined (STM32F103xG)
CLEAR_BIT(ADCx->CR1,
( ADC_CR1_AWDEN | ADC_CR1_JAWDEN | ADC_CR1_DUALMOD
| ADC_CR1_DISCNUM | ADC_CR1_JDISCEN | ADC_CR1_DISCEN
| ADC_CR1_JAUTO | ADC_CR1_AWDSGL | ADC_CR1_SCAN
| ADC_CR1_JEOCIE | ADC_CR1_AWDIE | ADC_CR1_EOCIE
| ADC_CR1_AWDCH )
);
#else
CLEAR_BIT(ADCx->CR1,
( ADC_CR1_AWDEN | ADC_CR1_JAWDEN | ADC_CR1_DISCNUM
| ADC_CR1_JDISCEN | ADC_CR1_DISCEN | ADC_CR1_JAUTO
| ADC_CR1_AWDSGL | ADC_CR1_SCAN | ADC_CR1_JEOCIE
| ADC_CR1_AWDIE | ADC_CR1_EOCIE | ADC_CR1_AWDCH )
);
#endif
/* Reset register CR2 */
CLEAR_BIT(ADCx->CR2,
( ADC_CR2_TSVREFE
| ADC_CR2_SWSTART | ADC_CR2_EXTTRIG | ADC_CR2_EXTSEL
| ADC_CR2_JSWSTART | ADC_CR2_JEXTTRIG | ADC_CR2_JEXTSEL
| ADC_CR2_ALIGN | ADC_CR2_DMA
| ADC_CR2_RSTCAL | ADC_CR2_CAL
| ADC_CR2_CONT | ADC_CR2_ADON )
);
/* Reset register SMPR1 */
CLEAR_BIT(ADCx->SMPR1,
( ADC_SMPR1_SMP17 | ADC_SMPR1_SMP16
| ADC_SMPR1_SMP15 | ADC_SMPR1_SMP14 | ADC_SMPR1_SMP13
| ADC_SMPR1_SMP12 | ADC_SMPR1_SMP11 | ADC_SMPR1_SMP10)
);
/* Reset register SMPR2 */
CLEAR_BIT(ADCx->SMPR2,
( ADC_SMPR2_SMP9
| ADC_SMPR2_SMP8 | ADC_SMPR2_SMP7 | ADC_SMPR2_SMP6
| ADC_SMPR2_SMP5 | ADC_SMPR2_SMP4 | ADC_SMPR2_SMP3
| ADC_SMPR2_SMP2 | ADC_SMPR2_SMP1 | ADC_SMPR2_SMP0)
);
/* Reset register JOFR1 */
CLEAR_BIT(ADCx->JOFR1, ADC_JOFR1_JOFFSET1);
/* Reset register JOFR2 */
CLEAR_BIT(ADCx->JOFR2, ADC_JOFR2_JOFFSET2);
/* Reset register JOFR3 */
CLEAR_BIT(ADCx->JOFR3, ADC_JOFR3_JOFFSET3);
/* Reset register JOFR4 */
CLEAR_BIT(ADCx->JOFR4, ADC_JOFR4_JOFFSET4);
/* Reset register HTR */
SET_BIT(ADCx->HTR, ADC_HTR_HT);
/* Reset register LTR */
CLEAR_BIT(ADCx->LTR, ADC_LTR_LT);
/* Reset register SQR1 */
CLEAR_BIT(ADCx->SQR1,
( ADC_SQR1_L
| ADC_SQR1_SQ16
| ADC_SQR1_SQ15 | ADC_SQR1_SQ14 | ADC_SQR1_SQ13)
);
/* Reset register SQR2 */
CLEAR_BIT(ADCx->SQR2,
( ADC_SQR2_SQ12 | ADC_SQR2_SQ11 | ADC_SQR2_SQ10
| ADC_SQR2_SQ9 | ADC_SQR2_SQ8 | ADC_SQR2_SQ7)
);
/* Reset register SQR3 */
CLEAR_BIT(ADCx->SQR3,
( ADC_SQR3_SQ6 | ADC_SQR3_SQ5 | ADC_SQR3_SQ4
| ADC_SQR3_SQ3 | ADC_SQR3_SQ2 | ADC_SQR3_SQ1)
);
/* Reset register JSQR */
CLEAR_BIT(ADCx->JSQR,
( ADC_JSQR_JL
| ADC_JSQR_JSQ4 | ADC_JSQR_JSQ3
| ADC_JSQR_JSQ2 | ADC_JSQR_JSQ1 )
);
/* Reset register DR */
/* bits in access mode read only, no direct reset applicable */
/* Reset registers JDR1, JDR2, JDR3, JDR4 */
/* bits in access mode read only, no direct reset applicable */
}
return status;
}
/**
* @brief Initialize some features of ADC instance.
* @note These parameters have an impact on ADC scope: ADC instance.
* Affects both group regular and group injected (availability
* of ADC group injected depends on STM32 families).
* Refer to corresponding unitary functions into
* @ref ADC_LL_EF_Configuration_ADC_Instance .
* @note The setting of these parameters by function @ref LL_ADC_Init()
* is conditioned to ADC state:
* ADC instance must be disabled.
* This condition is applied to all ADC features, for efficiency
* and compatibility over all STM32 families. However, the different
* features can be set under different ADC state conditions
* (setting possible with ADC enabled without conversion on going,
* ADC enabled with conversion on going, ...)
* Each feature can be updated afterwards with a unitary function
* and potentially with ADC in a different state than disabled,
* refer to description of each function for setting
* conditioned to ADC state.
* @note After using this function, some other features must be configured
* using LL unitary functions.
* The minimum configuration remaining to be done is:
* - Set ADC group regular or group injected sequencer:
* map channel on the selected sequencer rank.
* Refer to function @ref LL_ADC_REG_SetSequencerRanks().
* - Set ADC channel sampling time
* Refer to function LL_ADC_SetChannelSamplingTime();
* @param ADCx ADC instance
* @param ADC_InitStruct Pointer to a @ref LL_ADC_REG_InitTypeDef structure
* @retval An ErrorStatus enumeration value:
* - SUCCESS: ADC registers are initialized
* - ERROR: ADC registers are not initialized
*/
ErrorStatus LL_ADC_Init(ADC_TypeDef *ADCx, LL_ADC_InitTypeDef *ADC_InitStruct)
{
ErrorStatus status = SUCCESS;
/* Check the parameters */
assert_param(IS_ADC_ALL_INSTANCE(ADCx));
assert_param(IS_LL_ADC_DATA_ALIGN(ADC_InitStruct->DataAlignment));
assert_param(IS_LL_ADC_SCAN_SELECTION(ADC_InitStruct->SequencersScanMode));
/* Note: Hardware constraint (refer to description of this function): */
/* ADC instance must be disabled. */
if(LL_ADC_IsEnabled(ADCx) == 0U)
{
/* Configuration of ADC hierarchical scope: */
/* - ADC instance */
/* - Set ADC conversion data alignment */
MODIFY_REG(ADCx->CR1,
ADC_CR1_SCAN
,
ADC_InitStruct->SequencersScanMode
);
MODIFY_REG(ADCx->CR2,
ADC_CR2_ALIGN
,
ADC_InitStruct->DataAlignment
);
}
else
{
/* Initialization error: ADC instance is not disabled. */
status = ERROR;
}
return status;
}
/**
* @brief Set each @ref LL_ADC_InitTypeDef field to default value.
* @param ADC_InitStruct Pointer to a @ref LL_ADC_InitTypeDef structure
* whose fields will be set to default values.
* @retval None
*/
void LL_ADC_StructInit(LL_ADC_InitTypeDef *ADC_InitStruct)
{
/* Set ADC_InitStruct fields to default values */
/* Set fields of ADC instance */
ADC_InitStruct->DataAlignment = LL_ADC_DATA_ALIGN_RIGHT;
/* Enable scan mode to have a generic behavior with ADC of other */
/* STM32 families, without this setting available: */
/* ADC group regular sequencer and ADC group injected sequencer depend */
/* only of their own configuration. */
ADC_InitStruct->SequencersScanMode = LL_ADC_SEQ_SCAN_ENABLE;
}
/**
* @brief Initialize some features of ADC group regular.
* @note These parameters have an impact on ADC scope: ADC group regular.
* Refer to corresponding unitary functions into
* @ref ADC_LL_EF_Configuration_ADC_Group_Regular
* (functions with prefix "REG").
* @note The setting of these parameters by function @ref LL_ADC_Init()
* is conditioned to ADC state:
* ADC instance must be disabled.
* This condition is applied to all ADC features, for efficiency
* and compatibility over all STM32 families. However, the different
* features can be set under different ADC state conditions
* (setting possible with ADC enabled without conversion on going,
* ADC enabled with conversion on going, ...)
* Each feature can be updated afterwards with a unitary function
* and potentially with ADC in a different state than disabled,
* refer to description of each function for setting
* conditioned to ADC state.
* @note After using this function, other features must be configured
* using LL unitary functions.
* The minimum configuration remaining to be done is:
* - Set ADC group regular or group injected sequencer:
* map channel on the selected sequencer rank.
* Refer to function @ref LL_ADC_REG_SetSequencerRanks().
* - Set ADC channel sampling time
* Refer to function LL_ADC_SetChannelSamplingTime();
* @param ADCx ADC instance
* @param ADC_REG_InitStruct Pointer to a @ref LL_ADC_REG_InitTypeDef structure
* @retval An ErrorStatus enumeration value:
* - SUCCESS: ADC registers are initialized
* - ERROR: ADC registers are not initialized
*/
ErrorStatus LL_ADC_REG_Init(ADC_TypeDef *ADCx, LL_ADC_REG_InitTypeDef *ADC_REG_InitStruct)
{
ErrorStatus status = SUCCESS;
/* Check the parameters */
assert_param(IS_ADC_ALL_INSTANCE(ADCx));
#if defined(ADC3)
assert_param(IS_LL_ADC_REG_TRIG_SOURCE(ADCx, ADC_REG_InitStruct->TriggerSource));
#else
assert_param(IS_LL_ADC_REG_TRIG_SOURCE(ADC_REG_InitStruct->TriggerSource));
#endif
assert_param(IS_LL_ADC_REG_SEQ_SCAN_LENGTH(ADC_REG_InitStruct->SequencerLength));
if(ADC_REG_InitStruct->SequencerLength != LL_ADC_REG_SEQ_SCAN_DISABLE)
{
assert_param(IS_LL_ADC_REG_SEQ_SCAN_DISCONT_MODE(ADC_REG_InitStruct->SequencerDiscont));
}
assert_param(IS_LL_ADC_REG_CONTINUOUS_MODE(ADC_REG_InitStruct->ContinuousMode));
assert_param(IS_LL_ADC_REG_DMA_TRANSFER(ADC_REG_InitStruct->DMATransfer));
/* ADC group regular continuous mode and discontinuous mode */
/* can not be enabled simultenaeously */
assert_param((ADC_REG_InitStruct->ContinuousMode == LL_ADC_REG_CONV_SINGLE)
|| (ADC_REG_InitStruct->SequencerDiscont == LL_ADC_REG_SEQ_DISCONT_DISABLE));
/* Note: Hardware constraint (refer to description of this function): */
/* ADC instance must be disabled. */
if(LL_ADC_IsEnabled(ADCx) == 0U)
{
/* Configuration of ADC hierarchical scope: */
/* - ADC group regular */
/* - Set ADC group regular trigger source */
/* - Set ADC group regular sequencer length */
/* - Set ADC group regular sequencer discontinuous mode */
/* - Set ADC group regular continuous mode */
/* - Set ADC group regular conversion data transfer: no transfer or */
/* transfer by DMA, and DMA requests mode */
/* Note: On this STM32 series, ADC trigger edge is set when starting */
/* ADC conversion. */
/* Refer to function @ref LL_ADC_REG_StartConversionExtTrig(). */
if(ADC_REG_InitStruct->SequencerLength != LL_ADC_REG_SEQ_SCAN_DISABLE)
{
MODIFY_REG(ADCx->CR1,
ADC_CR1_DISCEN
| ADC_CR1_DISCNUM
,
ADC_REG_InitStruct->SequencerLength
| ADC_REG_InitStruct->SequencerDiscont
);
}
else
{
MODIFY_REG(ADCx->CR1,
ADC_CR1_DISCEN
| ADC_CR1_DISCNUM
,
ADC_REG_InitStruct->SequencerLength
| LL_ADC_REG_SEQ_DISCONT_DISABLE
);
}
MODIFY_REG(ADCx->CR2,
ADC_CR2_EXTSEL
| ADC_CR2_CONT
| ADC_CR2_DMA
,
ADC_REG_InitStruct->TriggerSource
| ADC_REG_InitStruct->ContinuousMode
| ADC_REG_InitStruct->DMATransfer
);
/* Set ADC group regular sequencer length and scan direction */
/* Note: Hardware constraint (refer to description of this function): */
/* Note: If ADC instance feature scan mode is disabled */
/* (refer to ADC instance initialization structure */
/* parameter @ref SequencersScanMode */
/* or function @ref LL_ADC_SetSequencersScanMode() ), */
/* this parameter is discarded. */
LL_ADC_REG_SetSequencerLength(ADCx, ADC_REG_InitStruct->SequencerLength);
}
else
{
/* Initialization error: ADC instance is not disabled. */
status = ERROR;
}
return status;
}
/**
* @brief Set each @ref LL_ADC_REG_InitTypeDef field to default value.
* @param ADC_REG_InitStruct Pointer to a @ref LL_ADC_REG_InitTypeDef structure
* whose fields will be set to default values.
* @retval None
*/
void LL_ADC_REG_StructInit(LL_ADC_REG_InitTypeDef *ADC_REG_InitStruct)
{
/* Set ADC_REG_InitStruct fields to default values */
/* Set fields of ADC group regular */
/* Note: On this STM32 series, ADC trigger edge is set when starting */
/* ADC conversion. */
/* Refer to function @ref LL_ADC_REG_StartConversionExtTrig(). */
ADC_REG_InitStruct->TriggerSource = LL_ADC_REG_TRIG_SOFTWARE;
ADC_REG_InitStruct->SequencerLength = LL_ADC_REG_SEQ_SCAN_DISABLE;
ADC_REG_InitStruct->SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE;
ADC_REG_InitStruct->ContinuousMode = LL_ADC_REG_CONV_SINGLE;
ADC_REG_InitStruct->DMATransfer = LL_ADC_REG_DMA_TRANSFER_NONE;
}
/**
* @brief Initialize some features of ADC group injected.
* @note These parameters have an impact on ADC scope: ADC group injected.
* Refer to corresponding unitary functions into
* @ref ADC_LL_EF_Configuration_ADC_Group_Regular
* (functions with prefix "INJ").
* @note The setting of these parameters by function @ref LL_ADC_Init()
* is conditioned to ADC state:
* ADC instance must be disabled.
* This condition is applied to all ADC features, for efficiency
* and compatibility over all STM32 families. However, the different
* features can be set under different ADC state conditions
* (setting possible with ADC enabled without conversion on going,
* ADC enabled with conversion on going, ...)
* Each feature can be updated afterwards with a unitary function
* and potentially with ADC in a different state than disabled,
* refer to description of each function for setting
* conditioned to ADC state.
* @note After using this function, other features must be configured
* using LL unitary functions.
* The minimum configuration remaining to be done is:
* - Set ADC group injected sequencer:
* map channel on the selected sequencer rank.
* Refer to function @ref LL_ADC_INJ_SetSequencerRanks().
* - Set ADC channel sampling time
* Refer to function LL_ADC_SetChannelSamplingTime();
* @param ADCx ADC instance
* @param ADC_INJ_InitStruct Pointer to a @ref LL_ADC_INJ_InitTypeDef structure
* @retval An ErrorStatus enumeration value:
* - SUCCESS: ADC registers are initialized
* - ERROR: ADC registers are not initialized
*/
ErrorStatus LL_ADC_INJ_Init(ADC_TypeDef *ADCx, LL_ADC_INJ_InitTypeDef *ADC_INJ_InitStruct)
{
ErrorStatus status = SUCCESS;
/* Check the parameters */
assert_param(IS_ADC_ALL_INSTANCE(ADCx));
#if defined(ADC3)
assert_param(IS_LL_ADC_INJ_TRIG_SOURCE(ADCx, ADC_INJ_InitStruct->TriggerSource));
#else
assert_param(IS_LL_ADC_INJ_TRIG_SOURCE(ADC_INJ_InitStruct->TriggerSource));
#endif
assert_param(IS_LL_ADC_INJ_SEQ_SCAN_LENGTH(ADC_INJ_InitStruct->SequencerLength));
if(ADC_INJ_InitStruct->SequencerLength != LL_ADC_INJ_SEQ_SCAN_DISABLE)
{
assert_param(IS_LL_ADC_INJ_SEQ_SCAN_DISCONT_MODE(ADC_INJ_InitStruct->SequencerDiscont));
}
assert_param(IS_LL_ADC_INJ_TRIG_AUTO(ADC_INJ_InitStruct->TrigAuto));
/* Note: Hardware constraint (refer to description of this function): */
/* ADC instance must be disabled. */
if(LL_ADC_IsEnabled(ADCx) == 0U)
{
/* Configuration of ADC hierarchical scope: */
/* - ADC group injected */
/* - Set ADC group injected trigger source */
/* - Set ADC group injected sequencer length */
/* - Set ADC group injected sequencer discontinuous mode */
/* - Set ADC group injected conversion trigger: independent or */
/* from ADC group regular */
/* Note: On this STM32 series, ADC trigger edge is set when starting */
/* ADC conversion. */
/* Refer to function @ref LL_ADC_INJ_StartConversionExtTrig(). */
if(ADC_INJ_InitStruct->SequencerLength != LL_ADC_REG_SEQ_SCAN_DISABLE)
{
MODIFY_REG(ADCx->CR1,
ADC_CR1_JDISCEN
| ADC_CR1_JAUTO
,
ADC_INJ_InitStruct->SequencerDiscont
| ADC_INJ_InitStruct->TrigAuto
);
}
else
{
MODIFY_REG(ADCx->CR1,
ADC_CR1_JDISCEN
| ADC_CR1_JAUTO
,
LL_ADC_REG_SEQ_DISCONT_DISABLE
| ADC_INJ_InitStruct->TrigAuto
);
}
MODIFY_REG(ADCx->CR2,
ADC_CR2_JEXTSEL
,
ADC_INJ_InitStruct->TriggerSource
);
/* Note: Hardware constraint (refer to description of this function): */
/* Note: If ADC instance feature scan mode is disabled */
/* (refer to ADC instance initialization structure */
/* parameter @ref SequencersScanMode */
/* or function @ref LL_ADC_SetSequencersScanMode() ), */
/* this parameter is discarded. */
LL_ADC_INJ_SetSequencerLength(ADCx, ADC_INJ_InitStruct->SequencerLength);
}
else
{
/* Initialization error: ADC instance is not disabled. */
status = ERROR;
}
return status;
}
/**
* @brief Set each @ref LL_ADC_INJ_InitTypeDef field to default value.
* @param ADC_INJ_InitStruct Pointer to a @ref LL_ADC_INJ_InitTypeDef structure
* whose fields will be set to default values.
* @retval None
*/
void LL_ADC_INJ_StructInit(LL_ADC_INJ_InitTypeDef *ADC_INJ_InitStruct)
{
/* Set ADC_INJ_InitStruct fields to default values */
/* Set fields of ADC group injected */
ADC_INJ_InitStruct->TriggerSource = LL_ADC_INJ_TRIG_SOFTWARE;
ADC_INJ_InitStruct->SequencerLength = LL_ADC_INJ_SEQ_SCAN_DISABLE;
ADC_INJ_InitStruct->SequencerDiscont = LL_ADC_INJ_SEQ_DISCONT_DISABLE;
ADC_INJ_InitStruct->TrigAuto = LL_ADC_INJ_TRIG_INDEPENDENT;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#endif /* ADC1 || ADC2 || ADC3 */
/**
* @}
*/
#endif /* USE_FULL_LL_DRIVER */

View File

@@ -0,0 +1,104 @@
/**
******************************************************************************
* @file stm32f1xx_ll_crc.c
* @author MCD Application Team
* @brief CRC LL module driver.
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#if defined(USE_FULL_LL_DRIVER)
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_ll_crc.h"
#include "stm32f1xx_ll_bus.h"
#ifdef USE_FULL_ASSERT
#include "stm32_assert.h"
#else
#define assert_param(expr) ((void)0U)
#endif /* USE_FULL_ASSERT */
/** @addtogroup STM32F1xx_LL_Driver
* @{
*/
#if defined (CRC)
/** @addtogroup CRC_LL
* @{
*/
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup CRC_LL_Exported_Functions
* @{
*/
/** @addtogroup CRC_LL_EF_Init
* @{
*/
/**
* @brief De-initialize CRC registers (Registers restored to their default values).
* @param CRCx CRC Instance
* @retval An ErrorStatus enumeration value:
* - SUCCESS: CRC registers are de-initialized
* - ERROR: CRC registers are not de-initialized
*/
ErrorStatus LL_CRC_DeInit(CRC_TypeDef *CRCx)
{
ErrorStatus status = SUCCESS;
/* Check the parameters */
assert_param(IS_CRC_ALL_INSTANCE(CRCx));
if (CRCx == CRC)
{
/* Reset the CRC calculation unit */
LL_CRC_ResetCRCCalculationUnit(CRCx);
/* Reset IDR register */
LL_CRC_Write_IDR(CRCx, 0x00U);
}
else
{
status = ERROR;
}
return (status);
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#endif /* defined (CRC) */
/**
* @}
*/
#endif /* USE_FULL_LL_DRIVER */

View File

@@ -0,0 +1,270 @@
/**
******************************************************************************
* @file stm32f1xx_ll_dac.c
* @author MCD Application Team
* @brief DAC LL module driver
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#if defined(USE_FULL_LL_DRIVER)
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_ll_dac.h"
#include "stm32f1xx_ll_bus.h"
#ifdef USE_FULL_ASSERT
#include "stm32_assert.h"
#else
#define assert_param(expr) ((void)0U)
#endif /* USE_FULL_ASSERT */
/** @addtogroup STM32F1xx_LL_Driver
* @{
*/
#if defined(DAC)
/** @addtogroup DAC_LL DAC
* @{
*/
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/** @addtogroup DAC_LL_Private_Macros
* @{
*/
#define IS_LL_DAC_CHANNEL(__DAC_CHANNEL__) \
(((__DAC_CHANNEL__) == LL_DAC_CHANNEL_1) \
|| ((__DAC_CHANNEL__) == LL_DAC_CHANNEL_2) \
)
#define IS_LL_DAC_TRIGGER_SOURCE(__TRIGGER_SOURCE__) \
(((__TRIGGER_SOURCE__) == LL_DAC_TRIG_SOFTWARE) \
|| ((__TRIGGER_SOURCE__) == LL_DAC_TRIG_EXT_TIM3_TRGO) \
|| ((__TRIGGER_SOURCE__) == LL_DAC_TRIG_EXT_TIM15_TRGO) \
|| ((__TRIGGER_SOURCE__) == LL_DAC_TRIG_EXT_TIM2_TRGO) \
|| ((__TRIGGER_SOURCE__) == LL_DAC_TRIG_EXT_TIM4_TRGO) \
|| ((__TRIGGER_SOURCE__) == LL_DAC_TRIG_EXT_TIM5_TRGO) \
|| ((__TRIGGER_SOURCE__) == LL_DAC_TRIG_EXT_TIM6_TRGO) \
|| ((__TRIGGER_SOURCE__) == LL_DAC_TRIG_EXT_TIM7_TRGO) \
|| ((__TRIGGER_SOURCE__) == LL_DAC_TRIG_EXT_TIM8_TRGO) \
|| ((__TRIGGER_SOURCE__) == LL_DAC_TRIG_EXT_EXTI_LINE9) \
)
#define IS_LL_DAC_WAVE_AUTO_GENER_MODE(__WAVE_AUTO_GENERATION_MODE__) \
(((__WAVE_AUTO_GENERATION_MODE__) == LL_DAC_WAVE_AUTO_GENERATION_NONE) \
|| ((__WAVE_AUTO_GENERATION_MODE__) == LL_DAC_WAVE_AUTO_GENERATION_NOISE) \
|| ((__WAVE_AUTO_GENERATION_MODE__) == LL_DAC_WAVE_AUTO_GENERATION_TRIANGLE) \
)
#define IS_LL_DAC_WAVE_AUTO_GENER_CONFIG(__WAVE_AUTO_GENERATION_MODE__, __WAVE_AUTO_GENERATION_CONFIG__) \
( (((__WAVE_AUTO_GENERATION_MODE__) == LL_DAC_WAVE_AUTO_GENERATION_NOISE) \
&& (((__WAVE_AUTO_GENERATION_CONFIG__) == LL_DAC_NOISE_LFSR_UNMASK_BIT0) \
|| ((__WAVE_AUTO_GENERATION_CONFIG__) == LL_DAC_NOISE_LFSR_UNMASK_BITS1_0) \
|| ((__WAVE_AUTO_GENERATION_CONFIG__) == LL_DAC_NOISE_LFSR_UNMASK_BITS2_0) \
|| ((__WAVE_AUTO_GENERATION_CONFIG__) == LL_DAC_NOISE_LFSR_UNMASK_BITS3_0) \
|| ((__WAVE_AUTO_GENERATION_CONFIG__) == LL_DAC_NOISE_LFSR_UNMASK_BITS4_0) \
|| ((__WAVE_AUTO_GENERATION_CONFIG__) == LL_DAC_NOISE_LFSR_UNMASK_BITS5_0) \
|| ((__WAVE_AUTO_GENERATION_CONFIG__) == LL_DAC_NOISE_LFSR_UNMASK_BITS6_0) \
|| ((__WAVE_AUTO_GENERATION_CONFIG__) == LL_DAC_NOISE_LFSR_UNMASK_BITS7_0) \
|| ((__WAVE_AUTO_GENERATION_CONFIG__) == LL_DAC_NOISE_LFSR_UNMASK_BITS8_0) \
|| ((__WAVE_AUTO_GENERATION_CONFIG__) == LL_DAC_NOISE_LFSR_UNMASK_BITS9_0) \
|| ((__WAVE_AUTO_GENERATION_CONFIG__) == LL_DAC_NOISE_LFSR_UNMASK_BITS10_0) \
|| ((__WAVE_AUTO_GENERATION_CONFIG__) == LL_DAC_NOISE_LFSR_UNMASK_BITS11_0)) \
) \
||(((__WAVE_AUTO_GENERATION_MODE__) == LL_DAC_WAVE_AUTO_GENERATION_TRIANGLE) \
&& (((__WAVE_AUTO_GENERATION_CONFIG__) == LL_DAC_TRIANGLE_AMPLITUDE_1) \
|| ((__WAVE_AUTO_GENERATION_CONFIG__) == LL_DAC_TRIANGLE_AMPLITUDE_3) \
|| ((__WAVE_AUTO_GENERATION_CONFIG__) == LL_DAC_TRIANGLE_AMPLITUDE_7) \
|| ((__WAVE_AUTO_GENERATION_CONFIG__) == LL_DAC_TRIANGLE_AMPLITUDE_15) \
|| ((__WAVE_AUTO_GENERATION_CONFIG__) == LL_DAC_TRIANGLE_AMPLITUDE_31) \
|| ((__WAVE_AUTO_GENERATION_CONFIG__) == LL_DAC_TRIANGLE_AMPLITUDE_63) \
|| ((__WAVE_AUTO_GENERATION_CONFIG__) == LL_DAC_TRIANGLE_AMPLITUDE_127) \
|| ((__WAVE_AUTO_GENERATION_CONFIG__) == LL_DAC_TRIANGLE_AMPLITUDE_255) \
|| ((__WAVE_AUTO_GENERATION_CONFIG__) == LL_DAC_TRIANGLE_AMPLITUDE_511) \
|| ((__WAVE_AUTO_GENERATION_CONFIG__) == LL_DAC_TRIANGLE_AMPLITUDE_1023) \
|| ((__WAVE_AUTO_GENERATION_CONFIG__) == LL_DAC_TRIANGLE_AMPLITUDE_2047) \
|| ((__WAVE_AUTO_GENERATION_CONFIG__) == LL_DAC_TRIANGLE_AMPLITUDE_4095)) \
) \
)
#define IS_LL_DAC_OUTPUT_BUFFER(__OUTPUT_BUFFER__) \
(((__OUTPUT_BUFFER__) == LL_DAC_OUTPUT_BUFFER_ENABLE) \
|| ((__OUTPUT_BUFFER__) == LL_DAC_OUTPUT_BUFFER_DISABLE) \
)
/**
* @}
*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup DAC_LL_Exported_Functions
* @{
*/
/** @addtogroup DAC_LL_EF_Init
* @{
*/
/**
* @brief De-initialize registers of the selected DAC instance
* to their default reset values.
* @param DACx DAC instance
* @retval An ErrorStatus enumeration value:
* - SUCCESS: DAC registers are de-initialized
* - ERROR: not applicable
*/
ErrorStatus LL_DAC_DeInit(const DAC_TypeDef *DACx)
{
/* Check the parameters */
assert_param(IS_DAC_ALL_INSTANCE(DACx));
/* Force reset of DAC clock */
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_DAC1);
/* Release reset of DAC clock */
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_DAC1);
return SUCCESS;
}
/**
* @brief Initialize some features of DAC channel.
* @note @ref LL_DAC_Init() aims to ease basic configuration of a DAC channel.
* Leaving it ready to be enabled and output:
* a level by calling one of
* @ref LL_DAC_ConvertData12RightAligned
* @ref LL_DAC_ConvertData12LeftAligned
* @ref LL_DAC_ConvertData8RightAligned
* or one of the supported autogenerated wave.
* @note This function allows configuration of:
* - Output mode
* - Trigger
* - Wave generation
* @note The setting of these parameters by function @ref LL_DAC_Init()
* is conditioned to DAC state:
* DAC channel must be disabled.
* @param DACx DAC instance
* @param DAC_Channel This parameter can be one of the following values:
* @arg @ref LL_DAC_CHANNEL_1
* @arg @ref LL_DAC_CHANNEL_2
* @param DAC_InitStruct Pointer to a @ref LL_DAC_InitTypeDef structure
* @retval An ErrorStatus enumeration value:
* - SUCCESS: DAC registers are initialized
* - ERROR: DAC registers are not initialized
*/
ErrorStatus LL_DAC_Init(DAC_TypeDef *DACx, uint32_t DAC_Channel, const LL_DAC_InitTypeDef *DAC_InitStruct)
{
ErrorStatus status = SUCCESS;
/* Check the parameters */
assert_param(IS_DAC_ALL_INSTANCE(DACx));
assert_param(IS_LL_DAC_CHANNEL(DAC_Channel));
assert_param(IS_LL_DAC_TRIGGER_SOURCE(DAC_InitStruct->TriggerSource));
assert_param(IS_LL_DAC_OUTPUT_BUFFER(DAC_InitStruct->OutputBuffer));
assert_param(IS_LL_DAC_WAVE_AUTO_GENER_MODE(DAC_InitStruct->WaveAutoGeneration));
if (DAC_InitStruct->WaveAutoGeneration != LL_DAC_WAVE_AUTO_GENERATION_NONE)
{
assert_param(IS_LL_DAC_WAVE_AUTO_GENER_CONFIG(DAC_InitStruct->WaveAutoGeneration,
DAC_InitStruct->WaveAutoGenerationConfig));
}
/* Note: Hardware constraint (refer to description of this function) */
/* DAC instance must be disabled. */
if (LL_DAC_IsEnabled(DACx, DAC_Channel) == 0UL)
{
/* Configuration of DAC channel: */
/* - TriggerSource */
/* - WaveAutoGeneration */
/* - OutputBuffer */
/* - OutputMode */
if (DAC_InitStruct->WaveAutoGeneration != LL_DAC_WAVE_AUTO_GENERATION_NONE)
{
MODIFY_REG(DACx->CR,
(DAC_CR_TSEL1
| DAC_CR_WAVE1
| DAC_CR_MAMP1
| DAC_CR_BOFF1
) << (DAC_Channel & DAC_CR_CHX_BITOFFSET_MASK)
,
(DAC_InitStruct->TriggerSource
| DAC_InitStruct->WaveAutoGeneration
| DAC_InitStruct->WaveAutoGenerationConfig
| DAC_InitStruct->OutputBuffer
) << (DAC_Channel & DAC_CR_CHX_BITOFFSET_MASK)
);
}
else
{
MODIFY_REG(DACx->CR,
(DAC_CR_TSEL1
| DAC_CR_WAVE1
| DAC_CR_BOFF1
) << (DAC_Channel & DAC_CR_CHX_BITOFFSET_MASK)
,
(DAC_InitStruct->TriggerSource
| LL_DAC_WAVE_AUTO_GENERATION_NONE
| DAC_InitStruct->OutputBuffer
) << (DAC_Channel & DAC_CR_CHX_BITOFFSET_MASK)
);
}
}
else
{
/* Initialization error: DAC instance is not disabled. */
status = ERROR;
}
return status;
}
/**
* @brief Set each @ref LL_DAC_InitTypeDef field to default value.
* @param DAC_InitStruct pointer to a @ref LL_DAC_InitTypeDef structure
* whose fields will be set to default values.
* @retval None
*/
void LL_DAC_StructInit(LL_DAC_InitTypeDef *DAC_InitStruct)
{
/* Set DAC_InitStruct fields to default values */
DAC_InitStruct->TriggerSource = LL_DAC_TRIG_SOFTWARE;
DAC_InitStruct->WaveAutoGeneration = LL_DAC_WAVE_AUTO_GENERATION_NONE;
/* Note: Parameter discarded if wave auto generation is disabled, */
/* set anyway to its default value. */
DAC_InitStruct->WaveAutoGenerationConfig = LL_DAC_NOISE_LFSR_UNMASK_BIT0;
DAC_InitStruct->OutputBuffer = LL_DAC_OUTPUT_BUFFER_ENABLE;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#endif /* DAC */
/**
* @}
*/
#endif /* USE_FULL_LL_DRIVER */

View File

@@ -0,0 +1,312 @@
/**
******************************************************************************
* @file stm32f1xx_ll_dma.c
* @author MCD Application Team
* @brief DMA LL module driver.
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file in
* the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#if defined(USE_FULL_LL_DRIVER)
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_ll_dma.h"
#include "stm32f1xx_ll_bus.h"
#ifdef USE_FULL_ASSERT
#include "stm32_assert.h"
#else
#define assert_param(expr) ((void)0U)
#endif
/** @addtogroup STM32F1xx_LL_Driver
* @{
*/
#if defined (DMA1) || defined (DMA2)
/** @defgroup DMA_LL DMA
* @{
*/
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/** @addtogroup DMA_LL_Private_Macros
* @{
*/
#define IS_LL_DMA_DIRECTION(__VALUE__) (((__VALUE__) == LL_DMA_DIRECTION_PERIPH_TO_MEMORY) || \
((__VALUE__) == LL_DMA_DIRECTION_MEMORY_TO_PERIPH) || \
((__VALUE__) == LL_DMA_DIRECTION_MEMORY_TO_MEMORY))
#define IS_LL_DMA_MODE(__VALUE__) (((__VALUE__) == LL_DMA_MODE_NORMAL) || \
((__VALUE__) == LL_DMA_MODE_CIRCULAR))
#define IS_LL_DMA_PERIPHINCMODE(__VALUE__) (((__VALUE__) == LL_DMA_PERIPH_INCREMENT) || \
((__VALUE__) == LL_DMA_PERIPH_NOINCREMENT))
#define IS_LL_DMA_MEMORYINCMODE(__VALUE__) (((__VALUE__) == LL_DMA_MEMORY_INCREMENT) || \
((__VALUE__) == LL_DMA_MEMORY_NOINCREMENT))
#define IS_LL_DMA_PERIPHDATASIZE(__VALUE__) (((__VALUE__) == LL_DMA_PDATAALIGN_BYTE) || \
((__VALUE__) == LL_DMA_PDATAALIGN_HALFWORD) || \
((__VALUE__) == LL_DMA_PDATAALIGN_WORD))
#define IS_LL_DMA_MEMORYDATASIZE(__VALUE__) (((__VALUE__) == LL_DMA_MDATAALIGN_BYTE) || \
((__VALUE__) == LL_DMA_MDATAALIGN_HALFWORD) || \
((__VALUE__) == LL_DMA_MDATAALIGN_WORD))
#define IS_LL_DMA_NBDATA(__VALUE__) ((__VALUE__) <= 0x0000FFFFU)
#define IS_LL_DMA_PRIORITY(__VALUE__) (((__VALUE__) == LL_DMA_PRIORITY_LOW) || \
((__VALUE__) == LL_DMA_PRIORITY_MEDIUM) || \
((__VALUE__) == LL_DMA_PRIORITY_HIGH) || \
((__VALUE__) == LL_DMA_PRIORITY_VERYHIGH))
#if defined (DMA2)
#define IS_LL_DMA_ALL_CHANNEL_INSTANCE(INSTANCE, CHANNEL) ((((INSTANCE) == DMA1) && \
(((CHANNEL) == LL_DMA_CHANNEL_1) || \
((CHANNEL) == LL_DMA_CHANNEL_2) || \
((CHANNEL) == LL_DMA_CHANNEL_3) || \
((CHANNEL) == LL_DMA_CHANNEL_4) || \
((CHANNEL) == LL_DMA_CHANNEL_5) || \
((CHANNEL) == LL_DMA_CHANNEL_6) || \
((CHANNEL) == LL_DMA_CHANNEL_7))) || \
(((INSTANCE) == DMA2) && \
(((CHANNEL) == LL_DMA_CHANNEL_1) || \
((CHANNEL) == LL_DMA_CHANNEL_2) || \
((CHANNEL) == LL_DMA_CHANNEL_3) || \
((CHANNEL) == LL_DMA_CHANNEL_4) || \
((CHANNEL) == LL_DMA_CHANNEL_5))))
#else
#define IS_LL_DMA_ALL_CHANNEL_INSTANCE(INSTANCE, CHANNEL) ((((INSTANCE) == DMA1) && \
(((CHANNEL) == LL_DMA_CHANNEL_1) || \
((CHANNEL) == LL_DMA_CHANNEL_2) || \
((CHANNEL) == LL_DMA_CHANNEL_3) || \
((CHANNEL) == LL_DMA_CHANNEL_4) || \
((CHANNEL) == LL_DMA_CHANNEL_5) || \
((CHANNEL) == LL_DMA_CHANNEL_6) || \
((CHANNEL) == LL_DMA_CHANNEL_7))))
#endif
/**
* @}
*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup DMA_LL_Exported_Functions
* @{
*/
/** @addtogroup DMA_LL_EF_Init
* @{
*/
/**
* @brief De-initialize the DMA registers to their default reset values.
* @param DMAx DMAx Instance
* @param Channel This parameter can be one of the following values:
* @arg @ref LL_DMA_CHANNEL_1
* @arg @ref LL_DMA_CHANNEL_2
* @arg @ref LL_DMA_CHANNEL_3
* @arg @ref LL_DMA_CHANNEL_4
* @arg @ref LL_DMA_CHANNEL_5
* @arg @ref LL_DMA_CHANNEL_6
* @arg @ref LL_DMA_CHANNEL_7
* @retval An ErrorStatus enumeration value:
* - SUCCESS: DMA registers are de-initialized
* - ERROR: DMA registers are not de-initialized
*/
uint32_t LL_DMA_DeInit(DMA_TypeDef *DMAx, uint32_t Channel)
{
DMA_Channel_TypeDef *tmp = (DMA_Channel_TypeDef *)DMA1_Channel1;
ErrorStatus status = SUCCESS;
/* Check the DMA Instance DMAx and Channel parameters*/
assert_param(IS_LL_DMA_ALL_CHANNEL_INSTANCE(DMAx, Channel));
tmp = (DMA_Channel_TypeDef *)(__LL_DMA_GET_CHANNEL_INSTANCE(DMAx, Channel));
/* Disable the selected DMAx_Channely */
CLEAR_BIT(tmp->CCR, DMA_CCR_EN);
/* Reset DMAx_Channely control register */
LL_DMA_WriteReg(tmp, CCR, 0U);
/* Reset DMAx_Channely remaining bytes register */
LL_DMA_WriteReg(tmp, CNDTR, 0U);
/* Reset DMAx_Channely peripheral address register */
LL_DMA_WriteReg(tmp, CPAR, 0U);
/* Reset DMAx_Channely memory address register */
LL_DMA_WriteReg(tmp, CMAR, 0U);
if (Channel == LL_DMA_CHANNEL_1)
{
/* Reset interrupt pending bits for DMAx Channel1 */
LL_DMA_ClearFlag_GI1(DMAx);
}
else if (Channel == LL_DMA_CHANNEL_2)
{
/* Reset interrupt pending bits for DMAx Channel2 */
LL_DMA_ClearFlag_GI2(DMAx);
}
else if (Channel == LL_DMA_CHANNEL_3)
{
/* Reset interrupt pending bits for DMAx Channel3 */
LL_DMA_ClearFlag_GI3(DMAx);
}
else if (Channel == LL_DMA_CHANNEL_4)
{
/* Reset interrupt pending bits for DMAx Channel4 */
LL_DMA_ClearFlag_GI4(DMAx);
}
else if (Channel == LL_DMA_CHANNEL_5)
{
/* Reset interrupt pending bits for DMAx Channel5 */
LL_DMA_ClearFlag_GI5(DMAx);
}
else if (Channel == LL_DMA_CHANNEL_6)
{
/* Reset interrupt pending bits for DMAx Channel6 */
LL_DMA_ClearFlag_GI6(DMAx);
}
else if (Channel == LL_DMA_CHANNEL_7)
{
/* Reset interrupt pending bits for DMAx Channel7 */
LL_DMA_ClearFlag_GI7(DMAx);
}
else
{
status = ERROR;
}
return status;
}
/**
* @brief Initialize the DMA registers according to the specified parameters in DMA_InitStruct.
* @note To convert DMAx_Channely Instance to DMAx Instance and Channely, use helper macros :
* @arg @ref __LL_DMA_GET_INSTANCE
* @arg @ref __LL_DMA_GET_CHANNEL
* @param DMAx DMAx Instance
* @param Channel This parameter can be one of the following values:
* @arg @ref LL_DMA_CHANNEL_1
* @arg @ref LL_DMA_CHANNEL_2
* @arg @ref LL_DMA_CHANNEL_3
* @arg @ref LL_DMA_CHANNEL_4
* @arg @ref LL_DMA_CHANNEL_5
* @arg @ref LL_DMA_CHANNEL_6
* @arg @ref LL_DMA_CHANNEL_7
* @param DMA_InitStruct pointer to a @ref LL_DMA_InitTypeDef structure.
* @retval An ErrorStatus enumeration value:
* - SUCCESS: DMA registers are initialized
* - ERROR: Not applicable
*/
uint32_t LL_DMA_Init(DMA_TypeDef *DMAx, uint32_t Channel, LL_DMA_InitTypeDef *DMA_InitStruct)
{
/* Check the DMA Instance DMAx and Channel parameters*/
assert_param(IS_LL_DMA_ALL_CHANNEL_INSTANCE(DMAx, Channel));
/* Check the DMA parameters from DMA_InitStruct */
assert_param(IS_LL_DMA_DIRECTION(DMA_InitStruct->Direction));
assert_param(IS_LL_DMA_MODE(DMA_InitStruct->Mode));
assert_param(IS_LL_DMA_PERIPHINCMODE(DMA_InitStruct->PeriphOrM2MSrcIncMode));
assert_param(IS_LL_DMA_MEMORYINCMODE(DMA_InitStruct->MemoryOrM2MDstIncMode));
assert_param(IS_LL_DMA_PERIPHDATASIZE(DMA_InitStruct->PeriphOrM2MSrcDataSize));
assert_param(IS_LL_DMA_MEMORYDATASIZE(DMA_InitStruct->MemoryOrM2MDstDataSize));
assert_param(IS_LL_DMA_NBDATA(DMA_InitStruct->NbData));
assert_param(IS_LL_DMA_PRIORITY(DMA_InitStruct->Priority));
/*---------------------------- DMAx CCR Configuration ------------------------
* Configure DMAx_Channely: data transfer direction, data transfer mode,
* peripheral and memory increment mode,
* data size alignment and priority level with parameters :
* - Direction: DMA_CCR_DIR and DMA_CCR_MEM2MEM bits
* - Mode: DMA_CCR_CIRC bit
* - PeriphOrM2MSrcIncMode: DMA_CCR_PINC bit
* - MemoryOrM2MDstIncMode: DMA_CCR_MINC bit
* - PeriphOrM2MSrcDataSize: DMA_CCR_PSIZE[1:0] bits
* - MemoryOrM2MDstDataSize: DMA_CCR_MSIZE[1:0] bits
* - Priority: DMA_CCR_PL[1:0] bits
*/
LL_DMA_ConfigTransfer(DMAx, Channel, DMA_InitStruct->Direction | \
DMA_InitStruct->Mode | \
DMA_InitStruct->PeriphOrM2MSrcIncMode | \
DMA_InitStruct->MemoryOrM2MDstIncMode | \
DMA_InitStruct->PeriphOrM2MSrcDataSize | \
DMA_InitStruct->MemoryOrM2MDstDataSize | \
DMA_InitStruct->Priority);
/*-------------------------- DMAx CMAR Configuration -------------------------
* Configure the memory or destination base address with parameter :
* - MemoryOrM2MDstAddress: DMA_CMAR_MA[31:0] bits
*/
LL_DMA_SetMemoryAddress(DMAx, Channel, DMA_InitStruct->MemoryOrM2MDstAddress);
/*-------------------------- DMAx CPAR Configuration -------------------------
* Configure the peripheral or source base address with parameter :
* - PeriphOrM2MSrcAddress: DMA_CPAR_PA[31:0] bits
*/
LL_DMA_SetPeriphAddress(DMAx, Channel, DMA_InitStruct->PeriphOrM2MSrcAddress);
/*--------------------------- DMAx CNDTR Configuration -----------------------
* Configure the peripheral base address with parameter :
* - NbData: DMA_CNDTR_NDT[15:0] bits
*/
LL_DMA_SetDataLength(DMAx, Channel, DMA_InitStruct->NbData);
return SUCCESS;
}
/**
* @brief Set each @ref LL_DMA_InitTypeDef field to default value.
* @param DMA_InitStruct Pointer to a @ref LL_DMA_InitTypeDef structure.
* @retval None
*/
void LL_DMA_StructInit(LL_DMA_InitTypeDef *DMA_InitStruct)
{
/* Set DMA_InitStruct fields to default values */
DMA_InitStruct->PeriphOrM2MSrcAddress = 0x00000000U;
DMA_InitStruct->MemoryOrM2MDstAddress = 0x00000000U;
DMA_InitStruct->Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY;
DMA_InitStruct->Mode = LL_DMA_MODE_NORMAL;
DMA_InitStruct->PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
DMA_InitStruct->MemoryOrM2MDstIncMode = LL_DMA_MEMORY_NOINCREMENT;
DMA_InitStruct->PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_BYTE;
DMA_InitStruct->MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_BYTE;
DMA_InitStruct->NbData = 0x00000000U;
DMA_InitStruct->Priority = LL_DMA_PRIORITY_LOW;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#endif /* DMA1 || DMA2 */
/**
* @}
*/
#endif /* USE_FULL_LL_DRIVER */

View File

@@ -0,0 +1,213 @@
/**
******************************************************************************
* @file stm32f1xx_ll_exti.c
* @author MCD Application Team
* @brief EXTI LL module driver.
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#if defined(USE_FULL_LL_DRIVER)
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_ll_exti.h"
#ifdef USE_FULL_ASSERT
#include "stm32_assert.h"
#else
#define assert_param(expr) ((void)0U)
#endif
/** @addtogroup STM32F1xx_LL_Driver
* @{
*/
#if defined (EXTI)
/** @defgroup EXTI_LL EXTI
* @{
*/
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/** @addtogroup EXTI_LL_Private_Macros
* @{
*/
#define IS_LL_EXTI_LINE_0_31(__VALUE__) (((__VALUE__) & ~LL_EXTI_LINE_ALL_0_31) == 0x00000000U)
#define IS_LL_EXTI_MODE(__VALUE__) (((__VALUE__) == LL_EXTI_MODE_IT) \
|| ((__VALUE__) == LL_EXTI_MODE_EVENT) \
|| ((__VALUE__) == LL_EXTI_MODE_IT_EVENT))
#define IS_LL_EXTI_TRIGGER(__VALUE__) (((__VALUE__) == LL_EXTI_TRIGGER_NONE) \
|| ((__VALUE__) == LL_EXTI_TRIGGER_RISING) \
|| ((__VALUE__) == LL_EXTI_TRIGGER_FALLING) \
|| ((__VALUE__) == LL_EXTI_TRIGGER_RISING_FALLING))
/**
* @}
*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup EXTI_LL_Exported_Functions
* @{
*/
/** @addtogroup EXTI_LL_EF_Init
* @{
*/
/**
* @brief De-initialize the EXTI registers to their default reset values.
* @retval An ErrorStatus enumeration value:
* - SUCCESS: EXTI registers are de-initialized
* - ERROR: not applicable
*/
uint32_t LL_EXTI_DeInit(void)
{
/* Interrupt mask register set to default reset values */
LL_EXTI_WriteReg(IMR, 0x00000000U);
/* Event mask register set to default reset values */
LL_EXTI_WriteReg(EMR, 0x00000000U);
/* Rising Trigger selection register set to default reset values */
LL_EXTI_WriteReg(RTSR, 0x00000000U);
/* Falling Trigger selection register set to default reset values */
LL_EXTI_WriteReg(FTSR, 0x00000000U);
/* Software interrupt event register set to default reset values */
LL_EXTI_WriteReg(SWIER, 0x00000000U);
/* Pending register clear */
LL_EXTI_WriteReg(PR, 0x000FFFFFU);
return SUCCESS;
}
/**
* @brief Initialize the EXTI registers according to the specified parameters in EXTI_InitStruct.
* @param EXTI_InitStruct pointer to a @ref LL_EXTI_InitTypeDef structure.
* @retval An ErrorStatus enumeration value:
* - SUCCESS: EXTI registers are initialized
* - ERROR: not applicable
*/
uint32_t LL_EXTI_Init(LL_EXTI_InitTypeDef *EXTI_InitStruct)
{
ErrorStatus status = SUCCESS;
/* Check the parameters */
assert_param(IS_LL_EXTI_LINE_0_31(EXTI_InitStruct->Line_0_31));
assert_param(IS_FUNCTIONAL_STATE(EXTI_InitStruct->LineCommand));
assert_param(IS_LL_EXTI_MODE(EXTI_InitStruct->Mode));
/* ENABLE LineCommand */
if (EXTI_InitStruct->LineCommand != DISABLE)
{
assert_param(IS_LL_EXTI_TRIGGER(EXTI_InitStruct->Trigger));
/* Configure EXTI Lines in range from 0 to 31 */
if (EXTI_InitStruct->Line_0_31 != LL_EXTI_LINE_NONE)
{
switch (EXTI_InitStruct->Mode)
{
case LL_EXTI_MODE_IT:
/* First Disable Event on provided Lines */
LL_EXTI_DisableEvent_0_31(EXTI_InitStruct->Line_0_31);
/* Then Enable IT on provided Lines */
LL_EXTI_EnableIT_0_31(EXTI_InitStruct->Line_0_31);
break;
case LL_EXTI_MODE_EVENT:
/* First Disable IT on provided Lines */
LL_EXTI_DisableIT_0_31(EXTI_InitStruct->Line_0_31);
/* Then Enable Event on provided Lines */
LL_EXTI_EnableEvent_0_31(EXTI_InitStruct->Line_0_31);
break;
case LL_EXTI_MODE_IT_EVENT:
/* Directly Enable IT & Event on provided Lines */
LL_EXTI_EnableIT_0_31(EXTI_InitStruct->Line_0_31);
LL_EXTI_EnableEvent_0_31(EXTI_InitStruct->Line_0_31);
break;
default:
status = ERROR;
break;
}
if (EXTI_InitStruct->Trigger != LL_EXTI_TRIGGER_NONE)
{
switch (EXTI_InitStruct->Trigger)
{
case LL_EXTI_TRIGGER_RISING:
/* First Disable Falling Trigger on provided Lines */
LL_EXTI_DisableFallingTrig_0_31(EXTI_InitStruct->Line_0_31);
/* Then Enable Rising Trigger on provided Lines */
LL_EXTI_EnableRisingTrig_0_31(EXTI_InitStruct->Line_0_31);
break;
case LL_EXTI_TRIGGER_FALLING:
/* First Disable Rising Trigger on provided Lines */
LL_EXTI_DisableRisingTrig_0_31(EXTI_InitStruct->Line_0_31);
/* Then Enable Falling Trigger on provided Lines */
LL_EXTI_EnableFallingTrig_0_31(EXTI_InitStruct->Line_0_31);
break;
case LL_EXTI_TRIGGER_RISING_FALLING:
LL_EXTI_EnableRisingTrig_0_31(EXTI_InitStruct->Line_0_31);
LL_EXTI_EnableFallingTrig_0_31(EXTI_InitStruct->Line_0_31);
break;
default:
status = ERROR;
break;
}
}
}
}
/* DISABLE LineCommand */
else
{
/* De-configure EXTI Lines in range from 0 to 31 */
LL_EXTI_DisableIT_0_31(EXTI_InitStruct->Line_0_31);
LL_EXTI_DisableEvent_0_31(EXTI_InitStruct->Line_0_31);
}
return status;
}
/**
* @brief Set each @ref LL_EXTI_InitTypeDef field to default value.
* @param EXTI_InitStruct Pointer to a @ref LL_EXTI_InitTypeDef structure.
* @retval None
*/
void LL_EXTI_StructInit(LL_EXTI_InitTypeDef *EXTI_InitStruct)
{
EXTI_InitStruct->Line_0_31 = LL_EXTI_LINE_NONE;
EXTI_InitStruct->LineCommand = DISABLE;
EXTI_InitStruct->Mode = LL_EXTI_MODE_IT;
EXTI_InitStruct->Trigger = LL_EXTI_TRIGGER_FALLING;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#endif /* defined (EXTI) */
/**
* @}
*/
#endif /* USE_FULL_LL_DRIVER */

View File

@@ -0,0 +1,1014 @@
/**
******************************************************************************
* @file stm32f1xx_ll_fsmc.c
* @author MCD Application Team
* @brief FSMC Low Layer HAL module driver.
*
* This file provides firmware functions to manage the following
* functionalities of the Flexible Memory Controller (FSMC) peripheral memories:
* + Initialization/de-initialization functions
* + Peripheral Control functions
* + Peripheral State functions
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
==============================================================================
##### FSMC peripheral features #####
==============================================================================
[..] The Flexible memory controller (FSMC) includes following memory controllers:
(+) The NOR/PSRAM memory controller
(+) The NAND/PC Card memory controller
[..] The FSMC functional block makes the interface with synchronous and asynchronous static
memories and 16-bit PC memory cards. Its main purposes are:
(+) to translate AHB transactions into the appropriate external device protocol
(+) to meet the access time requirements of the external memory devices
[..] All external memories share the addresses, data and control signals with the controller.
Each external device is accessed by means of a unique Chip Select. The FSMC performs
only one access at a time to an external device.
The main features of the FSMC controller are the following:
(+) Interface with static-memory mapped devices including:
(++) Static random access memory (SRAM)
(++) Read-only memory (ROM)
(++) NOR Flash memory/OneNAND Flash memory
(++) PSRAM (4 memory banks)
(++) 16-bit PC Card compatible devices
(++) Two banks of NAND Flash memory with ECC hardware to check up to 8 Kbytes of
data
(+) Independent Chip Select control for each memory bank
(+) Independent configuration for each memory bank
@endverbatim
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
#if defined(HAL_NOR_MODULE_ENABLED) || defined(HAL_NAND_MODULE_ENABLED) || defined(HAL_PCCARD_MODULE_ENABLED) \
|| defined(HAL_SRAM_MODULE_ENABLED)
/** @defgroup FSMC_LL FSMC Low Layer
* @brief FSMC driver modules
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/** @defgroup FSMC_LL_Private_Constants FSMC Low Layer Private Constants
* @{
*/
/* ----------------------- FSMC registers bit mask --------------------------- */
#if defined(FSMC_BANK1)
/* --- BCR Register ---*/
/* BCR register clear mask */
/* --- BTR Register ---*/
/* BTR register clear mask */
#define BTR_CLEAR_MASK ((uint32_t)(FSMC_BTRx_ADDSET | FSMC_BTRx_ADDHLD |\
FSMC_BTRx_DATAST | FSMC_BTRx_BUSTURN |\
FSMC_BTRx_CLKDIV | FSMC_BTRx_DATLAT |\
FSMC_BTRx_ACCMOD))
/* --- BWTR Register ---*/
/* BWTR register clear mask */
#if defined(FSMC_BWTRx_BUSTURN)
#define BWTR_CLEAR_MASK ((uint32_t)(FSMC_BWTRx_ADDSET | FSMC_BWTRx_ADDHLD |\
FSMC_BWTRx_DATAST | FSMC_BWTRx_BUSTURN |\
FSMC_BWTRx_ACCMOD))
#else
#define BWTR_CLEAR_MASK ((uint32_t)(FSMC_BWTRx_ADDSET | FSMC_BWTRx_ADDHLD |\
FSMC_BWTRx_DATAST | FSMC_BWTRx_ACCMOD |\
FSMC_BWTRx_CLKDIV | FSMC_BWTRx_DATLAT))
#endif /* FSMC_BWTRx_BUSTURN */
#endif /* FSMC_BANK1 */
#if defined(FSMC_BANK3)
/* --- PCR Register ---*/
/* PCR register clear mask */
#define PCR_CLEAR_MASK ((uint32_t)(FSMC_PCRx_PWAITEN | FSMC_PCRx_PBKEN | \
FSMC_PCRx_PTYP | FSMC_PCRx_PWID | \
FSMC_PCRx_ECCEN | FSMC_PCRx_TCLR | \
FSMC_PCRx_TAR | FSMC_PCRx_ECCPS))
/* --- PMEM Register ---*/
/* PMEM register clear mask */
#define PMEM_CLEAR_MASK ((uint32_t)(FSMC_PMEMx_MEMSETx | FSMC_PMEMx_MEMWAITx |\
FSMC_PMEMx_MEMHOLDx | FSMC_PMEMx_MEMHIZx))
/* --- PATT Register ---*/
/* PATT register clear mask */
#define PATT_CLEAR_MASK ((uint32_t)(FSMC_PATTx_ATTSETx | FSMC_PATTx_ATTWAITx |\
FSMC_PATTx_ATTHOLDx | FSMC_PATTx_ATTHIZx))
#endif /* FSMC_BANK3 */
#if defined(FSMC_BANK4)
/* --- PCR Register ---*/
/* PCR register clear mask */
#define PCR4_CLEAR_MASK ((uint32_t)(FSMC_PCR4_PWAITEN | FSMC_PCR4_PBKEN | \
FSMC_PCR4_PTYP | FSMC_PCR4_PWID | \
FSMC_PCR4_ECCEN | FSMC_PCR4_TCLR | \
FSMC_PCR4_TAR | FSMC_PCR4_ECCPS))
/* --- PMEM Register ---*/
/* PMEM register clear mask */
#define PMEM4_CLEAR_MASK ((uint32_t)(FSMC_PMEM4_MEMSET4 | FSMC_PMEM4_MEMWAIT4 |\
FSMC_PMEM4_MEMHOLD4 | FSMC_PMEM4_MEMHIZ4))
/* --- PATT Register ---*/
/* PATT register clear mask */
#define PATT4_CLEAR_MASK ((uint32_t)(FSMC_PATT4_ATTSET4 | FSMC_PATT4_ATTWAIT4 |\
FSMC_PATT4_ATTHOLD4 | FSMC_PATT4_ATTHIZ4))
/* --- PIO4 Register ---*/
/* PIO4 register clear mask */
#define PIO4_CLEAR_MASK ((uint32_t)(FSMC_PIO4_IOSET4 | FSMC_PIO4_IOWAIT4 | \
FSMC_PIO4_IOHOLD4 | FSMC_PIO4_IOHIZ4))
#endif /* FSMC_BANK4 */
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @defgroup FSMC_LL_Exported_Functions FSMC Low Layer Exported Functions
* @{
*/
#if defined(FSMC_BANK1)
/** @defgroup FSMC_LL_Exported_Functions_NORSRAM FSMC Low Layer NOR SRAM Exported Functions
* @brief NORSRAM Controller functions
*
@verbatim
==============================================================================
##### How to use NORSRAM device driver #####
==============================================================================
[..]
This driver contains a set of APIs to interface with the FSMC NORSRAM banks in order
to run the NORSRAM external devices.
(+) FSMC NORSRAM bank reset using the function FSMC_NORSRAM_DeInit()
(+) FSMC NORSRAM bank control configuration using the function FSMC_NORSRAM_Init()
(+) FSMC NORSRAM bank timing configuration using the function FSMC_NORSRAM_Timing_Init()
(+) FSMC NORSRAM bank extended timing configuration using the function
FSMC_NORSRAM_Extended_Timing_Init()
(+) FSMC NORSRAM bank enable/disable write operation using the functions
FSMC_NORSRAM_WriteOperation_Enable()/FSMC_NORSRAM_WriteOperation_Disable()
@endverbatim
* @{
*/
/** @defgroup FSMC_LL_NORSRAM_Exported_Functions_Group1 Initialization and de-initialization functions
* @brief Initialization and Configuration functions
*
@verbatim
==============================================================================
##### Initialization and de_initialization functions #####
==============================================================================
[..]
This section provides functions allowing to:
(+) Initialize and configure the FSMC NORSRAM interface
(+) De-initialize the FSMC NORSRAM interface
(+) Configure the FSMC clock and associated GPIOs
@endverbatim
* @{
*/
/**
* @brief Initialize the FSMC_NORSRAM device according to the specified
* control parameters in the FSMC_NORSRAM_InitTypeDef
* @param Device Pointer to NORSRAM device instance
* @param Init Pointer to NORSRAM Initialization structure
* @retval HAL status
*/
HAL_StatusTypeDef FSMC_NORSRAM_Init(FSMC_NORSRAM_TypeDef *Device,
const FSMC_NORSRAM_InitTypeDef *Init)
{
uint32_t flashaccess;
uint32_t btcr_reg;
uint32_t mask;
/* Check the parameters */
assert_param(IS_FSMC_NORSRAM_DEVICE(Device));
assert_param(IS_FSMC_NORSRAM_BANK(Init->NSBank));
assert_param(IS_FSMC_MUX(Init->DataAddressMux));
assert_param(IS_FSMC_MEMORY(Init->MemoryType));
assert_param(IS_FSMC_NORSRAM_MEMORY_WIDTH(Init->MemoryDataWidth));
assert_param(IS_FSMC_BURSTMODE(Init->BurstAccessMode));
assert_param(IS_FSMC_WAIT_POLARITY(Init->WaitSignalPolarity));
assert_param(IS_FSMC_WRAP_MODE(Init->WrapMode));
assert_param(IS_FSMC_WAIT_SIGNAL_ACTIVE(Init->WaitSignalActive));
assert_param(IS_FSMC_WRITE_OPERATION(Init->WriteOperation));
assert_param(IS_FSMC_WAITE_SIGNAL(Init->WaitSignal));
assert_param(IS_FSMC_EXTENDED_MODE(Init->ExtendedMode));
assert_param(IS_FSMC_ASYNWAIT(Init->AsynchronousWait));
assert_param(IS_FSMC_WRITE_BURST(Init->WriteBurst));
assert_param(IS_FSMC_PAGESIZE(Init->PageSize));
/* Disable NORSRAM Device */
__FSMC_NORSRAM_DISABLE(Device, Init->NSBank);
/* Set NORSRAM device control parameters */
if (Init->MemoryType == FSMC_MEMORY_TYPE_NOR)
{
flashaccess = FSMC_NORSRAM_FLASH_ACCESS_ENABLE;
}
else
{
flashaccess = FSMC_NORSRAM_FLASH_ACCESS_DISABLE;
}
btcr_reg = (flashaccess | \
Init->DataAddressMux | \
Init->MemoryType | \
Init->MemoryDataWidth | \
Init->BurstAccessMode | \
Init->WaitSignalPolarity | \
Init->WaitSignalActive | \
Init->WriteOperation | \
Init->WaitSignal | \
Init->ExtendedMode | \
Init->AsynchronousWait | \
Init->WriteBurst);
btcr_reg |= Init->WrapMode;
btcr_reg |= Init->PageSize;
mask = (FSMC_BCRx_MBKEN |
FSMC_BCRx_MUXEN |
FSMC_BCRx_MTYP |
FSMC_BCRx_MWID |
FSMC_BCRx_FACCEN |
FSMC_BCRx_BURSTEN |
FSMC_BCRx_WAITPOL |
FSMC_BCRx_WAITCFG |
FSMC_BCRx_WREN |
FSMC_BCRx_WAITEN |
FSMC_BCRx_EXTMOD |
FSMC_BCRx_ASYNCWAIT |
FSMC_BCRx_CBURSTRW);
mask |= FSMC_BCRx_WRAPMOD;
mask |= 0x00070000U; /* CPSIZE to be defined in CMSIS file */
MODIFY_REG(Device->BTCR[Init->NSBank], mask, btcr_reg);
return HAL_OK;
}
/**
* @brief DeInitialize the FSMC_NORSRAM peripheral
* @param Device Pointer to NORSRAM device instance
* @param ExDevice Pointer to NORSRAM extended mode device instance
* @param Bank NORSRAM bank number
* @retval HAL status
*/
HAL_StatusTypeDef FSMC_NORSRAM_DeInit(FSMC_NORSRAM_TypeDef *Device,
FSMC_NORSRAM_EXTENDED_TypeDef *ExDevice, uint32_t Bank)
{
/* Check the parameters */
assert_param(IS_FSMC_NORSRAM_DEVICE(Device));
assert_param(IS_FSMC_NORSRAM_EXTENDED_DEVICE(ExDevice));
assert_param(IS_FSMC_NORSRAM_BANK(Bank));
/* Disable the FSMC_NORSRAM device */
__FSMC_NORSRAM_DISABLE(Device, Bank);
/* De-initialize the FSMC_NORSRAM device */
/* FSMC_NORSRAM_BANK1 */
if (Bank == FSMC_NORSRAM_BANK1)
{
Device->BTCR[Bank] = 0x000030DBU;
}
/* FSMC_NORSRAM_BANK2, FSMC_NORSRAM_BANK3 or FSMC_NORSRAM_BANK4 */
else
{
Device->BTCR[Bank] = 0x000030D2U;
}
Device->BTCR[Bank + 1U] = 0x0FFFFFFFU;
ExDevice->BWTR[Bank] = 0x0FFFFFFFU;
return HAL_OK;
}
/**
* @brief Initialize the FSMC_NORSRAM Timing according to the specified
* parameters in the FSMC_NORSRAM_TimingTypeDef
* @param Device Pointer to NORSRAM device instance
* @param Timing Pointer to NORSRAM Timing structure
* @param Bank NORSRAM bank number
* @retval HAL status
*/
HAL_StatusTypeDef FSMC_NORSRAM_Timing_Init(FSMC_NORSRAM_TypeDef *Device,
const FSMC_NORSRAM_TimingTypeDef *Timing, uint32_t Bank)
{
/* Check the parameters */
assert_param(IS_FSMC_NORSRAM_DEVICE(Device));
assert_param(IS_FSMC_ADDRESS_SETUP_TIME(Timing->AddressSetupTime));
assert_param(IS_FSMC_ADDRESS_HOLD_TIME(Timing->AddressHoldTime));
assert_param(IS_FSMC_DATASETUP_TIME(Timing->DataSetupTime));
assert_param(IS_FSMC_TURNAROUND_TIME(Timing->BusTurnAroundDuration));
assert_param(IS_FSMC_CLK_DIV(Timing->CLKDivision));
assert_param(IS_FSMC_DATA_LATENCY(Timing->DataLatency));
assert_param(IS_FSMC_ACCESS_MODE(Timing->AccessMode));
assert_param(IS_FSMC_NORSRAM_BANK(Bank));
/* Set FSMC_NORSRAM device timing parameters */
Device->BTCR[Bank + 1U] =
(Timing->AddressSetupTime << FSMC_BTRx_ADDSET_Pos) |
(Timing->AddressHoldTime << FSMC_BTRx_ADDHLD_Pos) |
(Timing->DataSetupTime << FSMC_BTRx_DATAST_Pos) |
(Timing->BusTurnAroundDuration << FSMC_BTRx_BUSTURN_Pos) |
((Timing->CLKDivision - 1U) << FSMC_BTRx_CLKDIV_Pos) |
((Timing->DataLatency - 2U) << FSMC_BTRx_DATLAT_Pos) |
Timing->AccessMode;
return HAL_OK;
}
/**
* @brief Initialize the FSMC_NORSRAM Extended mode Timing according to the specified
* parameters in the FSMC_NORSRAM_TimingTypeDef
* @param Device Pointer to NORSRAM device instance
* @param Timing Pointer to NORSRAM Timing structure
* @param Bank NORSRAM bank number
* @param ExtendedMode FSMC Extended Mode
* This parameter can be one of the following values:
* @arg FSMC_EXTENDED_MODE_DISABLE
* @arg FSMC_EXTENDED_MODE_ENABLE
* @retval HAL status
*/
HAL_StatusTypeDef FSMC_NORSRAM_Extended_Timing_Init(FSMC_NORSRAM_EXTENDED_TypeDef *Device,
const FSMC_NORSRAM_TimingTypeDef *Timing, uint32_t Bank,
uint32_t ExtendedMode)
{
/* Check the parameters */
assert_param(IS_FSMC_EXTENDED_MODE(ExtendedMode));
/* Set NORSRAM device timing register for write configuration, if extended mode is used */
if (ExtendedMode == FSMC_EXTENDED_MODE_ENABLE)
{
/* Check the parameters */
assert_param(IS_FSMC_NORSRAM_EXTENDED_DEVICE(Device));
assert_param(IS_FSMC_ADDRESS_SETUP_TIME(Timing->AddressSetupTime));
assert_param(IS_FSMC_ADDRESS_HOLD_TIME(Timing->AddressHoldTime));
assert_param(IS_FSMC_DATASETUP_TIME(Timing->DataSetupTime));
#if defined(FSMC_BWTRx_BUSTURN)
assert_param(IS_FSMC_TURNAROUND_TIME(Timing->BusTurnAroundDuration));
#else
assert_param(IS_FSMC_CLK_DIV(Timing->CLKDivision));
assert_param(IS_FSMC_DATA_LATENCY(Timing->DataLatency));
#endif /* FSMC_BWTRx_BUSTURN */
assert_param(IS_FSMC_ACCESS_MODE(Timing->AccessMode));
assert_param(IS_FSMC_NORSRAM_BANK(Bank));
/* Set NORSRAM device timing register for write configuration, if extended mode is used */
#if defined(FSMC_BWTRx_BUSTURN)
MODIFY_REG(Device->BWTR[Bank], BWTR_CLEAR_MASK, (Timing->AddressSetupTime |
((Timing->AddressHoldTime) << FSMC_BWTRx_ADDHLD_Pos) |
((Timing->DataSetupTime) << FSMC_BWTRx_DATAST_Pos) |
Timing->AccessMode |
((Timing->BusTurnAroundDuration) << FSMC_BWTRx_BUSTURN_Pos)));
#else
MODIFY_REG(Device->BWTR[Bank], BWTR_CLEAR_MASK, (Timing->AddressSetupTime |
((Timing->AddressHoldTime) << FSMC_BWTRx_ADDHLD_Pos) |
((Timing->DataSetupTime) << FSMC_BWTRx_DATAST_Pos) |
Timing->AccessMode |
(((Timing->CLKDivision) - 1U) << FSMC_BWTRx_CLKDIV_Pos) |
(((Timing->DataLatency) - 2U) << FSMC_BWTRx_DATLAT_Pos)));
#endif /* FSMC_BWTRx_BUSTURN */
}
else
{
Device->BWTR[Bank] = 0x0FFFFFFFU;
}
return HAL_OK;
}
/**
* @}
*/
/** @addtogroup FSMC_LL_NORSRAM_Private_Functions_Group2
* @brief management functions
*
@verbatim
==============================================================================
##### FSMC_NORSRAM Control functions #####
==============================================================================
[..]
This subsection provides a set of functions allowing to control dynamically
the FSMC NORSRAM interface.
@endverbatim
* @{
*/
/**
* @brief Enables dynamically FSMC_NORSRAM write operation.
* @param Device Pointer to NORSRAM device instance
* @param Bank NORSRAM bank number
* @retval HAL status
*/
HAL_StatusTypeDef FSMC_NORSRAM_WriteOperation_Enable(FSMC_NORSRAM_TypeDef *Device, uint32_t Bank)
{
/* Check the parameters */
assert_param(IS_FSMC_NORSRAM_DEVICE(Device));
assert_param(IS_FSMC_NORSRAM_BANK(Bank));
/* Enable write operation */
SET_BIT(Device->BTCR[Bank], FSMC_WRITE_OPERATION_ENABLE);
return HAL_OK;
}
/**
* @brief Disables dynamically FSMC_NORSRAM write operation.
* @param Device Pointer to NORSRAM device instance
* @param Bank NORSRAM bank number
* @retval HAL status
*/
HAL_StatusTypeDef FSMC_NORSRAM_WriteOperation_Disable(FSMC_NORSRAM_TypeDef *Device, uint32_t Bank)
{
/* Check the parameters */
assert_param(IS_FSMC_NORSRAM_DEVICE(Device));
assert_param(IS_FSMC_NORSRAM_BANK(Bank));
/* Disable write operation */
CLEAR_BIT(Device->BTCR[Bank], FSMC_WRITE_OPERATION_ENABLE);
return HAL_OK;
}
/**
* @}
*/
/**
* @}
*/
#endif /* FSMC_BANK1 */
#if defined(FSMC_BANK3)
/** @defgroup FSMC_LL_Exported_Functions_NAND FSMC Low Layer NAND Exported Functions
* @brief NAND Controller functions
*
@verbatim
==============================================================================
##### How to use NAND device driver #####
==============================================================================
[..]
This driver contains a set of APIs to interface with the FSMC NAND banks in order
to run the NAND external devices.
(+) FSMC NAND bank reset using the function FSMC_NAND_DeInit()
(+) FSMC NAND bank control configuration using the function FSMC_NAND_Init()
(+) FSMC NAND bank common space timing configuration using the function
FSMC_NAND_CommonSpace_Timing_Init()
(+) FSMC NAND bank attribute space timing configuration using the function
FSMC_NAND_AttributeSpace_Timing_Init()
(+) FSMC NAND bank enable/disable ECC correction feature using the functions
FSMC_NAND_ECC_Enable()/FSMC_NAND_ECC_Disable()
(+) FSMC NAND bank get ECC correction code using the function FSMC_NAND_GetECC()
@endverbatim
* @{
*/
/** @defgroup FSMC_LL_NAND_Exported_Functions_Group1 Initialization and de-initialization functions
* @brief Initialization and Configuration functions
*
@verbatim
==============================================================================
##### Initialization and de_initialization functions #####
==============================================================================
[..]
This section provides functions allowing to:
(+) Initialize and configure the FSMC NAND interface
(+) De-initialize the FSMC NAND interface
(+) Configure the FSMC clock and associated GPIOs
@endverbatim
* @{
*/
/**
* @brief Initializes the FSMC_NAND device according to the specified
* control parameters in the FSMC_NAND_HandleTypeDef
* @param Device Pointer to NAND device instance
* @param Init Pointer to NAND Initialization structure
* @retval HAL status
*/
HAL_StatusTypeDef FSMC_NAND_Init(FSMC_NAND_TypeDef *Device, const FSMC_NAND_InitTypeDef *Init)
{
/* Check the parameters */
assert_param(IS_FSMC_NAND_DEVICE(Device));
assert_param(IS_FSMC_NAND_BANK(Init->NandBank));
assert_param(IS_FSMC_WAIT_FEATURE(Init->Waitfeature));
assert_param(IS_FSMC_NAND_MEMORY_WIDTH(Init->MemoryDataWidth));
assert_param(IS_FSMC_ECC_STATE(Init->EccComputation));
assert_param(IS_FSMC_ECCPAGE_SIZE(Init->ECCPageSize));
assert_param(IS_FSMC_TCLR_TIME(Init->TCLRSetupTime));
assert_param(IS_FSMC_TAR_TIME(Init->TARSetupTime));
/* Set NAND device control parameters */
if (Init->NandBank == FSMC_NAND_BANK2)
{
/* NAND bank 2 registers configuration */
MODIFY_REG(Device->PCR2, PCR_CLEAR_MASK, (Init->Waitfeature |
FSMC_PCR_MEMORY_TYPE_NAND |
Init->MemoryDataWidth |
Init->EccComputation |
Init->ECCPageSize |
((Init->TCLRSetupTime) << FSMC_PCRx_TCLR_Pos) |
((Init->TARSetupTime) << FSMC_PCRx_TAR_Pos)));
}
else
{
/* NAND bank 3 registers configuration */
MODIFY_REG(Device->PCR3, PCR_CLEAR_MASK, (Init->Waitfeature |
FSMC_PCR_MEMORY_TYPE_NAND |
Init->MemoryDataWidth |
Init->EccComputation |
Init->ECCPageSize |
((Init->TCLRSetupTime) << FSMC_PCRx_TCLR_Pos) |
((Init->TARSetupTime) << FSMC_PCRx_TAR_Pos)));
}
return HAL_OK;
}
/**
* @brief Initializes the FSMC_NAND Common space Timing according to the specified
* parameters in the FSMC_NAND_PCC_TimingTypeDef
* @param Device Pointer to NAND device instance
* @param Timing Pointer to NAND timing structure
* @param Bank NAND bank number
* @retval HAL status
*/
HAL_StatusTypeDef FSMC_NAND_CommonSpace_Timing_Init(FSMC_NAND_TypeDef *Device,
const FSMC_NAND_PCC_TimingTypeDef *Timing, uint32_t Bank)
{
/* Check the parameters */
assert_param(IS_FSMC_NAND_DEVICE(Device));
assert_param(IS_FSMC_SETUP_TIME(Timing->SetupTime));
assert_param(IS_FSMC_WAIT_TIME(Timing->WaitSetupTime));
assert_param(IS_FSMC_HOLD_TIME(Timing->HoldSetupTime));
assert_param(IS_FSMC_HIZ_TIME(Timing->HiZSetupTime));
assert_param(IS_FSMC_NAND_BANK(Bank));
/* Set FSMC_NAND device timing parameters */
if (Bank == FSMC_NAND_BANK2)
{
/* NAND bank 2 registers configuration */
MODIFY_REG(Device->PMEM2, PMEM_CLEAR_MASK, (Timing->SetupTime |
((Timing->WaitSetupTime) << FSMC_PMEMx_MEMWAITx_Pos) |
((Timing->HoldSetupTime) << FSMC_PMEMx_MEMHOLDx_Pos) |
((Timing->HiZSetupTime) << FSMC_PMEMx_MEMHIZx_Pos)));
}
else
{
/* NAND bank 3 registers configuration */
MODIFY_REG(Device->PMEM3, PMEM_CLEAR_MASK, (Timing->SetupTime |
((Timing->WaitSetupTime) << FSMC_PMEMx_MEMWAITx_Pos) |
((Timing->HoldSetupTime) << FSMC_PMEMx_MEMHOLDx_Pos) |
((Timing->HiZSetupTime) << FSMC_PMEMx_MEMHIZx_Pos)));
}
return HAL_OK;
}
/**
* @brief Initializes the FSMC_NAND Attribute space Timing according to the specified
* parameters in the FSMC_NAND_PCC_TimingTypeDef
* @param Device Pointer to NAND device instance
* @param Timing Pointer to NAND timing structure
* @param Bank NAND bank number
* @retval HAL status
*/
HAL_StatusTypeDef FSMC_NAND_AttributeSpace_Timing_Init(FSMC_NAND_TypeDef *Device,
const FSMC_NAND_PCC_TimingTypeDef *Timing, uint32_t Bank)
{
/* Check the parameters */
assert_param(IS_FSMC_NAND_DEVICE(Device));
assert_param(IS_FSMC_SETUP_TIME(Timing->SetupTime));
assert_param(IS_FSMC_WAIT_TIME(Timing->WaitSetupTime));
assert_param(IS_FSMC_HOLD_TIME(Timing->HoldSetupTime));
assert_param(IS_FSMC_HIZ_TIME(Timing->HiZSetupTime));
assert_param(IS_FSMC_NAND_BANK(Bank));
/* Set FSMC_NAND device timing parameters */
if (Bank == FSMC_NAND_BANK2)
{
/* NAND bank 2 registers configuration */
MODIFY_REG(Device->PATT2, PATT_CLEAR_MASK, (Timing->SetupTime |
((Timing->WaitSetupTime) << FSMC_PATTx_ATTWAITx_Pos) |
((Timing->HoldSetupTime) << FSMC_PATTx_ATTHOLDx_Pos) |
((Timing->HiZSetupTime) << FSMC_PATTx_ATTHIZx_Pos)));
}
else
{
/* NAND bank 3 registers configuration */
MODIFY_REG(Device->PATT3, PATT_CLEAR_MASK, (Timing->SetupTime |
((Timing->WaitSetupTime) << FSMC_PATTx_ATTWAITx_Pos) |
((Timing->HoldSetupTime) << FSMC_PATTx_ATTHOLDx_Pos) |
((Timing->HiZSetupTime) << FSMC_PATTx_ATTHIZx_Pos)));
}
return HAL_OK;
}
/**
* @brief DeInitializes the FSMC_NAND device
* @param Device Pointer to NAND device instance
* @param Bank NAND bank number
* @retval HAL status
*/
HAL_StatusTypeDef FSMC_NAND_DeInit(FSMC_NAND_TypeDef *Device, uint32_t Bank)
{
/* Check the parameters */
assert_param(IS_FSMC_NAND_DEVICE(Device));
assert_param(IS_FSMC_NAND_BANK(Bank));
/* Disable the NAND Bank */
__FSMC_NAND_DISABLE(Device, Bank);
/* De-initialize the NAND Bank */
if (Bank == FSMC_NAND_BANK2)
{
/* Set the FSMC_NAND_BANK2 registers to their reset values */
WRITE_REG(Device->PCR2, 0x00000018U);
WRITE_REG(Device->SR2, 0x00000040U);
WRITE_REG(Device->PMEM2, 0xFCFCFCFCU);
WRITE_REG(Device->PATT2, 0xFCFCFCFCU);
}
/* FSMC_Bank3_NAND */
else
{
/* Set the FSMC_NAND_BANK3 registers to their reset values */
WRITE_REG(Device->PCR3, 0x00000018U);
WRITE_REG(Device->SR3, 0x00000040U);
WRITE_REG(Device->PMEM3, 0xFCFCFCFCU);
WRITE_REG(Device->PATT3, 0xFCFCFCFCU);
}
return HAL_OK;
}
/**
* @}
*/
/** @defgroup HAL_FSMC_NAND_Group2 Peripheral Control functions
* @brief management functions
*
@verbatim
==============================================================================
##### FSMC_NAND Control functions #####
==============================================================================
[..]
This subsection provides a set of functions allowing to control dynamically
the FSMC NAND interface.
@endverbatim
* @{
*/
/**
* @brief Enables dynamically FSMC_NAND ECC feature.
* @param Device Pointer to NAND device instance
* @param Bank NAND bank number
* @retval HAL status
*/
HAL_StatusTypeDef FSMC_NAND_ECC_Enable(FSMC_NAND_TypeDef *Device, uint32_t Bank)
{
/* Check the parameters */
assert_param(IS_FSMC_NAND_DEVICE(Device));
assert_param(IS_FSMC_NAND_BANK(Bank));
/* Enable ECC feature */
if (Bank == FSMC_NAND_BANK2)
{
SET_BIT(Device->PCR2, FSMC_PCRx_ECCEN);
}
else
{
SET_BIT(Device->PCR3, FSMC_PCRx_ECCEN);
}
return HAL_OK;
}
/**
* @brief Disables dynamically FSMC_NAND ECC feature.
* @param Device Pointer to NAND device instance
* @param Bank NAND bank number
* @retval HAL status
*/
HAL_StatusTypeDef FSMC_NAND_ECC_Disable(FSMC_NAND_TypeDef *Device, uint32_t Bank)
{
/* Check the parameters */
assert_param(IS_FSMC_NAND_DEVICE(Device));
assert_param(IS_FSMC_NAND_BANK(Bank));
/* Disable ECC feature */
if (Bank == FSMC_NAND_BANK2)
{
CLEAR_BIT(Device->PCR2, FSMC_PCRx_ECCEN);
}
else
{
CLEAR_BIT(Device->PCR3, FSMC_PCRx_ECCEN);
}
return HAL_OK;
}
/**
* @brief Disables dynamically FSMC_NAND ECC feature.
* @param Device Pointer to NAND device instance
* @param ECCval Pointer to ECC value
* @param Bank NAND bank number
* @param Timeout Timeout wait value
* @retval HAL status
*/
HAL_StatusTypeDef FSMC_NAND_GetECC(const FSMC_NAND_TypeDef *Device, uint32_t *ECCval, uint32_t Bank,
uint32_t Timeout)
{
uint32_t tickstart;
/* Check the parameters */
assert_param(IS_FSMC_NAND_DEVICE(Device));
assert_param(IS_FSMC_NAND_BANK(Bank));
/* Get tick */
tickstart = HAL_GetTick();
/* Wait until FIFO is empty */
while (__FSMC_NAND_GET_FLAG(Device, Bank, FSMC_FLAG_FEMPT) == RESET)
{
/* Check for the Timeout */
if (Timeout != HAL_MAX_DELAY)
{
if (((HAL_GetTick() - tickstart) > Timeout) || (Timeout == 0U))
{
return HAL_TIMEOUT;
}
}
}
if (Bank == FSMC_NAND_BANK2)
{
/* Get the ECCR2 register value */
*ECCval = (uint32_t)Device->ECCR2;
}
else
{
/* Get the ECCR3 register value */
*ECCval = (uint32_t)Device->ECCR3;
}
return HAL_OK;
}
/**
* @}
*/
#endif /* FSMC_BANK3 */
#if defined(FSMC_BANK4)
/** @addtogroup FSMC_LL_PCCARD
* @brief PCCARD Controller functions
*
@verbatim
==============================================================================
##### How to use PCCARD device driver #####
==============================================================================
[..]
This driver contains a set of APIs to interface with the FSMC PCCARD bank in order
to run the PCCARD/compact flash external devices.
(+) FSMC PCCARD bank reset using the function FSMC_PCCARD_DeInit()
(+) FSMC PCCARD bank control configuration using the function FSMC_PCCARD_Init()
(+) FSMC PCCARD bank common space timing configuration using the function
FSMC_PCCARD_CommonSpace_Timing_Init()
(+) FSMC PCCARD bank attribute space timing configuration using the function
FSMC_PCCARD_AttributeSpace_Timing_Init()
(+) FSMC PCCARD bank IO space timing configuration using the function
FSMC_PCCARD_IOSpace_Timing_Init()
@endverbatim
* @{
*/
/** @addtogroup FSMC_LL_PCCARD_Private_Functions_Group1
* @brief Initialization and Configuration functions
*
@verbatim
==============================================================================
##### Initialization and de_initialization functions #####
==============================================================================
[..]
This section provides functions allowing to:
(+) Initialize and configure the FSMC PCCARD interface
(+) De-initialize the FSMC PCCARD interface
(+) Configure the FSMC clock and associated GPIOs
@endverbatim
* @{
*/
/**
* @brief Initializes the FSMC_PCCARD device according to the specified
* control parameters in the FSMC_PCCARD_HandleTypeDef
* @param Device Pointer to PCCARD device instance
* @param Init Pointer to PCCARD Initialization structure
* @retval HAL status
*/
HAL_StatusTypeDef FSMC_PCCARD_Init(FSMC_PCCARD_TypeDef *Device, const FSMC_PCCARD_InitTypeDef *Init)
{
/* Check the parameters */
assert_param(IS_FSMC_PCCARD_DEVICE(Device));
#if defined(FSMC_BANK3)
assert_param(IS_FSMC_WAIT_FEATURE(Init->Waitfeature));
assert_param(IS_FSMC_TCLR_TIME(Init->TCLRSetupTime));
assert_param(IS_FSMC_TAR_TIME(Init->TARSetupTime));
#endif /* FSMC_BANK3 */
/* Set FSMC_PCCARD device control parameters */
MODIFY_REG(Device->PCR4,
(FSMC_PCRx_PTYP |
FSMC_PCRx_PWAITEN |
FSMC_PCRx_PWID |
FSMC_PCRx_TCLR |
FSMC_PCRx_TAR),
(FSMC_PCR_MEMORY_TYPE_PCCARD |
Init->Waitfeature |
FSMC_NAND_PCC_MEM_BUS_WIDTH_16 |
(Init->TCLRSetupTime << FSMC_PCRx_TCLR_Pos) |
(Init->TARSetupTime << FSMC_PCRx_TAR_Pos)));
return HAL_OK;
}
/**
* @brief Initializes the FSMC_PCCARD Common space Timing according to the specified
* parameters in the FSMC_NAND_PCC_TimingTypeDef
* @param Device Pointer to PCCARD device instance
* @param Timing Pointer to PCCARD timing structure
* @retval HAL status
*/
HAL_StatusTypeDef FSMC_PCCARD_CommonSpace_Timing_Init(FSMC_PCCARD_TypeDef *Device,
const FSMC_NAND_PCC_TimingTypeDef *Timing)
{
/* Check the parameters */
assert_param(IS_FSMC_PCCARD_DEVICE(Device));
#if defined(FSMC_BANK3)
assert_param(IS_FSMC_SETUP_TIME(Timing->SetupTime));
assert_param(IS_FSMC_WAIT_TIME(Timing->WaitSetupTime));
assert_param(IS_FSMC_HOLD_TIME(Timing->HoldSetupTime));
assert_param(IS_FSMC_HIZ_TIME(Timing->HiZSetupTime));
#endif /* FSMC_BANK3 */
/* Set PCCARD timing parameters */
MODIFY_REG(Device->PMEM4, PMEM_CLEAR_MASK,
(Timing->SetupTime |
((Timing->WaitSetupTime) << FSMC_PMEMx_MEMWAITx_Pos) |
((Timing->HoldSetupTime) << FSMC_PMEMx_MEMHOLDx_Pos) |
((Timing->HiZSetupTime) << FSMC_PMEMx_MEMHIZx_Pos)));
return HAL_OK;
}
/**
* @brief Initializes the FSMC_PCCARD Attribute space Timing according to the specified
* parameters in the FSMC_NAND_PCC_TimingTypeDef
* @param Device Pointer to PCCARD device instance
* @param Timing Pointer to PCCARD timing structure
* @retval HAL status
*/
HAL_StatusTypeDef FSMC_PCCARD_AttributeSpace_Timing_Init(FSMC_PCCARD_TypeDef *Device,
const FSMC_NAND_PCC_TimingTypeDef *Timing)
{
/* Check the parameters */
assert_param(IS_FSMC_PCCARD_DEVICE(Device));
#if defined(FSMC_BANK3)
assert_param(IS_FSMC_SETUP_TIME(Timing->SetupTime));
assert_param(IS_FSMC_WAIT_TIME(Timing->WaitSetupTime));
assert_param(IS_FSMC_HOLD_TIME(Timing->HoldSetupTime));
assert_param(IS_FSMC_HIZ_TIME(Timing->HiZSetupTime));
#endif /* FSMC_BANK3 */
/* Set PCCARD timing parameters */
MODIFY_REG(Device->PATT4, PATT_CLEAR_MASK,
(Timing->SetupTime |
((Timing->WaitSetupTime) << FSMC_PATTx_ATTWAITx_Pos) |
((Timing->HoldSetupTime) << FSMC_PATTx_ATTHOLDx_Pos) |
((Timing->HiZSetupTime) << FSMC_PATTx_ATTHIZx_Pos)));
return HAL_OK;
}
/**
* @brief Initializes the FSMC_PCCARD IO space Timing according to the specified
* parameters in the FSMC_NAND_PCC_TimingTypeDef
* @param Device Pointer to PCCARD device instance
* @param Timing Pointer to PCCARD timing structure
* @retval HAL status
*/
HAL_StatusTypeDef FSMC_PCCARD_IOSpace_Timing_Init(FSMC_PCCARD_TypeDef *Device,
const FSMC_NAND_PCC_TimingTypeDef *Timing)
{
/* Check the parameters */
assert_param(IS_FSMC_PCCARD_DEVICE(Device));
#if defined(FSMC_BANK3)
assert_param(IS_FSMC_SETUP_TIME(Timing->SetupTime));
assert_param(IS_FSMC_WAIT_TIME(Timing->WaitSetupTime));
assert_param(IS_FSMC_HOLD_TIME(Timing->HoldSetupTime));
assert_param(IS_FSMC_HIZ_TIME(Timing->HiZSetupTime));
#endif /* FSMC_BANK3 */
/* Set FSMC_PCCARD device timing parameters */
MODIFY_REG(Device->PIO4, PIO4_CLEAR_MASK,
(Timing->SetupTime |
(Timing->WaitSetupTime << FSMC_PIO4_IOWAIT4_Pos) |
(Timing->HoldSetupTime << FSMC_PIO4_IOHOLD4_Pos) |
(Timing->HiZSetupTime << FSMC_PIO4_IOHIZ4_Pos)));
return HAL_OK;
}
/**
* @brief DeInitializes the FSMC_PCCARD device
* @param Device Pointer to PCCARD device instance
* @retval HAL status
*/
HAL_StatusTypeDef FSMC_PCCARD_DeInit(FSMC_PCCARD_TypeDef *Device)
{
/* Check the parameters */
assert_param(IS_FSMC_PCCARD_DEVICE(Device));
/* Disable the FSMC_PCCARD device */
__FSMC_PCCARD_DISABLE(Device);
/* De-initialize the FSMC_PCCARD device */
Device->PCR4 = 0x00000018U;
Device->SR4 = 0x00000040U;
Device->PMEM4 = 0xFCFCFCFCU;
Device->PATT4 = 0xFCFCFCFCU;
Device->PIO4 = 0xFCFCFCFCU;
return HAL_OK;
}
/**
* @}
*/
#endif /* FSMC_BANK4 */
/**
* @}
*/
/**
* @}
*/
#endif /* HAL_NOR_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/

View File

@@ -0,0 +1,256 @@
/**
******************************************************************************
* @file stm32f1xx_ll_gpio.c
* @author MCD Application Team
* @brief GPIO LL module driver.
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#if defined(USE_FULL_LL_DRIVER)
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_ll_gpio.h"
#include "stm32f1xx_ll_bus.h"
#ifdef USE_FULL_ASSERT
#include "stm32_assert.h"
#else
#define assert_param(expr) ((void)0U)
#endif
/** @addtogroup STM32F1xx_LL_Driver
* @{
*/
#if defined (GPIOA) || defined (GPIOB) || defined (GPIOC) || defined (GPIOD) || defined (GPIOE) || defined (GPIOF) || defined (GPIOG)
/** @addtogroup GPIO_LL
* @{
*/
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/** @addtogroup GPIO_LL_Private_Macros
* @{
*/
#define IS_LL_GPIO_PIN(__VALUE__) ((((__VALUE__) & LL_GPIO_PIN_ALL)!= 0u) &&\
(((__VALUE__) & (~LL_GPIO_PIN_ALL))== 0u))
#define IS_LL_GPIO_MODE(__VALUE__) (((__VALUE__) == LL_GPIO_MODE_ANALOG) ||\
((__VALUE__) == LL_GPIO_MODE_FLOATING) ||\
((__VALUE__) == LL_GPIO_MODE_INPUT) ||\
((__VALUE__) == LL_GPIO_MODE_OUTPUT) ||\
((__VALUE__) == LL_GPIO_MODE_ALTERNATE))
#define IS_LL_GPIO_SPEED(__VALUE__) (((__VALUE__) == LL_GPIO_SPEED_FREQ_LOW) ||\
((__VALUE__) == LL_GPIO_SPEED_FREQ_MEDIUM) ||\
((__VALUE__) == LL_GPIO_SPEED_FREQ_HIGH))
#define IS_LL_GPIO_OUTPUT_TYPE(__VALUE__) (((__VALUE__) == LL_GPIO_OUTPUT_PUSHPULL) ||\
((__VALUE__) == LL_GPIO_OUTPUT_OPENDRAIN))
#define IS_LL_GPIO_PULL(__VALUE__) (((__VALUE__) == LL_GPIO_PULL_DOWN) ||\
((__VALUE__) == LL_GPIO_PULL_UP))
/**
* @}
*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup GPIO_LL_Exported_Functions
* @{
*/
/** @addtogroup GPIO_LL_EF_Init
* @{
*/
/**
* @brief De-initialize GPIO registers (Registers restored to their default values).
* @param GPIOx GPIO Port
* @retval An ErrorStatus enumeration value:
* - SUCCESS: GPIO registers are de-initialized
* - ERROR: Wrong GPIO Port
*/
ErrorStatus LL_GPIO_DeInit(GPIO_TypeDef *GPIOx)
{
ErrorStatus status = SUCCESS;
/* Check the parameters */
assert_param(IS_GPIO_ALL_INSTANCE(GPIOx));
/* Force and Release reset on clock of GPIOx Port */
if (GPIOx == GPIOA)
{
LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_GPIOA);
LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_GPIOA);
}
else if (GPIOx == GPIOB)
{
LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_GPIOB);
LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_GPIOB);
}
else if (GPIOx == GPIOC)
{
LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_GPIOC);
LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_GPIOC);
}
else if (GPIOx == GPIOD)
{
LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_GPIOD);
LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_GPIOD);
}
#if defined(GPIOE)
else if (GPIOx == GPIOE)
{
LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_GPIOE);
LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_GPIOE);
}
#endif
#if defined(GPIOF)
else if (GPIOx == GPIOF)
{
LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_GPIOF);
LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_GPIOF);
}
#endif
#if defined(GPIOG)
else if (GPIOx == GPIOG)
{
LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_GPIOG);
LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_GPIOG);
}
#endif
else
{
status = ERROR;
}
return (status);
}
/**
* @brief Initialize GPIO registers according to the specified parameters in GPIO_InitStruct.
* @param GPIOx GPIO Port
* @param GPIO_InitStruct: pointer to a @ref LL_GPIO_InitTypeDef structure
* that contains the configuration information for the specified GPIO peripheral.
* @retval An ErrorStatus enumeration value:
* - SUCCESS: GPIO registers are initialized according to GPIO_InitStruct content
* - ERROR: Not applicable
*/
ErrorStatus LL_GPIO_Init(GPIO_TypeDef *GPIOx, LL_GPIO_InitTypeDef *GPIO_InitStruct)
{
uint32_t pinmask;
uint32_t pinpos;
uint32_t currentpin;
/* Check the parameters */
assert_param(IS_GPIO_ALL_INSTANCE(GPIOx));
assert_param(IS_LL_GPIO_PIN(GPIO_InitStruct->Pin));
/* ------------------------- Configure the port pins ---------------- */
/* Initialize pinpos on first pin set */
pinmask = ((GPIO_InitStruct->Pin) << GPIO_PIN_MASK_POS) >> GPIO_PIN_NB;
pinpos = POSITION_VAL(pinmask);
/* Configure the port pins */
while ((pinmask >> pinpos) != 0u)
{
/* skip if bit is not set */
if ((pinmask & (1u << pinpos)) != 0u)
{
/* Get current io position */
if (pinpos < GPIO_PIN_MASK_POS)
{
currentpin = (0x00000101uL << pinpos);
}
else
{
currentpin = ((0x00010001u << (pinpos - GPIO_PIN_MASK_POS)) | 0x04000000u);
}
if (GPIO_InitStruct->Mode == LL_GPIO_MODE_INPUT)
{
/* Check The Pull parameter */
assert_param(IS_LL_GPIO_PULL(GPIO_InitStruct->Pull));
/* Pull-up Pull-down resistor configuration*/
LL_GPIO_SetPinPull(GPIOx, currentpin, GPIO_InitStruct->Pull);
}
/* Check Pin Mode parameters */
assert_param(IS_LL_GPIO_MODE(GPIO_InitStruct->Mode));
/* Pin Mode configuration */
LL_GPIO_SetPinMode(GPIOx, currentpin, GPIO_InitStruct->Mode);
if ((GPIO_InitStruct->Mode == LL_GPIO_MODE_OUTPUT) || (GPIO_InitStruct->Mode == LL_GPIO_MODE_ALTERNATE))
{
/* Check speed and Output mode parameters */
assert_param(IS_LL_GPIO_SPEED(GPIO_InitStruct->Speed));
assert_param(IS_LL_GPIO_OUTPUT_TYPE(GPIO_InitStruct->OutputType));
/* Speed mode configuration */
LL_GPIO_SetPinSpeed(GPIOx, currentpin, GPIO_InitStruct->Speed);
/* Output mode configuration*/
LL_GPIO_SetPinOutputType(GPIOx, currentpin, GPIO_InitStruct->OutputType);
}
}
pinpos++;
}
return (SUCCESS);
}
/**
* @brief Set each @ref LL_GPIO_InitTypeDef field to default value.
* @param GPIO_InitStruct: pointer to a @ref LL_GPIO_InitTypeDef structure
* whose fields will be set to default values.
* @retval None
*/
void LL_GPIO_StructInit(LL_GPIO_InitTypeDef *GPIO_InitStruct)
{
/* Reset GPIO init structure parameters values */
GPIO_InitStruct->Pin = LL_GPIO_PIN_ALL;
GPIO_InitStruct->Mode = LL_GPIO_MODE_FLOATING;
GPIO_InitStruct->Speed = LL_GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct->OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
GPIO_InitStruct->Pull = LL_GPIO_PULL_DOWN;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#endif /* defined (GPIOA) || defined (GPIOB) || defined (GPIOC) || defined (GPIOD) || defined (GPIOE) || defined (GPIOF) || defined (GPIOG) */
/**
* @}
*/
#endif /* USE_FULL_LL_DRIVER */

View File

@@ -0,0 +1,219 @@
/**
******************************************************************************
* @file stm32f1xx_ll_i2c.c
* @author MCD Application Team
* @brief I2C LL module driver.
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#if defined(USE_FULL_LL_DRIVER)
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_ll_i2c.h"
#include "stm32f1xx_ll_bus.h"
#include "stm32f1xx_ll_rcc.h"
#ifdef USE_FULL_ASSERT
#include "stm32_assert.h"
#else
#define assert_param(expr) ((void)0U)
#endif
/** @addtogroup STM32F1xx_LL_Driver
* @{
*/
#if defined (I2C1) || defined (I2C2)
/** @defgroup I2C_LL I2C
* @{
*/
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/** @addtogroup I2C_LL_Private_Macros
* @{
*/
#define IS_LL_I2C_PERIPHERAL_MODE(__VALUE__) (((__VALUE__) == LL_I2C_MODE_I2C) || \
((__VALUE__) == LL_I2C_MODE_SMBUS_HOST) || \
((__VALUE__) == LL_I2C_MODE_SMBUS_DEVICE) || \
((__VALUE__) == LL_I2C_MODE_SMBUS_DEVICE_ARP))
#define IS_LL_I2C_CLOCK_SPEED(__VALUE__) (((__VALUE__) > 0U) && ((__VALUE__) <= LL_I2C_MAX_SPEED_FAST))
#define IS_LL_I2C_DUTY_CYCLE(__VALUE__) (((__VALUE__) == LL_I2C_DUTYCYCLE_2) || \
((__VALUE__) == LL_I2C_DUTYCYCLE_16_9))
#define IS_LL_I2C_OWN_ADDRESS1(__VALUE__) ((__VALUE__) <= 0x000003FFU)
#define IS_LL_I2C_TYPE_ACKNOWLEDGE(__VALUE__) (((__VALUE__) == LL_I2C_ACK) || \
((__VALUE__) == LL_I2C_NACK))
#define IS_LL_I2C_OWN_ADDRSIZE(__VALUE__) (((__VALUE__) == LL_I2C_OWNADDRESS1_7BIT) || \
((__VALUE__) == LL_I2C_OWNADDRESS1_10BIT))
/**
* @}
*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup I2C_LL_Exported_Functions
* @{
*/
/** @addtogroup I2C_LL_EF_Init
* @{
*/
/**
* @brief De-initialize the I2C registers to their default reset values.
* @param I2Cx I2C Instance.
* @retval An ErrorStatus enumeration value:
* - SUCCESS I2C registers are de-initialized
* - ERROR I2C registers are not de-initialized
*/
uint32_t LL_I2C_DeInit(I2C_TypeDef *I2Cx)
{
ErrorStatus status = SUCCESS;
/* Check the I2C Instance I2Cx */
assert_param(IS_I2C_ALL_INSTANCE(I2Cx));
if (I2Cx == I2C1)
{
/* Force reset of I2C clock */
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1);
/* Release reset of I2C clock */
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C1);
}
#if defined(I2C2)
else if (I2Cx == I2C2)
{
/* Force reset of I2C clock */
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C2);
/* Release reset of I2C clock */
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C2);
}
#endif /* I2C2 */
else
{
status = ERROR;
}
return status;
}
/**
* @brief Initialize the I2C registers according to the specified parameters in I2C_InitStruct.
* @param I2Cx I2C Instance.
* @param I2C_InitStruct pointer to a @ref LL_I2C_InitTypeDef structure.
* @retval An ErrorStatus enumeration value:
* - SUCCESS I2C registers are initialized
* - ERROR Not applicable
*/
uint32_t LL_I2C_Init(I2C_TypeDef *I2Cx, LL_I2C_InitTypeDef *I2C_InitStruct)
{
LL_RCC_ClocksTypeDef rcc_clocks;
/* Check the I2C Instance I2Cx */
assert_param(IS_I2C_ALL_INSTANCE(I2Cx));
/* Check the I2C parameters from I2C_InitStruct */
assert_param(IS_LL_I2C_PERIPHERAL_MODE(I2C_InitStruct->PeripheralMode));
assert_param(IS_LL_I2C_CLOCK_SPEED(I2C_InitStruct->ClockSpeed));
assert_param(IS_LL_I2C_DUTY_CYCLE(I2C_InitStruct->DutyCycle));
assert_param(IS_LL_I2C_OWN_ADDRESS1(I2C_InitStruct->OwnAddress1));
assert_param(IS_LL_I2C_TYPE_ACKNOWLEDGE(I2C_InitStruct->TypeAcknowledge));
assert_param(IS_LL_I2C_OWN_ADDRSIZE(I2C_InitStruct->OwnAddrSize));
/* Disable the selected I2Cx Peripheral */
LL_I2C_Disable(I2Cx);
/* Retrieve Clock frequencies */
LL_RCC_GetSystemClocksFreq(&rcc_clocks);
/*---------------------------- I2Cx SCL Clock Speed Configuration ------------
* Configure the SCL speed :
* - ClockSpeed: I2C_CR2_FREQ[5:0], I2C_TRISE_TRISE[5:0], I2C_CCR_FS,
* and I2C_CCR_CCR[11:0] bits
* - DutyCycle: I2C_CCR_DUTY[7:0] bits
*/
LL_I2C_ConfigSpeed(I2Cx, rcc_clocks.PCLK1_Frequency, I2C_InitStruct->ClockSpeed, I2C_InitStruct->DutyCycle);
/*---------------------------- I2Cx OAR1 Configuration -----------------------
* Disable, Configure and Enable I2Cx device own address 1 with parameters :
* - OwnAddress1: I2C_OAR1_ADD[9:8], I2C_OAR1_ADD[7:1] and I2C_OAR1_ADD0 bits
* - OwnAddrSize: I2C_OAR1_ADDMODE bit
*/
LL_I2C_SetOwnAddress1(I2Cx, I2C_InitStruct->OwnAddress1, I2C_InitStruct->OwnAddrSize);
/*---------------------------- I2Cx MODE Configuration -----------------------
* Configure I2Cx peripheral mode with parameter :
* - PeripheralMode: I2C_CR1_SMBUS, I2C_CR1_SMBTYPE and I2C_CR1_ENARP bits
*/
LL_I2C_SetMode(I2Cx, I2C_InitStruct->PeripheralMode);
/* Enable the selected I2Cx Peripheral */
LL_I2C_Enable(I2Cx);
/*---------------------------- I2Cx CR2 Configuration ------------------------
* Configure the ACKnowledge or Non ACKnowledge condition
* after the address receive match code or next received byte with parameter :
* - TypeAcknowledge: I2C_CR2_NACK bit
*/
LL_I2C_AcknowledgeNextData(I2Cx, I2C_InitStruct->TypeAcknowledge);
return SUCCESS;
}
/**
* @brief Set each @ref LL_I2C_InitTypeDef field to default value.
* @param I2C_InitStruct Pointer to a @ref LL_I2C_InitTypeDef structure.
* @retval None
*/
void LL_I2C_StructInit(LL_I2C_InitTypeDef *I2C_InitStruct)
{
/* Set I2C_InitStruct fields to default values */
I2C_InitStruct->PeripheralMode = LL_I2C_MODE_I2C;
I2C_InitStruct->ClockSpeed = 5000U;
I2C_InitStruct->DutyCycle = LL_I2C_DUTYCYCLE_2;
I2C_InitStruct->OwnAddress1 = 0U;
I2C_InitStruct->TypeAcknowledge = LL_I2C_NACK;
I2C_InitStruct->OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#endif /* I2C1 || I2C2 */
/**
* @}
*/
#endif /* USE_FULL_LL_DRIVER */

View File

@@ -0,0 +1,83 @@
/**
******************************************************************************
* @file stm32f1xx_ll_pwr.c
* @author MCD Application Team
* @brief PWR LL module driver.
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#if defined(USE_FULL_LL_DRIVER)
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_ll_pwr.h"
#include "stm32f1xx_ll_bus.h"
/** @addtogroup STM32F1xx_LL_Driver
* @{
*/
#if defined(PWR)
/** @defgroup PWR_LL PWR
* @{
*/
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup PWR_LL_Exported_Functions
* @{
*/
/** @addtogroup PWR_LL_EF_Init
* @{
*/
/**
* @brief De-initialize the PWR registers to their default reset values.
* @retval An ErrorStatus enumeration value:
* - SUCCESS: PWR registers are de-initialized
* - ERROR: not applicable
*/
ErrorStatus LL_PWR_DeInit(void)
{
/* Force reset of PWR clock */
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_PWR);
/* Release reset of PWR clock */
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_PWR);
return SUCCESS;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#endif /* defined(PWR) */
/**
* @}
*/
#endif /* USE_FULL_LL_DRIVER */

View File

@@ -0,0 +1,471 @@
/**
******************************************************************************
* @file stm32f1xx_ll_rcc.c
* @author MCD Application Team
* @brief RCC LL module driver.
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file in
* the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
******************************************************************************
*/
#if defined(USE_FULL_LL_DRIVER)
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_ll_rcc.h"
#ifdef USE_FULL_ASSERT
#include "stm32_assert.h"
#else
#define assert_param(expr) ((void)0U)
#endif /* USE_FULL_ASSERT */
/** @addtogroup STM32F1xx_LL_Driver
* @{
*/
#if defined(RCC)
/** @defgroup RCC_LL RCC
* @{
*/
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/** @addtogroup RCC_LL_Private_Macros
* @{
*/
#if defined(RCC_PLLI2S_SUPPORT)
#define IS_LL_RCC_I2S_CLKSOURCE(__VALUE__) (((__VALUE__) == LL_RCC_I2S2_CLKSOURCE) \
|| ((__VALUE__) == LL_RCC_I2S3_CLKSOURCE))
#endif /* RCC_PLLI2S_SUPPORT */
#if defined(USB) || defined(USB_OTG_FS)
#define IS_LL_RCC_USB_CLKSOURCE(__VALUE__) (((__VALUE__) == LL_RCC_USB_CLKSOURCE))
#endif /* USB */
#define IS_LL_RCC_ADC_CLKSOURCE(__VALUE__) (((__VALUE__) == LL_RCC_ADC_CLKSOURCE))
/**
* @}
*/
/* Private function prototypes -----------------------------------------------*/
/** @defgroup RCC_LL_Private_Functions RCC Private functions
* @{
*/
uint32_t RCC_GetSystemClockFreq(void);
uint32_t RCC_GetHCLKClockFreq(uint32_t SYSCLK_Frequency);
uint32_t RCC_GetPCLK1ClockFreq(uint32_t HCLK_Frequency);
uint32_t RCC_GetPCLK2ClockFreq(uint32_t HCLK_Frequency);
uint32_t RCC_PLL_GetFreqDomain_SYS(void);
#if defined(RCC_PLLI2S_SUPPORT)
uint32_t RCC_PLLI2S_GetFreqDomain_I2S(void);
#endif /* RCC_PLLI2S_SUPPORT */
#if defined(RCC_PLL2_SUPPORT)
uint32_t RCC_PLL2_GetFreqClockFreq(void);
#endif /* RCC_PLL2_SUPPORT */
/**
* @}
*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup RCC_LL_Exported_Functions
* @{
*/
/** @addtogroup RCC_LL_EF_Init
* @{
*/
/**
* @brief Reset the RCC clock configuration to the default reset state.
* @note The default reset state of the clock configuration is given below:
* - HSI ON and used as system clock source
* - HSE PLL, PLL2 & PLL3 are OFF
* - AHB, APB1 and APB2 prescaler set to 1.
* - CSS, MCO OFF
* - All interrupts disabled
* @note This function doesn't modify the configuration of the
* - Peripheral clocks
* - LSI, LSE and RTC clocks
* @retval An ErrorStatus enumeration value:
* - SUCCESS: RCC registers are de-initialized
* - ERROR: not applicable
*/
ErrorStatus LL_RCC_DeInit(void)
{
/* Set HSION bit */
LL_RCC_HSI_Enable();
/* Wait for HSI READY bit */
while (LL_RCC_HSI_IsReady() != 1U)
{}
/* Configure HSI as system clock source */
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSI);
/* Wait till clock switch is ready */
while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSI)
{}
/* Reset PLLON bit */
CLEAR_BIT(RCC->CR, RCC_CR_PLLON);
/* Wait for PLL READY bit to be reset */
while (LL_RCC_PLL_IsReady() != 0U)
{}
/* Reset CFGR register */
LL_RCC_WriteReg(CFGR, 0x00000000U);
/* Reset HSEON, HSEBYP & CSSON bits */
CLEAR_BIT(RCC->CR, (RCC_CR_CSSON | RCC_CR_HSEON | RCC_CR_HSEBYP));
#if defined(RCC_CR_PLL2ON)
/* Reset PLL2ON bit */
CLEAR_BIT(RCC->CR, RCC_CR_PLL2ON);
#endif /* RCC_CR_PLL2ON */
#if defined(RCC_CR_PLL3ON)
/* Reset PLL3ON bit */
CLEAR_BIT(RCC->CR, RCC_CR_PLL3ON);
#endif /* RCC_CR_PLL3ON */
/* Set HSITRIM bits to the reset value */
LL_RCC_HSI_SetCalibTrimming(0x10U);
#if defined(RCC_CFGR2_PREDIV1)
/* Reset CFGR2 register */
LL_RCC_WriteReg(CFGR2, 0x00000000U);
#endif /* RCC_CFGR2_PREDIV1 */
/* Disable all interrupts */
LL_RCC_WriteReg(CIR, 0x00000000U);
/* Clear reset flags */
LL_RCC_ClearResetFlags();
return SUCCESS;
}
/**
* @}
*/
/** @addtogroup RCC_LL_EF_Get_Freq
* @brief Return the frequencies of different on chip clocks; System, AHB, APB1 and APB2 buses clocks
* and different peripheral clocks available on the device.
* @note If SYSCLK source is HSI, function returns values based on HSI_VALUE(**)
* @note If SYSCLK source is HSE, function returns values based on HSE_VALUE(***)
* @note If SYSCLK source is PLL, function returns values based on
* HSI_VALUE(**) or HSE_VALUE(***) multiplied/divided by the PLL factors.
* @note (**) HSI_VALUE is a defined constant but the real value may vary
* depending on the variations in voltage and temperature.
* @note (***) HSE_VALUE is a defined constant, user has to ensure that
* HSE_VALUE is same as the real frequency of the crystal used.
* Otherwise, this function may have wrong result.
* @note The result of this function could be incorrect when using fractional
* value for HSE crystal.
* @note This function can be used by the user application to compute the
* baud-rate for the communication peripherals or configure other parameters.
* @{
*/
/**
* @brief Return the frequencies of different on chip clocks; System, AHB, APB1 and APB2 buses clocks
* @note Each time SYSCLK, HCLK, PCLK1 and/or PCLK2 clock changes, this function
* must be called to update structure fields. Otherwise, any
* configuration based on this function will be incorrect.
* @param RCC_Clocks pointer to a @ref LL_RCC_ClocksTypeDef structure which will hold the clocks frequencies
* @retval None
*/
void LL_RCC_GetSystemClocksFreq(LL_RCC_ClocksTypeDef *RCC_Clocks)
{
/* Get SYSCLK frequency */
RCC_Clocks->SYSCLK_Frequency = RCC_GetSystemClockFreq();
/* HCLK clock frequency */
RCC_Clocks->HCLK_Frequency = RCC_GetHCLKClockFreq(RCC_Clocks->SYSCLK_Frequency);
/* PCLK1 clock frequency */
RCC_Clocks->PCLK1_Frequency = RCC_GetPCLK1ClockFreq(RCC_Clocks->HCLK_Frequency);
/* PCLK2 clock frequency */
RCC_Clocks->PCLK2_Frequency = RCC_GetPCLK2ClockFreq(RCC_Clocks->HCLK_Frequency);
}
#if defined(RCC_CFGR2_I2S2SRC)
/**
* @brief Return I2Sx clock frequency
* @param I2SxSource This parameter can be one of the following values:
* @arg @ref LL_RCC_I2S2_CLKSOURCE
* @arg @ref LL_RCC_I2S3_CLKSOURCE
* @retval I2S clock frequency (in Hz)
*/
uint32_t LL_RCC_GetI2SClockFreq(uint32_t I2SxSource)
{
uint32_t i2s_frequency = LL_RCC_PERIPH_FREQUENCY_NO;
/* Check parameter */
assert_param(IS_LL_RCC_I2S_CLKSOURCE(I2SxSource));
/* I2S1CLK clock frequency */
switch (LL_RCC_GetI2SClockSource(I2SxSource))
{
case LL_RCC_I2S2_CLKSOURCE_SYSCLK: /*!< System clock selected as I2S clock source */
case LL_RCC_I2S3_CLKSOURCE_SYSCLK:
i2s_frequency = RCC_GetSystemClockFreq();
break;
case LL_RCC_I2S2_CLKSOURCE_PLLI2S_VCO: /*!< PLLI2S oscillator clock selected as I2S clock source */
case LL_RCC_I2S3_CLKSOURCE_PLLI2S_VCO:
default:
i2s_frequency = RCC_PLLI2S_GetFreqDomain_I2S() * 2U;
break;
}
return i2s_frequency;
}
#endif /* RCC_CFGR2_I2S2SRC */
#if defined(USB) || defined(USB_OTG_FS)
/**
* @brief Return USBx clock frequency
* @param USBxSource This parameter can be one of the following values:
* @arg @ref LL_RCC_USB_CLKSOURCE
* @retval USB clock frequency (in Hz)
* @arg @ref LL_RCC_PERIPH_FREQUENCY_NO indicates that oscillator (HSI), HSE or PLL is not ready
*/
uint32_t LL_RCC_GetUSBClockFreq(uint32_t USBxSource)
{
uint32_t usb_frequency = LL_RCC_PERIPH_FREQUENCY_NO;
/* Check parameter */
assert_param(IS_LL_RCC_USB_CLKSOURCE(USBxSource));
/* USBCLK clock frequency */
switch (LL_RCC_GetUSBClockSource(USBxSource))
{
#if defined(RCC_CFGR_USBPRE)
case LL_RCC_USB_CLKSOURCE_PLL: /* PLL clock used as USB clock source */
if (LL_RCC_PLL_IsReady())
{
usb_frequency = RCC_PLL_GetFreqDomain_SYS();
}
break;
case LL_RCC_USB_CLKSOURCE_PLL_DIV_1_5: /* PLL clock divided by 1.5 used as USB clock source */
default:
if (LL_RCC_PLL_IsReady())
{
usb_frequency = (RCC_PLL_GetFreqDomain_SYS() * 3U) / 2U;
}
break;
#endif /* RCC_CFGR_USBPRE */
#if defined(RCC_CFGR_OTGFSPRE)
/* USBCLK = PLLVCO/2
= (2 x PLLCLK) / 2
= PLLCLK */
case LL_RCC_USB_CLKSOURCE_PLL_DIV_2: /* PLL clock used as USB clock source */
if (LL_RCC_PLL_IsReady())
{
usb_frequency = RCC_PLL_GetFreqDomain_SYS();
}
break;
/* USBCLK = PLLVCO/3
= (2 x PLLCLK) / 3 */
case LL_RCC_USB_CLKSOURCE_PLL_DIV_3: /* PLL clock divided by 3 used as USB clock source */
default:
if (LL_RCC_PLL_IsReady())
{
usb_frequency = (RCC_PLL_GetFreqDomain_SYS() * 2U) / 3U;
}
break;
#endif /* RCC_CFGR_OTGFSPRE */
}
return usb_frequency;
}
#endif /* USB */
/**
* @brief Return ADCx clock frequency
* @param ADCxSource This parameter can be one of the following values:
* @arg @ref LL_RCC_ADC_CLKSOURCE
* @retval ADC clock frequency (in Hz)
*/
uint32_t LL_RCC_GetADCClockFreq(uint32_t ADCxSource)
{
uint32_t adc_prescaler = 0U;
uint32_t adc_frequency = 0U;
/* Check parameter */
assert_param(IS_LL_RCC_ADC_CLKSOURCE(ADCxSource));
/* Get ADC prescaler */
adc_prescaler = LL_RCC_GetADCClockSource(ADCxSource);
/* ADC frequency = PCLK2 frequency / ADC prescaler (2, 4, 6 or 8) */
adc_frequency = RCC_GetPCLK2ClockFreq(RCC_GetHCLKClockFreq(RCC_GetSystemClockFreq()))
/ (((adc_prescaler >> POSITION_VAL(ADCxSource)) + 1U) * 2U);
return adc_frequency;
}
/**
* @}
*/
/**
* @}
*/
/** @addtogroup RCC_LL_Private_Functions
* @{
*/
/**
* @brief Return SYSTEM clock frequency
* @retval SYSTEM clock frequency (in Hz)
*/
uint32_t RCC_GetSystemClockFreq(void)
{
uint32_t frequency = 0U;
/* Get SYSCLK source -------------------------------------------------------*/
switch (LL_RCC_GetSysClkSource())
{
case LL_RCC_SYS_CLKSOURCE_STATUS_HSI: /* HSI used as system clock source */
frequency = HSI_VALUE;
break;
case LL_RCC_SYS_CLKSOURCE_STATUS_HSE: /* HSE used as system clock source */
frequency = HSE_VALUE;
break;
case LL_RCC_SYS_CLKSOURCE_STATUS_PLL: /* PLL used as system clock source */
frequency = RCC_PLL_GetFreqDomain_SYS();
break;
default:
frequency = HSI_VALUE;
break;
}
return frequency;
}
/**
* @brief Return HCLK clock frequency
* @param SYSCLK_Frequency SYSCLK clock frequency
* @retval HCLK clock frequency (in Hz)
*/
uint32_t RCC_GetHCLKClockFreq(uint32_t SYSCLK_Frequency)
{
/* HCLK clock frequency */
return __LL_RCC_CALC_HCLK_FREQ(SYSCLK_Frequency, LL_RCC_GetAHBPrescaler());
}
/**
* @brief Return PCLK1 clock frequency
* @param HCLK_Frequency HCLK clock frequency
* @retval PCLK1 clock frequency (in Hz)
*/
uint32_t RCC_GetPCLK1ClockFreq(uint32_t HCLK_Frequency)
{
/* PCLK1 clock frequency */
return __LL_RCC_CALC_PCLK1_FREQ(HCLK_Frequency, LL_RCC_GetAPB1Prescaler());
}
/**
* @brief Return PCLK2 clock frequency
* @param HCLK_Frequency HCLK clock frequency
* @retval PCLK2 clock frequency (in Hz)
*/
uint32_t RCC_GetPCLK2ClockFreq(uint32_t HCLK_Frequency)
{
/* PCLK2 clock frequency */
return __LL_RCC_CALC_PCLK2_FREQ(HCLK_Frequency, LL_RCC_GetAPB2Prescaler());
}
/**
* @brief Return PLL clock frequency used for system domain
* @retval PLL clock frequency (in Hz)
*/
uint32_t RCC_PLL_GetFreqDomain_SYS(void)
{
uint32_t pllinputfreq = 0U, pllsource = 0U;
/* PLL_VCO = (HSE_VALUE, HSI_VALUE or PLL2 / PLL Predivider) * PLL Multiplicator */
/* Get PLL source */
pllsource = LL_RCC_PLL_GetMainSource();
switch (pllsource)
{
case LL_RCC_PLLSOURCE_HSI_DIV_2: /* HSI used as PLL clock source */
pllinputfreq = HSI_VALUE / 2U;
break;
case LL_RCC_PLLSOURCE_HSE: /* HSE used as PLL clock source */
pllinputfreq = HSE_VALUE / (LL_RCC_PLL_GetPrediv() + 1U);
break;
#if defined(RCC_PLL2_SUPPORT)
case LL_RCC_PLLSOURCE_PLL2: /* PLL2 used as PLL clock source */
pllinputfreq = RCC_PLL2_GetFreqClockFreq() / (LL_RCC_PLL_GetPrediv() + 1U);
break;
#endif /* RCC_PLL2_SUPPORT */
default:
pllinputfreq = HSI_VALUE / 2U;
break;
}
return __LL_RCC_CALC_PLLCLK_FREQ(pllinputfreq, LL_RCC_PLL_GetMultiplicator());
}
#if defined(RCC_PLL2_SUPPORT)
/**
* @brief Return PLL clock frequency used for system domain
* @retval PLL clock frequency (in Hz)
*/
uint32_t RCC_PLL2_GetFreqClockFreq(void)
{
return __LL_RCC_CALC_PLL2CLK_FREQ(HSE_VALUE, LL_RCC_PLL2_GetMultiplicator(), LL_RCC_HSE_GetPrediv2());
}
#endif /* RCC_PLL2_SUPPORT */
#if defined(RCC_PLLI2S_SUPPORT)
/**
* @brief Return PLL clock frequency used for system domain
* @retval PLL clock frequency (in Hz)
*/
uint32_t RCC_PLLI2S_GetFreqDomain_I2S(void)
{
return __LL_RCC_CALC_PLLI2SCLK_FREQ(HSE_VALUE, LL_RCC_PLLI2S_GetMultiplicator(), LL_RCC_HSE_GetPrediv2());
}
#endif /* RCC_PLLI2S_SUPPORT */
/**
* @}
*/
/**
* @}
*/
#endif /* defined(RCC) */
/**
* @}
*/
#endif /* USE_FULL_LL_DRIVER */

View File

@@ -0,0 +1,541 @@
/**
******************************************************************************
* @file stm32f1xx_ll_rtc.c
* @author MCD Application Team
* @brief RTC LL module driver.
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#if defined(USE_FULL_LL_DRIVER)
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_ll_rtc.h"
#include "stm32f1xx_ll_cortex.h"
#ifdef USE_FULL_ASSERT
#include "stm32_assert.h"
#else
#define assert_param(expr) ((void)0U)
#endif
/** @addtogroup STM32F1xx_LL_Driver
* @{
*/
#if defined(RTC)
/** @addtogroup RTC_LL
* @{
*/
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/** @addtogroup RTC_LL_Private_Constants
* @{
*/
/* Default values used for prescaler */
#define RTC_ASYNCH_PRESC_DEFAULT 0x00007FFFU
/* Values used for timeout */
#define RTC_INITMODE_TIMEOUT 1000U /* 1s when tick set to 1ms */
#define RTC_SYNCHRO_TIMEOUT 1000U /* 1s when tick set to 1ms */
/**
* @}
*/
/* Private macros ------------------------------------------------------------*/
/** @addtogroup RTC_LL_Private_Macros
* @{
*/
#define IS_LL_RTC_ASYNCH_PREDIV(__VALUE__) ((__VALUE__) <= 0xFFFFFU)
#define IS_LL_RTC_FORMAT(__VALUE__) (((__VALUE__) == LL_RTC_FORMAT_BIN) \
|| ((__VALUE__) == LL_RTC_FORMAT_BCD))
#define IS_LL_RTC_HOUR24(__HOUR__) ((__HOUR__) <= 23U)
#define IS_LL_RTC_MINUTES(__MINUTES__) ((__MINUTES__) <= 59U)
#define IS_LL_RTC_SECONDS(__SECONDS__) ((__SECONDS__) <= 59U)
#define IS_LL_RTC_CALIB_OUTPUT(__OUTPUT__) (((__OUTPUT__) == LL_RTC_CALIB_OUTPUT_NONE) || \
((__OUTPUT__) == LL_RTC_CALIB_OUTPUT_RTCCLOCK) || \
((__OUTPUT__) == LL_RTC_CALIB_OUTPUT_ALARM) || \
((__OUTPUT__) == LL_RTC_CALIB_OUTPUT_SECOND))
/**
* @}
*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup RTC_LL_Exported_Functions
* @{
*/
/** @addtogroup RTC_LL_EF_Init
* @{
*/
/**
* @brief De-Initializes the RTC registers to their default reset values.
* @note This function doesn't reset the RTC Clock source and RTC Backup Data
* registers.
* @param RTCx RTC Instance
* @retval An ErrorStatus enumeration value:
* - SUCCESS: RTC registers are de-initialized
* - ERROR: RTC registers are not de-initialized
*/
ErrorStatus LL_RTC_DeInit(RTC_TypeDef *RTCx)
{
ErrorStatus status = ERROR;
/* Check the parameter */
assert_param(IS_RTC_ALL_INSTANCE(RTCx));
/* Disable the write protection for RTC registers */
LL_RTC_DisableWriteProtection(RTCx);
/* Set Initialization mode */
if (LL_RTC_EnterInitMode(RTCx) != ERROR)
{
LL_RTC_WriteReg(RTCx, CNTL, 0x0000);
LL_RTC_WriteReg(RTCx, CNTH, 0x0000);
LL_RTC_WriteReg(RTCx, PRLH, 0x0000);
LL_RTC_WriteReg(RTCx, PRLL, 0x8000);
LL_RTC_WriteReg(RTCx, CRH, 0x0000);
LL_RTC_WriteReg(RTCx, CRL, 0x0020);
/* Reset Tamper and alternate functions configuration register */
LL_RTC_WriteReg(BKP, RTCCR, 0x00000000U);
LL_RTC_WriteReg(BKP, CR, 0x00000000U);
LL_RTC_WriteReg(BKP, CSR, 0x00000000U);
/* Exit Initialization Mode */
if (LL_RTC_ExitInitMode(RTCx) != ERROR)
{
/* Wait till the RTC RSF flag is set */
status = LL_RTC_WaitForSynchro(RTCx);
/* Clear RSF Flag */
LL_RTC_ClearFlag_RS(RTCx);
/* Enable the write protection for RTC registers */
LL_RTC_EnableWriteProtection(RTCx);
}
}
else
{
/* Enable the write protection for RTC registers */
LL_RTC_EnableWriteProtection(RTCx);
}
return status;
}
/**
* @brief Initializes the RTC registers according to the specified parameters
* in RTC_InitStruct.
* @param RTCx RTC Instance
* @param RTC_InitStruct pointer to a @ref LL_RTC_InitTypeDef structure that contains
* the configuration information for the RTC peripheral.
* @note The RTC Prescaler register is write protected and can be written in
* initialization mode only.
* @note the user should call LL_RTC_StructInit() or the structure of Prescaler
* need to be initialized before RTC init()
* @retval An ErrorStatus enumeration value:
* - SUCCESS: RTC registers are initialized
* - ERROR: RTC registers are not initialized
*/
ErrorStatus LL_RTC_Init(RTC_TypeDef *RTCx, LL_RTC_InitTypeDef *RTC_InitStruct)
{
ErrorStatus status = ERROR;
/* Check the parameters */
assert_param(IS_RTC_ALL_INSTANCE(RTCx));
assert_param(IS_LL_RTC_ASYNCH_PREDIV(RTC_InitStruct->AsynchPrescaler));
assert_param(IS_LL_RTC_CALIB_OUTPUT(RTC_InitStruct->OutPutSource));
/* Waiting for synchro */
if (LL_RTC_WaitForSynchro(RTCx) != ERROR)
{
/* Set Initialization mode */
if (LL_RTC_EnterInitMode(RTCx) != ERROR)
{
/* Clear Flag Bits */
LL_RTC_ClearFlag_ALR(RTCx);
LL_RTC_ClearFlag_OW(RTCx);
LL_RTC_ClearFlag_SEC(RTCx);
if (RTC_InitStruct->OutPutSource != LL_RTC_CALIB_OUTPUT_NONE)
{
/* Disable the selected Tamper Pin */
LL_RTC_TAMPER_Disable(BKP);
}
/* Set the signal which will be routed to RTC Tamper Pin */
LL_RTC_SetOutputSource(BKP, RTC_InitStruct->OutPutSource);
/* Configure Synchronous and Asynchronous prescaler factor */
LL_RTC_SetAsynchPrescaler(RTCx, RTC_InitStruct->AsynchPrescaler);
/* Exit Initialization Mode */
LL_RTC_ExitInitMode(RTCx);
status = SUCCESS;
}
}
return status;
}
/**
* @brief Set each @ref LL_RTC_InitTypeDef field to default value.
* @param RTC_InitStruct pointer to a @ref LL_RTC_InitTypeDef structure which will be initialized.
* @retval None
*/
void LL_RTC_StructInit(LL_RTC_InitTypeDef *RTC_InitStruct)
{
/* Set RTC_InitStruct fields to default values */
RTC_InitStruct->AsynchPrescaler = RTC_ASYNCH_PRESC_DEFAULT;
RTC_InitStruct->OutPutSource = LL_RTC_CALIB_OUTPUT_NONE;
}
/**
* @brief Set the RTC current time.
* @param RTCx RTC Instance
* @param RTC_Format This parameter can be one of the following values:
* @arg @ref LL_RTC_FORMAT_BIN
* @arg @ref LL_RTC_FORMAT_BCD
* @param RTC_TimeStruct pointer to a RTC_TimeTypeDef structure that contains
* the time configuration information for the RTC.
* @note The user should call LL_RTC_TIME_StructInit() or the structure
* of time need to be initialized before time init()
* @retval An ErrorStatus enumeration value:
* - SUCCESS: RTC Time register is configured
* - ERROR: RTC Time register is not configured
*/
ErrorStatus LL_RTC_TIME_Init(RTC_TypeDef *RTCx, uint32_t RTC_Format, LL_RTC_TimeTypeDef *RTC_TimeStruct)
{
ErrorStatus status = ERROR;
uint32_t counter_time = 0U;
/* Check the parameters */
assert_param(IS_RTC_ALL_INSTANCE(RTCx));
assert_param(IS_LL_RTC_FORMAT(RTC_Format));
if (RTC_Format == LL_RTC_FORMAT_BIN)
{
assert_param(IS_LL_RTC_HOUR24(RTC_TimeStruct->Hours));
assert_param(IS_LL_RTC_MINUTES(RTC_TimeStruct->Minutes));
assert_param(IS_LL_RTC_SECONDS(RTC_TimeStruct->Seconds));
}
else
{
assert_param(IS_LL_RTC_HOUR24(__LL_RTC_CONVERT_BCD2BIN(RTC_TimeStruct->Hours)));
assert_param(IS_LL_RTC_MINUTES(__LL_RTC_CONVERT_BCD2BIN(RTC_TimeStruct->Minutes)));
assert_param(IS_LL_RTC_SECONDS(__LL_RTC_CONVERT_BCD2BIN(RTC_TimeStruct->Seconds)));
}
/* Enter Initialization mode */
if (LL_RTC_EnterInitMode(RTCx) != ERROR)
{
/* Check the input parameters format */
if (RTC_Format == LL_RTC_FORMAT_BIN)
{
counter_time = (uint32_t)(((uint32_t)RTC_TimeStruct->Hours * 3600U) + \
((uint32_t)RTC_TimeStruct->Minutes * 60U) + \
((uint32_t)RTC_TimeStruct->Seconds));
LL_RTC_TIME_Set(RTCx, counter_time);
}
else
{
counter_time = (((uint32_t)(__LL_RTC_CONVERT_BCD2BIN(RTC_TimeStruct->Hours)) * 3600U) + \
((uint32_t)(__LL_RTC_CONVERT_BCD2BIN(RTC_TimeStruct->Minutes)) * 60U) + \
((uint32_t)(__LL_RTC_CONVERT_BCD2BIN(RTC_TimeStruct->Seconds))));
LL_RTC_TIME_Set(RTCx, counter_time);
}
status = SUCCESS;
}
/* Exit Initialization mode */
LL_RTC_ExitInitMode(RTCx);
return status;
}
/**
* @brief Set each @ref LL_RTC_TimeTypeDef field to default value (Time = 00h:00min:00sec).
* @param RTC_TimeStruct pointer to a @ref LL_RTC_TimeTypeDef structure which will be initialized.
* @retval None
*/
void LL_RTC_TIME_StructInit(LL_RTC_TimeTypeDef *RTC_TimeStruct)
{
/* Time = 00h:00min:00sec */
RTC_TimeStruct->Hours = 0U;
RTC_TimeStruct->Minutes = 0U;
RTC_TimeStruct->Seconds = 0U;
}
/**
* @brief Set the RTC Alarm.
* @param RTCx RTC Instance
* @param RTC_Format This parameter can be one of the following values:
* @arg @ref LL_RTC_FORMAT_BIN
* @arg @ref LL_RTC_FORMAT_BCD
* @param RTC_AlarmStruct pointer to a @ref LL_RTC_AlarmTypeDef structure that
* contains the alarm configuration parameters.
* @note the user should call LL_RTC_ALARM_StructInit() or the structure
* of Alarm need to be initialized before Alarm init()
* @retval An ErrorStatus enumeration value:
* - SUCCESS: ALARM registers are configured
* - ERROR: ALARM registers are not configured
*/
ErrorStatus LL_RTC_ALARM_Init(RTC_TypeDef *RTCx, uint32_t RTC_Format, LL_RTC_AlarmTypeDef *RTC_AlarmStruct)
{
ErrorStatus status = ERROR;
uint32_t counter_alarm = 0U;
/* Check the parameters */
assert_param(IS_RTC_ALL_INSTANCE(RTCx));
assert_param(IS_LL_RTC_FORMAT(RTC_Format));
if (RTC_Format == LL_RTC_FORMAT_BIN)
{
assert_param(IS_LL_RTC_HOUR24(RTC_AlarmStruct->AlarmTime.Hours));
assert_param(IS_LL_RTC_MINUTES(RTC_AlarmStruct->AlarmTime.Minutes));
assert_param(IS_LL_RTC_SECONDS(RTC_AlarmStruct->AlarmTime.Seconds));
}
else
{
assert_param(IS_LL_RTC_HOUR24(__LL_RTC_CONVERT_BCD2BIN(RTC_AlarmStruct->AlarmTime.Hours)));
assert_param(IS_LL_RTC_MINUTES(__LL_RTC_CONVERT_BCD2BIN(RTC_AlarmStruct->AlarmTime.Minutes)));
assert_param(IS_LL_RTC_SECONDS(__LL_RTC_CONVERT_BCD2BIN(RTC_AlarmStruct->AlarmTime.Seconds)));
}
/* Enter Initialization mode */
if (LL_RTC_EnterInitMode(RTCx) != ERROR)
{
/* Check the input parameters format */
if (RTC_Format == LL_RTC_FORMAT_BIN)
{
counter_alarm = (uint32_t)(((uint32_t)RTC_AlarmStruct->AlarmTime.Hours * 3600U) + \
((uint32_t)RTC_AlarmStruct->AlarmTime.Minutes * 60U) + \
((uint32_t)RTC_AlarmStruct->AlarmTime.Seconds));
LL_RTC_ALARM_Set(RTCx, counter_alarm);
}
else
{
counter_alarm = (((uint32_t)(__LL_RTC_CONVERT_BCD2BIN(RTC_AlarmStruct->AlarmTime.Hours)) * 3600U) + \
((uint32_t)(__LL_RTC_CONVERT_BCD2BIN(RTC_AlarmStruct->AlarmTime.Minutes)) * 60U) + \
((uint32_t)(__LL_RTC_CONVERT_BCD2BIN(RTC_AlarmStruct->AlarmTime.Seconds))));
LL_RTC_ALARM_Set(RTCx, counter_alarm);
}
status = SUCCESS;
}
/* Exit Initialization mode */
LL_RTC_ExitInitMode(RTCx);
return status;
}
/**
* @brief Set each @ref LL_RTC_AlarmTypeDef of ALARM field to default value (Time = 00h:00mn:00sec /
* Day = 1st day of the month/Mask = all fields are masked).
* @param RTC_AlarmStruct pointer to a @ref LL_RTC_AlarmTypeDef structure which will be initialized.
* @retval None
*/
void LL_RTC_ALARM_StructInit(LL_RTC_AlarmTypeDef *RTC_AlarmStruct)
{
/* Alarm Time Settings : Time = 00h:00mn:00sec */
RTC_AlarmStruct->AlarmTime.Hours = 0U;
RTC_AlarmStruct->AlarmTime.Minutes = 0U;
RTC_AlarmStruct->AlarmTime.Seconds = 0U;
}
/**
* @brief Enters the RTC Initialization mode.
* @param RTCx RTC Instance
* @retval An ErrorStatus enumeration value:
* - SUCCESS: RTC is in Init mode
* - ERROR: RTC is not in Init mode
*/
ErrorStatus LL_RTC_EnterInitMode(RTC_TypeDef *RTCx)
{
__IO uint32_t timeout = RTC_INITMODE_TIMEOUT;
ErrorStatus status = SUCCESS;
uint32_t tmp = 0U;
/* Check the parameter */
assert_param(IS_RTC_ALL_INSTANCE(RTCx));
/* Wait till RTC is in INIT state and if Time out is reached exit */
tmp = LL_RTC_IsActiveFlag_RTOF(RTCx);
while ((timeout != 0U) && (tmp != 1U))
{
if (LL_SYSTICK_IsActiveCounterFlag() == 1U)
{
timeout --;
}
tmp = LL_RTC_IsActiveFlag_RTOF(RTCx);
if (timeout == 0U)
{
status = ERROR;
}
}
/* Disable the write protection for RTC registers */
LL_RTC_DisableWriteProtection(RTCx);
return status;
}
/**
* @brief Exit the RTC Initialization mode.
* @note When the initialization sequence is complete, the calendar restarts
* counting after 4 RTCCLK cycles.
* @param RTCx RTC Instance
* @retval An ErrorStatus enumeration value:
* - SUCCESS: RTC exited from in Init mode
* - ERROR: Not applicable
*/
ErrorStatus LL_RTC_ExitInitMode(RTC_TypeDef *RTCx)
{
__IO uint32_t timeout = RTC_INITMODE_TIMEOUT;
ErrorStatus status = SUCCESS;
uint32_t tmp = 0U;
/* Check the parameter */
assert_param(IS_RTC_ALL_INSTANCE(RTCx));
/* Disable initialization mode */
LL_RTC_EnableWriteProtection(RTCx);
/* Wait till RTC is in INIT state and if Time out is reached exit */
tmp = LL_RTC_IsActiveFlag_RTOF(RTCx);
while ((timeout != 0U) && (tmp != 1U))
{
if (LL_SYSTICK_IsActiveCounterFlag() == 1U)
{
timeout --;
}
tmp = LL_RTC_IsActiveFlag_RTOF(RTCx);
if (timeout == 0U)
{
status = ERROR;
}
}
return status;
}
/**
* @brief Set the Time Counter
* @param RTCx RTC Instance
* @param TimeCounter this value can be from 0 to 0xFFFFFFFF
* @retval An ErrorStatus enumeration value:
* - SUCCESS: RTC Counter register configured
* - ERROR: Not applicable
*/
ErrorStatus LL_RTC_TIME_SetCounter(RTC_TypeDef *RTCx, uint32_t TimeCounter)
{
ErrorStatus status = ERROR;
/* Check the parameter */
assert_param(IS_RTC_ALL_INSTANCE(RTCx));
/* Enter Initialization mode */
if (LL_RTC_EnterInitMode(RTCx) != ERROR)
{
LL_RTC_TIME_Set(RTCx, TimeCounter);
status = SUCCESS;
}
/* Exit Initialization mode */
LL_RTC_ExitInitMode(RTCx);
return status;
}
/**
* @brief Set Alarm Counter.
* @param RTCx RTC Instance
* @param AlarmCounter this value can be from 0 to 0xFFFFFFFF
* @retval An ErrorStatus enumeration value:
* - SUCCESS: RTC exited from in Init mode
* - ERROR: Not applicable
*/
ErrorStatus LL_RTC_ALARM_SetCounter(RTC_TypeDef *RTCx, uint32_t AlarmCounter)
{
ErrorStatus status = ERROR;
/* Check the parameter */
assert_param(IS_RTC_ALL_INSTANCE(RTCx));
/* Enter Initialization mode */
if (LL_RTC_EnterInitMode(RTCx) != ERROR)
{
LL_RTC_ALARM_Set(RTCx, AlarmCounter);
status = SUCCESS;
}
/* Exit Initialization mode */
LL_RTC_ExitInitMode(RTCx);
return status;
}
/**
* @brief Waits until the RTC registers are synchronized with RTC APB clock.
* @note The RTC Resynchronization mode is write protected, use the
* @ref LL_RTC_DisableWriteProtection before calling this function.
* @param RTCx RTC Instance
* @retval An ErrorStatus enumeration value:
* - SUCCESS: RTC registers are synchronised
* - ERROR: RTC registers are not synchronised
*/
ErrorStatus LL_RTC_WaitForSynchro(RTC_TypeDef *RTCx)
{
__IO uint32_t timeout = RTC_SYNCHRO_TIMEOUT;
ErrorStatus status = SUCCESS;
uint32_t tmp = 0U;
/* Check the parameter */
assert_param(IS_RTC_ALL_INSTANCE(RTCx));
/* Clear RSF flag */
LL_RTC_ClearFlag_RS(RTCx);
/* Wait the registers to be synchronised */
tmp = LL_RTC_IsActiveFlag_RS(RTCx);
while ((timeout != 0U) && (tmp != 0U))
{
if (LL_SYSTICK_IsActiveCounterFlag() == 1U)
{
timeout--;
}
tmp = LL_RTC_IsActiveFlag_RS(RTCx);
if (timeout == 0U)
{
status = ERROR;
}
}
return (status);
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#endif /* defined(RTC) */
/**
* @}
*/
#endif /* USE_FULL_LL_DRIVER */

View File

@@ -0,0 +1,1578 @@
/**
******************************************************************************
* @file stm32f1xx_ll_sdmmc.c
* @author MCD Application Team
* @brief SDMMC Low Layer HAL module driver.
*
* This file provides firmware functions to manage the following
* functionalities of the SDMMC peripheral:
* + Initialization/de-initialization functions
* + I/O operation functions
* + Peripheral Control functions
* + Peripheral State functions
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
==============================================================================
##### SDMMC peripheral features #####
==============================================================================
[..] The SD/SDMMC MMC card host interface (SDMMC) provides an interface between the AHB
peripheral bus and MultiMedia cards (MMCs), SD memory cards, SDMMC cards and CE-ATA
devices.
[..] The SDMMC features include the following:
(+) Full compliance with MultiMedia Card System Specification Version 4.2. Card support
for three different databus modes: 1-bit (default), 4-bit and 8-bit
(+) Full compatibility with previous versions of MultiMedia Cards (forward compatibility)
(+) Full compliance with SD Memory Card Specifications Version 2.0
(+) Full compliance with SD I/O Card Specification Version 2.0: card support for two
different data bus modes: 1-bit (default) and 4-bit
(+) Full support of the CE-ATA features (full compliance with CE-ATA digital protocol
Rev1.1)
(+) Data transfer up to 48 MHz for the 8 bit mode
(+) Data and command output enable signals to control external bidirectional drivers
##### How to use this driver #####
==============================================================================
[..]
This driver is a considered as a driver of service for external devices drivers
that interfaces with the SDMMC peripheral.
According to the device used (SD card/ MMC card / SDMMC card ...), a set of APIs
is used in the device's driver to perform SDMMC operations and functionalities.
This driver is almost transparent for the final user, it is only used to implement other
functionalities of the external device.
[..]
(+) The SDMMC clock (SDMMCCLK = 48 MHz) is coming from a specific output (MSI, PLLUSB1CLK,
PLLUSB2CLK). Before start working with SDMMC peripheral make sure that the
PLL is well configured.
The SDMMC peripheral uses two clock signals:
(++) SDMMC adapter clock (SDMMCCLK = 48 MHz)
(++) APB2 bus clock (PCLK2)
-@@- PCLK2 and SDMMC_CK clock frequencies must respect the following condition:
Frequency(PCLK2) >= (3 / 8 x Frequency(SDMMC_CK))
(+) Enable/Disable peripheral clock using RCC peripheral macros related to SDMMC
peripheral.
(+) Enable the Power ON State using the SDIO_PowerState_ON()
function and disable it using the function SDIO_PowerState_OFF().
(+) Enable/Disable the clock using the __SDIO_ENABLE()/__SDIO_DISABLE() macros.
(+) Enable/Disable the peripheral interrupts using the macros __SDIO_ENABLE_IT()
and __SDIO_DISABLE_IT() if you need to use interrupt mode.
(+) When using the DMA mode
(++) Configure the DMA in the MSP layer of the external device
(++) Active the needed channel Request
(++) Enable the DMA using __SDIO_DMA_ENABLE() macro or Disable it using the macro
__SDIO_DMA_DISABLE().
(+) To control the CPSM (Command Path State Machine) and send
commands to the card use the SDIO_SendCommand(),
SDIO_GetCommandResponse() and SDIO_GetResponse() functions. First, user has
to fill the command structure (pointer to SDIO_CmdInitTypeDef) according
to the selected command to be sent.
The parameters that should be filled are:
(++) Command Argument
(++) Command Index
(++) Command Response type
(++) Command Wait
(++) CPSM Status (Enable or Disable).
-@@- To check if the command is well received, read the SDIO_CMDRESP
register using the SDIO_GetCommandResponse().
The SDMMC responses registers (SDIO_RESP1 to SDIO_RESP2), use the
SDIO_GetResponse() function.
(+) To control the DPSM (Data Path State Machine) and send/receive
data to/from the card use the SDIO_DataConfig(), SDIO_GetDataCounter(),
SDIO_ReadFIFO(), SDIO_WriteFIFO() and SDIO_GetFIFOCount() functions.
*** Read Operations ***
=======================
[..]
(#) First, user has to fill the data structure (pointer to
SDIO_DataInitTypeDef) according to the selected data type to be received.
The parameters that should be filled are:
(++) Data TimeOut
(++) Data Length
(++) Data Block size
(++) Data Transfer direction: should be from card (To SDMMC)
(++) Data Transfer mode
(++) DPSM Status (Enable or Disable)
(#) Configure the SDMMC resources to receive the data from the card
according to selected transfer mode (Refer to Step 8, 9 and 10).
(#) Send the selected Read command (refer to step 11).
(#) Use the SDIO flags/interrupts to check the transfer status.
*** Write Operations ***
========================
[..]
(#) First, user has to fill the data structure (pointer to
SDIO_DataInitTypeDef) according to the selected data type to be received.
The parameters that should be filled are:
(++) Data TimeOut
(++) Data Length
(++) Data Block size
(++) Data Transfer direction: should be to card (To CARD)
(++) Data Transfer mode
(++) DPSM Status (Enable or Disable)
(#) Configure the SDMMC resources to send the data to the card according to
selected transfer mode.
(#) Send the selected Write command.
(#) Use the SDIO flags/interrupts to check the transfer status.
*** Command management operations ***
=====================================
[..]
(#) The commands used for Read/Write/Erase operations are managed in
separate functions.
Each function allows to send the needed command with the related argument,
then check the response.
By the same approach, you could implement a command and check the response.
@endverbatim
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
#if defined(SDIO)
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
/** @defgroup SDMMC_LL SDMMC Low Layer
* @brief Low layer module for SD
* @{
*/
#if defined(HAL_SD_MODULE_ENABLED) || defined(HAL_MMC_MODULE_ENABLED)
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
static uint32_t SDMMC_GetCmdError(SDIO_TypeDef *SDIOx);
/* Exported functions --------------------------------------------------------*/
/** @defgroup SDMMC_LL_Exported_Functions SDMMC Low Layer Exported Functions
* @{
*/
/** @defgroup HAL_SDMMC_LL_Group1 Initialization de-initialization functions
* @brief Initialization and Configuration functions
*
@verbatim
===============================================================================
##### Initialization/de-initialization functions #####
===============================================================================
[..] This section provides functions allowing to:
@endverbatim
* @{
*/
/**
* @brief Initializes the SDMMC according to the specified
* parameters in the SDMMC_InitTypeDef and create the associated handle.
* @param SDIOx: Pointer to SDMMC register base
* @param Init: SDMMC initialization structure
* @retval HAL status
*/
HAL_StatusTypeDef SDIO_Init(SDIO_TypeDef *SDIOx, SDIO_InitTypeDef Init)
{
uint32_t tmpreg = 0;
/* Check the parameters */
assert_param(IS_SDIO_ALL_INSTANCE(SDIOx));
assert_param(IS_SDIO_CLOCK_EDGE(Init.ClockEdge));
assert_param(IS_SDIO_CLOCK_BYPASS(Init.ClockBypass));
assert_param(IS_SDIO_CLOCK_POWER_SAVE(Init.ClockPowerSave));
assert_param(IS_SDIO_BUS_WIDE(Init.BusWide));
assert_param(IS_SDIO_HARDWARE_FLOW_CONTROL(Init.HardwareFlowControl));
assert_param(IS_SDIO_CLKDIV(Init.ClockDiv));
/* Set SDMMC configuration parameters */
tmpreg |= (Init.ClockEdge |\
Init.ClockBypass |\
Init.ClockPowerSave |\
Init.BusWide |\
Init.HardwareFlowControl |\
Init.ClockDiv
);
/* Write to SDMMC CLKCR */
MODIFY_REG(SDIOx->CLKCR, CLKCR_CLEAR_MASK, tmpreg);
return HAL_OK;
}
/**
* @}
*/
/** @defgroup HAL_SDMMC_LL_Group2 IO operation functions
* @brief Data transfers functions
*
@verbatim
===============================================================================
##### I/O operation functions #####
===============================================================================
[..]
This subsection provides a set of functions allowing to manage the SDMMC data
transfers.
@endverbatim
* @{
*/
/**
* @brief Read data (word) from Rx FIFO in blocking mode (polling)
* @param SDIOx: Pointer to SDMMC register base
* @retval HAL status
*/
uint32_t SDIO_ReadFIFO(SDIO_TypeDef *SDIOx)
{
/* Read data from Rx FIFO */
return (SDIOx->FIFO);
}
/**
* @brief Write data (word) to Tx FIFO in blocking mode (polling)
* @param SDIOx: Pointer to SDMMC register base
* @param pWriteData: pointer to data to write
* @retval HAL status
*/
HAL_StatusTypeDef SDIO_WriteFIFO(SDIO_TypeDef *SDIOx, uint32_t *pWriteData)
{
/* Write data to FIFO */
SDIOx->FIFO = *pWriteData;
return HAL_OK;
}
/**
* @}
*/
/** @defgroup HAL_SDMMC_LL_Group3 Peripheral Control functions
* @brief management functions
*
@verbatim
===============================================================================
##### Peripheral Control functions #####
===============================================================================
[..]
This subsection provides a set of functions allowing to control the SDMMC data
transfers.
@endverbatim
* @{
*/
/**
* @brief Set SDMMC Power state to ON.
* @param SDIOx: Pointer to SDMMC register base
* @retval HAL status
*/
HAL_StatusTypeDef SDIO_PowerState_ON(SDIO_TypeDef *SDIOx)
{
/* Set power state to ON */
SDIOx->POWER = SDIO_POWER_PWRCTRL;
return HAL_OK;
}
/**
* @brief Set SDMMC Power state to OFF.
* @param SDIOx: Pointer to SDMMC register base
* @retval HAL status
*/
HAL_StatusTypeDef SDIO_PowerState_OFF(SDIO_TypeDef *SDIOx)
{
/* Set power state to OFF */
SDIOx->POWER = (uint32_t)0x00000000;
return HAL_OK;
}
/**
* @brief Get SDMMC Power state.
* @param SDIOx: Pointer to SDMMC register base
* @retval Power status of the controller. The returned value can be one of the
* following values:
* - 0x00: Power OFF
* - 0x02: Power UP
* - 0x03: Power ON
*/
uint32_t SDIO_GetPowerState(SDIO_TypeDef *SDIOx)
{
return (SDIOx->POWER & SDIO_POWER_PWRCTRL);
}
/**
* @brief Configure the SDMMC command path according to the specified parameters in
* SDIO_CmdInitTypeDef structure and send the command
* @param SDIOx: Pointer to SDMMC register base
* @param Command: pointer to a SDIO_CmdInitTypeDef structure that contains
* the configuration information for the SDMMC command
* @retval HAL status
*/
HAL_StatusTypeDef SDIO_SendCommand(SDIO_TypeDef *SDIOx, SDIO_CmdInitTypeDef *Command)
{
uint32_t tmpreg = 0;
/* Check the parameters */
assert_param(IS_SDIO_CMD_INDEX(Command->CmdIndex));
assert_param(IS_SDIO_RESPONSE(Command->Response));
assert_param(IS_SDIO_WAIT(Command->WaitForInterrupt));
assert_param(IS_SDIO_CPSM(Command->CPSM));
/* Set the SDMMC Argument value */
SDIOx->ARG = Command->Argument;
/* Set SDMMC command parameters */
tmpreg |= (uint32_t)(Command->CmdIndex |\
Command->Response |\
Command->WaitForInterrupt |\
Command->CPSM);
/* Write to SDMMC CMD register */
MODIFY_REG(SDIOx->CMD, CMD_CLEAR_MASK, tmpreg);
return HAL_OK;
}
/**
* @brief Return the command index of last command for which response received
* @param SDIOx: Pointer to SDMMC register base
* @retval Command index of the last command response received
*/
uint8_t SDIO_GetCommandResponse(SDIO_TypeDef *SDIOx)
{
return (uint8_t)(SDIOx->RESPCMD);
}
/**
* @brief Return the response received from the card for the last command
* @param SDIOx: Pointer to SDMMC register base
* @param Response: Specifies the SDMMC response register.
* This parameter can be one of the following values:
* @arg SDIO_RESP1: Response Register 1
* @arg SDIO_RESP2: Response Register 2
* @arg SDIO_RESP3: Response Register 3
* @arg SDIO_RESP4: Response Register 4
* @retval The Corresponding response register value
*/
uint32_t SDIO_GetResponse(SDIO_TypeDef *SDIOx, uint32_t Response)
{
uint32_t tmp;
/* Check the parameters */
assert_param(IS_SDIO_RESP(Response));
/* Get the response */
tmp = (uint32_t)(&(SDIOx->RESP1)) + Response;
return (*(__IO uint32_t *) tmp);
}
/**
* @brief Configure the SDMMC data path according to the specified
* parameters in the SDIO_DataInitTypeDef.
* @param SDIOx: Pointer to SDIO register base
* @param Data : pointer to a SDIO_DataInitTypeDef structure
* that contains the configuration information for the SDMMC data.
* @retval HAL status
*/
HAL_StatusTypeDef SDIO_ConfigData(SDIO_TypeDef *SDIOx, SDIO_DataInitTypeDef* Data)
{
uint32_t tmpreg = 0;
/* Check the parameters */
assert_param(IS_SDIO_DATA_LENGTH(Data->DataLength));
assert_param(IS_SDIO_BLOCK_SIZE(Data->DataBlockSize));
assert_param(IS_SDIO_TRANSFER_DIR(Data->TransferDir));
assert_param(IS_SDIO_TRANSFER_MODE(Data->TransferMode));
assert_param(IS_SDIO_DPSM(Data->DPSM));
/* Set the SDMMC Data TimeOut value */
SDIOx->DTIMER = Data->DataTimeOut;
/* Set the SDMMC DataLength value */
SDIOx->DLEN = Data->DataLength;
/* Set the SDMMC data configuration parameters */
tmpreg |= (uint32_t)(Data->DataBlockSize |\
Data->TransferDir |\
Data->TransferMode |\
Data->DPSM);
/* Write to SDMMC DCTRL */
MODIFY_REG(SDIOx->DCTRL, DCTRL_CLEAR_MASK, tmpreg);
return HAL_OK;
}
/**
* @brief Returns number of remaining data bytes to be transferred.
* @param SDIOx: Pointer to SDIO register base
* @retval Number of remaining data bytes to be transferred
*/
uint32_t SDIO_GetDataCounter(SDIO_TypeDef *SDIOx)
{
return (SDIOx->DCOUNT);
}
/**
* @brief Get the FIFO data
* @param SDIOx: Pointer to SDIO register base
* @retval Data received
*/
uint32_t SDIO_GetFIFOCount(SDIO_TypeDef *SDIOx)
{
return (SDIOx->FIFO);
}
/**
* @brief Sets one of the two options of inserting read wait interval.
* @param SDIOx: Pointer to SDIO register base
* @param SDIO_ReadWaitMode: SDMMC Read Wait operation mode.
* This parameter can be:
* @arg SDIO_READ_WAIT_MODE_CLK: Read Wait control by stopping SDMMCCLK
* @arg SDIO_READ_WAIT_MODE_DATA2: Read Wait control using SDMMC_DATA2
* @retval None
*/
HAL_StatusTypeDef SDIO_SetSDMMCReadWaitMode(SDIO_TypeDef *SDIOx, uint32_t SDIO_ReadWaitMode)
{
/* Check the parameters */
assert_param(IS_SDIO_READWAIT_MODE(SDIO_ReadWaitMode));
/* Set SDMMC read wait mode */
MODIFY_REG(SDIOx->DCTRL, SDIO_DCTRL_RWMOD, SDIO_ReadWaitMode);
return HAL_OK;
}
/**
* @}
*/
/** @defgroup HAL_SDMMC_LL_Group4 Command management functions
* @brief Data transfers functions
*
@verbatim
===============================================================================
##### Commands management functions #####
===============================================================================
[..]
This subsection provides a set of functions allowing to manage the needed commands.
@endverbatim
* @{
*/
/**
* @brief Send the Data Block Length command and check the response
* @param SDIOx: Pointer to SDIO register base
* @retval HAL status
*/
uint32_t SDMMC_CmdBlockLength(SDIO_TypeDef *SDIOx, uint32_t BlockSize)
{
SDIO_CmdInitTypeDef sdmmc_cmdinit;
uint32_t errorstate;
/* Set Block Size for Card */
sdmmc_cmdinit.Argument = (uint32_t)BlockSize;
sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SET_BLOCKLEN;
sdmmc_cmdinit.Response = SDIO_RESPONSE_SHORT;
sdmmc_cmdinit.WaitForInterrupt = SDIO_WAIT_NO;
sdmmc_cmdinit.CPSM = SDIO_CPSM_ENABLE;
(void)SDIO_SendCommand(SDIOx, &sdmmc_cmdinit);
/* Check for error conditions */
errorstate = SDMMC_GetCmdResp1(SDIOx, SDMMC_CMD_SET_BLOCKLEN, SDIO_CMDTIMEOUT);
return errorstate;
}
/**
* @brief Send the Read Single Block command and check the response
* @param SDIOx: Pointer to SDIO register base
* @retval HAL status
*/
uint32_t SDMMC_CmdReadSingleBlock(SDIO_TypeDef *SDIOx, uint32_t ReadAdd)
{
SDIO_CmdInitTypeDef sdmmc_cmdinit;
uint32_t errorstate;
/* Set Block Size for Card */
sdmmc_cmdinit.Argument = (uint32_t)ReadAdd;
sdmmc_cmdinit.CmdIndex = SDMMC_CMD_READ_SINGLE_BLOCK;
sdmmc_cmdinit.Response = SDIO_RESPONSE_SHORT;
sdmmc_cmdinit.WaitForInterrupt = SDIO_WAIT_NO;
sdmmc_cmdinit.CPSM = SDIO_CPSM_ENABLE;
(void)SDIO_SendCommand(SDIOx, &sdmmc_cmdinit);
/* Check for error conditions */
errorstate = SDMMC_GetCmdResp1(SDIOx, SDMMC_CMD_READ_SINGLE_BLOCK, SDIO_CMDTIMEOUT);
return errorstate;
}
/**
* @brief Send the Read Multi Block command and check the response
* @param SDIOx: Pointer to SDIO register base
* @retval HAL status
*/
uint32_t SDMMC_CmdReadMultiBlock(SDIO_TypeDef *SDIOx, uint32_t ReadAdd)
{
SDIO_CmdInitTypeDef sdmmc_cmdinit;
uint32_t errorstate;
/* Set Block Size for Card */
sdmmc_cmdinit.Argument = (uint32_t)ReadAdd;
sdmmc_cmdinit.CmdIndex = SDMMC_CMD_READ_MULT_BLOCK;
sdmmc_cmdinit.Response = SDIO_RESPONSE_SHORT;
sdmmc_cmdinit.WaitForInterrupt = SDIO_WAIT_NO;
sdmmc_cmdinit.CPSM = SDIO_CPSM_ENABLE;
(void)SDIO_SendCommand(SDIOx, &sdmmc_cmdinit);
/* Check for error conditions */
errorstate = SDMMC_GetCmdResp1(SDIOx, SDMMC_CMD_READ_MULT_BLOCK, SDIO_CMDTIMEOUT);
return errorstate;
}
/**
* @brief Send the Write Single Block command and check the response
* @param SDIOx: Pointer to SDIO register base
* @retval HAL status
*/
uint32_t SDMMC_CmdWriteSingleBlock(SDIO_TypeDef *SDIOx, uint32_t WriteAdd)
{
SDIO_CmdInitTypeDef sdmmc_cmdinit;
uint32_t errorstate;
/* Set Block Size for Card */
sdmmc_cmdinit.Argument = (uint32_t)WriteAdd;
sdmmc_cmdinit.CmdIndex = SDMMC_CMD_WRITE_SINGLE_BLOCK;
sdmmc_cmdinit.Response = SDIO_RESPONSE_SHORT;
sdmmc_cmdinit.WaitForInterrupt = SDIO_WAIT_NO;
sdmmc_cmdinit.CPSM = SDIO_CPSM_ENABLE;
(void)SDIO_SendCommand(SDIOx, &sdmmc_cmdinit);
/* Check for error conditions */
errorstate = SDMMC_GetCmdResp1(SDIOx, SDMMC_CMD_WRITE_SINGLE_BLOCK, SDIO_CMDTIMEOUT);
return errorstate;
}
/**
* @brief Send the Write Multi Block command and check the response
* @param SDIOx: Pointer to SDIO register base
* @retval HAL status
*/
uint32_t SDMMC_CmdWriteMultiBlock(SDIO_TypeDef *SDIOx, uint32_t WriteAdd)
{
SDIO_CmdInitTypeDef sdmmc_cmdinit;
uint32_t errorstate;
/* Set Block Size for Card */
sdmmc_cmdinit.Argument = (uint32_t)WriteAdd;
sdmmc_cmdinit.CmdIndex = SDMMC_CMD_WRITE_MULT_BLOCK;
sdmmc_cmdinit.Response = SDIO_RESPONSE_SHORT;
sdmmc_cmdinit.WaitForInterrupt = SDIO_WAIT_NO;
sdmmc_cmdinit.CPSM = SDIO_CPSM_ENABLE;
(void)SDIO_SendCommand(SDIOx, &sdmmc_cmdinit);
/* Check for error conditions */
errorstate = SDMMC_GetCmdResp1(SDIOx, SDMMC_CMD_WRITE_MULT_BLOCK, SDIO_CMDTIMEOUT);
return errorstate;
}
/**
* @brief Send the Start Address Erase command for SD and check the response
* @param SDIOx: Pointer to SDIO register base
* @retval HAL status
*/
uint32_t SDMMC_CmdSDEraseStartAdd(SDIO_TypeDef *SDIOx, uint32_t StartAdd)
{
SDIO_CmdInitTypeDef sdmmc_cmdinit;
uint32_t errorstate;
/* Set Block Size for Card */
sdmmc_cmdinit.Argument = (uint32_t)StartAdd;
sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SD_ERASE_GRP_START;
sdmmc_cmdinit.Response = SDIO_RESPONSE_SHORT;
sdmmc_cmdinit.WaitForInterrupt = SDIO_WAIT_NO;
sdmmc_cmdinit.CPSM = SDIO_CPSM_ENABLE;
(void)SDIO_SendCommand(SDIOx, &sdmmc_cmdinit);
/* Check for error conditions */
errorstate = SDMMC_GetCmdResp1(SDIOx, SDMMC_CMD_SD_ERASE_GRP_START, SDIO_CMDTIMEOUT);
return errorstate;
}
/**
* @brief Send the End Address Erase command for SD and check the response
* @param SDIOx: Pointer to SDIO register base
* @retval HAL status
*/
uint32_t SDMMC_CmdSDEraseEndAdd(SDIO_TypeDef *SDIOx, uint32_t EndAdd)
{
SDIO_CmdInitTypeDef sdmmc_cmdinit;
uint32_t errorstate;
/* Set Block Size for Card */
sdmmc_cmdinit.Argument = (uint32_t)EndAdd;
sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SD_ERASE_GRP_END;
sdmmc_cmdinit.Response = SDIO_RESPONSE_SHORT;
sdmmc_cmdinit.WaitForInterrupt = SDIO_WAIT_NO;
sdmmc_cmdinit.CPSM = SDIO_CPSM_ENABLE;
(void)SDIO_SendCommand(SDIOx, &sdmmc_cmdinit);
/* Check for error conditions */
errorstate = SDMMC_GetCmdResp1(SDIOx, SDMMC_CMD_SD_ERASE_GRP_END, SDIO_CMDTIMEOUT);
return errorstate;
}
/**
* @brief Send the Start Address Erase command and check the response
* @param SDIOx: Pointer to SDIO register base
* @retval HAL status
*/
uint32_t SDMMC_CmdEraseStartAdd(SDIO_TypeDef *SDIOx, uint32_t StartAdd)
{
SDIO_CmdInitTypeDef sdmmc_cmdinit;
uint32_t errorstate;
/* Set Block Size for Card */
sdmmc_cmdinit.Argument = (uint32_t)StartAdd;
sdmmc_cmdinit.CmdIndex = SDMMC_CMD_ERASE_GRP_START;
sdmmc_cmdinit.Response = SDIO_RESPONSE_SHORT;
sdmmc_cmdinit.WaitForInterrupt = SDIO_WAIT_NO;
sdmmc_cmdinit.CPSM = SDIO_CPSM_ENABLE;
(void)SDIO_SendCommand(SDIOx, &sdmmc_cmdinit);
/* Check for error conditions */
errorstate = SDMMC_GetCmdResp1(SDIOx, SDMMC_CMD_ERASE_GRP_START, SDIO_CMDTIMEOUT);
return errorstate;
}
/**
* @brief Send the End Address Erase command and check the response
* @param SDIOx: Pointer to SDIO register base
* @retval HAL status
*/
uint32_t SDMMC_CmdEraseEndAdd(SDIO_TypeDef *SDIOx, uint32_t EndAdd)
{
SDIO_CmdInitTypeDef sdmmc_cmdinit;
uint32_t errorstate;
/* Set Block Size for Card */
sdmmc_cmdinit.Argument = (uint32_t)EndAdd;
sdmmc_cmdinit.CmdIndex = SDMMC_CMD_ERASE_GRP_END;
sdmmc_cmdinit.Response = SDIO_RESPONSE_SHORT;
sdmmc_cmdinit.WaitForInterrupt = SDIO_WAIT_NO;
sdmmc_cmdinit.CPSM = SDIO_CPSM_ENABLE;
(void)SDIO_SendCommand(SDIOx, &sdmmc_cmdinit);
/* Check for error conditions */
errorstate = SDMMC_GetCmdResp1(SDIOx, SDMMC_CMD_ERASE_GRP_END, SDIO_CMDTIMEOUT);
return errorstate;
}
/**
* @brief Send the Erase command and check the response
* @param SDIOx: Pointer to SDIO register base
* @retval HAL status
*/
uint32_t SDMMC_CmdErase(SDIO_TypeDef *SDIOx)
{
SDIO_CmdInitTypeDef sdmmc_cmdinit;
uint32_t errorstate;
/* Set Block Size for Card */
sdmmc_cmdinit.Argument = 0U;
sdmmc_cmdinit.CmdIndex = SDMMC_CMD_ERASE;
sdmmc_cmdinit.Response = SDIO_RESPONSE_SHORT;
sdmmc_cmdinit.WaitForInterrupt = SDIO_WAIT_NO;
sdmmc_cmdinit.CPSM = SDIO_CPSM_ENABLE;
(void)SDIO_SendCommand(SDIOx, &sdmmc_cmdinit);
/* Check for error conditions */
errorstate = SDMMC_GetCmdResp1(SDIOx, SDMMC_CMD_ERASE, SDIO_MAXERASETIMEOUT);
return errorstate;
}
/**
* @brief Send the Stop Transfer command and check the response.
* @param SDIOx: Pointer to SDIO register base
* @retval HAL status
*/
uint32_t SDMMC_CmdStopTransfer(SDIO_TypeDef *SDIOx)
{
SDIO_CmdInitTypeDef sdmmc_cmdinit;
uint32_t errorstate;
/* Send CMD12 STOP_TRANSMISSION */
sdmmc_cmdinit.Argument = 0U;
sdmmc_cmdinit.CmdIndex = SDMMC_CMD_STOP_TRANSMISSION;
sdmmc_cmdinit.Response = SDIO_RESPONSE_SHORT;
sdmmc_cmdinit.WaitForInterrupt = SDIO_WAIT_NO;
sdmmc_cmdinit.CPSM = SDIO_CPSM_ENABLE;
(void)SDIO_SendCommand(SDIOx, &sdmmc_cmdinit);
/* Check for error conditions */
errorstate = SDMMC_GetCmdResp1(SDIOx, SDMMC_CMD_STOP_TRANSMISSION, SDIO_STOPTRANSFERTIMEOUT);
return errorstate;
}
/**
* @brief Send the Select Deselect command and check the response.
* @param SDIOx: Pointer to SDIO register base
* @param addr: Address of the card to be selected
* @retval HAL status
*/
uint32_t SDMMC_CmdSelDesel(SDIO_TypeDef *SDIOx, uint64_t Addr)
{
SDIO_CmdInitTypeDef sdmmc_cmdinit;
uint32_t errorstate;
/* Send CMD7 SDMMC_SEL_DESEL_CARD */
sdmmc_cmdinit.Argument = (uint32_t)Addr;
sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SEL_DESEL_CARD;
sdmmc_cmdinit.Response = SDIO_RESPONSE_SHORT;
sdmmc_cmdinit.WaitForInterrupt = SDIO_WAIT_NO;
sdmmc_cmdinit.CPSM = SDIO_CPSM_ENABLE;
(void)SDIO_SendCommand(SDIOx, &sdmmc_cmdinit);
/* Check for error conditions */
errorstate = SDMMC_GetCmdResp1(SDIOx, SDMMC_CMD_SEL_DESEL_CARD, SDIO_CMDTIMEOUT);
return errorstate;
}
/**
* @brief Send the Go Idle State command and check the response.
* @param SDIOx: Pointer to SDIO register base
* @retval HAL status
*/
uint32_t SDMMC_CmdGoIdleState(SDIO_TypeDef *SDIOx)
{
SDIO_CmdInitTypeDef sdmmc_cmdinit;
uint32_t errorstate;
sdmmc_cmdinit.Argument = 0U;
sdmmc_cmdinit.CmdIndex = SDMMC_CMD_GO_IDLE_STATE;
sdmmc_cmdinit.Response = SDIO_RESPONSE_NO;
sdmmc_cmdinit.WaitForInterrupt = SDIO_WAIT_NO;
sdmmc_cmdinit.CPSM = SDIO_CPSM_ENABLE;
(void)SDIO_SendCommand(SDIOx, &sdmmc_cmdinit);
/* Check for error conditions */
errorstate = SDMMC_GetCmdError(SDIOx);
return errorstate;
}
/**
* @brief Send the Operating Condition command and check the response.
* @param SDIOx: Pointer to SDIO register base
* @retval HAL status
*/
uint32_t SDMMC_CmdOperCond(SDIO_TypeDef *SDIOx)
{
SDIO_CmdInitTypeDef sdmmc_cmdinit;
uint32_t errorstate;
/* Send CMD8 to verify SD card interface operating condition */
/* Argument: - [31:12]: Reserved (shall be set to '0')
- [11:8]: Supply Voltage (VHS) 0x1 (Range: 2.7-3.6 V)
- [7:0]: Check Pattern (recommended 0xAA) */
/* CMD Response: R7 */
sdmmc_cmdinit.Argument = SDMMC_CHECK_PATTERN;
sdmmc_cmdinit.CmdIndex = SDMMC_CMD_HS_SEND_EXT_CSD;
sdmmc_cmdinit.Response = SDIO_RESPONSE_SHORT;
sdmmc_cmdinit.WaitForInterrupt = SDIO_WAIT_NO;
sdmmc_cmdinit.CPSM = SDIO_CPSM_ENABLE;
(void)SDIO_SendCommand(SDIOx, &sdmmc_cmdinit);
/* Check for error conditions */
errorstate = SDMMC_GetCmdResp7(SDIOx);
return errorstate;
}
/**
* @brief Send the Application command to verify that that the next command
* is an application specific com-mand rather than a standard command
* and check the response.
* @param SDIOx: Pointer to SDIO register base
* @param Argument: Command Argument
* @retval HAL status
*/
uint32_t SDMMC_CmdAppCommand(SDIO_TypeDef *SDIOx, uint32_t Argument)
{
SDIO_CmdInitTypeDef sdmmc_cmdinit;
uint32_t errorstate;
sdmmc_cmdinit.Argument = (uint32_t)Argument;
sdmmc_cmdinit.CmdIndex = SDMMC_CMD_APP_CMD;
sdmmc_cmdinit.Response = SDIO_RESPONSE_SHORT;
sdmmc_cmdinit.WaitForInterrupt = SDIO_WAIT_NO;
sdmmc_cmdinit.CPSM = SDIO_CPSM_ENABLE;
(void)SDIO_SendCommand(SDIOx, &sdmmc_cmdinit);
/* Check for error conditions */
/* If there is a HAL_ERROR, it is a MMC card, else
it is a SD card: SD card 2.0 (voltage range mismatch)
or SD card 1.x */
errorstate = SDMMC_GetCmdResp1(SDIOx, SDMMC_CMD_APP_CMD, SDIO_CMDTIMEOUT);
return errorstate;
}
/**
* @brief Send the command asking the accessed card to send its operating
* condition register (OCR)
* @param SDIOx: Pointer to SDIO register base
* @param Argument: Command Argument
* @retval HAL status
*/
uint32_t SDMMC_CmdAppOperCommand(SDIO_TypeDef *SDIOx, uint32_t Argument)
{
SDIO_CmdInitTypeDef sdmmc_cmdinit;
uint32_t errorstate;
sdmmc_cmdinit.Argument = SDMMC_VOLTAGE_WINDOW_SD | Argument;
sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SD_APP_OP_COND;
sdmmc_cmdinit.Response = SDIO_RESPONSE_SHORT;
sdmmc_cmdinit.WaitForInterrupt = SDIO_WAIT_NO;
sdmmc_cmdinit.CPSM = SDIO_CPSM_ENABLE;
(void)SDIO_SendCommand(SDIOx, &sdmmc_cmdinit);
/* Check for error conditions */
errorstate = SDMMC_GetCmdResp3(SDIOx);
return errorstate;
}
/**
* @brief Send the Bus Width command and check the response.
* @param SDIOx: Pointer to SDIO register base
* @param BusWidth: BusWidth
* @retval HAL status
*/
uint32_t SDMMC_CmdBusWidth(SDIO_TypeDef *SDIOx, uint32_t BusWidth)
{
SDIO_CmdInitTypeDef sdmmc_cmdinit;
uint32_t errorstate;
sdmmc_cmdinit.Argument = (uint32_t)BusWidth;
sdmmc_cmdinit.CmdIndex = SDMMC_CMD_APP_SD_SET_BUSWIDTH;
sdmmc_cmdinit.Response = SDIO_RESPONSE_SHORT;
sdmmc_cmdinit.WaitForInterrupt = SDIO_WAIT_NO;
sdmmc_cmdinit.CPSM = SDIO_CPSM_ENABLE;
(void)SDIO_SendCommand(SDIOx, &sdmmc_cmdinit);
/* Check for error conditions */
errorstate = SDMMC_GetCmdResp1(SDIOx, SDMMC_CMD_APP_SD_SET_BUSWIDTH, SDIO_CMDTIMEOUT);
return errorstate;
}
/**
* @brief Send the Send SCR command and check the response.
* @param SDIOx: Pointer to SDIO register base
* @retval HAL status
*/
uint32_t SDMMC_CmdSendSCR(SDIO_TypeDef *SDIOx)
{
SDIO_CmdInitTypeDef sdmmc_cmdinit;
uint32_t errorstate;
/* Send CMD51 SD_APP_SEND_SCR */
sdmmc_cmdinit.Argument = 0U;
sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SD_APP_SEND_SCR;
sdmmc_cmdinit.Response = SDIO_RESPONSE_SHORT;
sdmmc_cmdinit.WaitForInterrupt = SDIO_WAIT_NO;
sdmmc_cmdinit.CPSM = SDIO_CPSM_ENABLE;
(void)SDIO_SendCommand(SDIOx, &sdmmc_cmdinit);
/* Check for error conditions */
errorstate = SDMMC_GetCmdResp1(SDIOx, SDMMC_CMD_SD_APP_SEND_SCR, SDIO_CMDTIMEOUT);
return errorstate;
}
/**
* @brief Send the Send CID command and check the response.
* @param SDIOx: Pointer to SDIO register base
* @retval HAL status
*/
uint32_t SDMMC_CmdSendCID(SDIO_TypeDef *SDIOx)
{
SDIO_CmdInitTypeDef sdmmc_cmdinit;
uint32_t errorstate;
/* Send CMD2 ALL_SEND_CID */
sdmmc_cmdinit.Argument = 0U;
sdmmc_cmdinit.CmdIndex = SDMMC_CMD_ALL_SEND_CID;
sdmmc_cmdinit.Response = SDIO_RESPONSE_LONG;
sdmmc_cmdinit.WaitForInterrupt = SDIO_WAIT_NO;
sdmmc_cmdinit.CPSM = SDIO_CPSM_ENABLE;
(void)SDIO_SendCommand(SDIOx, &sdmmc_cmdinit);
/* Check for error conditions */
errorstate = SDMMC_GetCmdResp2(SDIOx);
return errorstate;
}
/**
* @brief Send the Send CSD command and check the response.
* @param SDIOx: Pointer to SDIO register base
* @param Argument: Command Argument
* @retval HAL status
*/
uint32_t SDMMC_CmdSendCSD(SDIO_TypeDef *SDIOx, uint32_t Argument)
{
SDIO_CmdInitTypeDef sdmmc_cmdinit;
uint32_t errorstate;
/* Send CMD9 SEND_CSD */
sdmmc_cmdinit.Argument = Argument;
sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SEND_CSD;
sdmmc_cmdinit.Response = SDIO_RESPONSE_LONG;
sdmmc_cmdinit.WaitForInterrupt = SDIO_WAIT_NO;
sdmmc_cmdinit.CPSM = SDIO_CPSM_ENABLE;
(void)SDIO_SendCommand(SDIOx, &sdmmc_cmdinit);
/* Check for error conditions */
errorstate = SDMMC_GetCmdResp2(SDIOx);
return errorstate;
}
/**
* @brief Send the Send CSD command and check the response.
* @param SDIOx: Pointer to SDIO register base
* @param pRCA: Card RCA
* @retval HAL status
*/
uint32_t SDMMC_CmdSetRelAdd(SDIO_TypeDef *SDIOx, uint16_t *pRCA)
{
SDIO_CmdInitTypeDef sdmmc_cmdinit;
uint32_t errorstate;
/* Send CMD3 SD_CMD_SET_REL_ADDR */
sdmmc_cmdinit.Argument = 0U;
sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SET_REL_ADDR;
sdmmc_cmdinit.Response = SDIO_RESPONSE_SHORT;
sdmmc_cmdinit.WaitForInterrupt = SDIO_WAIT_NO;
sdmmc_cmdinit.CPSM = SDIO_CPSM_ENABLE;
(void)SDIO_SendCommand(SDIOx, &sdmmc_cmdinit);
/* Check for error conditions */
errorstate = SDMMC_GetCmdResp6(SDIOx, SDMMC_CMD_SET_REL_ADDR, pRCA);
return errorstate;
}
/**
* @brief Send the Set Relative Address command to MMC card (not SD card).
* @param SDIOx Pointer to SDIO register base
* @param RCA Card RCA
* @retval HAL status
*/
uint32_t SDMMC_CmdSetRelAddMmc(SDIO_TypeDef *SDIOx, uint16_t RCA)
{
SDIO_CmdInitTypeDef sdmmc_cmdinit;
uint32_t errorstate;
/* Send CMD3 SD_CMD_SET_REL_ADDR */
sdmmc_cmdinit.Argument = ((uint32_t)RCA << 16U);
sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SET_REL_ADDR;
sdmmc_cmdinit.Response = SDIO_RESPONSE_SHORT;
sdmmc_cmdinit.WaitForInterrupt = SDIO_WAIT_NO;
sdmmc_cmdinit.CPSM = SDIO_CPSM_ENABLE;
(void)SDIO_SendCommand(SDIOx, &sdmmc_cmdinit);
/* Check for error conditions */
errorstate = SDMMC_GetCmdResp1(SDIOx, SDMMC_CMD_SET_REL_ADDR, SDIO_CMDTIMEOUT);
return errorstate;
}
/**
* @brief Send the Status command and check the response.
* @param SDIOx: Pointer to SDIO register base
* @param Argument: Command Argument
* @retval HAL status
*/
uint32_t SDMMC_CmdSendStatus(SDIO_TypeDef *SDIOx, uint32_t Argument)
{
SDIO_CmdInitTypeDef sdmmc_cmdinit;
uint32_t errorstate;
sdmmc_cmdinit.Argument = Argument;
sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SEND_STATUS;
sdmmc_cmdinit.Response = SDIO_RESPONSE_SHORT;
sdmmc_cmdinit.WaitForInterrupt = SDIO_WAIT_NO;
sdmmc_cmdinit.CPSM = SDIO_CPSM_ENABLE;
(void)SDIO_SendCommand(SDIOx, &sdmmc_cmdinit);
/* Check for error conditions */
errorstate = SDMMC_GetCmdResp1(SDIOx, SDMMC_CMD_SEND_STATUS, SDIO_CMDTIMEOUT);
return errorstate;
}
/**
* @brief Send the Status register command and check the response.
* @param SDIOx: Pointer to SDIO register base
* @retval HAL status
*/
uint32_t SDMMC_CmdStatusRegister(SDIO_TypeDef *SDIOx)
{
SDIO_CmdInitTypeDef sdmmc_cmdinit;
uint32_t errorstate;
sdmmc_cmdinit.Argument = 0U;
sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SD_APP_STATUS;
sdmmc_cmdinit.Response = SDIO_RESPONSE_SHORT;
sdmmc_cmdinit.WaitForInterrupt = SDIO_WAIT_NO;
sdmmc_cmdinit.CPSM = SDIO_CPSM_ENABLE;
(void)SDIO_SendCommand(SDIOx, &sdmmc_cmdinit);
/* Check for error conditions */
errorstate = SDMMC_GetCmdResp1(SDIOx, SDMMC_CMD_SD_APP_STATUS, SDIO_CMDTIMEOUT);
return errorstate;
}
/**
* @brief Sends host capacity support information and activates the card's
* initialization process. Send SDMMC_CMD_SEND_OP_COND command
* @param SDIOx: Pointer to SDIO register base
* @parame Argument: Argument used for the command
* @retval HAL status
*/
uint32_t SDMMC_CmdOpCondition(SDIO_TypeDef *SDIOx, uint32_t Argument)
{
SDIO_CmdInitTypeDef sdmmc_cmdinit;
uint32_t errorstate;
sdmmc_cmdinit.Argument = Argument;
sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SEND_OP_COND;
sdmmc_cmdinit.Response = SDIO_RESPONSE_SHORT;
sdmmc_cmdinit.WaitForInterrupt = SDIO_WAIT_NO;
sdmmc_cmdinit.CPSM = SDIO_CPSM_ENABLE;
(void)SDIO_SendCommand(SDIOx, &sdmmc_cmdinit);
/* Check for error conditions */
errorstate = SDMMC_GetCmdResp3(SDIOx);
return errorstate;
}
/**
* @brief Checks switchable function and switch card function. SDMMC_CMD_HS_SWITCH command
* @param SDIOx: Pointer to SDIO register base
* @parame Argument: Argument used for the command
* @retval HAL status
*/
uint32_t SDMMC_CmdSwitch(SDIO_TypeDef *SDIOx, uint32_t Argument)
{
SDIO_CmdInitTypeDef sdmmc_cmdinit;
uint32_t errorstate;
/* Send CMD6 to activate SDR50 Mode and Power Limit 1.44W */
/* CMD Response: R1 */
sdmmc_cmdinit.Argument = Argument; /* SDMMC_SDR25_SWITCH_PATTERN */
sdmmc_cmdinit.CmdIndex = SDMMC_CMD_HS_SWITCH;
sdmmc_cmdinit.Response = SDIO_RESPONSE_SHORT;
sdmmc_cmdinit.WaitForInterrupt = SDIO_WAIT_NO;
sdmmc_cmdinit.CPSM = SDIO_CPSM_ENABLE;
(void)SDIO_SendCommand(SDIOx, &sdmmc_cmdinit);
/* Check for error conditions */
errorstate = SDMMC_GetCmdResp1(SDIOx, SDMMC_CMD_HS_SWITCH, SDIO_CMDTIMEOUT);
return errorstate;
}
/**
* @brief Send the Send EXT_CSD command and check the response.
* @param SDIOx Pointer to SDMMC register base
* @param Argument Command Argument
* @retval HAL status
*/
uint32_t SDMMC_CmdSendEXTCSD(SDIO_TypeDef *SDIOx, uint32_t Argument)
{
SDIO_CmdInitTypeDef sdmmc_cmdinit;
uint32_t errorstate;
/* Send CMD9 SEND_CSD */
sdmmc_cmdinit.Argument = Argument;
sdmmc_cmdinit.CmdIndex = SDMMC_CMD_HS_SEND_EXT_CSD;
sdmmc_cmdinit.Response = SDIO_RESPONSE_SHORT;
sdmmc_cmdinit.WaitForInterrupt = SDIO_WAIT_NO;
sdmmc_cmdinit.CPSM = SDIO_CPSM_ENABLE;
(void)SDIO_SendCommand(SDIOx, &sdmmc_cmdinit);
/* Check for error conditions */
errorstate = SDMMC_GetCmdResp1(SDIOx, SDMMC_CMD_HS_SEND_EXT_CSD,SDIO_CMDTIMEOUT);
return errorstate;
}
/**
* @}
*/
/** @defgroup HAL_SDMMC_LL_Group5 Responses management functions
* @brief Responses functions
*
@verbatim
===============================================================================
##### Responses management functions #####
===============================================================================
[..]
This subsection provides a set of functions allowing to manage the needed responses.
@endverbatim
* @{
*/
/**
* @brief Checks for error conditions for R1 response.
* @param SDIOx Pointer to SDMMC register base
* @param SD_CMD: The sent command index
* @retval SD Card error state
*/
uint32_t SDMMC_GetCmdResp1(SDIO_TypeDef *SDIOx, uint8_t SD_CMD, uint32_t Timeout)
{
uint32_t response_r1;
uint32_t sta_reg;
/* 8 is the number of required instructions cycles for the below loop statement.
The Timeout is expressed in ms */
uint32_t count = Timeout * (SystemCoreClock / 8U /1000U);
do
{
if (count-- == 0U)
{
return SDMMC_ERROR_TIMEOUT;
}
sta_reg = SDIOx->STA;
}while(((sta_reg & (SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT)) == 0U) ||
((sta_reg & SDIO_FLAG_CMDACT) != 0U ));
if(__SDIO_GET_FLAG(SDIOx, SDIO_FLAG_CTIMEOUT))
{
__SDIO_CLEAR_FLAG(SDIOx, SDIO_FLAG_CTIMEOUT);
return SDMMC_ERROR_CMD_RSP_TIMEOUT;
}
else if(__SDIO_GET_FLAG(SDIOx, SDIO_FLAG_CCRCFAIL))
{
__SDIO_CLEAR_FLAG(SDIOx, SDIO_FLAG_CCRCFAIL);
return SDMMC_ERROR_CMD_CRC_FAIL;
}
else
{
/* Nothing to do */
}
/* Clear all the static flags */
__SDIO_CLEAR_FLAG(SDIOx, SDIO_STATIC_CMD_FLAGS);
/* Check response received is of desired command */
if(SDIO_GetCommandResponse(SDIOx) != SD_CMD)
{
return SDMMC_ERROR_CMD_CRC_FAIL;
}
/* We have received response, retrieve it for analysis */
response_r1 = SDIO_GetResponse(SDIOx, SDIO_RESP1);
if((response_r1 & SDMMC_OCR_ERRORBITS) == SDMMC_ALLZERO)
{
return SDMMC_ERROR_NONE;
}
else if((response_r1 & SDMMC_OCR_ADDR_OUT_OF_RANGE) == SDMMC_OCR_ADDR_OUT_OF_RANGE)
{
return SDMMC_ERROR_ADDR_OUT_OF_RANGE;
}
else if((response_r1 & SDMMC_OCR_ADDR_MISALIGNED) == SDMMC_OCR_ADDR_MISALIGNED)
{
return SDMMC_ERROR_ADDR_MISALIGNED;
}
else if((response_r1 & SDMMC_OCR_BLOCK_LEN_ERR) == SDMMC_OCR_BLOCK_LEN_ERR)
{
return SDMMC_ERROR_BLOCK_LEN_ERR;
}
else if((response_r1 & SDMMC_OCR_ERASE_SEQ_ERR) == SDMMC_OCR_ERASE_SEQ_ERR)
{
return SDMMC_ERROR_ERASE_SEQ_ERR;
}
else if((response_r1 & SDMMC_OCR_BAD_ERASE_PARAM) == SDMMC_OCR_BAD_ERASE_PARAM)
{
return SDMMC_ERROR_BAD_ERASE_PARAM;
}
else if((response_r1 & SDMMC_OCR_WRITE_PROT_VIOLATION) == SDMMC_OCR_WRITE_PROT_VIOLATION)
{
return SDMMC_ERROR_WRITE_PROT_VIOLATION;
}
else if((response_r1 & SDMMC_OCR_LOCK_UNLOCK_FAILED) == SDMMC_OCR_LOCK_UNLOCK_FAILED)
{
return SDMMC_ERROR_LOCK_UNLOCK_FAILED;
}
else if((response_r1 & SDMMC_OCR_COM_CRC_FAILED) == SDMMC_OCR_COM_CRC_FAILED)
{
return SDMMC_ERROR_COM_CRC_FAILED;
}
else if((response_r1 & SDMMC_OCR_ILLEGAL_CMD) == SDMMC_OCR_ILLEGAL_CMD)
{
return SDMMC_ERROR_ILLEGAL_CMD;
}
else if((response_r1 & SDMMC_OCR_CARD_ECC_FAILED) == SDMMC_OCR_CARD_ECC_FAILED)
{
return SDMMC_ERROR_CARD_ECC_FAILED;
}
else if((response_r1 & SDMMC_OCR_CC_ERROR) == SDMMC_OCR_CC_ERROR)
{
return SDMMC_ERROR_CC_ERR;
}
else if((response_r1 & SDMMC_OCR_STREAM_READ_UNDERRUN) == SDMMC_OCR_STREAM_READ_UNDERRUN)
{
return SDMMC_ERROR_STREAM_READ_UNDERRUN;
}
else if((response_r1 & SDMMC_OCR_STREAM_WRITE_OVERRUN) == SDMMC_OCR_STREAM_WRITE_OVERRUN)
{
return SDMMC_ERROR_STREAM_WRITE_OVERRUN;
}
else if((response_r1 & SDMMC_OCR_CID_CSD_OVERWRITE) == SDMMC_OCR_CID_CSD_OVERWRITE)
{
return SDMMC_ERROR_CID_CSD_OVERWRITE;
}
else if((response_r1 & SDMMC_OCR_WP_ERASE_SKIP) == SDMMC_OCR_WP_ERASE_SKIP)
{
return SDMMC_ERROR_WP_ERASE_SKIP;
}
else if((response_r1 & SDMMC_OCR_CARD_ECC_DISABLED) == SDMMC_OCR_CARD_ECC_DISABLED)
{
return SDMMC_ERROR_CARD_ECC_DISABLED;
}
else if((response_r1 & SDMMC_OCR_ERASE_RESET) == SDMMC_OCR_ERASE_RESET)
{
return SDMMC_ERROR_ERASE_RESET;
}
else if((response_r1 & SDMMC_OCR_AKE_SEQ_ERROR) == SDMMC_OCR_AKE_SEQ_ERROR)
{
return SDMMC_ERROR_AKE_SEQ_ERR;
}
else
{
return SDMMC_ERROR_GENERAL_UNKNOWN_ERR;
}
}
/**
* @brief Checks for error conditions for R2 (CID or CSD) response.
* @param SDIOx Pointer to SDMMC register base
* @retval SD Card error state
*/
uint32_t SDMMC_GetCmdResp2(SDIO_TypeDef *SDIOx)
{
uint32_t sta_reg;
/* 8 is the number of required instructions cycles for the below loop statement.
The SDIO_CMDTIMEOUT is expressed in ms */
uint32_t count = SDIO_CMDTIMEOUT * (SystemCoreClock / 8U /1000U);
do
{
if (count-- == 0U)
{
return SDMMC_ERROR_TIMEOUT;
}
sta_reg = SDIOx->STA;
}while(((sta_reg & (SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT)) == 0U) ||
((sta_reg & SDIO_FLAG_CMDACT) != 0U ));
if (__SDIO_GET_FLAG(SDIOx, SDIO_FLAG_CTIMEOUT))
{
__SDIO_CLEAR_FLAG(SDIOx, SDIO_FLAG_CTIMEOUT);
return SDMMC_ERROR_CMD_RSP_TIMEOUT;
}
else if (__SDIO_GET_FLAG(SDIOx, SDIO_FLAG_CCRCFAIL))
{
__SDIO_CLEAR_FLAG(SDIOx, SDIO_FLAG_CCRCFAIL);
return SDMMC_ERROR_CMD_CRC_FAIL;
}
else
{
/* No error flag set */
/* Clear all the static flags */
__SDIO_CLEAR_FLAG(SDIOx, SDIO_STATIC_CMD_FLAGS);
}
return SDMMC_ERROR_NONE;
}
/**
* @brief Checks for error conditions for R3 (OCR) response.
* @param SDIOx Pointer to SDMMC register base
* @retval SD Card error state
*/
uint32_t SDMMC_GetCmdResp3(SDIO_TypeDef *SDIOx)
{
uint32_t sta_reg;
/* 8 is the number of required instructions cycles for the below loop statement.
The SDIO_CMDTIMEOUT is expressed in ms */
uint32_t count = SDIO_CMDTIMEOUT * (SystemCoreClock / 8U /1000U);
do
{
if (count-- == 0U)
{
return SDMMC_ERROR_TIMEOUT;
}
sta_reg = SDIOx->STA;
}while(((sta_reg & (SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT)) == 0U) ||
((sta_reg & SDIO_FLAG_CMDACT) != 0U ));
if(__SDIO_GET_FLAG(SDIOx, SDIO_FLAG_CTIMEOUT))
{
__SDIO_CLEAR_FLAG(SDIOx, SDIO_FLAG_CTIMEOUT);
return SDMMC_ERROR_CMD_RSP_TIMEOUT;
}
else
{
/* Clear all the static flags */
__SDIO_CLEAR_FLAG(SDIOx, SDIO_STATIC_CMD_FLAGS);
}
return SDMMC_ERROR_NONE;
}
/**
* @brief Checks for error conditions for R6 (RCA) response.
* @param SDIOx Pointer to SDMMC register base
* @param SD_CMD: The sent command index
* @param pRCA: Pointer to the variable that will contain the SD card relative
* address RCA
* @retval SD Card error state
*/
uint32_t SDMMC_GetCmdResp6(SDIO_TypeDef *SDIOx, uint8_t SD_CMD, uint16_t *pRCA)
{
uint32_t response_r1;
uint32_t sta_reg;
/* 8 is the number of required instructions cycles for the below loop statement.
The SDIO_CMDTIMEOUT is expressed in ms */
uint32_t count = SDIO_CMDTIMEOUT * (SystemCoreClock / 8U /1000U);
do
{
if (count-- == 0U)
{
return SDMMC_ERROR_TIMEOUT;
}
sta_reg = SDIOx->STA;
}while(((sta_reg & (SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT)) == 0U) ||
((sta_reg & SDIO_FLAG_CMDACT) != 0U ));
if(__SDIO_GET_FLAG(SDIOx, SDIO_FLAG_CTIMEOUT))
{
__SDIO_CLEAR_FLAG(SDIOx, SDIO_FLAG_CTIMEOUT);
return SDMMC_ERROR_CMD_RSP_TIMEOUT;
}
else if(__SDIO_GET_FLAG(SDIOx, SDIO_FLAG_CCRCFAIL))
{
__SDIO_CLEAR_FLAG(SDIOx, SDIO_FLAG_CCRCFAIL);
return SDMMC_ERROR_CMD_CRC_FAIL;
}
else
{
/* Nothing to do */
}
/* Check response received is of desired command */
if(SDIO_GetCommandResponse(SDIOx) != SD_CMD)
{
return SDMMC_ERROR_CMD_CRC_FAIL;
}
/* Clear all the static flags */
__SDIO_CLEAR_FLAG(SDIOx, SDIO_STATIC_CMD_FLAGS);
/* We have received response, retrieve it. */
response_r1 = SDIO_GetResponse(SDIOx, SDIO_RESP1);
if((response_r1 & (SDMMC_R6_GENERAL_UNKNOWN_ERROR | SDMMC_R6_ILLEGAL_CMD | SDMMC_R6_COM_CRC_FAILED)) == SDMMC_ALLZERO)
{
*pRCA = (uint16_t) (response_r1 >> 16);
return SDMMC_ERROR_NONE;
}
else if((response_r1 & SDMMC_R6_ILLEGAL_CMD) == SDMMC_R6_ILLEGAL_CMD)
{
return SDMMC_ERROR_ILLEGAL_CMD;
}
else if((response_r1 & SDMMC_R6_COM_CRC_FAILED) == SDMMC_R6_COM_CRC_FAILED)
{
return SDMMC_ERROR_COM_CRC_FAILED;
}
else
{
return SDMMC_ERROR_GENERAL_UNKNOWN_ERR;
}
}
/**
* @brief Checks for error conditions for R7 response.
* @param SDIOx Pointer to SDMMC register base
* @retval SD Card error state
*/
uint32_t SDMMC_GetCmdResp7(SDIO_TypeDef *SDIOx)
{
uint32_t sta_reg;
/* 8 is the number of required instructions cycles for the below loop statement.
The SDIO_CMDTIMEOUT is expressed in ms */
uint32_t count = SDIO_CMDTIMEOUT * (SystemCoreClock / 8U /1000U);
do
{
if (count-- == 0U)
{
return SDMMC_ERROR_TIMEOUT;
}
sta_reg = SDIOx->STA;
}while(((sta_reg & (SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT)) == 0U) ||
((sta_reg & SDIO_FLAG_CMDACT) != 0U ));
if(__SDIO_GET_FLAG(SDIOx, SDIO_FLAG_CTIMEOUT))
{
/* Card is SD V2.0 compliant */
__SDIO_CLEAR_FLAG(SDIOx, SDIO_FLAG_CTIMEOUT);
return SDMMC_ERROR_CMD_RSP_TIMEOUT;
}
else if(__SDIO_GET_FLAG(SDIOx, SDIO_FLAG_CCRCFAIL))
{
/* Card is SD V2.0 compliant */
__SDIO_CLEAR_FLAG(SDIOx, SDIO_FLAG_CCRCFAIL);
return SDMMC_ERROR_CMD_CRC_FAIL;
}
else
{
/* Nothing to do */
}
if(__SDIO_GET_FLAG(SDIOx, SDIO_FLAG_CMDREND))
{
/* Card is SD V2.0 compliant */
__SDIO_CLEAR_FLAG(SDIOx, SDIO_FLAG_CMDREND);
}
return SDMMC_ERROR_NONE;
}
/**
* @}
*/
/* Private function ----------------------------------------------------------*/
/** @addtogroup SD_Private_Functions
* @{
*/
/**
* @brief Checks for error conditions for CMD0.
* @param SDIOx Pointer to SDMMC register base
* @retval SD Card error state
*/
static uint32_t SDMMC_GetCmdError(SDIO_TypeDef *SDIOx)
{
/* 8 is the number of required instructions cycles for the below loop statement.
The SDIO_CMDTIMEOUT is expressed in ms */
uint32_t count = SDIO_CMDTIMEOUT * (SystemCoreClock / 8U /1000U);
do
{
if (count-- == 0U)
{
return SDMMC_ERROR_TIMEOUT;
}
}while(!__SDIO_GET_FLAG(SDIOx, SDIO_FLAG_CMDSENT));
/* Clear all the static flags */
__SDIO_CLEAR_FLAG(SDIOx, SDIO_STATIC_CMD_FLAGS);
return SDMMC_ERROR_NONE;
}
/**
* @}
*/
#endif /* HAL_SD_MODULE_ENABLED || HAL_MMC_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/
#endif /* SDIO */

View File

@@ -0,0 +1,529 @@
/**
******************************************************************************
* @file stm32f1xx_ll_spi.c
* @author MCD Application Team
* @brief SPI LL module driver.
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#if defined(USE_FULL_LL_DRIVER)
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_ll_spi.h"
#include "stm32f1xx_ll_bus.h"
#include "stm32f1xx_ll_rcc.h"
#ifdef USE_FULL_ASSERT
#include "stm32_assert.h"
#else
#define assert_param(expr) ((void)0U)
#endif /* USE_FULL_ASSERT */
/** @addtogroup STM32F1xx_LL_Driver
* @{
*/
#if defined (SPI1) || defined (SPI2) || defined (SPI3)
/** @addtogroup SPI_LL
* @{
*/
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/** @defgroup SPI_LL_Private_Constants SPI Private Constants
* @{
*/
/* SPI registers Masks */
#define SPI_CR1_CLEAR_MASK (SPI_CR1_CPHA | SPI_CR1_CPOL | SPI_CR1_MSTR | \
SPI_CR1_BR | SPI_CR1_LSBFIRST | SPI_CR1_SSI | \
SPI_CR1_SSM | SPI_CR1_RXONLY | SPI_CR1_DFF | \
SPI_CR1_CRCNEXT | SPI_CR1_CRCEN | SPI_CR1_BIDIOE | \
SPI_CR1_BIDIMODE)
/**
* @}
*/
/* Private macros ------------------------------------------------------------*/
/** @defgroup SPI_LL_Private_Macros SPI Private Macros
* @{
*/
#define IS_LL_SPI_TRANSFER_DIRECTION(__VALUE__) (((__VALUE__) == LL_SPI_FULL_DUPLEX) \
|| ((__VALUE__) == LL_SPI_SIMPLEX_RX) \
|| ((__VALUE__) == LL_SPI_HALF_DUPLEX_RX) \
|| ((__VALUE__) == LL_SPI_HALF_DUPLEX_TX))
#define IS_LL_SPI_MODE(__VALUE__) (((__VALUE__) == LL_SPI_MODE_MASTER) \
|| ((__VALUE__) == LL_SPI_MODE_SLAVE))
#define IS_LL_SPI_DATAWIDTH(__VALUE__) (((__VALUE__) == LL_SPI_DATAWIDTH_8BIT) \
|| ((__VALUE__) == LL_SPI_DATAWIDTH_16BIT))
#define IS_LL_SPI_POLARITY(__VALUE__) (((__VALUE__) == LL_SPI_POLARITY_LOW) \
|| ((__VALUE__) == LL_SPI_POLARITY_HIGH))
#define IS_LL_SPI_PHASE(__VALUE__) (((__VALUE__) == LL_SPI_PHASE_1EDGE) \
|| ((__VALUE__) == LL_SPI_PHASE_2EDGE))
#define IS_LL_SPI_NSS(__VALUE__) (((__VALUE__) == LL_SPI_NSS_SOFT) \
|| ((__VALUE__) == LL_SPI_NSS_HARD_INPUT) \
|| ((__VALUE__) == LL_SPI_NSS_HARD_OUTPUT))
#define IS_LL_SPI_BAUDRATE(__VALUE__) (((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV2) \
|| ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV4) \
|| ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV8) \
|| ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV16) \
|| ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV32) \
|| ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV64) \
|| ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV128) \
|| ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV256))
#define IS_LL_SPI_BITORDER(__VALUE__) (((__VALUE__) == LL_SPI_LSB_FIRST) \
|| ((__VALUE__) == LL_SPI_MSB_FIRST))
#define IS_LL_SPI_CRCCALCULATION(__VALUE__) (((__VALUE__) == LL_SPI_CRCCALCULATION_ENABLE) \
|| ((__VALUE__) == LL_SPI_CRCCALCULATION_DISABLE))
#define IS_LL_SPI_CRC_POLYNOMIAL(__VALUE__) ((__VALUE__) >= 0x1U)
/**
* @}
*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup SPI_LL_Exported_Functions
* @{
*/
/** @addtogroup SPI_LL_EF_Init
* @{
*/
/**
* @brief De-initialize the SPI registers to their default reset values.
* @param SPIx SPI Instance
* @retval An ErrorStatus enumeration value:
* - SUCCESS: SPI registers are de-initialized
* - ERROR: SPI registers are not de-initialized
*/
ErrorStatus LL_SPI_DeInit(const SPI_TypeDef *SPIx)
{
ErrorStatus status = ERROR;
/* Check the parameters */
assert_param(IS_SPI_ALL_INSTANCE(SPIx));
#if defined(SPI1)
if (SPIx == SPI1)
{
/* Force reset of SPI clock */
LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1);
/* Release reset of SPI clock */
LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_SPI1);
status = SUCCESS;
}
#endif /* SPI1 */
#if defined(SPI2)
if (SPIx == SPI2)
{
/* Force reset of SPI clock */
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2);
/* Release reset of SPI clock */
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI2);
status = SUCCESS;
}
#endif /* SPI2 */
#if defined(SPI3)
if (SPIx == SPI3)
{
/* Force reset of SPI clock */
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI3);
/* Release reset of SPI clock */
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI3);
status = SUCCESS;
}
#endif /* SPI3 */
return status;
}
/**
* @brief Initialize the SPI registers according to the specified parameters in SPI_InitStruct.
* @note As some bits in SPI configuration registers can only be written when the
* SPI is disabled (SPI_CR1_SPE bit = 0), SPI peripheral should be in disabled state prior
* calling this function. Otherwise, ERROR result will be returned.
* @param SPIx SPI Instance
* @param SPI_InitStruct pointer to a @ref LL_SPI_InitTypeDef structure
* @retval An ErrorStatus enumeration value. (Return always SUCCESS)
*/
ErrorStatus LL_SPI_Init(SPI_TypeDef *SPIx, LL_SPI_InitTypeDef *SPI_InitStruct)
{
ErrorStatus status = ERROR;
/* Check the SPI Instance SPIx*/
assert_param(IS_SPI_ALL_INSTANCE(SPIx));
/* Check the SPI parameters from SPI_InitStruct*/
assert_param(IS_LL_SPI_TRANSFER_DIRECTION(SPI_InitStruct->TransferDirection));
assert_param(IS_LL_SPI_MODE(SPI_InitStruct->Mode));
assert_param(IS_LL_SPI_DATAWIDTH(SPI_InitStruct->DataWidth));
assert_param(IS_LL_SPI_POLARITY(SPI_InitStruct->ClockPolarity));
assert_param(IS_LL_SPI_PHASE(SPI_InitStruct->ClockPhase));
assert_param(IS_LL_SPI_NSS(SPI_InitStruct->NSS));
assert_param(IS_LL_SPI_BAUDRATE(SPI_InitStruct->BaudRate));
assert_param(IS_LL_SPI_BITORDER(SPI_InitStruct->BitOrder));
assert_param(IS_LL_SPI_CRCCALCULATION(SPI_InitStruct->CRCCalculation));
if (LL_SPI_IsEnabled(SPIx) == 0x00000000U)
{
/*---------------------------- SPIx CR1 Configuration ------------------------
* Configure SPIx CR1 with parameters:
* - TransferDirection: SPI_CR1_BIDIMODE, SPI_CR1_BIDIOE and SPI_CR1_RXONLY bits
* - Master/Slave Mode: SPI_CR1_MSTR bit
* - DataWidth: SPI_CR1_DFF bit
* - ClockPolarity: SPI_CR1_CPOL bit
* - ClockPhase: SPI_CR1_CPHA bit
* - NSS management: SPI_CR1_SSM bit
* - BaudRate prescaler: SPI_CR1_BR[2:0] bits
* - BitOrder: SPI_CR1_LSBFIRST bit
* - CRCCalculation: SPI_CR1_CRCEN bit
*/
MODIFY_REG(SPIx->CR1,
SPI_CR1_CLEAR_MASK,
SPI_InitStruct->TransferDirection | SPI_InitStruct->Mode | SPI_InitStruct->DataWidth |
SPI_InitStruct->ClockPolarity | SPI_InitStruct->ClockPhase |
SPI_InitStruct->NSS | SPI_InitStruct->BaudRate |
SPI_InitStruct->BitOrder | SPI_InitStruct->CRCCalculation);
/*---------------------------- SPIx CR2 Configuration ------------------------
* Configure SPIx CR2 with parameters:
* - NSS management: SSOE bit
*/
MODIFY_REG(SPIx->CR2, SPI_CR2_SSOE, (SPI_InitStruct->NSS >> 16U));
/*---------------------------- SPIx CRCPR Configuration ----------------------
* Configure SPIx CRCPR with parameters:
* - CRCPoly: CRCPOLY[15:0] bits
*/
if (SPI_InitStruct->CRCCalculation == LL_SPI_CRCCALCULATION_ENABLE)
{
assert_param(IS_LL_SPI_CRC_POLYNOMIAL(SPI_InitStruct->CRCPoly));
LL_SPI_SetCRCPolynomial(SPIx, SPI_InitStruct->CRCPoly);
}
status = SUCCESS;
}
#if defined (SPI_I2S_SUPPORT)
/* Activate the SPI mode (Reset I2SMOD bit in I2SCFGR register) */
CLEAR_BIT(SPIx->I2SCFGR, SPI_I2SCFGR_I2SMOD);
#endif /* SPI_I2S_SUPPORT */
return status;
}
/**
* @brief Set each @ref LL_SPI_InitTypeDef field to default value.
* @param SPI_InitStruct pointer to a @ref LL_SPI_InitTypeDef structure
* whose fields will be set to default values.
* @retval None
*/
void LL_SPI_StructInit(LL_SPI_InitTypeDef *SPI_InitStruct)
{
/* Set SPI_InitStruct fields to default values */
SPI_InitStruct->TransferDirection = LL_SPI_FULL_DUPLEX;
SPI_InitStruct->Mode = LL_SPI_MODE_SLAVE;
SPI_InitStruct->DataWidth = LL_SPI_DATAWIDTH_8BIT;
SPI_InitStruct->ClockPolarity = LL_SPI_POLARITY_LOW;
SPI_InitStruct->ClockPhase = LL_SPI_PHASE_1EDGE;
SPI_InitStruct->NSS = LL_SPI_NSS_HARD_INPUT;
SPI_InitStruct->BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV2;
SPI_InitStruct->BitOrder = LL_SPI_MSB_FIRST;
SPI_InitStruct->CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;
SPI_InitStruct->CRCPoly = 7U;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#if defined(SPI_I2S_SUPPORT)
/** @addtogroup I2S_LL
* @{
*/
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/** @defgroup I2S_LL_Private_Constants I2S Private Constants
* @{
*/
/* I2S registers Masks */
#define I2S_I2SCFGR_CLEAR_MASK (SPI_I2SCFGR_CHLEN | SPI_I2SCFGR_DATLEN | \
SPI_I2SCFGR_CKPOL | SPI_I2SCFGR_I2SSTD | \
SPI_I2SCFGR_I2SCFG | SPI_I2SCFGR_I2SMOD )
#define I2S_I2SPR_CLEAR_MASK 0x0002U
/**
* @}
*/
/* Private macros ------------------------------------------------------------*/
/** @defgroup I2S_LL_Private_Macros I2S Private Macros
* @{
*/
#define IS_LL_I2S_DATAFORMAT(__VALUE__) (((__VALUE__) == LL_I2S_DATAFORMAT_16B) \
|| ((__VALUE__) == LL_I2S_DATAFORMAT_16B_EXTENDED) \
|| ((__VALUE__) == LL_I2S_DATAFORMAT_24B) \
|| ((__VALUE__) == LL_I2S_DATAFORMAT_32B))
#define IS_LL_I2S_CPOL(__VALUE__) (((__VALUE__) == LL_I2S_POLARITY_LOW) \
|| ((__VALUE__) == LL_I2S_POLARITY_HIGH))
#define IS_LL_I2S_STANDARD(__VALUE__) (((__VALUE__) == LL_I2S_STANDARD_PHILIPS) \
|| ((__VALUE__) == LL_I2S_STANDARD_MSB) \
|| ((__VALUE__) == LL_I2S_STANDARD_LSB) \
|| ((__VALUE__) == LL_I2S_STANDARD_PCM_SHORT) \
|| ((__VALUE__) == LL_I2S_STANDARD_PCM_LONG))
#define IS_LL_I2S_MODE(__VALUE__) (((__VALUE__) == LL_I2S_MODE_SLAVE_TX) \
|| ((__VALUE__) == LL_I2S_MODE_SLAVE_RX) \
|| ((__VALUE__) == LL_I2S_MODE_MASTER_TX) \
|| ((__VALUE__) == LL_I2S_MODE_MASTER_RX))
#define IS_LL_I2S_MCLK_OUTPUT(__VALUE__) (((__VALUE__) == LL_I2S_MCLK_OUTPUT_ENABLE) \
|| ((__VALUE__) == LL_I2S_MCLK_OUTPUT_DISABLE))
#define IS_LL_I2S_AUDIO_FREQ(__VALUE__) ((((__VALUE__) >= LL_I2S_AUDIOFREQ_8K) \
&& ((__VALUE__) <= LL_I2S_AUDIOFREQ_192K)) \
|| ((__VALUE__) == LL_I2S_AUDIOFREQ_DEFAULT))
#define IS_LL_I2S_PRESCALER_LINEAR(__VALUE__) ((__VALUE__) >= 0x2U)
#define IS_LL_I2S_PRESCALER_PARITY(__VALUE__) (((__VALUE__) == LL_I2S_PRESCALER_PARITY_EVEN) \
|| ((__VALUE__) == LL_I2S_PRESCALER_PARITY_ODD))
/**
* @}
*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup I2S_LL_Exported_Functions
* @{
*/
/** @addtogroup I2S_LL_EF_Init
* @{
*/
/**
* @brief De-initialize the SPI/I2S registers to their default reset values.
* @param SPIx SPI Instance
* @retval An ErrorStatus enumeration value:
* - SUCCESS: SPI registers are de-initialized
* - ERROR: SPI registers are not de-initialized
*/
ErrorStatus LL_I2S_DeInit(const SPI_TypeDef *SPIx)
{
return LL_SPI_DeInit(SPIx);
}
/**
* @brief Initializes the SPI/I2S registers according to the specified parameters in I2S_InitStruct.
* @note As some bits in SPI configuration registers can only be written when the SPI is disabled (SPI_CR1_SPE bit =0),
* SPI peripheral should be in disabled state prior calling this function. Otherwise, ERROR result will be returned.
* @param SPIx SPI Instance
* @param I2S_InitStruct pointer to a @ref LL_I2S_InitTypeDef structure
* @retval An ErrorStatus enumeration value:
* - SUCCESS: SPI registers are Initialized
* - ERROR: SPI registers are not Initialized
*/
ErrorStatus LL_I2S_Init(SPI_TypeDef *SPIx, LL_I2S_InitTypeDef *I2S_InitStruct)
{
uint32_t i2sdiv = 2U;
uint32_t i2sodd = 0U;
uint32_t packetlength = 1U;
uint32_t tmp;
LL_RCC_ClocksTypeDef rcc_clocks;
uint32_t sourceclock;
ErrorStatus status = ERROR;
/* Check the I2S parameters */
assert_param(IS_I2S_ALL_INSTANCE(SPIx));
assert_param(IS_LL_I2S_MODE(I2S_InitStruct->Mode));
assert_param(IS_LL_I2S_STANDARD(I2S_InitStruct->Standard));
assert_param(IS_LL_I2S_DATAFORMAT(I2S_InitStruct->DataFormat));
assert_param(IS_LL_I2S_MCLK_OUTPUT(I2S_InitStruct->MCLKOutput));
assert_param(IS_LL_I2S_AUDIO_FREQ(I2S_InitStruct->AudioFreq));
assert_param(IS_LL_I2S_CPOL(I2S_InitStruct->ClockPolarity));
if (LL_I2S_IsEnabled(SPIx) == 0x00000000U)
{
/*---------------------------- SPIx I2SCFGR Configuration --------------------
* Configure SPIx I2SCFGR with parameters:
* - Mode: SPI_I2SCFGR_I2SCFG[1:0] bit
* - Standard: SPI_I2SCFGR_I2SSTD[1:0] and SPI_I2SCFGR_PCMSYNC bits
* - DataFormat: SPI_I2SCFGR_CHLEN and SPI_I2SCFGR_DATLEN bits
* - ClockPolarity: SPI_I2SCFGR_CKPOL bit
*/
/* Write to SPIx I2SCFGR */
MODIFY_REG(SPIx->I2SCFGR,
I2S_I2SCFGR_CLEAR_MASK,
I2S_InitStruct->Mode | I2S_InitStruct->Standard |
I2S_InitStruct->DataFormat | I2S_InitStruct->ClockPolarity |
SPI_I2SCFGR_I2SMOD);
/*---------------------------- SPIx I2SPR Configuration ----------------------
* Configure SPIx I2SPR with parameters:
* - MCLKOutput: SPI_I2SPR_MCKOE bit
* - AudioFreq: SPI_I2SPR_I2SDIV[7:0] and SPI_I2SPR_ODD bits
*/
/* If the requested audio frequency is not the default, compute the prescaler (i2sodd, i2sdiv)
* else, default values are used: i2sodd = 0U, i2sdiv = 2U.
*/
if (I2S_InitStruct->AudioFreq != LL_I2S_AUDIOFREQ_DEFAULT)
{
/* Check the frame length (For the Prescaler computing)
* Default value: LL_I2S_DATAFORMAT_16B (packetlength = 1U).
*/
if (I2S_InitStruct->DataFormat != LL_I2S_DATAFORMAT_16B)
{
/* Packet length is 32 bits */
packetlength = 2U;
}
/* I2S Clock source is System clock: Get System Clock frequency */
LL_RCC_GetSystemClocksFreq(&rcc_clocks);
/* Get the source clock value: based on System Clock value */
sourceclock = rcc_clocks.SYSCLK_Frequency;
/* Compute the Real divider depending on the MCLK output state with a floating point */
if (I2S_InitStruct->MCLKOutput == LL_I2S_MCLK_OUTPUT_ENABLE)
{
/* MCLK output is enabled */
tmp = (((((sourceclock / 256U) * 10U) / I2S_InitStruct->AudioFreq)) + 5U);
}
else
{
/* MCLK output is disabled */
tmp = (((((sourceclock / (32U * packetlength)) * 10U) / I2S_InitStruct->AudioFreq)) + 5U);
}
/* Remove the floating point */
tmp = tmp / 10U;
/* Check the parity of the divider */
i2sodd = (tmp & (uint16_t)0x0001U);
/* Compute the i2sdiv prescaler */
i2sdiv = ((tmp - i2sodd) / 2U);
/* Get the Mask for the Odd bit (SPI_I2SPR[8]) register */
i2sodd = (i2sodd << 8U);
}
/* Test if the divider is 1 or 0 or greater than 0xFF */
if ((i2sdiv < 2U) || (i2sdiv > 0xFFU))
{
/* Set the default values */
i2sdiv = 2U;
i2sodd = 0U;
}
/* Write to SPIx I2SPR register the computed value */
WRITE_REG(SPIx->I2SPR, i2sdiv | i2sodd | I2S_InitStruct->MCLKOutput);
status = SUCCESS;
}
return status;
}
/**
* @brief Set each @ref LL_I2S_InitTypeDef field to default value.
* @param I2S_InitStruct pointer to a @ref LL_I2S_InitTypeDef structure
* whose fields will be set to default values.
* @retval None
*/
void LL_I2S_StructInit(LL_I2S_InitTypeDef *I2S_InitStruct)
{
/*--------------- Reset I2S init structure parameters values -----------------*/
I2S_InitStruct->Mode = LL_I2S_MODE_SLAVE_TX;
I2S_InitStruct->Standard = LL_I2S_STANDARD_PHILIPS;
I2S_InitStruct->DataFormat = LL_I2S_DATAFORMAT_16B;
I2S_InitStruct->MCLKOutput = LL_I2S_MCLK_OUTPUT_DISABLE;
I2S_InitStruct->AudioFreq = LL_I2S_AUDIOFREQ_DEFAULT;
I2S_InitStruct->ClockPolarity = LL_I2S_POLARITY_LOW;
}
/**
* @brief Set linear and parity prescaler.
* @note To calculate value of PrescalerLinear(I2SDIV[7:0] bits) and PrescalerParity(ODD bit)\n
* Check Audio frequency table and formulas inside Reference Manual (SPI/I2S).
* @param SPIx SPI Instance
* @param PrescalerLinear value Min_Data=0x02 and Max_Data=0xFF.
* @param PrescalerParity This parameter can be one of the following values:
* @arg @ref LL_I2S_PRESCALER_PARITY_EVEN
* @arg @ref LL_I2S_PRESCALER_PARITY_ODD
* @retval None
*/
void LL_I2S_ConfigPrescaler(SPI_TypeDef *SPIx, uint32_t PrescalerLinear, uint32_t PrescalerParity)
{
/* Check the I2S parameters */
assert_param(IS_I2S_ALL_INSTANCE(SPIx));
assert_param(IS_LL_I2S_PRESCALER_LINEAR(PrescalerLinear));
assert_param(IS_LL_I2S_PRESCALER_PARITY(PrescalerParity));
/* Write to SPIx I2SPR */
MODIFY_REG(SPIx->I2SPR, SPI_I2SPR_I2SDIV | SPI_I2SPR_ODD, PrescalerLinear | (PrescalerParity << 8U));
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#endif /* SPI_I2S_SUPPORT */
#endif /* defined (SPI1) || defined (SPI2) || defined (SPI3) */
/**
* @}
*/
#endif /* USE_FULL_LL_DRIVER */

View File

@@ -0,0 +1,1202 @@
/**
******************************************************************************
* @file stm32f1xx_ll_tim.c
* @author MCD Application Team
* @brief TIM LL module driver.
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#if defined(USE_FULL_LL_DRIVER)
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_ll_tim.h"
#include "stm32f1xx_ll_bus.h"
#ifdef USE_FULL_ASSERT
#include "stm32_assert.h"
#else
#define assert_param(expr) ((void)0U)
#endif /* USE_FULL_ASSERT */
/** @addtogroup STM32F1xx_LL_Driver
* @{
*/
#if defined (TIM1) || defined (TIM2) || defined (TIM3) || defined (TIM4) || defined (TIM5) || defined (TIM6) || defined (TIM7) || defined (TIM8) || defined (TIM9) || defined (TIM10) || defined (TIM11) || defined (TIM12) || defined (TIM13) || defined (TIM14) || defined (TIM15) || defined (TIM16) || defined (TIM17)
/** @addtogroup TIM_LL
* @{
*/
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/** @addtogroup TIM_LL_Private_Macros
* @{
*/
#define IS_LL_TIM_COUNTERMODE(__VALUE__) (((__VALUE__) == LL_TIM_COUNTERMODE_UP) \
|| ((__VALUE__) == LL_TIM_COUNTERMODE_DOWN) \
|| ((__VALUE__) == LL_TIM_COUNTERMODE_CENTER_UP) \
|| ((__VALUE__) == LL_TIM_COUNTERMODE_CENTER_DOWN) \
|| ((__VALUE__) == LL_TIM_COUNTERMODE_CENTER_UP_DOWN))
#define IS_LL_TIM_CLOCKDIVISION(__VALUE__) (((__VALUE__) == LL_TIM_CLOCKDIVISION_DIV1) \
|| ((__VALUE__) == LL_TIM_CLOCKDIVISION_DIV2) \
|| ((__VALUE__) == LL_TIM_CLOCKDIVISION_DIV4))
#define IS_LL_TIM_OCMODE(__VALUE__) (((__VALUE__) == LL_TIM_OCMODE_FROZEN) \
|| ((__VALUE__) == LL_TIM_OCMODE_ACTIVE) \
|| ((__VALUE__) == LL_TIM_OCMODE_INACTIVE) \
|| ((__VALUE__) == LL_TIM_OCMODE_TOGGLE) \
|| ((__VALUE__) == LL_TIM_OCMODE_FORCED_INACTIVE) \
|| ((__VALUE__) == LL_TIM_OCMODE_FORCED_ACTIVE) \
|| ((__VALUE__) == LL_TIM_OCMODE_PWM1) \
|| ((__VALUE__) == LL_TIM_OCMODE_PWM2))
#define IS_LL_TIM_OCSTATE(__VALUE__) (((__VALUE__) == LL_TIM_OCSTATE_DISABLE) \
|| ((__VALUE__) == LL_TIM_OCSTATE_ENABLE))
#define IS_LL_TIM_OCPOLARITY(__VALUE__) (((__VALUE__) == LL_TIM_OCPOLARITY_HIGH) \
|| ((__VALUE__) == LL_TIM_OCPOLARITY_LOW))
#define IS_LL_TIM_OCIDLESTATE(__VALUE__) (((__VALUE__) == LL_TIM_OCIDLESTATE_LOW) \
|| ((__VALUE__) == LL_TIM_OCIDLESTATE_HIGH))
#define IS_LL_TIM_ACTIVEINPUT(__VALUE__) (((__VALUE__) == LL_TIM_ACTIVEINPUT_DIRECTTI) \
|| ((__VALUE__) == LL_TIM_ACTIVEINPUT_INDIRECTTI) \
|| ((__VALUE__) == LL_TIM_ACTIVEINPUT_TRC))
#define IS_LL_TIM_ICPSC(__VALUE__) (((__VALUE__) == LL_TIM_ICPSC_DIV1) \
|| ((__VALUE__) == LL_TIM_ICPSC_DIV2) \
|| ((__VALUE__) == LL_TIM_ICPSC_DIV4) \
|| ((__VALUE__) == LL_TIM_ICPSC_DIV8))
#define IS_LL_TIM_IC_FILTER(__VALUE__) (((__VALUE__) == LL_TIM_IC_FILTER_FDIV1) \
|| ((__VALUE__) == LL_TIM_IC_FILTER_FDIV1_N2) \
|| ((__VALUE__) == LL_TIM_IC_FILTER_FDIV1_N4) \
|| ((__VALUE__) == LL_TIM_IC_FILTER_FDIV1_N8) \
|| ((__VALUE__) == LL_TIM_IC_FILTER_FDIV2_N6) \
|| ((__VALUE__) == LL_TIM_IC_FILTER_FDIV2_N8) \
|| ((__VALUE__) == LL_TIM_IC_FILTER_FDIV4_N6) \
|| ((__VALUE__) == LL_TIM_IC_FILTER_FDIV4_N8) \
|| ((__VALUE__) == LL_TIM_IC_FILTER_FDIV8_N6) \
|| ((__VALUE__) == LL_TIM_IC_FILTER_FDIV8_N8) \
|| ((__VALUE__) == LL_TIM_IC_FILTER_FDIV16_N5) \
|| ((__VALUE__) == LL_TIM_IC_FILTER_FDIV16_N6) \
|| ((__VALUE__) == LL_TIM_IC_FILTER_FDIV16_N8) \
|| ((__VALUE__) == LL_TIM_IC_FILTER_FDIV32_N5) \
|| ((__VALUE__) == LL_TIM_IC_FILTER_FDIV32_N6) \
|| ((__VALUE__) == LL_TIM_IC_FILTER_FDIV32_N8))
#define IS_LL_TIM_IC_POLARITY(__VALUE__) (((__VALUE__) == LL_TIM_IC_POLARITY_RISING) \
|| ((__VALUE__) == LL_TIM_IC_POLARITY_FALLING))
#define IS_LL_TIM_ENCODERMODE(__VALUE__) (((__VALUE__) == LL_TIM_ENCODERMODE_X2_TI1) \
|| ((__VALUE__) == LL_TIM_ENCODERMODE_X2_TI2) \
|| ((__VALUE__) == LL_TIM_ENCODERMODE_X4_TI12))
#define IS_LL_TIM_IC_POLARITY_ENCODER(__VALUE__) (((__VALUE__) == LL_TIM_IC_POLARITY_RISING) \
|| ((__VALUE__) == LL_TIM_IC_POLARITY_FALLING))
#define IS_LL_TIM_OSSR_STATE(__VALUE__) (((__VALUE__) == LL_TIM_OSSR_DISABLE) \
|| ((__VALUE__) == LL_TIM_OSSR_ENABLE))
#define IS_LL_TIM_OSSI_STATE(__VALUE__) (((__VALUE__) == LL_TIM_OSSI_DISABLE) \
|| ((__VALUE__) == LL_TIM_OSSI_ENABLE))
#define IS_LL_TIM_LOCK_LEVEL(__VALUE__) (((__VALUE__) == LL_TIM_LOCKLEVEL_OFF) \
|| ((__VALUE__) == LL_TIM_LOCKLEVEL_1) \
|| ((__VALUE__) == LL_TIM_LOCKLEVEL_2) \
|| ((__VALUE__) == LL_TIM_LOCKLEVEL_3))
#define IS_LL_TIM_BREAK_STATE(__VALUE__) (((__VALUE__) == LL_TIM_BREAK_DISABLE) \
|| ((__VALUE__) == LL_TIM_BREAK_ENABLE))
#define IS_LL_TIM_BREAK_POLARITY(__VALUE__) (((__VALUE__) == LL_TIM_BREAK_POLARITY_LOW) \
|| ((__VALUE__) == LL_TIM_BREAK_POLARITY_HIGH))
#define IS_LL_TIM_AUTOMATIC_OUTPUT_STATE(__VALUE__) (((__VALUE__) == LL_TIM_AUTOMATICOUTPUT_DISABLE) \
|| ((__VALUE__) == LL_TIM_AUTOMATICOUTPUT_ENABLE))
/**
* @}
*/
/* Private function prototypes -----------------------------------------------*/
/** @defgroup TIM_LL_Private_Functions TIM Private Functions
* @{
*/
static ErrorStatus OC1Config(TIM_TypeDef *TIMx, const LL_TIM_OC_InitTypeDef *TIM_OCInitStruct);
static ErrorStatus OC2Config(TIM_TypeDef *TIMx, const LL_TIM_OC_InitTypeDef *TIM_OCInitStruct);
static ErrorStatus OC3Config(TIM_TypeDef *TIMx, const LL_TIM_OC_InitTypeDef *TIM_OCInitStruct);
static ErrorStatus OC4Config(TIM_TypeDef *TIMx, const LL_TIM_OC_InitTypeDef *TIM_OCInitStruct);
static ErrorStatus IC1Config(TIM_TypeDef *TIMx, const LL_TIM_IC_InitTypeDef *TIM_ICInitStruct);
static ErrorStatus IC2Config(TIM_TypeDef *TIMx, const LL_TIM_IC_InitTypeDef *TIM_ICInitStruct);
static ErrorStatus IC3Config(TIM_TypeDef *TIMx, const LL_TIM_IC_InitTypeDef *TIM_ICInitStruct);
static ErrorStatus IC4Config(TIM_TypeDef *TIMx, const LL_TIM_IC_InitTypeDef *TIM_ICInitStruct);
/**
* @}
*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup TIM_LL_Exported_Functions
* @{
*/
/** @addtogroup TIM_LL_EF_Init
* @{
*/
/**
* @brief Set TIMx registers to their reset values.
* @param TIMx Timer instance
* @retval An ErrorStatus enumeration value:
* - SUCCESS: TIMx registers are de-initialized
* - ERROR: invalid TIMx instance
*/
ErrorStatus LL_TIM_DeInit(const TIM_TypeDef *TIMx)
{
ErrorStatus result = SUCCESS;
/* Check the parameters */
assert_param(IS_TIM_INSTANCE(TIMx));
if (TIMx == TIM2)
{
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_TIM2);
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_TIM2);
}
#if defined(TIM1)
else if (TIMx == TIM1)
{
LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_TIM1);
LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_TIM1);
}
#endif /* TIM1 */
#if defined(TIM3)
else if (TIMx == TIM3)
{
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_TIM3);
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_TIM3);
}
#endif /* TIM3 */
#if defined(TIM4)
else if (TIMx == TIM4)
{
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_TIM4);
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_TIM4);
}
#endif /* TIM4 */
#if defined(TIM5)
else if (TIMx == TIM5)
{
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_TIM5);
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_TIM5);
}
#endif /* TIM5 */
#if defined(TIM6)
else if (TIMx == TIM6)
{
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_TIM6);
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_TIM6);
}
#endif /* TIM6 */
#if defined (TIM7)
else if (TIMx == TIM7)
{
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_TIM7);
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_TIM7);
}
#endif /* TIM7 */
#if defined(TIM8)
else if (TIMx == TIM8)
{
LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_TIM8);
LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_TIM8);
}
#endif /* TIM8 */
#if defined(TIM9)
else if (TIMx == TIM9)
{
LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_TIM9);
LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_TIM9);
}
#endif /* TIM9 */
#if defined(TIM10)
else if (TIMx == TIM10)
{
LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_TIM10);
LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_TIM10);
}
#endif /* TIM10 */
#if defined(TIM11)
else if (TIMx == TIM11)
{
LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_TIM11);
LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_TIM11);
}
#endif /* TIM11 */
#if defined(TIM12)
else if (TIMx == TIM12)
{
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_TIM12);
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_TIM12);
}
#endif /* TIM12 */
#if defined(TIM13)
else if (TIMx == TIM13)
{
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_TIM13);
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_TIM13);
}
#endif /* TIM13 */
#if defined(TIM14)
else if (TIMx == TIM14)
{
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_TIM14);
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_TIM14);
}
#endif /* TIM14 */
#if defined(TIM15)
else if (TIMx == TIM15)
{
LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_TIM15);
LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_TIM15);
}
#endif /* TIM15 */
#if defined(TIM16)
else if (TIMx == TIM16)
{
LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_TIM16);
LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_TIM16);
}
#endif /* TIM16 */
#if defined(TIM17)
else if (TIMx == TIM17)
{
LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_TIM17);
LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_TIM17);
}
#endif /* TIM17 */
else
{
result = ERROR;
}
return result;
}
/**
* @brief Set the fields of the time base unit configuration data structure
* to their default values.
* @param TIM_InitStruct pointer to a @ref LL_TIM_InitTypeDef structure (time base unit configuration data structure)
* @retval None
*/
void LL_TIM_StructInit(LL_TIM_InitTypeDef *TIM_InitStruct)
{
/* Set the default configuration */
TIM_InitStruct->Prescaler = (uint16_t)0x0000;
TIM_InitStruct->CounterMode = LL_TIM_COUNTERMODE_UP;
TIM_InitStruct->Autoreload = 0xFFFFFFFFU;
TIM_InitStruct->ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
TIM_InitStruct->RepetitionCounter = 0x00000000U;
}
/**
* @brief Configure the TIMx time base unit.
* @param TIMx Timer Instance
* @param TIM_InitStruct pointer to a @ref LL_TIM_InitTypeDef structure
* (TIMx time base unit configuration data structure)
* @retval An ErrorStatus enumeration value:
* - SUCCESS: TIMx registers are de-initialized
* - ERROR: not applicable
*/
ErrorStatus LL_TIM_Init(TIM_TypeDef *TIMx, const LL_TIM_InitTypeDef *TIM_InitStruct)
{
uint32_t tmpcr1;
/* Check the parameters */
assert_param(IS_TIM_INSTANCE(TIMx));
assert_param(IS_LL_TIM_COUNTERMODE(TIM_InitStruct->CounterMode));
assert_param(IS_LL_TIM_CLOCKDIVISION(TIM_InitStruct->ClockDivision));
tmpcr1 = LL_TIM_ReadReg(TIMx, CR1);
if (IS_TIM_COUNTER_MODE_SELECT_INSTANCE(TIMx))
{
/* Select the Counter Mode */
MODIFY_REG(tmpcr1, (TIM_CR1_DIR | TIM_CR1_CMS), TIM_InitStruct->CounterMode);
}
if (IS_TIM_CLOCK_DIVISION_INSTANCE(TIMx))
{
/* Set the clock division */
MODIFY_REG(tmpcr1, TIM_CR1_CKD, TIM_InitStruct->ClockDivision);
}
/* Write to TIMx CR1 */
LL_TIM_WriteReg(TIMx, CR1, tmpcr1);
/* Set the Autoreload value */
LL_TIM_SetAutoReload(TIMx, TIM_InitStruct->Autoreload);
/* Set the Prescaler value */
LL_TIM_SetPrescaler(TIMx, TIM_InitStruct->Prescaler);
if (IS_TIM_REPETITION_COUNTER_INSTANCE(TIMx))
{
/* Set the Repetition Counter value */
LL_TIM_SetRepetitionCounter(TIMx, TIM_InitStruct->RepetitionCounter);
}
/* Generate an update event to reload the Prescaler
and the repetition counter value (if applicable) immediately */
LL_TIM_GenerateEvent_UPDATE(TIMx);
return SUCCESS;
}
/**
* @brief Set the fields of the TIMx output channel configuration data
* structure to their default values.
* @param TIM_OC_InitStruct pointer to a @ref LL_TIM_OC_InitTypeDef structure
* (the output channel configuration data structure)
* @retval None
*/
void LL_TIM_OC_StructInit(LL_TIM_OC_InitTypeDef *TIM_OC_InitStruct)
{
/* Set the default configuration */
TIM_OC_InitStruct->OCMode = LL_TIM_OCMODE_FROZEN;
TIM_OC_InitStruct->OCState = LL_TIM_OCSTATE_DISABLE;
TIM_OC_InitStruct->OCNState = LL_TIM_OCSTATE_DISABLE;
TIM_OC_InitStruct->CompareValue = 0x00000000U;
TIM_OC_InitStruct->OCPolarity = LL_TIM_OCPOLARITY_HIGH;
TIM_OC_InitStruct->OCNPolarity = LL_TIM_OCPOLARITY_HIGH;
TIM_OC_InitStruct->OCIdleState = LL_TIM_OCIDLESTATE_LOW;
TIM_OC_InitStruct->OCNIdleState = LL_TIM_OCIDLESTATE_LOW;
}
/**
* @brief Configure the TIMx output channel.
* @param TIMx Timer Instance
* @param Channel This parameter can be one of the following values:
* @arg @ref LL_TIM_CHANNEL_CH1
* @arg @ref LL_TIM_CHANNEL_CH2
* @arg @ref LL_TIM_CHANNEL_CH3
* @arg @ref LL_TIM_CHANNEL_CH4
* @param TIM_OC_InitStruct pointer to a @ref LL_TIM_OC_InitTypeDef structure (TIMx output channel configuration
* data structure)
* @retval An ErrorStatus enumeration value:
* - SUCCESS: TIMx output channel is initialized
* - ERROR: TIMx output channel is not initialized
*/
ErrorStatus LL_TIM_OC_Init(TIM_TypeDef *TIMx, uint32_t Channel, const LL_TIM_OC_InitTypeDef *TIM_OC_InitStruct)
{
ErrorStatus result = ERROR;
switch (Channel)
{
case LL_TIM_CHANNEL_CH1:
result = OC1Config(TIMx, TIM_OC_InitStruct);
break;
case LL_TIM_CHANNEL_CH2:
result = OC2Config(TIMx, TIM_OC_InitStruct);
break;
case LL_TIM_CHANNEL_CH3:
result = OC3Config(TIMx, TIM_OC_InitStruct);
break;
case LL_TIM_CHANNEL_CH4:
result = OC4Config(TIMx, TIM_OC_InitStruct);
break;
default:
break;
}
return result;
}
/**
* @brief Set the fields of the TIMx input channel configuration data
* structure to their default values.
* @param TIM_ICInitStruct pointer to a @ref LL_TIM_IC_InitTypeDef structure (the input channel configuration
* data structure)
* @retval None
*/
void LL_TIM_IC_StructInit(LL_TIM_IC_InitTypeDef *TIM_ICInitStruct)
{
/* Set the default configuration */
TIM_ICInitStruct->ICPolarity = LL_TIM_IC_POLARITY_RISING;
TIM_ICInitStruct->ICActiveInput = LL_TIM_ACTIVEINPUT_DIRECTTI;
TIM_ICInitStruct->ICPrescaler = LL_TIM_ICPSC_DIV1;
TIM_ICInitStruct->ICFilter = LL_TIM_IC_FILTER_FDIV1;
}
/**
* @brief Configure the TIMx input channel.
* @param TIMx Timer Instance
* @param Channel This parameter can be one of the following values:
* @arg @ref LL_TIM_CHANNEL_CH1
* @arg @ref LL_TIM_CHANNEL_CH2
* @arg @ref LL_TIM_CHANNEL_CH3
* @arg @ref LL_TIM_CHANNEL_CH4
* @param TIM_IC_InitStruct pointer to a @ref LL_TIM_IC_InitTypeDef structure (TIMx input channel configuration data
* structure)
* @retval An ErrorStatus enumeration value:
* - SUCCESS: TIMx output channel is initialized
* - ERROR: TIMx output channel is not initialized
*/
ErrorStatus LL_TIM_IC_Init(TIM_TypeDef *TIMx, uint32_t Channel, const LL_TIM_IC_InitTypeDef *TIM_IC_InitStruct)
{
ErrorStatus result = ERROR;
switch (Channel)
{
case LL_TIM_CHANNEL_CH1:
result = IC1Config(TIMx, TIM_IC_InitStruct);
break;
case LL_TIM_CHANNEL_CH2:
result = IC2Config(TIMx, TIM_IC_InitStruct);
break;
case LL_TIM_CHANNEL_CH3:
result = IC3Config(TIMx, TIM_IC_InitStruct);
break;
case LL_TIM_CHANNEL_CH4:
result = IC4Config(TIMx, TIM_IC_InitStruct);
break;
default:
break;
}
return result;
}
/**
* @brief Fills each TIM_EncoderInitStruct field with its default value
* @param TIM_EncoderInitStruct pointer to a @ref LL_TIM_ENCODER_InitTypeDef structure (encoder interface
* configuration data structure)
* @retval None
*/
void LL_TIM_ENCODER_StructInit(LL_TIM_ENCODER_InitTypeDef *TIM_EncoderInitStruct)
{
/* Set the default configuration */
TIM_EncoderInitStruct->EncoderMode = LL_TIM_ENCODERMODE_X2_TI1;
TIM_EncoderInitStruct->IC1Polarity = LL_TIM_IC_POLARITY_RISING;
TIM_EncoderInitStruct->IC1ActiveInput = LL_TIM_ACTIVEINPUT_DIRECTTI;
TIM_EncoderInitStruct->IC1Prescaler = LL_TIM_ICPSC_DIV1;
TIM_EncoderInitStruct->IC1Filter = LL_TIM_IC_FILTER_FDIV1;
TIM_EncoderInitStruct->IC2Polarity = LL_TIM_IC_POLARITY_RISING;
TIM_EncoderInitStruct->IC2ActiveInput = LL_TIM_ACTIVEINPUT_DIRECTTI;
TIM_EncoderInitStruct->IC2Prescaler = LL_TIM_ICPSC_DIV1;
TIM_EncoderInitStruct->IC2Filter = LL_TIM_IC_FILTER_FDIV1;
}
/**
* @brief Configure the encoder interface of the timer instance.
* @param TIMx Timer Instance
* @param TIM_EncoderInitStruct pointer to a @ref LL_TIM_ENCODER_InitTypeDef structure (TIMx encoder interface
* configuration data structure)
* @retval An ErrorStatus enumeration value:
* - SUCCESS: TIMx registers are de-initialized
* - ERROR: not applicable
*/
ErrorStatus LL_TIM_ENCODER_Init(TIM_TypeDef *TIMx, const LL_TIM_ENCODER_InitTypeDef *TIM_EncoderInitStruct)
{
uint32_t tmpccmr1;
uint32_t tmpccer;
/* Check the parameters */
assert_param(IS_TIM_ENCODER_INTERFACE_INSTANCE(TIMx));
assert_param(IS_LL_TIM_ENCODERMODE(TIM_EncoderInitStruct->EncoderMode));
assert_param(IS_LL_TIM_IC_POLARITY_ENCODER(TIM_EncoderInitStruct->IC1Polarity));
assert_param(IS_LL_TIM_ACTIVEINPUT(TIM_EncoderInitStruct->IC1ActiveInput));
assert_param(IS_LL_TIM_ICPSC(TIM_EncoderInitStruct->IC1Prescaler));
assert_param(IS_LL_TIM_IC_FILTER(TIM_EncoderInitStruct->IC1Filter));
assert_param(IS_LL_TIM_IC_POLARITY_ENCODER(TIM_EncoderInitStruct->IC2Polarity));
assert_param(IS_LL_TIM_ACTIVEINPUT(TIM_EncoderInitStruct->IC2ActiveInput));
assert_param(IS_LL_TIM_ICPSC(TIM_EncoderInitStruct->IC2Prescaler));
assert_param(IS_LL_TIM_IC_FILTER(TIM_EncoderInitStruct->IC2Filter));
/* Disable the CC1 and CC2: Reset the CC1E and CC2E Bits */
TIMx->CCER &= (uint32_t)~(TIM_CCER_CC1E | TIM_CCER_CC2E);
/* Get the TIMx CCMR1 register value */
tmpccmr1 = LL_TIM_ReadReg(TIMx, CCMR1);
/* Get the TIMx CCER register value */
tmpccer = LL_TIM_ReadReg(TIMx, CCER);
/* Configure TI1 */
tmpccmr1 &= (uint32_t)~(TIM_CCMR1_CC1S | TIM_CCMR1_IC1F | TIM_CCMR1_IC1PSC);
tmpccmr1 |= (uint32_t)(TIM_EncoderInitStruct->IC1ActiveInput >> 16U);
tmpccmr1 |= (uint32_t)(TIM_EncoderInitStruct->IC1Filter >> 16U);
tmpccmr1 |= (uint32_t)(TIM_EncoderInitStruct->IC1Prescaler >> 16U);
/* Configure TI2 */
tmpccmr1 &= (uint32_t)~(TIM_CCMR1_CC2S | TIM_CCMR1_IC2F | TIM_CCMR1_IC2PSC);
tmpccmr1 |= (uint32_t)(TIM_EncoderInitStruct->IC2ActiveInput >> 8U);
tmpccmr1 |= (uint32_t)(TIM_EncoderInitStruct->IC2Filter >> 8U);
tmpccmr1 |= (uint32_t)(TIM_EncoderInitStruct->IC2Prescaler >> 8U);
/* Set TI1 and TI2 polarity and enable TI1 and TI2 */
tmpccer &= (uint32_t)~(TIM_CCER_CC1P | TIM_CCER_CC1NP | TIM_CCER_CC2P | TIM_CCER_CC2NP);
tmpccer |= (uint32_t)(TIM_EncoderInitStruct->IC1Polarity);
tmpccer |= (uint32_t)(TIM_EncoderInitStruct->IC2Polarity << 4U);
tmpccer |= (uint32_t)(TIM_CCER_CC1E | TIM_CCER_CC2E);
/* Set encoder mode */
LL_TIM_SetEncoderMode(TIMx, TIM_EncoderInitStruct->EncoderMode);
/* Write to TIMx CCMR1 */
LL_TIM_WriteReg(TIMx, CCMR1, tmpccmr1);
/* Write to TIMx CCER */
LL_TIM_WriteReg(TIMx, CCER, tmpccer);
return SUCCESS;
}
/**
* @brief Set the fields of the TIMx Hall sensor interface configuration data
* structure to their default values.
* @param TIM_HallSensorInitStruct pointer to a @ref LL_TIM_HALLSENSOR_InitTypeDef structure (HALL sensor interface
* configuration data structure)
* @retval None
*/
void LL_TIM_HALLSENSOR_StructInit(LL_TIM_HALLSENSOR_InitTypeDef *TIM_HallSensorInitStruct)
{
/* Set the default configuration */
TIM_HallSensorInitStruct->IC1Polarity = LL_TIM_IC_POLARITY_RISING;
TIM_HallSensorInitStruct->IC1Prescaler = LL_TIM_ICPSC_DIV1;
TIM_HallSensorInitStruct->IC1Filter = LL_TIM_IC_FILTER_FDIV1;
TIM_HallSensorInitStruct->CommutationDelay = 0U;
}
/**
* @brief Configure the Hall sensor interface of the timer instance.
* @note TIMx CH1, CH2 and CH3 inputs connected through a XOR
* to the TI1 input channel
* @note TIMx slave mode controller is configured in reset mode.
Selected internal trigger is TI1F_ED.
* @note Channel 1 is configured as input, IC1 is mapped on TRC.
* @note Captured value stored in TIMx_CCR1 correspond to the time elapsed
* between 2 changes on the inputs. It gives information about motor speed.
* @note Channel 2 is configured in output PWM 2 mode.
* @note Compare value stored in TIMx_CCR2 corresponds to the commutation delay.
* @note OC2REF is selected as trigger output on TRGO.
* @param TIMx Timer Instance
* @param TIM_HallSensorInitStruct pointer to a @ref LL_TIM_HALLSENSOR_InitTypeDef structure (TIMx HALL sensor
* interface configuration data structure)
* @retval An ErrorStatus enumeration value:
* - SUCCESS: TIMx registers are de-initialized
* - ERROR: not applicable
*/
ErrorStatus LL_TIM_HALLSENSOR_Init(TIM_TypeDef *TIMx, const LL_TIM_HALLSENSOR_InitTypeDef *TIM_HallSensorInitStruct)
{
uint32_t tmpcr2;
uint32_t tmpccmr1;
uint32_t tmpccer;
uint32_t tmpsmcr;
/* Check the parameters */
assert_param(IS_TIM_HALL_SENSOR_INTERFACE_INSTANCE(TIMx));
assert_param(IS_LL_TIM_IC_POLARITY_ENCODER(TIM_HallSensorInitStruct->IC1Polarity));
assert_param(IS_LL_TIM_ICPSC(TIM_HallSensorInitStruct->IC1Prescaler));
assert_param(IS_LL_TIM_IC_FILTER(TIM_HallSensorInitStruct->IC1Filter));
/* Disable the CC1 and CC2: Reset the CC1E and CC2E Bits */
TIMx->CCER &= (uint32_t)~(TIM_CCER_CC1E | TIM_CCER_CC2E);
/* Get the TIMx CR2 register value */
tmpcr2 = LL_TIM_ReadReg(TIMx, CR2);
/* Get the TIMx CCMR1 register value */
tmpccmr1 = LL_TIM_ReadReg(TIMx, CCMR1);
/* Get the TIMx CCER register value */
tmpccer = LL_TIM_ReadReg(TIMx, CCER);
/* Get the TIMx SMCR register value */
tmpsmcr = LL_TIM_ReadReg(TIMx, SMCR);
/* Connect TIMx_CH1, CH2 and CH3 pins to the TI1 input */
tmpcr2 |= TIM_CR2_TI1S;
/* OC2REF signal is used as trigger output (TRGO) */
tmpcr2 |= LL_TIM_TRGO_OC2REF;
/* Configure the slave mode controller */
tmpsmcr &= (uint32_t)~(TIM_SMCR_TS | TIM_SMCR_SMS);
tmpsmcr |= LL_TIM_TS_TI1F_ED;
tmpsmcr |= LL_TIM_SLAVEMODE_RESET;
/* Configure input channel 1 */
tmpccmr1 &= (uint32_t)~(TIM_CCMR1_CC1S | TIM_CCMR1_IC1F | TIM_CCMR1_IC1PSC);
tmpccmr1 |= (uint32_t)(LL_TIM_ACTIVEINPUT_TRC >> 16U);
tmpccmr1 |= (uint32_t)(TIM_HallSensorInitStruct->IC1Filter >> 16U);
tmpccmr1 |= (uint32_t)(TIM_HallSensorInitStruct->IC1Prescaler >> 16U);
/* Configure input channel 2 */
tmpccmr1 &= (uint32_t)~(TIM_CCMR1_OC2M | TIM_CCMR1_OC2FE | TIM_CCMR1_OC2PE | TIM_CCMR1_OC2CE);
tmpccmr1 |= (uint32_t)(LL_TIM_OCMODE_PWM2 << 8U);
/* Set Channel 1 polarity and enable Channel 1 and Channel2 */
tmpccer &= (uint32_t)~(TIM_CCER_CC1P | TIM_CCER_CC1NP | TIM_CCER_CC2P | TIM_CCER_CC2NP);
tmpccer |= (uint32_t)(TIM_HallSensorInitStruct->IC1Polarity);
tmpccer |= (uint32_t)(TIM_CCER_CC1E | TIM_CCER_CC2E);
/* Write to TIMx CR2 */
LL_TIM_WriteReg(TIMx, CR2, tmpcr2);
/* Write to TIMx SMCR */
LL_TIM_WriteReg(TIMx, SMCR, tmpsmcr);
/* Write to TIMx CCMR1 */
LL_TIM_WriteReg(TIMx, CCMR1, tmpccmr1);
/* Write to TIMx CCER */
LL_TIM_WriteReg(TIMx, CCER, tmpccer);
/* Write to TIMx CCR2 */
LL_TIM_OC_SetCompareCH2(TIMx, TIM_HallSensorInitStruct->CommutationDelay);
return SUCCESS;
}
/**
* @brief Set the fields of the Break and Dead Time configuration data structure
* to their default values.
* @param TIM_BDTRInitStruct pointer to a @ref LL_TIM_BDTR_InitTypeDef structure (Break and Dead Time configuration
* data structure)
* @retval None
*/
void LL_TIM_BDTR_StructInit(LL_TIM_BDTR_InitTypeDef *TIM_BDTRInitStruct)
{
/* Set the default configuration */
TIM_BDTRInitStruct->OSSRState = LL_TIM_OSSR_DISABLE;
TIM_BDTRInitStruct->OSSIState = LL_TIM_OSSI_DISABLE;
TIM_BDTRInitStruct->LockLevel = LL_TIM_LOCKLEVEL_OFF;
TIM_BDTRInitStruct->DeadTime = (uint8_t)0x00;
TIM_BDTRInitStruct->BreakState = LL_TIM_BREAK_DISABLE;
TIM_BDTRInitStruct->BreakPolarity = LL_TIM_BREAK_POLARITY_LOW;
TIM_BDTRInitStruct->AutomaticOutput = LL_TIM_AUTOMATICOUTPUT_DISABLE;
}
/**
* @brief Configure the Break and Dead Time feature of the timer instance.
* @note As the bits AOE, BKP, BKE, OSSR, OSSI and DTG[7:0] can be write-locked
* depending on the LOCK configuration, it can be necessary to configure all of
* them during the first write access to the TIMx_BDTR register.
* @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not
* a timer instance provides a break input.
* @param TIMx Timer Instance
* @param TIM_BDTRInitStruct pointer to a @ref LL_TIM_BDTR_InitTypeDef structure (Break and Dead Time configuration
* data structure)
* @retval An ErrorStatus enumeration value:
* - SUCCESS: Break and Dead Time is initialized
* - ERROR: not applicable
*/
ErrorStatus LL_TIM_BDTR_Init(TIM_TypeDef *TIMx, const LL_TIM_BDTR_InitTypeDef *TIM_BDTRInitStruct)
{
uint32_t tmpbdtr = 0;
/* Check the parameters */
assert_param(IS_TIM_BREAK_INSTANCE(TIMx));
assert_param(IS_LL_TIM_OSSR_STATE(TIM_BDTRInitStruct->OSSRState));
assert_param(IS_LL_TIM_OSSI_STATE(TIM_BDTRInitStruct->OSSIState));
assert_param(IS_LL_TIM_LOCK_LEVEL(TIM_BDTRInitStruct->LockLevel));
assert_param(IS_LL_TIM_BREAK_STATE(TIM_BDTRInitStruct->BreakState));
assert_param(IS_LL_TIM_BREAK_POLARITY(TIM_BDTRInitStruct->BreakPolarity));
assert_param(IS_LL_TIM_AUTOMATIC_OUTPUT_STATE(TIM_BDTRInitStruct->AutomaticOutput));
/* Set the Lock level, the Break enable Bit and the Polarity, the OSSR State,
the OSSI State, the dead time value and the Automatic Output Enable Bit */
/* Set the BDTR bits */
MODIFY_REG(tmpbdtr, TIM_BDTR_DTG, TIM_BDTRInitStruct->DeadTime);
MODIFY_REG(tmpbdtr, TIM_BDTR_LOCK, TIM_BDTRInitStruct->LockLevel);
MODIFY_REG(tmpbdtr, TIM_BDTR_OSSI, TIM_BDTRInitStruct->OSSIState);
MODIFY_REG(tmpbdtr, TIM_BDTR_OSSR, TIM_BDTRInitStruct->OSSRState);
MODIFY_REG(tmpbdtr, TIM_BDTR_BKE, TIM_BDTRInitStruct->BreakState);
MODIFY_REG(tmpbdtr, TIM_BDTR_BKP, TIM_BDTRInitStruct->BreakPolarity);
MODIFY_REG(tmpbdtr, TIM_BDTR_AOE, TIM_BDTRInitStruct->AutomaticOutput);
/* Set TIMx_BDTR */
LL_TIM_WriteReg(TIMx, BDTR, tmpbdtr);
return SUCCESS;
}
/**
* @}
*/
/**
* @}
*/
/** @addtogroup TIM_LL_Private_Functions TIM Private Functions
* @brief Private functions
* @{
*/
/**
* @brief Configure the TIMx output channel 1.
* @param TIMx Timer Instance
* @param TIM_OCInitStruct pointer to the the TIMx output channel 1 configuration data structure
* @retval An ErrorStatus enumeration value:
* - SUCCESS: TIMx registers are de-initialized
* - ERROR: not applicable
*/
static ErrorStatus OC1Config(TIM_TypeDef *TIMx, const LL_TIM_OC_InitTypeDef *TIM_OCInitStruct)
{
uint32_t tmpccmr1;
uint32_t tmpccer;
uint32_t tmpcr2;
/* Check the parameters */
assert_param(IS_TIM_CC1_INSTANCE(TIMx));
assert_param(IS_LL_TIM_OCMODE(TIM_OCInitStruct->OCMode));
assert_param(IS_LL_TIM_OCSTATE(TIM_OCInitStruct->OCState));
assert_param(IS_LL_TIM_OCPOLARITY(TIM_OCInitStruct->OCPolarity));
/* Disable the Channel 1: Reset the CC1E Bit */
CLEAR_BIT(TIMx->CCER, TIM_CCER_CC1E);
/* Get the TIMx CCER register value */
tmpccer = LL_TIM_ReadReg(TIMx, CCER);
/* Get the TIMx CR2 register value */
tmpcr2 = LL_TIM_ReadReg(TIMx, CR2);
/* Get the TIMx CCMR1 register value */
tmpccmr1 = LL_TIM_ReadReg(TIMx, CCMR1);
/* Reset Capture/Compare selection Bits */
CLEAR_BIT(tmpccmr1, TIM_CCMR1_CC1S);
/* Set the Output Compare Mode */
MODIFY_REG(tmpccmr1, TIM_CCMR1_OC1M, TIM_OCInitStruct->OCMode);
/* Set the Output Compare Polarity */
MODIFY_REG(tmpccer, TIM_CCER_CC1P, TIM_OCInitStruct->OCPolarity);
/* Set the Output State */
MODIFY_REG(tmpccer, TIM_CCER_CC1E, TIM_OCInitStruct->OCState);
if (IS_TIM_BREAK_INSTANCE(TIMx))
{
assert_param(IS_LL_TIM_OCIDLESTATE(TIM_OCInitStruct->OCIdleState));
assert_param(IS_LL_TIM_OCSTATE(TIM_OCInitStruct->OCNState));
assert_param(IS_LL_TIM_OCPOLARITY(TIM_OCInitStruct->OCNPolarity));
assert_param(IS_LL_TIM_OCIDLESTATE(TIM_OCInitStruct->OCNIdleState));
/* Set the complementary output Polarity */
MODIFY_REG(tmpccer, TIM_CCER_CC1NP, TIM_OCInitStruct->OCNPolarity << 2U);
/* Set the complementary output State */
MODIFY_REG(tmpccer, TIM_CCER_CC1NE, TIM_OCInitStruct->OCNState << 2U);
/* Set the Output Idle state */
MODIFY_REG(tmpcr2, TIM_CR2_OIS1, TIM_OCInitStruct->OCIdleState);
/* Set the complementary output Idle state */
MODIFY_REG(tmpcr2, TIM_CR2_OIS1N, TIM_OCInitStruct->OCNIdleState << 1U);
}
/* Write to TIMx CR2 */
LL_TIM_WriteReg(TIMx, CR2, tmpcr2);
/* Write to TIMx CCMR1 */
LL_TIM_WriteReg(TIMx, CCMR1, tmpccmr1);
/* Set the Capture Compare Register value */
LL_TIM_OC_SetCompareCH1(TIMx, TIM_OCInitStruct->CompareValue);
/* Write to TIMx CCER */
LL_TIM_WriteReg(TIMx, CCER, tmpccer);
return SUCCESS;
}
/**
* @brief Configure the TIMx output channel 2.
* @param TIMx Timer Instance
* @param TIM_OCInitStruct pointer to the the TIMx output channel 2 configuration data structure
* @retval An ErrorStatus enumeration value:
* - SUCCESS: TIMx registers are de-initialized
* - ERROR: not applicable
*/
static ErrorStatus OC2Config(TIM_TypeDef *TIMx, const LL_TIM_OC_InitTypeDef *TIM_OCInitStruct)
{
uint32_t tmpccmr1;
uint32_t tmpccer;
uint32_t tmpcr2;
/* Check the parameters */
assert_param(IS_TIM_CC2_INSTANCE(TIMx));
assert_param(IS_LL_TIM_OCMODE(TIM_OCInitStruct->OCMode));
assert_param(IS_LL_TIM_OCSTATE(TIM_OCInitStruct->OCState));
assert_param(IS_LL_TIM_OCPOLARITY(TIM_OCInitStruct->OCPolarity));
/* Disable the Channel 2: Reset the CC2E Bit */
CLEAR_BIT(TIMx->CCER, TIM_CCER_CC2E);
/* Get the TIMx CCER register value */
tmpccer = LL_TIM_ReadReg(TIMx, CCER);
/* Get the TIMx CR2 register value */
tmpcr2 = LL_TIM_ReadReg(TIMx, CR2);
/* Get the TIMx CCMR1 register value */
tmpccmr1 = LL_TIM_ReadReg(TIMx, CCMR1);
/* Reset Capture/Compare selection Bits */
CLEAR_BIT(tmpccmr1, TIM_CCMR1_CC2S);
/* Select the Output Compare Mode */
MODIFY_REG(tmpccmr1, TIM_CCMR1_OC2M, TIM_OCInitStruct->OCMode << 8U);
/* Set the Output Compare Polarity */
MODIFY_REG(tmpccer, TIM_CCER_CC2P, TIM_OCInitStruct->OCPolarity << 4U);
/* Set the Output State */
MODIFY_REG(tmpccer, TIM_CCER_CC2E, TIM_OCInitStruct->OCState << 4U);
if (IS_TIM_BREAK_INSTANCE(TIMx))
{
assert_param(IS_LL_TIM_OCIDLESTATE(TIM_OCInitStruct->OCIdleState));
assert_param(IS_LL_TIM_OCSTATE(TIM_OCInitStruct->OCNState));
assert_param(IS_LL_TIM_OCPOLARITY(TIM_OCInitStruct->OCNPolarity));
assert_param(IS_LL_TIM_OCIDLESTATE(TIM_OCInitStruct->OCNIdleState));
/* Set the complementary output Polarity */
MODIFY_REG(tmpccer, TIM_CCER_CC2NP, TIM_OCInitStruct->OCNPolarity << 6U);
/* Set the complementary output State */
MODIFY_REG(tmpccer, TIM_CCER_CC2NE, TIM_OCInitStruct->OCNState << 6U);
/* Set the Output Idle state */
MODIFY_REG(tmpcr2, TIM_CR2_OIS2, TIM_OCInitStruct->OCIdleState << 2U);
/* Set the complementary output Idle state */
MODIFY_REG(tmpcr2, TIM_CR2_OIS2N, TIM_OCInitStruct->OCNIdleState << 3U);
}
/* Write to TIMx CR2 */
LL_TIM_WriteReg(TIMx, CR2, tmpcr2);
/* Write to TIMx CCMR1 */
LL_TIM_WriteReg(TIMx, CCMR1, tmpccmr1);
/* Set the Capture Compare Register value */
LL_TIM_OC_SetCompareCH2(TIMx, TIM_OCInitStruct->CompareValue);
/* Write to TIMx CCER */
LL_TIM_WriteReg(TIMx, CCER, tmpccer);
return SUCCESS;
}
/**
* @brief Configure the TIMx output channel 3.
* @param TIMx Timer Instance
* @param TIM_OCInitStruct pointer to the the TIMx output channel 3 configuration data structure
* @retval An ErrorStatus enumeration value:
* - SUCCESS: TIMx registers are de-initialized
* - ERROR: not applicable
*/
static ErrorStatus OC3Config(TIM_TypeDef *TIMx, const LL_TIM_OC_InitTypeDef *TIM_OCInitStruct)
{
uint32_t tmpccmr2;
uint32_t tmpccer;
uint32_t tmpcr2;
/* Check the parameters */
assert_param(IS_TIM_CC3_INSTANCE(TIMx));
assert_param(IS_LL_TIM_OCMODE(TIM_OCInitStruct->OCMode));
assert_param(IS_LL_TIM_OCSTATE(TIM_OCInitStruct->OCState));
assert_param(IS_LL_TIM_OCPOLARITY(TIM_OCInitStruct->OCPolarity));
/* Disable the Channel 3: Reset the CC3E Bit */
CLEAR_BIT(TIMx->CCER, TIM_CCER_CC3E);
/* Get the TIMx CCER register value */
tmpccer = LL_TIM_ReadReg(TIMx, CCER);
/* Get the TIMx CR2 register value */
tmpcr2 = LL_TIM_ReadReg(TIMx, CR2);
/* Get the TIMx CCMR2 register value */
tmpccmr2 = LL_TIM_ReadReg(TIMx, CCMR2);
/* Reset Capture/Compare selection Bits */
CLEAR_BIT(tmpccmr2, TIM_CCMR2_CC3S);
/* Select the Output Compare Mode */
MODIFY_REG(tmpccmr2, TIM_CCMR2_OC3M, TIM_OCInitStruct->OCMode);
/* Set the Output Compare Polarity */
MODIFY_REG(tmpccer, TIM_CCER_CC3P, TIM_OCInitStruct->OCPolarity << 8U);
/* Set the Output State */
MODIFY_REG(tmpccer, TIM_CCER_CC3E, TIM_OCInitStruct->OCState << 8U);
if (IS_TIM_BREAK_INSTANCE(TIMx))
{
assert_param(IS_LL_TIM_OCIDLESTATE(TIM_OCInitStruct->OCIdleState));
assert_param(IS_LL_TIM_OCSTATE(TIM_OCInitStruct->OCNState));
assert_param(IS_LL_TIM_OCPOLARITY(TIM_OCInitStruct->OCNPolarity));
assert_param(IS_LL_TIM_OCIDLESTATE(TIM_OCInitStruct->OCNIdleState));
/* Set the complementary output Polarity */
MODIFY_REG(tmpccer, TIM_CCER_CC3NP, TIM_OCInitStruct->OCNPolarity << 10U);
/* Set the complementary output State */
MODIFY_REG(tmpccer, TIM_CCER_CC3NE, TIM_OCInitStruct->OCNState << 10U);
/* Set the Output Idle state */
MODIFY_REG(tmpcr2, TIM_CR2_OIS3, TIM_OCInitStruct->OCIdleState << 4U);
/* Set the complementary output Idle state */
MODIFY_REG(tmpcr2, TIM_CR2_OIS3N, TIM_OCInitStruct->OCNIdleState << 5U);
}
/* Write to TIMx CR2 */
LL_TIM_WriteReg(TIMx, CR2, tmpcr2);
/* Write to TIMx CCMR2 */
LL_TIM_WriteReg(TIMx, CCMR2, tmpccmr2);
/* Set the Capture Compare Register value */
LL_TIM_OC_SetCompareCH3(TIMx, TIM_OCInitStruct->CompareValue);
/* Write to TIMx CCER */
LL_TIM_WriteReg(TIMx, CCER, tmpccer);
return SUCCESS;
}
/**
* @brief Configure the TIMx output channel 4.
* @param TIMx Timer Instance
* @param TIM_OCInitStruct pointer to the the TIMx output channel 4 configuration data structure
* @retval An ErrorStatus enumeration value:
* - SUCCESS: TIMx registers are de-initialized
* - ERROR: not applicable
*/
static ErrorStatus OC4Config(TIM_TypeDef *TIMx, const LL_TIM_OC_InitTypeDef *TIM_OCInitStruct)
{
uint32_t tmpccmr2;
uint32_t tmpccer;
uint32_t tmpcr2;
/* Check the parameters */
assert_param(IS_TIM_CC4_INSTANCE(TIMx));
assert_param(IS_LL_TIM_OCMODE(TIM_OCInitStruct->OCMode));
assert_param(IS_LL_TIM_OCSTATE(TIM_OCInitStruct->OCState));
assert_param(IS_LL_TIM_OCPOLARITY(TIM_OCInitStruct->OCPolarity));
/* Disable the Channel 4: Reset the CC4E Bit */
CLEAR_BIT(TIMx->CCER, TIM_CCER_CC4E);
/* Get the TIMx CCER register value */
tmpccer = LL_TIM_ReadReg(TIMx, CCER);
/* Get the TIMx CR2 register value */
tmpcr2 = LL_TIM_ReadReg(TIMx, CR2);
/* Get the TIMx CCMR2 register value */
tmpccmr2 = LL_TIM_ReadReg(TIMx, CCMR2);
/* Reset Capture/Compare selection Bits */
CLEAR_BIT(tmpccmr2, TIM_CCMR2_CC4S);
/* Select the Output Compare Mode */
MODIFY_REG(tmpccmr2, TIM_CCMR2_OC4M, TIM_OCInitStruct->OCMode << 8U);
/* Set the Output Compare Polarity */
MODIFY_REG(tmpccer, TIM_CCER_CC4P, TIM_OCInitStruct->OCPolarity << 12U);
/* Set the Output State */
MODIFY_REG(tmpccer, TIM_CCER_CC4E, TIM_OCInitStruct->OCState << 12U);
if (IS_TIM_BREAK_INSTANCE(TIMx))
{
assert_param(IS_LL_TIM_OCIDLESTATE(TIM_OCInitStruct->OCIdleState));
/* Set the Output Idle state */
MODIFY_REG(tmpcr2, TIM_CR2_OIS4, TIM_OCInitStruct->OCIdleState << 6U);
}
/* Write to TIMx CR2 */
LL_TIM_WriteReg(TIMx, CR2, tmpcr2);
/* Write to TIMx CCMR2 */
LL_TIM_WriteReg(TIMx, CCMR2, tmpccmr2);
/* Set the Capture Compare Register value */
LL_TIM_OC_SetCompareCH4(TIMx, TIM_OCInitStruct->CompareValue);
/* Write to TIMx CCER */
LL_TIM_WriteReg(TIMx, CCER, tmpccer);
return SUCCESS;
}
/**
* @brief Configure the TIMx input channel 1.
* @param TIMx Timer Instance
* @param TIM_ICInitStruct pointer to the the TIMx input channel 1 configuration data structure
* @retval An ErrorStatus enumeration value:
* - SUCCESS: TIMx registers are de-initialized
* - ERROR: not applicable
*/
static ErrorStatus IC1Config(TIM_TypeDef *TIMx, const LL_TIM_IC_InitTypeDef *TIM_ICInitStruct)
{
/* Check the parameters */
assert_param(IS_TIM_CC1_INSTANCE(TIMx));
assert_param(IS_LL_TIM_IC_POLARITY(TIM_ICInitStruct->ICPolarity));
assert_param(IS_LL_TIM_ACTIVEINPUT(TIM_ICInitStruct->ICActiveInput));
assert_param(IS_LL_TIM_ICPSC(TIM_ICInitStruct->ICPrescaler));
assert_param(IS_LL_TIM_IC_FILTER(TIM_ICInitStruct->ICFilter));
/* Disable the Channel 1: Reset the CC1E Bit */
TIMx->CCER &= (uint32_t)~TIM_CCER_CC1E;
/* Select the Input and set the filter and the prescaler value */
MODIFY_REG(TIMx->CCMR1,
(TIM_CCMR1_CC1S | TIM_CCMR1_IC1F | TIM_CCMR1_IC1PSC),
(TIM_ICInitStruct->ICActiveInput | TIM_ICInitStruct->ICFilter | TIM_ICInitStruct->ICPrescaler) >> 16U);
/* Select the Polarity and set the CC1E Bit */
MODIFY_REG(TIMx->CCER,
(TIM_CCER_CC1P | TIM_CCER_CC1NP),
(TIM_ICInitStruct->ICPolarity | TIM_CCER_CC1E));
return SUCCESS;
}
/**
* @brief Configure the TIMx input channel 2.
* @param TIMx Timer Instance
* @param TIM_ICInitStruct pointer to the the TIMx input channel 2 configuration data structure
* @retval An ErrorStatus enumeration value:
* - SUCCESS: TIMx registers are de-initialized
* - ERROR: not applicable
*/
static ErrorStatus IC2Config(TIM_TypeDef *TIMx, const LL_TIM_IC_InitTypeDef *TIM_ICInitStruct)
{
/* Check the parameters */
assert_param(IS_TIM_CC2_INSTANCE(TIMx));
assert_param(IS_LL_TIM_IC_POLARITY(TIM_ICInitStruct->ICPolarity));
assert_param(IS_LL_TIM_ACTIVEINPUT(TIM_ICInitStruct->ICActiveInput));
assert_param(IS_LL_TIM_ICPSC(TIM_ICInitStruct->ICPrescaler));
assert_param(IS_LL_TIM_IC_FILTER(TIM_ICInitStruct->ICFilter));
/* Disable the Channel 2: Reset the CC2E Bit */
TIMx->CCER &= (uint32_t)~TIM_CCER_CC2E;
/* Select the Input and set the filter and the prescaler value */
MODIFY_REG(TIMx->CCMR1,
(TIM_CCMR1_CC2S | TIM_CCMR1_IC2F | TIM_CCMR1_IC2PSC),
(TIM_ICInitStruct->ICActiveInput | TIM_ICInitStruct->ICFilter | TIM_ICInitStruct->ICPrescaler) >> 8U);
/* Select the Polarity and set the CC2E Bit */
MODIFY_REG(TIMx->CCER,
(TIM_CCER_CC2P | TIM_CCER_CC2NP),
((TIM_ICInitStruct->ICPolarity << 4U) | TIM_CCER_CC2E));
return SUCCESS;
}
/**
* @brief Configure the TIMx input channel 3.
* @param TIMx Timer Instance
* @param TIM_ICInitStruct pointer to the the TIMx input channel 3 configuration data structure
* @retval An ErrorStatus enumeration value:
* - SUCCESS: TIMx registers are de-initialized
* - ERROR: not applicable
*/
static ErrorStatus IC3Config(TIM_TypeDef *TIMx, const LL_TIM_IC_InitTypeDef *TIM_ICInitStruct)
{
/* Check the parameters */
assert_param(IS_TIM_CC3_INSTANCE(TIMx));
assert_param(IS_LL_TIM_IC_POLARITY(TIM_ICInitStruct->ICPolarity));
assert_param(IS_LL_TIM_ACTIVEINPUT(TIM_ICInitStruct->ICActiveInput));
assert_param(IS_LL_TIM_ICPSC(TIM_ICInitStruct->ICPrescaler));
assert_param(IS_LL_TIM_IC_FILTER(TIM_ICInitStruct->ICFilter));
/* Disable the Channel 3: Reset the CC3E Bit */
TIMx->CCER &= (uint32_t)~TIM_CCER_CC3E;
/* Select the Input and set the filter and the prescaler value */
MODIFY_REG(TIMx->CCMR2,
(TIM_CCMR2_CC3S | TIM_CCMR2_IC3F | TIM_CCMR2_IC3PSC),
(TIM_ICInitStruct->ICActiveInput | TIM_ICInitStruct->ICFilter | TIM_ICInitStruct->ICPrescaler) >> 16U);
/* Select the Polarity and set the CC3E Bit */
MODIFY_REG(TIMx->CCER,
(TIM_CCER_CC3P | TIM_CCER_CC3NP),
((TIM_ICInitStruct->ICPolarity << 8U) | TIM_CCER_CC3E));
return SUCCESS;
}
/**
* @brief Configure the TIMx input channel 4.
* @param TIMx Timer Instance
* @param TIM_ICInitStruct pointer to the the TIMx input channel 4 configuration data structure
* @retval An ErrorStatus enumeration value:
* - SUCCESS: TIMx registers are de-initialized
* - ERROR: not applicable
*/
static ErrorStatus IC4Config(TIM_TypeDef *TIMx, const LL_TIM_IC_InitTypeDef *TIM_ICInitStruct)
{
/* Check the parameters */
assert_param(IS_TIM_CC4_INSTANCE(TIMx));
assert_param(IS_LL_TIM_IC_POLARITY(TIM_ICInitStruct->ICPolarity));
assert_param(IS_LL_TIM_ACTIVEINPUT(TIM_ICInitStruct->ICActiveInput));
assert_param(IS_LL_TIM_ICPSC(TIM_ICInitStruct->ICPrescaler));
assert_param(IS_LL_TIM_IC_FILTER(TIM_ICInitStruct->ICFilter));
/* Disable the Channel 4: Reset the CC4E Bit */
TIMx->CCER &= (uint32_t)~TIM_CCER_CC4E;
/* Select the Input and set the filter and the prescaler value */
MODIFY_REG(TIMx->CCMR2,
(TIM_CCMR2_CC4S | TIM_CCMR2_IC4F | TIM_CCMR2_IC4PSC),
(TIM_ICInitStruct->ICActiveInput | TIM_ICInitStruct->ICFilter | TIM_ICInitStruct->ICPrescaler) >> 8U);
/* Select the Polarity and set the CC4E Bit */
MODIFY_REG(TIMx->CCER,
TIM_CCER_CC4P,
((TIM_ICInitStruct->ICPolarity << 12U) | TIM_CCER_CC4E));
return SUCCESS;
}
/**
* @}
*/
/**
* @}
*/
#endif /* TIM1 || TIM2 || TIM3 || TIM4 || TIM5 || TIM6 || TIM7 || TIM8 || TIM9 || TIM10 || TIM11 || TIM12 || TIM13 || TIM14 || TIM15 || TIM16 || TIM17 */
/**
* @}
*/
#endif /* USE_FULL_LL_DRIVER */

View File

@@ -0,0 +1,438 @@
/**
******************************************************************************
* @file stm32f1xx_ll_usart.c
* @author MCD Application Team
* @brief USART LL module driver.
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#if defined(USE_FULL_LL_DRIVER)
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_ll_usart.h"
#include "stm32f1xx_ll_rcc.h"
#include "stm32f1xx_ll_bus.h"
#ifdef USE_FULL_ASSERT
#include "stm32_assert.h"
#else
#define assert_param(expr) ((void)0U)
#endif
/** @addtogroup STM32F1xx_LL_Driver
* @{
*/
#if defined (USART1) || defined (USART2) || defined (USART3) || defined (UART4) || defined (UART5)
/** @addtogroup USART_LL
* @{
*/
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/** @addtogroup USART_LL_Private_Constants
* @{
*/
/**
* @}
*/
/* Private macros ------------------------------------------------------------*/
/** @addtogroup USART_LL_Private_Macros
* @{
*/
/* __BAUDRATE__ The maximum Baud Rate is derived from the maximum clock available
* divided by the smallest oversampling used on the USART (i.e. 8) */
#define IS_LL_USART_BAUDRATE(__BAUDRATE__) ((__BAUDRATE__) <= 4500000U)
/* __VALUE__ In case of oversampling by 16 and 8, BRR content must be greater than or equal to 16d. */
#define IS_LL_USART_BRR_MIN(__VALUE__) ((__VALUE__) >= 16U)
#define IS_LL_USART_DIRECTION(__VALUE__) (((__VALUE__) == LL_USART_DIRECTION_NONE) \
|| ((__VALUE__) == LL_USART_DIRECTION_RX) \
|| ((__VALUE__) == LL_USART_DIRECTION_TX) \
|| ((__VALUE__) == LL_USART_DIRECTION_TX_RX))
#define IS_LL_USART_PARITY(__VALUE__) (((__VALUE__) == LL_USART_PARITY_NONE) \
|| ((__VALUE__) == LL_USART_PARITY_EVEN) \
|| ((__VALUE__) == LL_USART_PARITY_ODD))
#define IS_LL_USART_DATAWIDTH(__VALUE__) (((__VALUE__) == LL_USART_DATAWIDTH_8B) \
|| ((__VALUE__) == LL_USART_DATAWIDTH_9B))
#define IS_LL_USART_OVERSAMPLING(__VALUE__) (((__VALUE__) == LL_USART_OVERSAMPLING_16) \
|| ((__VALUE__) == LL_USART_OVERSAMPLING_8))
#define IS_LL_USART_LASTBITCLKOUTPUT(__VALUE__) (((__VALUE__) == LL_USART_LASTCLKPULSE_NO_OUTPUT) \
|| ((__VALUE__) == LL_USART_LASTCLKPULSE_OUTPUT))
#define IS_LL_USART_CLOCKPHASE(__VALUE__) (((__VALUE__) == LL_USART_PHASE_1EDGE) \
|| ((__VALUE__) == LL_USART_PHASE_2EDGE))
#define IS_LL_USART_CLOCKPOLARITY(__VALUE__) (((__VALUE__) == LL_USART_POLARITY_LOW) \
|| ((__VALUE__) == LL_USART_POLARITY_HIGH))
#define IS_LL_USART_CLOCKOUTPUT(__VALUE__) (((__VALUE__) == LL_USART_CLOCK_DISABLE) \
|| ((__VALUE__) == LL_USART_CLOCK_ENABLE))
#define IS_LL_USART_STOPBITS(__VALUE__) (((__VALUE__) == LL_USART_STOPBITS_0_5) \
|| ((__VALUE__) == LL_USART_STOPBITS_1) \
|| ((__VALUE__) == LL_USART_STOPBITS_1_5) \
|| ((__VALUE__) == LL_USART_STOPBITS_2))
#define IS_LL_USART_HWCONTROL(__VALUE__) (((__VALUE__) == LL_USART_HWCONTROL_NONE) \
|| ((__VALUE__) == LL_USART_HWCONTROL_RTS) \
|| ((__VALUE__) == LL_USART_HWCONTROL_CTS) \
|| ((__VALUE__) == LL_USART_HWCONTROL_RTS_CTS))
/**
* @}
*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup USART_LL_Exported_Functions
* @{
*/
/** @addtogroup USART_LL_EF_Init
* @{
*/
/**
* @brief De-initialize USART registers (Registers restored to their default values).
* @param USARTx USART Instance
* @retval An ErrorStatus enumeration value:
* - SUCCESS: USART registers are de-initialized
* - ERROR: USART registers are not de-initialized
*/
ErrorStatus LL_USART_DeInit(const USART_TypeDef *USARTx)
{
ErrorStatus status = SUCCESS;
/* Check the parameters */
assert_param(IS_UART_INSTANCE(USARTx));
if (USARTx == USART1)
{
/* Force reset of USART clock */
LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_USART1);
/* Release reset of USART clock */
LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_USART1);
}
else if (USARTx == USART2)
{
/* Force reset of USART clock */
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_USART2);
/* Release reset of USART clock */
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_USART2);
}
#if defined(USART3)
else if (USARTx == USART3)
{
/* Force reset of USART clock */
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_USART3);
/* Release reset of USART clock */
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_USART3);
}
#endif /* USART3 */
#if defined(UART4)
else if (USARTx == UART4)
{
/* Force reset of UART clock */
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_UART4);
/* Release reset of UART clock */
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_UART4);
}
#endif /* UART4 */
#if defined(UART5)
else if (USARTx == UART5)
{
/* Force reset of UART clock */
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_UART5);
/* Release reset of UART clock */
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_UART5);
}
#endif /* UART5 */
else
{
status = ERROR;
}
return (status);
}
/**
* @brief Initialize USART registers according to the specified
* parameters in USART_InitStruct.
* @note As some bits in USART configuration registers can only be written when the USART is disabled (USART_CR1_UE bit =0),
* USART IP should be in disabled state prior calling this function. Otherwise, ERROR result will be returned.
* @note Baud rate value stored in USART_InitStruct BaudRate field, should be valid (different from 0).
* @param USARTx USART Instance
* @param USART_InitStruct pointer to a LL_USART_InitTypeDef structure
* that contains the configuration information for the specified USART peripheral.
* @retval An ErrorStatus enumeration value:
* - SUCCESS: USART registers are initialized according to USART_InitStruct content
* - ERROR: Problem occurred during USART Registers initialization
*/
ErrorStatus LL_USART_Init(USART_TypeDef *USARTx, const LL_USART_InitTypeDef *USART_InitStruct)
{
ErrorStatus status = ERROR;
uint32_t periphclk = LL_RCC_PERIPH_FREQUENCY_NO;
LL_RCC_ClocksTypeDef rcc_clocks;
/* Check the parameters */
assert_param(IS_UART_INSTANCE(USARTx));
assert_param(IS_LL_USART_BAUDRATE(USART_InitStruct->BaudRate));
assert_param(IS_LL_USART_DATAWIDTH(USART_InitStruct->DataWidth));
assert_param(IS_LL_USART_STOPBITS(USART_InitStruct->StopBits));
assert_param(IS_LL_USART_PARITY(USART_InitStruct->Parity));
assert_param(IS_LL_USART_DIRECTION(USART_InitStruct->TransferDirection));
assert_param(IS_LL_USART_HWCONTROL(USART_InitStruct->HardwareFlowControl));
#if defined(USART_CR1_OVER8)
assert_param(IS_LL_USART_OVERSAMPLING(USART_InitStruct->OverSampling));
#endif /* USART_OverSampling_Feature */
/* USART needs to be in disabled state, in order to be able to configure some bits in
CRx registers */
if (LL_USART_IsEnabled(USARTx) == 0U)
{
/*---------------------------- USART CR1 Configuration -----------------------
* Configure USARTx CR1 (USART Word Length, Parity, Mode and Oversampling bits) with parameters:
* - DataWidth: USART_CR1_M bits according to USART_InitStruct->DataWidth value
* - Parity: USART_CR1_PCE, USART_CR1_PS bits according to USART_InitStruct->Parity value
* - TransferDirection: USART_CR1_TE, USART_CR1_RE bits according to USART_InitStruct->TransferDirection value
* - Oversampling: USART_CR1_OVER8 bit according to USART_InitStruct->OverSampling value.
*/
#if defined(USART_CR1_OVER8)
MODIFY_REG(USARTx->CR1,
(USART_CR1_M | USART_CR1_PCE | USART_CR1_PS |
USART_CR1_TE | USART_CR1_RE | USART_CR1_OVER8),
(USART_InitStruct->DataWidth | USART_InitStruct->Parity |
USART_InitStruct->TransferDirection | USART_InitStruct->OverSampling));
#else
MODIFY_REG(USARTx->CR1,
(USART_CR1_M | USART_CR1_PCE | USART_CR1_PS |
USART_CR1_TE | USART_CR1_RE),
(USART_InitStruct->DataWidth | USART_InitStruct->Parity |
USART_InitStruct->TransferDirection));
#endif /* USART_OverSampling_Feature */
/*---------------------------- USART CR2 Configuration -----------------------
* Configure USARTx CR2 (Stop bits) with parameters:
* - Stop Bits: USART_CR2_STOP bits according to USART_InitStruct->StopBits value.
* - CLKEN, CPOL, CPHA and LBCL bits are to be configured using LL_USART_ClockInit().
*/
LL_USART_SetStopBitsLength(USARTx, USART_InitStruct->StopBits);
/*---------------------------- USART CR3 Configuration -----------------------
* Configure USARTx CR3 (Hardware Flow Control) with parameters:
* - HardwareFlowControl: USART_CR3_RTSE, USART_CR3_CTSE bits according to USART_InitStruct->HardwareFlowControl value.
*/
LL_USART_SetHWFlowCtrl(USARTx, USART_InitStruct->HardwareFlowControl);
/*---------------------------- USART BRR Configuration -----------------------
* Retrieve Clock frequency used for USART Peripheral
*/
LL_RCC_GetSystemClocksFreq(&rcc_clocks);
if (USARTx == USART1)
{
periphclk = rcc_clocks.PCLK2_Frequency;
}
else if (USARTx == USART2)
{
periphclk = rcc_clocks.PCLK1_Frequency;
}
#if defined(USART3)
else if (USARTx == USART3)
{
periphclk = rcc_clocks.PCLK1_Frequency;
}
#endif /* USART3 */
#if defined(UART4)
else if (USARTx == UART4)
{
periphclk = rcc_clocks.PCLK1_Frequency;
}
#endif /* UART4 */
#if defined(UART5)
else if (USARTx == UART5)
{
periphclk = rcc_clocks.PCLK1_Frequency;
}
#endif /* UART5 */
else
{
/* Nothing to do, as error code is already assigned to ERROR value */
}
/* Configure the USART Baud Rate :
- valid baud rate value (different from 0) is required
- Peripheral clock as returned by RCC service, should be valid (different from 0).
*/
if ((periphclk != LL_RCC_PERIPH_FREQUENCY_NO)
&& (USART_InitStruct->BaudRate != 0U))
{
status = SUCCESS;
#if defined(USART_CR1_OVER8)
LL_USART_SetBaudRate(USARTx,
periphclk,
USART_InitStruct->OverSampling,
USART_InitStruct->BaudRate);
#else
LL_USART_SetBaudRate(USARTx,
periphclk,
USART_InitStruct->BaudRate);
#endif /* USART_OverSampling_Feature */
/* Check BRR is greater than or equal to 16d */
assert_param(IS_LL_USART_BRR_MIN(USARTx->BRR));
}
}
/* Endif (=> USART not in Disabled state => return ERROR) */
return (status);
}
/**
* @brief Set each @ref LL_USART_InitTypeDef field to default value.
* @param USART_InitStruct Pointer to a @ref LL_USART_InitTypeDef structure
* whose fields will be set to default values.
* @retval None
*/
void LL_USART_StructInit(LL_USART_InitTypeDef *USART_InitStruct)
{
/* Set USART_InitStruct fields to default values */
USART_InitStruct->BaudRate = 9600U;
USART_InitStruct->DataWidth = LL_USART_DATAWIDTH_8B;
USART_InitStruct->StopBits = LL_USART_STOPBITS_1;
USART_InitStruct->Parity = LL_USART_PARITY_NONE ;
USART_InitStruct->TransferDirection = LL_USART_DIRECTION_TX_RX;
USART_InitStruct->HardwareFlowControl = LL_USART_HWCONTROL_NONE;
#if defined(USART_CR1_OVER8)
USART_InitStruct->OverSampling = LL_USART_OVERSAMPLING_16;
#endif /* USART_OverSampling_Feature */
}
/**
* @brief Initialize USART Clock related settings according to the
* specified parameters in the USART_ClockInitStruct.
* @note As some bits in USART configuration registers can only be written when the USART is disabled (USART_CR1_UE bit =0),
* USART IP should be in disabled state prior calling this function. Otherwise, ERROR result will be returned.
* @param USARTx USART Instance
* @param USART_ClockInitStruct Pointer to a @ref LL_USART_ClockInitTypeDef structure
* that contains the Clock configuration information for the specified USART peripheral.
* @retval An ErrorStatus enumeration value:
* - SUCCESS: USART registers related to Clock settings are initialized according to USART_ClockInitStruct content
* - ERROR: Problem occurred during USART Registers initialization
*/
ErrorStatus LL_USART_ClockInit(USART_TypeDef *USARTx, const LL_USART_ClockInitTypeDef *USART_ClockInitStruct)
{
ErrorStatus status = SUCCESS;
/* Check USART Instance and Clock signal output parameters */
assert_param(IS_UART_INSTANCE(USARTx));
assert_param(IS_LL_USART_CLOCKOUTPUT(USART_ClockInitStruct->ClockOutput));
/* USART needs to be in disabled state, in order to be able to configure some bits in
CRx registers */
if (LL_USART_IsEnabled(USARTx) == 0U)
{
/*---------------------------- USART CR2 Configuration -----------------------*/
/* If Clock signal has to be output */
if (USART_ClockInitStruct->ClockOutput == LL_USART_CLOCK_DISABLE)
{
/* Deactivate Clock signal delivery :
* - Disable Clock Output: USART_CR2_CLKEN cleared
*/
LL_USART_DisableSCLKOutput(USARTx);
}
else
{
/* Ensure USART instance is USART capable */
assert_param(IS_USART_INSTANCE(USARTx));
/* Check clock related parameters */
assert_param(IS_LL_USART_CLOCKPOLARITY(USART_ClockInitStruct->ClockPolarity));
assert_param(IS_LL_USART_CLOCKPHASE(USART_ClockInitStruct->ClockPhase));
assert_param(IS_LL_USART_LASTBITCLKOUTPUT(USART_ClockInitStruct->LastBitClockPulse));
/*---------------------------- USART CR2 Configuration -----------------------
* Configure USARTx CR2 (Clock signal related bits) with parameters:
* - Enable Clock Output: USART_CR2_CLKEN set
* - Clock Polarity: USART_CR2_CPOL bit according to USART_ClockInitStruct->ClockPolarity value
* - Clock Phase: USART_CR2_CPHA bit according to USART_ClockInitStruct->ClockPhase value
* - Last Bit Clock Pulse Output: USART_CR2_LBCL bit according to USART_ClockInitStruct->LastBitClockPulse value.
*/
MODIFY_REG(USARTx->CR2,
USART_CR2_CLKEN | USART_CR2_CPHA | USART_CR2_CPOL | USART_CR2_LBCL,
USART_CR2_CLKEN | USART_ClockInitStruct->ClockPolarity |
USART_ClockInitStruct->ClockPhase | USART_ClockInitStruct->LastBitClockPulse);
}
}
/* Else (USART not in Disabled state => return ERROR */
else
{
status = ERROR;
}
return (status);
}
/**
* @brief Set each field of a @ref LL_USART_ClockInitTypeDef type structure to default value.
* @param USART_ClockInitStruct Pointer to a @ref LL_USART_ClockInitTypeDef structure
* whose fields will be set to default values.
* @retval None
*/
void LL_USART_ClockStructInit(LL_USART_ClockInitTypeDef *USART_ClockInitStruct)
{
/* Set LL_USART_ClockInitStruct fields with default values */
USART_ClockInitStruct->ClockOutput = LL_USART_CLOCK_DISABLE;
USART_ClockInitStruct->ClockPolarity = LL_USART_POLARITY_LOW; /* Not relevant when ClockOutput = LL_USART_CLOCK_DISABLE */
USART_ClockInitStruct->ClockPhase = LL_USART_PHASE_1EDGE; /* Not relevant when ClockOutput = LL_USART_CLOCK_DISABLE */
USART_ClockInitStruct->LastBitClockPulse = LL_USART_LASTCLKPULSE_NO_OUTPUT; /* Not relevant when ClockOutput = LL_USART_CLOCK_DISABLE */
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#endif /* USART1 || USART2 || USART3 || UART4 || UART5 */
/**
* @}
*/
#endif /* USE_FULL_LL_DRIVER */

View File

@@ -0,0 +1,2897 @@
/**
******************************************************************************
* @file stm32f1xx_ll_usb.c
* @author MCD Application Team
* @brief USB Low Layer HAL module driver.
*
* This file provides firmware functions to manage the following
* functionalities of the USB Peripheral Controller:
* + Initialization/de-initialization functions
* + I/O operation functions
* + Peripheral Control functions
* + Peripheral State functions
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
==============================================================================
##### How to use this driver #####
==============================================================================
[..]
(#) Fill parameters of Init structure in USB_CfgTypeDef structure.
(#) Call USB_CoreInit() API to initialize the USB Core peripheral.
(#) The upper HAL HCD/PCD driver will call the right routines for its internal processes.
@endverbatim
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_LL_USB_DRIVER
* @{
*/
#if defined (HAL_PCD_MODULE_ENABLED) || defined (HAL_HCD_MODULE_ENABLED)
#if defined (USB) || defined (USB_OTG_FS)
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
#if defined (USB_OTG_FS)
static HAL_StatusTypeDef USB_CoreReset(USB_OTG_GlobalTypeDef *USBx);
/* Exported functions --------------------------------------------------------*/
/** @defgroup USB_LL_Exported_Functions USB Low Layer Exported Functions
* @{
*/
/** @defgroup USB_LL_Exported_Functions_Group1 Initialization/de-initialization functions
* @brief Initialization and Configuration functions
*
@verbatim
===============================================================================
##### Initialization/de-initialization functions #####
===============================================================================
@endverbatim
* @{
*/
/**
* @brief Initializes the USB Core
* @param USBx USB Instance
* @param cfg pointer to a USB_OTG_CfgTypeDef structure that contains
* the configuration information for the specified USBx peripheral.
* @retval HAL status
*/
HAL_StatusTypeDef USB_CoreInit(USB_OTG_GlobalTypeDef *USBx, USB_OTG_CfgTypeDef cfg)
{
HAL_StatusTypeDef ret;
/* Select FS Embedded PHY */
USBx->GUSBCFG |= USB_OTG_GUSBCFG_PHYSEL;
/* Reset after a PHY select */
ret = USB_CoreReset(USBx);
/* Activate the USB Transceiver */
USBx->GCCFG |= USB_OTG_GCCFG_PWRDWN;
return ret;
}
/**
* @brief Set the USB turnaround time
* @param USBx USB Instance
* @param hclk: AHB clock frequency
* @retval USB turnaround time In PHY Clocks number
*/
HAL_StatusTypeDef USB_SetTurnaroundTime(USB_OTG_GlobalTypeDef *USBx,
uint32_t hclk, uint8_t speed)
{
uint32_t UsbTrd;
/* The USBTRD is configured according to the tables below, depending on AHB frequency
used by application. In the low AHB frequency range it is used to stretch enough the USB response
time to IN tokens, the USB turnaround time, so to compensate for the longer AHB read access
latency to the Data FIFO */
if (speed == USBD_FS_SPEED)
{
if ((hclk >= 14200000U) && (hclk < 15000000U))
{
/* hclk Clock Range between 14.2-15 MHz */
UsbTrd = 0xFU;
}
else if ((hclk >= 15000000U) && (hclk < 16000000U))
{
/* hclk Clock Range between 15-16 MHz */
UsbTrd = 0xEU;
}
else if ((hclk >= 16000000U) && (hclk < 17200000U))
{
/* hclk Clock Range between 16-17.2 MHz */
UsbTrd = 0xDU;
}
else if ((hclk >= 17200000U) && (hclk < 18500000U))
{
/* hclk Clock Range between 17.2-18.5 MHz */
UsbTrd = 0xCU;
}
else if ((hclk >= 18500000U) && (hclk < 20000000U))
{
/* hclk Clock Range between 18.5-20 MHz */
UsbTrd = 0xBU;
}
else if ((hclk >= 20000000U) && (hclk < 21800000U))
{
/* hclk Clock Range between 20-21.8 MHz */
UsbTrd = 0xAU;
}
else if ((hclk >= 21800000U) && (hclk < 24000000U))
{
/* hclk Clock Range between 21.8-24 MHz */
UsbTrd = 0x9U;
}
else if ((hclk >= 24000000U) && (hclk < 27700000U))
{
/* hclk Clock Range between 24-27.7 MHz */
UsbTrd = 0x8U;
}
else if ((hclk >= 27700000U) && (hclk < 32000000U))
{
/* hclk Clock Range between 27.7-32 MHz */
UsbTrd = 0x7U;
}
else /* if(hclk >= 32000000) */
{
/* hclk Clock Range between 32-200 MHz */
UsbTrd = 0x6U;
}
}
else
{
UsbTrd = USBD_DEFAULT_TRDT_VALUE;
}
USBx->GUSBCFG &= ~USB_OTG_GUSBCFG_TRDT;
USBx->GUSBCFG |= (uint32_t)((UsbTrd << 10) & USB_OTG_GUSBCFG_TRDT);
return HAL_OK;
}
/**
* @brief USB_EnableGlobalInt
* Enables the controller's Global Int in the AHB Config reg
* @param USBx Selected device
* @retval HAL status
*/
HAL_StatusTypeDef USB_EnableGlobalInt(USB_OTG_GlobalTypeDef *USBx)
{
USBx->GAHBCFG |= USB_OTG_GAHBCFG_GINT;
return HAL_OK;
}
/**
* @brief USB_DisableGlobalInt
* Disable the controller's Global Int in the AHB Config reg
* @param USBx Selected device
* @retval HAL status
*/
HAL_StatusTypeDef USB_DisableGlobalInt(USB_OTG_GlobalTypeDef *USBx)
{
USBx->GAHBCFG &= ~USB_OTG_GAHBCFG_GINT;
return HAL_OK;
}
/**
* @brief USB_SetCurrentMode Set functional mode
* @param USBx Selected device
* @param mode current core mode
* This parameter can be one of these values:
* @arg USB_DEVICE_MODE Peripheral mode
* @arg USB_HOST_MODE Host mode
* @retval HAL status
*/
HAL_StatusTypeDef USB_SetCurrentMode(USB_OTG_GlobalTypeDef *USBx, USB_ModeTypeDef mode)
{
uint32_t ms = 0U;
USBx->GUSBCFG &= ~(USB_OTG_GUSBCFG_FHMOD | USB_OTG_GUSBCFG_FDMOD);
if (mode == USB_HOST_MODE)
{
USBx->GUSBCFG |= USB_OTG_GUSBCFG_FHMOD;
do
{
HAL_Delay(10U);
ms += 10U;
} while ((USB_GetMode(USBx) != (uint32_t)USB_HOST_MODE) && (ms < HAL_USB_CURRENT_MODE_MAX_DELAY_MS));
}
else if (mode == USB_DEVICE_MODE)
{
USBx->GUSBCFG |= USB_OTG_GUSBCFG_FDMOD;
do
{
HAL_Delay(10U);
ms += 10U;
} while ((USB_GetMode(USBx) != (uint32_t)USB_DEVICE_MODE) && (ms < HAL_USB_CURRENT_MODE_MAX_DELAY_MS));
}
else
{
return HAL_ERROR;
}
if (ms == HAL_USB_CURRENT_MODE_MAX_DELAY_MS)
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief USB_DevInit Initializes the USB_OTG controller registers
* for device mode
* @param USBx Selected device
* @param cfg pointer to a USB_OTG_CfgTypeDef structure that contains
* the configuration information for the specified USBx peripheral.
* @retval HAL status
*/
HAL_StatusTypeDef USB_DevInit(USB_OTG_GlobalTypeDef *USBx, USB_OTG_CfgTypeDef cfg)
{
HAL_StatusTypeDef ret = HAL_OK;
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t i;
for (i = 0U; i < 15U; i++)
{
USBx->DIEPTXF[i] = 0U;
}
/* Enable HW VBUS sensing */
USBx->GCCFG |= USB_OTG_GCCFG_VBUSBSEN;
/* Restart the Phy Clock */
USBx_PCGCCTL = 0U;
/* Set Core speed to Full speed mode */
(void)USB_SetDevSpeed(USBx, USB_OTG_SPEED_FULL);
/* Flush the FIFOs */
if (USB_FlushTxFifo(USBx, 0x10U) != HAL_OK) /* all Tx FIFOs */
{
ret = HAL_ERROR;
}
if (USB_FlushRxFifo(USBx) != HAL_OK)
{
ret = HAL_ERROR;
}
/* Clear all pending Device Interrupts */
USBx_DEVICE->DIEPMSK = 0U;
USBx_DEVICE->DOEPMSK = 0U;
USBx_DEVICE->DAINTMSK = 0U;
for (i = 0U; i < cfg.dev_endpoints; i++)
{
if ((USBx_INEP(i)->DIEPCTL & USB_OTG_DIEPCTL_EPENA) == USB_OTG_DIEPCTL_EPENA)
{
if (i == 0U)
{
USBx_INEP(i)->DIEPCTL = USB_OTG_DIEPCTL_SNAK;
}
else
{
USBx_INEP(i)->DIEPCTL = USB_OTG_DIEPCTL_EPDIS | USB_OTG_DIEPCTL_SNAK;
}
}
else
{
USBx_INEP(i)->DIEPCTL = 0U;
}
USBx_INEP(i)->DIEPTSIZ = 0U;
USBx_INEP(i)->DIEPINT = 0xFB7FU;
}
for (i = 0U; i < cfg.dev_endpoints; i++)
{
if ((USBx_OUTEP(i)->DOEPCTL & USB_OTG_DOEPCTL_EPENA) == USB_OTG_DOEPCTL_EPENA)
{
if (i == 0U)
{
USBx_OUTEP(i)->DOEPCTL = USB_OTG_DOEPCTL_SNAK;
}
else
{
USBx_OUTEP(i)->DOEPCTL = USB_OTG_DOEPCTL_EPDIS | USB_OTG_DOEPCTL_SNAK;
}
}
else
{
USBx_OUTEP(i)->DOEPCTL = 0U;
}
USBx_OUTEP(i)->DOEPTSIZ = 0U;
USBx_OUTEP(i)->DOEPINT = 0xFB7FU;
}
USBx_DEVICE->DIEPMSK &= ~(USB_OTG_DIEPMSK_TXFURM);
/* Disable all interrupts. */
USBx->GINTMSK = 0U;
/* Clear any pending interrupts */
USBx->GINTSTS = 0xBFFFFFFFU;
/* Enable the common interrupts */
USBx->GINTMSK |= USB_OTG_GINTMSK_RXFLVLM;
/* Enable interrupts matching to the Device mode ONLY */
USBx->GINTMSK |= USB_OTG_GINTMSK_USBSUSPM | USB_OTG_GINTMSK_USBRST |
USB_OTG_GINTMSK_ENUMDNEM | USB_OTG_GINTMSK_IEPINT |
USB_OTG_GINTMSK_OEPINT | USB_OTG_GINTMSK_IISOIXFRM |
USB_OTG_GINTMSK_PXFRM_IISOOXFRM | USB_OTG_GINTMSK_WUIM;
if (cfg.Sof_enable != 0U)
{
USBx->GINTMSK |= USB_OTG_GINTMSK_SOFM;
}
if (cfg.vbus_sensing_enable == 1U)
{
USBx->GINTMSK |= (USB_OTG_GINTMSK_SRQIM | USB_OTG_GINTMSK_OTGINT);
}
return ret;
}
/**
* @brief USB_FlushTxFifo Flush a Tx FIFO
* @param USBx Selected device
* @param num FIFO number
* This parameter can be a value from 1 to 15
15 means Flush all Tx FIFOs
* @retval HAL status
*/
HAL_StatusTypeDef USB_FlushTxFifo(USB_OTG_GlobalTypeDef *USBx, uint32_t num)
{
__IO uint32_t count = 0U;
/* Wait for AHB master IDLE state. */
do
{
count++;
if (count > HAL_USB_TIMEOUT)
{
return HAL_TIMEOUT;
}
} while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_AHBIDL) == 0U);
/* Flush TX Fifo */
count = 0U;
USBx->GRSTCTL = (USB_OTG_GRSTCTL_TXFFLSH | (num << 6));
do
{
count++;
if (count > HAL_USB_TIMEOUT)
{
return HAL_TIMEOUT;
}
} while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_TXFFLSH) == USB_OTG_GRSTCTL_TXFFLSH);
return HAL_OK;
}
/**
* @brief USB_FlushRxFifo Flush Rx FIFO
* @param USBx Selected device
* @retval HAL status
*/
HAL_StatusTypeDef USB_FlushRxFifo(USB_OTG_GlobalTypeDef *USBx)
{
__IO uint32_t count = 0U;
/* Wait for AHB master IDLE state. */
do
{
count++;
if (count > HAL_USB_TIMEOUT)
{
return HAL_TIMEOUT;
}
} while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_AHBIDL) == 0U);
/* Flush RX Fifo */
count = 0U;
USBx->GRSTCTL = USB_OTG_GRSTCTL_RXFFLSH;
do
{
count++;
if (count > HAL_USB_TIMEOUT)
{
return HAL_TIMEOUT;
}
} while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_RXFFLSH) == USB_OTG_GRSTCTL_RXFFLSH);
return HAL_OK;
}
/**
* @brief USB_SetDevSpeed Initializes the DevSpd field of DCFG register
* depending the PHY type and the enumeration speed of the device.
* @param USBx Selected device
* @param speed device speed
* This parameter can be one of these values:
* @arg USB_OTG_SPEED_FULL: Full speed mode
* @retval Hal status
*/
HAL_StatusTypeDef USB_SetDevSpeed(const USB_OTG_GlobalTypeDef *USBx, uint8_t speed)
{
uint32_t USBx_BASE = (uint32_t)USBx;
USBx_DEVICE->DCFG |= speed;
return HAL_OK;
}
/**
* @brief USB_GetDevSpeed Return the Dev Speed
* @param USBx Selected device
* @retval speed device speed
* This parameter can be one of these values:
* @arg USBD_FS_SPEED: Full speed mode
*/
uint8_t USB_GetDevSpeed(const USB_OTG_GlobalTypeDef *USBx)
{
uint32_t USBx_BASE = (uint32_t)USBx;
uint8_t speed;
uint32_t DevEnumSpeed = USBx_DEVICE->DSTS & USB_OTG_DSTS_ENUMSPD;
if ((DevEnumSpeed == DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ) ||
(DevEnumSpeed == DSTS_ENUMSPD_FS_PHY_48MHZ))
{
speed = USBD_FS_SPEED;
}
else
{
speed = 0xFU;
}
return speed;
}
/**
* @brief Activate and configure an endpoint
* @param USBx Selected device
* @param ep pointer to endpoint structure
* @retval HAL status
*/
HAL_StatusTypeDef USB_ActivateEndpoint(const USB_OTG_GlobalTypeDef *USBx, const USB_OTG_EPTypeDef *ep)
{
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t epnum = (uint32_t)ep->num;
if (ep->is_in == 1U)
{
USBx_DEVICE->DAINTMSK |= USB_OTG_DAINTMSK_IEPM & (uint32_t)(1UL << (ep->num & EP_ADDR_MSK));
if ((USBx_INEP(epnum)->DIEPCTL & USB_OTG_DIEPCTL_USBAEP) == 0U)
{
USBx_INEP(epnum)->DIEPCTL |= (ep->maxpacket & USB_OTG_DIEPCTL_MPSIZ) |
((uint32_t)ep->type << 18) | (epnum << 22) |
USB_OTG_DIEPCTL_SD0PID_SEVNFRM |
USB_OTG_DIEPCTL_USBAEP;
}
}
else
{
USBx_DEVICE->DAINTMSK |= USB_OTG_DAINTMSK_OEPM & ((uint32_t)(1UL << (ep->num & EP_ADDR_MSK)) << 16);
if (((USBx_OUTEP(epnum)->DOEPCTL) & USB_OTG_DOEPCTL_USBAEP) == 0U)
{
USBx_OUTEP(epnum)->DOEPCTL |= (ep->maxpacket & USB_OTG_DOEPCTL_MPSIZ) |
((uint32_t)ep->type << 18) |
USB_OTG_DIEPCTL_SD0PID_SEVNFRM |
USB_OTG_DOEPCTL_USBAEP;
}
}
return HAL_OK;
}
/**
* @brief Activate and configure a dedicated endpoint
* @param USBx Selected device
* @param ep pointer to endpoint structure
* @retval HAL status
*/
HAL_StatusTypeDef USB_ActivateDedicatedEndpoint(const USB_OTG_GlobalTypeDef *USBx, const USB_OTG_EPTypeDef *ep)
{
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t epnum = (uint32_t)ep->num;
/* Read DEPCTLn register */
if (ep->is_in == 1U)
{
if (((USBx_INEP(epnum)->DIEPCTL) & USB_OTG_DIEPCTL_USBAEP) == 0U)
{
USBx_INEP(epnum)->DIEPCTL |= (ep->maxpacket & USB_OTG_DIEPCTL_MPSIZ) |
((uint32_t)ep->type << 18) | (epnum << 22) |
USB_OTG_DIEPCTL_SD0PID_SEVNFRM |
USB_OTG_DIEPCTL_USBAEP;
}
USBx_DEVICE->DEACHMSK |= USB_OTG_DAINTMSK_IEPM & (uint32_t)(1UL << (ep->num & EP_ADDR_MSK));
}
else
{
if (((USBx_OUTEP(epnum)->DOEPCTL) & USB_OTG_DOEPCTL_USBAEP) == 0U)
{
USBx_OUTEP(epnum)->DOEPCTL |= (ep->maxpacket & USB_OTG_DOEPCTL_MPSIZ) |
((uint32_t)ep->type << 18) | (epnum << 22) |
USB_OTG_DOEPCTL_USBAEP;
}
USBx_DEVICE->DEACHMSK |= USB_OTG_DAINTMSK_OEPM & ((uint32_t)(1UL << (ep->num & EP_ADDR_MSK)) << 16);
}
return HAL_OK;
}
/**
* @brief De-activate and de-initialize an endpoint
* @param USBx Selected device
* @param ep pointer to endpoint structure
* @retval HAL status
*/
HAL_StatusTypeDef USB_DeactivateEndpoint(const USB_OTG_GlobalTypeDef *USBx, const USB_OTG_EPTypeDef *ep)
{
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t epnum = (uint32_t)ep->num;
/* Read DEPCTLn register */
if (ep->is_in == 1U)
{
if ((USBx_INEP(epnum)->DIEPCTL & USB_OTG_DIEPCTL_EPENA) == USB_OTG_DIEPCTL_EPENA)
{
USBx_INEP(epnum)->DIEPCTL |= USB_OTG_DIEPCTL_SNAK;
USBx_INEP(epnum)->DIEPCTL |= USB_OTG_DIEPCTL_EPDIS;
}
USBx_DEVICE->DEACHMSK &= ~(USB_OTG_DAINTMSK_IEPM & (uint32_t)(1UL << (ep->num & EP_ADDR_MSK)));
USBx_DEVICE->DAINTMSK &= ~(USB_OTG_DAINTMSK_IEPM & (uint32_t)(1UL << (ep->num & EP_ADDR_MSK)));
USBx_INEP(epnum)->DIEPCTL &= ~(USB_OTG_DIEPCTL_USBAEP |
USB_OTG_DIEPCTL_MPSIZ |
USB_OTG_DIEPCTL_TXFNUM |
USB_OTG_DIEPCTL_SD0PID_SEVNFRM |
USB_OTG_DIEPCTL_EPTYP);
}
else
{
if ((USBx_OUTEP(epnum)->DOEPCTL & USB_OTG_DOEPCTL_EPENA) == USB_OTG_DOEPCTL_EPENA)
{
USBx_OUTEP(epnum)->DOEPCTL |= USB_OTG_DOEPCTL_SNAK;
USBx_OUTEP(epnum)->DOEPCTL |= USB_OTG_DOEPCTL_EPDIS;
}
USBx_DEVICE->DEACHMSK &= ~(USB_OTG_DAINTMSK_OEPM & ((uint32_t)(1UL << (ep->num & EP_ADDR_MSK)) << 16));
USBx_DEVICE->DAINTMSK &= ~(USB_OTG_DAINTMSK_OEPM & ((uint32_t)(1UL << (ep->num & EP_ADDR_MSK)) << 16));
USBx_OUTEP(epnum)->DOEPCTL &= ~(USB_OTG_DOEPCTL_USBAEP |
USB_OTG_DOEPCTL_MPSIZ |
USB_OTG_DOEPCTL_SD0PID_SEVNFRM |
USB_OTG_DOEPCTL_EPTYP);
}
return HAL_OK;
}
/**
* @brief De-activate and de-initialize a dedicated endpoint
* @param USBx Selected device
* @param ep pointer to endpoint structure
* @retval HAL status
*/
HAL_StatusTypeDef USB_DeactivateDedicatedEndpoint(const USB_OTG_GlobalTypeDef *USBx, const USB_OTG_EPTypeDef *ep)
{
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t epnum = (uint32_t)ep->num;
/* Read DEPCTLn register */
if (ep->is_in == 1U)
{
if ((USBx_INEP(epnum)->DIEPCTL & USB_OTG_DIEPCTL_EPENA) == USB_OTG_DIEPCTL_EPENA)
{
USBx_INEP(epnum)->DIEPCTL |= USB_OTG_DIEPCTL_SNAK;
USBx_INEP(epnum)->DIEPCTL |= USB_OTG_DIEPCTL_EPDIS;
}
USBx_INEP(epnum)->DIEPCTL &= ~ USB_OTG_DIEPCTL_USBAEP;
USBx_DEVICE->DAINTMSK &= ~(USB_OTG_DAINTMSK_IEPM & (uint32_t)(1UL << (ep->num & EP_ADDR_MSK)));
}
else
{
if ((USBx_OUTEP(epnum)->DOEPCTL & USB_OTG_DOEPCTL_EPENA) == USB_OTG_DOEPCTL_EPENA)
{
USBx_OUTEP(epnum)->DOEPCTL |= USB_OTG_DOEPCTL_SNAK;
USBx_OUTEP(epnum)->DOEPCTL |= USB_OTG_DOEPCTL_EPDIS;
}
USBx_OUTEP(epnum)->DOEPCTL &= ~USB_OTG_DOEPCTL_USBAEP;
USBx_DEVICE->DAINTMSK &= ~(USB_OTG_DAINTMSK_OEPM & ((uint32_t)(1UL << (ep->num & EP_ADDR_MSK)) << 16));
}
return HAL_OK;
}
/**
* @brief USB_EPStartXfer : setup and starts a transfer over an EP
* @param USBx Selected device
* @param ep pointer to endpoint structure
* @retval HAL status
*/
HAL_StatusTypeDef USB_EPStartXfer(USB_OTG_GlobalTypeDef *USBx, USB_OTG_EPTypeDef *ep)
{
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t epnum = (uint32_t)ep->num;
uint16_t pktcnt;
/* IN endpoint */
if (ep->is_in == 1U)
{
/* Zero Length Packet? */
if (ep->xfer_len == 0U)
{
USBx_INEP(epnum)->DIEPTSIZ &= ~(USB_OTG_DIEPTSIZ_PKTCNT);
USBx_INEP(epnum)->DIEPTSIZ |= (USB_OTG_DIEPTSIZ_PKTCNT & (1U << 19));
USBx_INEP(epnum)->DIEPTSIZ &= ~(USB_OTG_DIEPTSIZ_XFRSIZ);
}
else
{
/* Program the transfer size and packet count
* as follows: xfersize = N * maxpacket +
* short_packet pktcnt = N + (short_packet
* exist ? 1 : 0)
*/
USBx_INEP(epnum)->DIEPTSIZ &= ~(USB_OTG_DIEPTSIZ_XFRSIZ);
USBx_INEP(epnum)->DIEPTSIZ &= ~(USB_OTG_DIEPTSIZ_PKTCNT);
if (epnum == 0U)
{
if (ep->xfer_len > ep->maxpacket)
{
ep->xfer_len = ep->maxpacket;
}
USBx_INEP(epnum)->DIEPTSIZ |= (USB_OTG_DIEPTSIZ_PKTCNT & (1U << 19));
}
else
{
USBx_INEP(epnum)->DIEPTSIZ |= (USB_OTG_DIEPTSIZ_PKTCNT &
(((ep->xfer_len + ep->maxpacket - 1U) / ep->maxpacket) << 19));
}
USBx_INEP(epnum)->DIEPTSIZ |= (USB_OTG_DIEPTSIZ_XFRSIZ & ep->xfer_len);
if (ep->type == EP_TYPE_ISOC)
{
USBx_INEP(epnum)->DIEPTSIZ &= ~(USB_OTG_DIEPTSIZ_MULCNT);
USBx_INEP(epnum)->DIEPTSIZ |= (USB_OTG_DIEPTSIZ_MULCNT & (1U << 29));
}
}
/* EP enable, IN data in FIFO */
USBx_INEP(epnum)->DIEPCTL |= (USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA);
if (ep->type != EP_TYPE_ISOC)
{
/* Enable the Tx FIFO Empty Interrupt for this EP */
if (ep->xfer_len > 0U)
{
USBx_DEVICE->DIEPEMPMSK |= 1UL << (ep->num & EP_ADDR_MSK);
}
}
else
{
if ((USBx_DEVICE->DSTS & (1U << 8)) == 0U)
{
USBx_INEP(epnum)->DIEPCTL |= USB_OTG_DIEPCTL_SODDFRM;
}
else
{
USBx_INEP(epnum)->DIEPCTL |= USB_OTG_DIEPCTL_SD0PID_SEVNFRM;
}
(void)USB_WritePacket(USBx, ep->xfer_buff, ep->num, (uint16_t)ep->xfer_len);
}
}
else /* OUT endpoint */
{
/* Program the transfer size and packet count as follows:
* pktcnt = N
* xfersize = N * maxpacket
*/
USBx_OUTEP(epnum)->DOEPTSIZ &= ~(USB_OTG_DOEPTSIZ_XFRSIZ);
USBx_OUTEP(epnum)->DOEPTSIZ &= ~(USB_OTG_DOEPTSIZ_PKTCNT);
if (epnum == 0U)
{
if (ep->xfer_len > 0U)
{
ep->xfer_len = ep->maxpacket;
}
/* Store transfer size, for EP0 this is equal to endpoint max packet size */
ep->xfer_size = ep->maxpacket;
USBx_OUTEP(epnum)->DOEPTSIZ |= (USB_OTG_DOEPTSIZ_XFRSIZ & ep->xfer_size);
USBx_OUTEP(epnum)->DOEPTSIZ |= (USB_OTG_DOEPTSIZ_PKTCNT & (1U << 19));
}
else
{
if (ep->xfer_len == 0U)
{
USBx_OUTEP(epnum)->DOEPTSIZ |= (USB_OTG_DOEPTSIZ_XFRSIZ & ep->maxpacket);
USBx_OUTEP(epnum)->DOEPTSIZ |= (USB_OTG_DOEPTSIZ_PKTCNT & (1U << 19));
}
else
{
pktcnt = (uint16_t)((ep->xfer_len + ep->maxpacket - 1U) / ep->maxpacket);
ep->xfer_size = ep->maxpacket * pktcnt;
USBx_OUTEP(epnum)->DOEPTSIZ |= USB_OTG_DOEPTSIZ_PKTCNT & ((uint32_t)pktcnt << 19);
USBx_OUTEP(epnum)->DOEPTSIZ |= USB_OTG_DOEPTSIZ_XFRSIZ & ep->xfer_size;
}
}
if (ep->type == EP_TYPE_ISOC)
{
if ((USBx_DEVICE->DSTS & (1U << 8)) == 0U)
{
USBx_OUTEP(epnum)->DOEPCTL |= USB_OTG_DOEPCTL_SODDFRM;
}
else
{
USBx_OUTEP(epnum)->DOEPCTL |= USB_OTG_DOEPCTL_SD0PID_SEVNFRM;
}
}
/* EP enable */
USBx_OUTEP(epnum)->DOEPCTL |= (USB_OTG_DOEPCTL_CNAK | USB_OTG_DOEPCTL_EPENA);
}
return HAL_OK;
}
/**
* @brief USB_EPStoptXfer Stop transfer on an EP
* @param USBx usb device instance
* @param ep pointer to endpoint structure
* @retval HAL status
*/
HAL_StatusTypeDef USB_EPStopXfer(const USB_OTG_GlobalTypeDef *USBx, USB_OTG_EPTypeDef *ep)
{
__IO uint32_t count = 0U;
HAL_StatusTypeDef ret = HAL_OK;
uint32_t USBx_BASE = (uint32_t)USBx;
/* IN endpoint */
if (ep->is_in == 1U)
{
/* EP enable, IN data in FIFO */
if (((USBx_INEP(ep->num)->DIEPCTL) & USB_OTG_DIEPCTL_EPENA) == USB_OTG_DIEPCTL_EPENA)
{
USBx_INEP(ep->num)->DIEPCTL |= (USB_OTG_DIEPCTL_SNAK);
USBx_INEP(ep->num)->DIEPCTL |= (USB_OTG_DIEPCTL_EPDIS);
do
{
count++;
if (count > 10000U)
{
ret = HAL_ERROR;
break;
}
} while (((USBx_INEP(ep->num)->DIEPCTL) & USB_OTG_DIEPCTL_EPENA) == USB_OTG_DIEPCTL_EPENA);
}
}
else /* OUT endpoint */
{
if (((USBx_OUTEP(ep->num)->DOEPCTL) & USB_OTG_DOEPCTL_EPENA) == USB_OTG_DOEPCTL_EPENA)
{
USBx_OUTEP(ep->num)->DOEPCTL |= (USB_OTG_DOEPCTL_SNAK);
USBx_OUTEP(ep->num)->DOEPCTL |= (USB_OTG_DOEPCTL_EPDIS);
do
{
count++;
if (count > 10000U)
{
ret = HAL_ERROR;
break;
}
} while (((USBx_OUTEP(ep->num)->DOEPCTL) & USB_OTG_DOEPCTL_EPENA) == USB_OTG_DOEPCTL_EPENA);
}
}
return ret;
}
/**
* @brief USB_WritePacket : Writes a packet into the Tx FIFO associated
* with the EP/channel
* @param USBx Selected device
* @param src pointer to source buffer
* @param ch_ep_num endpoint or host channel number
* @param len Number of bytes to write
* @retval HAL status
*/
HAL_StatusTypeDef USB_WritePacket(const USB_OTG_GlobalTypeDef *USBx, uint8_t *src,
uint8_t ch_ep_num, uint16_t len)
{
uint32_t USBx_BASE = (uint32_t)USBx;
uint8_t *pSrc = src;
uint32_t count32b;
uint32_t i;
count32b = ((uint32_t)len + 3U) / 4U;
for (i = 0U; i < count32b; i++)
{
USBx_DFIFO((uint32_t)ch_ep_num) = __UNALIGNED_UINT32_READ(pSrc);
pSrc++;
pSrc++;
pSrc++;
pSrc++;
}
return HAL_OK;
}
/**
* @brief USB_ReadPacket : read a packet from the RX FIFO
* @param USBx Selected device
* @param dest source pointer
* @param len Number of bytes to read
* @retval pointer to destination buffer
*/
void *USB_ReadPacket(const USB_OTG_GlobalTypeDef *USBx, uint8_t *dest, uint16_t len)
{
uint32_t USBx_BASE = (uint32_t)USBx;
uint8_t *pDest = dest;
uint32_t pData;
uint32_t i;
uint32_t count32b = (uint32_t)len >> 2U;
uint16_t remaining_bytes = len % 4U;
for (i = 0U; i < count32b; i++)
{
__UNALIGNED_UINT32_WRITE(pDest, USBx_DFIFO(0U));
pDest++;
pDest++;
pDest++;
pDest++;
}
/* When Number of data is not word aligned, read the remaining byte */
if (remaining_bytes != 0U)
{
i = 0U;
__UNALIGNED_UINT32_WRITE(&pData, USBx_DFIFO(0U));
do
{
*(uint8_t *)pDest = (uint8_t)(pData >> (8U * (uint8_t)(i)));
i++;
pDest++;
remaining_bytes--;
} while (remaining_bytes != 0U);
}
return ((void *)pDest);
}
/**
* @brief USB_EPSetStall : set a stall condition over an EP
* @param USBx Selected device
* @param ep pointer to endpoint structure
* @retval HAL status
*/
HAL_StatusTypeDef USB_EPSetStall(const USB_OTG_GlobalTypeDef *USBx, const USB_OTG_EPTypeDef *ep)
{
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t epnum = (uint32_t)ep->num;
if (ep->is_in == 1U)
{
if (((USBx_INEP(epnum)->DIEPCTL & USB_OTG_DIEPCTL_EPENA) == 0U) && (epnum != 0U))
{
USBx_INEP(epnum)->DIEPCTL &= ~(USB_OTG_DIEPCTL_EPDIS);
}
USBx_INEP(epnum)->DIEPCTL |= USB_OTG_DIEPCTL_STALL;
}
else
{
if (((USBx_OUTEP(epnum)->DOEPCTL & USB_OTG_DOEPCTL_EPENA) == 0U) && (epnum != 0U))
{
USBx_OUTEP(epnum)->DOEPCTL &= ~(USB_OTG_DOEPCTL_EPDIS);
}
USBx_OUTEP(epnum)->DOEPCTL |= USB_OTG_DOEPCTL_STALL;
}
return HAL_OK;
}
/**
* @brief USB_EPClearStall : Clear a stall condition over an EP
* @param USBx Selected device
* @param ep pointer to endpoint structure
* @retval HAL status
*/
HAL_StatusTypeDef USB_EPClearStall(const USB_OTG_GlobalTypeDef *USBx, const USB_OTG_EPTypeDef *ep)
{
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t epnum = (uint32_t)ep->num;
if (ep->is_in == 1U)
{
USBx_INEP(epnum)->DIEPCTL &= ~USB_OTG_DIEPCTL_STALL;
if ((ep->type == EP_TYPE_INTR) || (ep->type == EP_TYPE_BULK))
{
USBx_INEP(epnum)->DIEPCTL |= USB_OTG_DIEPCTL_SD0PID_SEVNFRM; /* DATA0 */
}
}
else
{
USBx_OUTEP(epnum)->DOEPCTL &= ~USB_OTG_DOEPCTL_STALL;
if ((ep->type == EP_TYPE_INTR) || (ep->type == EP_TYPE_BULK))
{
USBx_OUTEP(epnum)->DOEPCTL |= USB_OTG_DOEPCTL_SD0PID_SEVNFRM; /* DATA0 */
}
}
return HAL_OK;
}
/**
* @brief USB_StopDevice : Stop the usb device mode
* @param USBx Selected device
* @retval HAL status
*/
HAL_StatusTypeDef USB_StopDevice(USB_OTG_GlobalTypeDef *USBx)
{
HAL_StatusTypeDef ret;
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t i;
/* Clear Pending interrupt */
for (i = 0U; i < 15U; i++)
{
USBx_INEP(i)->DIEPINT = 0xFB7FU;
USBx_OUTEP(i)->DOEPINT = 0xFB7FU;
}
/* Clear interrupt masks */
USBx_DEVICE->DIEPMSK = 0U;
USBx_DEVICE->DOEPMSK = 0U;
USBx_DEVICE->DAINTMSK = 0U;
/* Flush the FIFO */
ret = USB_FlushRxFifo(USBx);
if (ret != HAL_OK)
{
return ret;
}
ret = USB_FlushTxFifo(USBx, 0x10U);
if (ret != HAL_OK)
{
return ret;
}
return ret;
}
/**
* @brief USB_SetDevAddress : Stop the usb device mode
* @param USBx Selected device
* @param address new device address to be assigned
* This parameter can be a value from 0 to 255
* @retval HAL status
*/
HAL_StatusTypeDef USB_SetDevAddress(const USB_OTG_GlobalTypeDef *USBx, uint8_t address)
{
uint32_t USBx_BASE = (uint32_t)USBx;
USBx_DEVICE->DCFG &= ~(USB_OTG_DCFG_DAD);
USBx_DEVICE->DCFG |= ((uint32_t)address << 4) & USB_OTG_DCFG_DAD;
return HAL_OK;
}
/**
* @brief USB_DevConnect : Connect the USB device by enabling Rpu
* @param USBx Selected device
* @retval HAL status
*/
HAL_StatusTypeDef USB_DevConnect(const USB_OTG_GlobalTypeDef *USBx)
{
uint32_t USBx_BASE = (uint32_t)USBx;
/* In case phy is stopped, ensure to ungate and restore the phy CLK */
USBx_PCGCCTL &= ~(USB_OTG_PCGCCTL_STOPCLK | USB_OTG_PCGCCTL_GATECLK);
USBx_DEVICE->DCTL &= ~USB_OTG_DCTL_SDIS;
return HAL_OK;
}
/**
* @brief USB_DevDisconnect : Disconnect the USB device by disabling Rpu
* @param USBx Selected device
* @retval HAL status
*/
HAL_StatusTypeDef USB_DevDisconnect(const USB_OTG_GlobalTypeDef *USBx)
{
uint32_t USBx_BASE = (uint32_t)USBx;
/* In case phy is stopped, ensure to ungate and restore the phy CLK */
USBx_PCGCCTL &= ~(USB_OTG_PCGCCTL_STOPCLK | USB_OTG_PCGCCTL_GATECLK);
USBx_DEVICE->DCTL |= USB_OTG_DCTL_SDIS;
return HAL_OK;
}
/**
* @brief USB_ReadInterrupts: return the global USB interrupt status
* @param USBx Selected device
* @retval USB Global Interrupt status
*/
uint32_t USB_ReadInterrupts(USB_OTG_GlobalTypeDef const *USBx)
{
uint32_t tmpreg;
tmpreg = USBx->GINTSTS;
tmpreg &= USBx->GINTMSK;
return tmpreg;
}
/**
* @brief USB_ReadChInterrupts: return USB channel interrupt status
* @param USBx Selected device
* @param chnum Channel number
* @retval USB Channel Interrupt status
*/
uint32_t USB_ReadChInterrupts(const USB_OTG_GlobalTypeDef *USBx, uint8_t chnum)
{
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t tmpreg;
tmpreg = USBx_HC(chnum)->HCINT;
tmpreg &= USBx_HC(chnum)->HCINTMSK;
return tmpreg;
}
/**
* @brief USB_ReadDevAllOutEpInterrupt: return the USB device OUT endpoints interrupt status
* @param USBx Selected device
* @retval USB Device OUT EP interrupt status
*/
uint32_t USB_ReadDevAllOutEpInterrupt(const USB_OTG_GlobalTypeDef *USBx)
{
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t tmpreg;
tmpreg = USBx_DEVICE->DAINT;
tmpreg &= USBx_DEVICE->DAINTMSK;
return ((tmpreg & 0xffff0000U) >> 16);
}
/**
* @brief USB_ReadDevAllInEpInterrupt: return the USB device IN endpoints interrupt status
* @param USBx Selected device
* @retval USB Device IN EP interrupt status
*/
uint32_t USB_ReadDevAllInEpInterrupt(const USB_OTG_GlobalTypeDef *USBx)
{
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t tmpreg;
tmpreg = USBx_DEVICE->DAINT;
tmpreg &= USBx_DEVICE->DAINTMSK;
return ((tmpreg & 0xFFFFU));
}
/**
* @brief Returns Device OUT EP Interrupt register
* @param USBx Selected device
* @param epnum endpoint number
* This parameter can be a value from 0 to 15
* @retval Device OUT EP Interrupt register
*/
uint32_t USB_ReadDevOutEPInterrupt(const USB_OTG_GlobalTypeDef *USBx, uint8_t epnum)
{
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t tmpreg;
tmpreg = USBx_OUTEP((uint32_t)epnum)->DOEPINT;
tmpreg &= USBx_DEVICE->DOEPMSK;
return tmpreg;
}
/**
* @brief Returns Device IN EP Interrupt register
* @param USBx Selected device
* @param epnum endpoint number
* This parameter can be a value from 0 to 15
* @retval Device IN EP Interrupt register
*/
uint32_t USB_ReadDevInEPInterrupt(const USB_OTG_GlobalTypeDef *USBx, uint8_t epnum)
{
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t tmpreg;
uint32_t msk;
uint32_t emp;
msk = USBx_DEVICE->DIEPMSK;
emp = USBx_DEVICE->DIEPEMPMSK;
msk |= ((emp >> (epnum & EP_ADDR_MSK)) & 0x1U) << 7;
tmpreg = USBx_INEP((uint32_t)epnum)->DIEPINT & msk;
return tmpreg;
}
/**
* @brief USB_ClearInterrupts: clear a USB interrupt
* @param USBx Selected device
* @param interrupt flag
* @retval None
*/
void USB_ClearInterrupts(USB_OTG_GlobalTypeDef *USBx, uint32_t interrupt)
{
USBx->GINTSTS &= interrupt;
}
/**
* @brief Returns USB core mode
* @param USBx Selected device
* @retval return core mode : Host or Device
* This parameter can be one of these values:
* 0 : Host
* 1 : Device
*/
uint32_t USB_GetMode(const USB_OTG_GlobalTypeDef *USBx)
{
return ((USBx->GINTSTS) & 0x1U);
}
/**
* @brief Activate EP0 for Setup transactions
* @param USBx Selected device
* @retval HAL status
*/
HAL_StatusTypeDef USB_ActivateSetup(const USB_OTG_GlobalTypeDef *USBx)
{
uint32_t USBx_BASE = (uint32_t)USBx;
/* Set the MPS of the IN EP0 to 64 bytes */
USBx_INEP(0U)->DIEPCTL &= ~USB_OTG_DIEPCTL_MPSIZ;
USBx_DEVICE->DCTL |= USB_OTG_DCTL_CGINAK;
return HAL_OK;
}
/**
* @brief Prepare the EP0 to start the first control setup
* @param USBx Selected device
* @param psetup pointer to setup packet
* @retval HAL status
*/
HAL_StatusTypeDef USB_EP0_OutStart(const USB_OTG_GlobalTypeDef *USBx, const uint8_t *psetup)
{
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t gSNPSiD = *(__IO const uint32_t *)(&USBx->CID + 0x1U);
UNUSED(psetup);
if (gSNPSiD > USB_OTG_CORE_ID_300A)
{
if ((USBx_OUTEP(0U)->DOEPCTL & USB_OTG_DOEPCTL_EPENA) == USB_OTG_DOEPCTL_EPENA)
{
return HAL_OK;
}
}
USBx_OUTEP(0U)->DOEPTSIZ = 0U;
USBx_OUTEP(0U)->DOEPTSIZ |= (USB_OTG_DOEPTSIZ_PKTCNT & (1U << 19));
USBx_OUTEP(0U)->DOEPTSIZ |= (3U * 8U);
USBx_OUTEP(0U)->DOEPTSIZ |= USB_OTG_DOEPTSIZ_STUPCNT;
return HAL_OK;
}
/**
* @brief Reset the USB Core (needed after USB clock settings change)
* @param USBx Selected device
* @retval HAL status
*/
static HAL_StatusTypeDef USB_CoreReset(USB_OTG_GlobalTypeDef *USBx)
{
__IO uint32_t count = 0U;
/* Wait for AHB master IDLE state. */
do
{
count++;
if (count > HAL_USB_TIMEOUT)
{
return HAL_TIMEOUT;
}
} while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_AHBIDL) == 0U);
/* Core Soft Reset */
count = 0U;
USBx->GRSTCTL |= USB_OTG_GRSTCTL_CSRST;
do
{
count++;
if (count > HAL_USB_TIMEOUT)
{
return HAL_TIMEOUT;
}
} while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_CSRST) == USB_OTG_GRSTCTL_CSRST);
return HAL_OK;
}
/**
* @brief USB_HostInit : Initializes the USB OTG controller registers
* for Host mode
* @param USBx Selected device
* @param cfg pointer to a USB_OTG_CfgTypeDef structure that contains
* the configuration information for the specified USBx peripheral.
* @retval HAL status
*/
HAL_StatusTypeDef USB_HostInit(USB_OTG_GlobalTypeDef *USBx, USB_OTG_CfgTypeDef cfg)
{
HAL_StatusTypeDef ret = HAL_OK;
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t i;
/* Restart the Phy Clock */
USBx_PCGCCTL = 0U;
/* Disable VBUS sensing */
USBx->GCCFG &= ~(USB_OTG_GCCFG_VBUSASEN);
USBx->GCCFG &= ~(USB_OTG_GCCFG_VBUSBSEN);
/* Set default Max speed support */
USBx_HOST->HCFG &= ~(USB_OTG_HCFG_FSLSS);
/* Make sure the FIFOs are flushed. */
if (USB_FlushTxFifo(USBx, 0x10U) != HAL_OK) /* all Tx FIFOs */
{
ret = HAL_ERROR;
}
if (USB_FlushRxFifo(USBx) != HAL_OK)
{
ret = HAL_ERROR;
}
/* Clear all pending HC Interrupts */
for (i = 0U; i < cfg.Host_channels; i++)
{
USBx_HC(i)->HCINT = CLEAR_INTERRUPT_MASK;
USBx_HC(i)->HCINTMSK = 0U;
}
/* Disable all interrupts. */
USBx->GINTMSK = 0U;
/* Clear any pending interrupts */
USBx->GINTSTS = CLEAR_INTERRUPT_MASK;
/* set Rx FIFO size */
USBx->GRXFSIZ = 0x80U;
USBx->DIEPTXF0_HNPTXFSIZ = (uint32_t)(((0x60U << 16) & USB_OTG_NPTXFD) | 0x80U);
USBx->HPTXFSIZ = (uint32_t)(((0x40U << 16)& USB_OTG_HPTXFSIZ_PTXFD) | 0xE0U);
/* Enable the common interrupts */
USBx->GINTMSK |= USB_OTG_GINTMSK_RXFLVLM;
/* Enable interrupts matching to the Host mode ONLY */
USBx->GINTMSK |= (USB_OTG_GINTMSK_PRTIM | USB_OTG_GINTMSK_HCIM | \
USB_OTG_GINTMSK_SOFM | USB_OTG_GINTSTS_DISCINT | \
USB_OTG_GINTMSK_PXFRM_IISOOXFRM | USB_OTG_GINTMSK_WUIM);
return ret;
}
/**
* @brief USB_InitFSLSPClkSel : Initializes the FSLSPClkSel field of the
* HCFG register on the PHY type and set the right frame interval
* @param USBx Selected device
* @param freq clock frequency
* This parameter can be one of these values:
* HCFG_48_MHZ : Full Speed 48 MHz Clock
* HCFG_6_MHZ : Low Speed 6 MHz Clock
* @retval HAL status
*/
HAL_StatusTypeDef USB_InitFSLSPClkSel(const USB_OTG_GlobalTypeDef *USBx, uint8_t freq)
{
uint32_t USBx_BASE = (uint32_t)USBx;
USBx_HOST->HCFG &= ~(USB_OTG_HCFG_FSLSPCS);
USBx_HOST->HCFG |= (uint32_t)freq & USB_OTG_HCFG_FSLSPCS;
if (freq == HCFG_48_MHZ)
{
USBx_HOST->HFIR = HFIR_48_MHZ;
}
else if (freq == HCFG_6_MHZ)
{
USBx_HOST->HFIR = HFIR_6_MHZ;
}
else
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief USB_OTG_ResetPort : Reset Host Port
* @param USBx Selected device
* @retval HAL status
* @note (1)The application must wait at least 10 ms
* before clearing the reset bit.
*/
HAL_StatusTypeDef USB_ResetPort(const USB_OTG_GlobalTypeDef *USBx)
{
uint32_t USBx_BASE = (uint32_t)USBx;
__IO uint32_t hprt0 = 0U;
hprt0 = USBx_HPRT0;
hprt0 &= ~(USB_OTG_HPRT_PENA | USB_OTG_HPRT_PCDET |
USB_OTG_HPRT_PENCHNG | USB_OTG_HPRT_POCCHNG);
USBx_HPRT0 = (USB_OTG_HPRT_PRST | hprt0);
HAL_Delay(100U); /* See Note #1 */
USBx_HPRT0 = ((~USB_OTG_HPRT_PRST) & hprt0);
HAL_Delay(10U);
return HAL_OK;
}
/**
* @brief USB_DriveVbus : activate or de-activate vbus
* @param state VBUS state
* This parameter can be one of these values:
* 0 : Deactivate VBUS
* 1 : Activate VBUS
* @retval HAL status
*/
HAL_StatusTypeDef USB_DriveVbus(const USB_OTG_GlobalTypeDef *USBx, uint8_t state)
{
uint32_t USBx_BASE = (uint32_t)USBx;
__IO uint32_t hprt0 = 0U;
hprt0 = USBx_HPRT0;
hprt0 &= ~(USB_OTG_HPRT_PENA | USB_OTG_HPRT_PCDET |
USB_OTG_HPRT_PENCHNG | USB_OTG_HPRT_POCCHNG);
if (((hprt0 & USB_OTG_HPRT_PPWR) == 0U) && (state == 1U))
{
USBx_HPRT0 = (USB_OTG_HPRT_PPWR | hprt0);
}
if (((hprt0 & USB_OTG_HPRT_PPWR) == USB_OTG_HPRT_PPWR) && (state == 0U))
{
USBx_HPRT0 = ((~USB_OTG_HPRT_PPWR) & hprt0);
}
return HAL_OK;
}
/**
* @brief Return Host Core speed
* @param USBx Selected device
* @retval speed : Host speed
* This parameter can be one of these values:
* @arg HCD_SPEED_FULL: Full speed mode
* @arg HCD_SPEED_LOW: Low speed mode
*/
uint32_t USB_GetHostSpeed(USB_OTG_GlobalTypeDef const *USBx)
{
uint32_t USBx_BASE = (uint32_t)USBx;
__IO uint32_t hprt0 = 0U;
hprt0 = USBx_HPRT0;
return ((hprt0 & USB_OTG_HPRT_PSPD) >> 17);
}
/**
* @brief Return Host Current Frame number
* @param USBx Selected device
* @retval current frame number
*/
uint32_t USB_GetCurrentFrame(USB_OTG_GlobalTypeDef const *USBx)
{
uint32_t USBx_BASE = (uint32_t)USBx;
return (USBx_HOST->HFNUM & USB_OTG_HFNUM_FRNUM);
}
/**
* @brief Initialize a host channel
* @param USBx Selected device
* @param ch_num Channel number
* This parameter can be a value from 1 to 15
* @param epnum Endpoint number
* This parameter can be a value from 1 to 15
* @param dev_address Current device address
* This parameter can be a value from 0 to 255
* @param speed Current device speed
* This parameter can be one of these values:
* @arg USB_OTG_SPEED_FULL: Full speed mode
* @arg USB_OTG_SPEED_LOW: Low speed mode
* @param ep_type Endpoint Type
* This parameter can be one of these values:
* @arg EP_TYPE_CTRL: Control type
* @arg EP_TYPE_ISOC: Isochronous type
* @arg EP_TYPE_BULK: Bulk type
* @arg EP_TYPE_INTR: Interrupt type
* @param mps Max Packet Size
* This parameter can be a value from 0 to 32K
* @retval HAL state
*/
HAL_StatusTypeDef USB_HC_Init(USB_OTG_GlobalTypeDef *USBx, uint8_t ch_num,
uint8_t epnum, uint8_t dev_address, uint8_t speed,
uint8_t ep_type, uint16_t mps)
{
HAL_StatusTypeDef ret = HAL_OK;
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t HCcharEpDir;
uint32_t HCcharLowSpeed;
uint32_t HostCoreSpeed;
/* Clear old interrupt conditions for this host channel. */
USBx_HC((uint32_t)ch_num)->HCINT = CLEAR_INTERRUPT_MASK;
/* Enable channel interrupts required for this transfer. */
switch (ep_type)
{
case EP_TYPE_CTRL:
case EP_TYPE_BULK:
USBx_HC((uint32_t)ch_num)->HCINTMSK = USB_OTG_HCINTMSK_XFRCM |
USB_OTG_HCINTMSK_STALLM |
USB_OTG_HCINTMSK_TXERRM |
USB_OTG_HCINTMSK_DTERRM |
USB_OTG_HCINTMSK_AHBERR |
USB_OTG_HCINTMSK_NAKM;
if ((epnum & 0x80U) == 0x80U)
{
USBx_HC((uint32_t)ch_num)->HCINTMSK |= USB_OTG_HCINTMSK_BBERRM;
}
break;
case EP_TYPE_INTR:
USBx_HC((uint32_t)ch_num)->HCINTMSK = USB_OTG_HCINTMSK_XFRCM |
USB_OTG_HCINTMSK_STALLM |
USB_OTG_HCINTMSK_TXERRM |
USB_OTG_HCINTMSK_DTERRM |
USB_OTG_HCINTMSK_NAKM |
USB_OTG_HCINTMSK_AHBERR |
USB_OTG_HCINTMSK_FRMORM;
if ((epnum & 0x80U) == 0x80U)
{
USBx_HC((uint32_t)ch_num)->HCINTMSK |= USB_OTG_HCINTMSK_BBERRM;
}
break;
case EP_TYPE_ISOC:
USBx_HC((uint32_t)ch_num)->HCINTMSK = USB_OTG_HCINTMSK_XFRCM |
USB_OTG_HCINTMSK_ACKM |
USB_OTG_HCINTMSK_AHBERR |
USB_OTG_HCINTMSK_FRMORM;
if ((epnum & 0x80U) == 0x80U)
{
USBx_HC((uint32_t)ch_num)->HCINTMSK |= (USB_OTG_HCINTMSK_TXERRM | USB_OTG_HCINTMSK_BBERRM);
}
break;
default:
ret = HAL_ERROR;
break;
}
/* Enable host channel Halt interrupt */
USBx_HC((uint32_t)ch_num)->HCINTMSK |= USB_OTG_HCINTMSK_CHHM;
/* Enable the top level host channel interrupt. */
USBx_HOST->HAINTMSK |= 1UL << (ch_num & 0xFU);
/* Make sure host channel interrupts are enabled. */
USBx->GINTMSK |= USB_OTG_GINTMSK_HCIM;
/* Program the HCCHAR register */
if ((epnum & 0x80U) == 0x80U)
{
HCcharEpDir = (0x1U << 15) & USB_OTG_HCCHAR_EPDIR;
}
else
{
HCcharEpDir = 0U;
}
HostCoreSpeed = USB_GetHostSpeed(USBx);
/* LS device plugged to HUB */
if ((speed == HPRT0_PRTSPD_LOW_SPEED) && (HostCoreSpeed != HPRT0_PRTSPD_LOW_SPEED))
{
HCcharLowSpeed = (0x1U << 17) & USB_OTG_HCCHAR_LSDEV;
}
else
{
HCcharLowSpeed = 0U;
}
USBx_HC((uint32_t)ch_num)->HCCHAR = (((uint32_t)dev_address << 22) & USB_OTG_HCCHAR_DAD) |
((((uint32_t)epnum & 0x7FU) << 11) & USB_OTG_HCCHAR_EPNUM) |
(((uint32_t)ep_type << 18) & USB_OTG_HCCHAR_EPTYP) |
((uint32_t)mps & USB_OTG_HCCHAR_MPSIZ) |
USB_OTG_HCCHAR_MC_0 | HCcharEpDir | HCcharLowSpeed;
if ((ep_type == EP_TYPE_INTR) || (ep_type == EP_TYPE_ISOC))
{
USBx_HC((uint32_t)ch_num)->HCCHAR |= USB_OTG_HCCHAR_ODDFRM;
}
return ret;
}
/**
* @brief Start a transfer over a host channel
* @param USBx Selected device
* @param hc pointer to host channel structure
* @retval HAL state
*/
HAL_StatusTypeDef USB_HC_StartXfer(USB_OTG_GlobalTypeDef *USBx, USB_OTG_HCTypeDef *hc)
{
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t ch_num = (uint32_t)hc->ch_num;
__IO uint32_t tmpreg;
uint8_t is_oddframe;
uint16_t len_words;
uint16_t num_packets;
uint16_t max_hc_pkt_count = HC_MAX_PKT_CNT;
/* Compute the expected number of packets associated to the transfer */
if (hc->xfer_len > 0U)
{
num_packets = (uint16_t)((hc->xfer_len + hc->max_packet - 1U) / hc->max_packet);
if (num_packets > max_hc_pkt_count)
{
num_packets = max_hc_pkt_count;
hc->XferSize = (uint32_t)num_packets * hc->max_packet;
}
}
else
{
num_packets = 1U;
}
/*
* For IN channel HCTSIZ.XferSize is expected to be an integer multiple of
* max_packet size.
*/
if (hc->ep_is_in != 0U)
{
hc->XferSize = (uint32_t)num_packets * hc->max_packet;
}
else
{
hc->XferSize = hc->xfer_len;
}
/* Initialize the HCTSIZn register */
USBx_HC(ch_num)->HCTSIZ = (hc->XferSize & USB_OTG_HCTSIZ_XFRSIZ) |
(((uint32_t)num_packets << 19) & USB_OTG_HCTSIZ_PKTCNT) |
(((uint32_t)hc->data_pid << 29) & USB_OTG_HCTSIZ_DPID);
is_oddframe = (((uint32_t)USBx_HOST->HFNUM & 0x01U) != 0U) ? 0U : 1U;
USBx_HC(ch_num)->HCCHAR &= ~USB_OTG_HCCHAR_ODDFRM;
USBx_HC(ch_num)->HCCHAR |= (uint32_t)is_oddframe << 29;
/* Set host channel enable */
tmpreg = USBx_HC(ch_num)->HCCHAR;
tmpreg &= ~USB_OTG_HCCHAR_CHDIS;
/* make sure to set the correct ep direction */
if (hc->ep_is_in != 0U)
{
tmpreg |= USB_OTG_HCCHAR_EPDIR;
}
else
{
tmpreg &= ~USB_OTG_HCCHAR_EPDIR;
}
tmpreg |= USB_OTG_HCCHAR_CHENA;
USBx_HC(ch_num)->HCCHAR = tmpreg;
if ((hc->ep_is_in == 0U) && (hc->xfer_len > 0U))
{
switch (hc->ep_type)
{
/* Non periodic transfer */
case EP_TYPE_CTRL:
case EP_TYPE_BULK:
len_words = (uint16_t)((hc->xfer_len + 3U) / 4U);
/* check if there is enough space in FIFO space */
if (len_words > (USBx->HNPTXSTS & 0xFFFFU))
{
/* need to process data in nptxfempty interrupt */
USBx->GINTMSK |= USB_OTG_GINTMSK_NPTXFEM;
}
break;
/* Periodic transfer */
case EP_TYPE_INTR:
case EP_TYPE_ISOC:
len_words = (uint16_t)((hc->xfer_len + 3U) / 4U);
/* check if there is enough space in FIFO space */
if (len_words > (USBx_HOST->HPTXSTS & 0xFFFFU)) /* split the transfer */
{
/* need to process data in ptxfempty interrupt */
USBx->GINTMSK |= USB_OTG_GINTMSK_PTXFEM;
}
break;
default:
break;
}
/* Write packet into the Tx FIFO. */
(void)USB_WritePacket(USBx, hc->xfer_buff, hc->ch_num, (uint16_t)hc->xfer_len);
}
return HAL_OK;
}
/**
* @brief Read all host channel interrupts status
* @param USBx Selected device
* @retval HAL state
*/
uint32_t USB_HC_ReadInterrupt(const USB_OTG_GlobalTypeDef *USBx)
{
uint32_t USBx_BASE = (uint32_t)USBx;
return ((USBx_HOST->HAINT) & 0xFFFFU);
}
/**
* @brief Halt a host channel
* @param USBx Selected device
* @param hc_num Host Channel number
* This parameter can be a value from 1 to 15
* @retval HAL state
*/
HAL_StatusTypeDef USB_HC_Halt(const USB_OTG_GlobalTypeDef *USBx, uint8_t hc_num)
{
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t hcnum = (uint32_t)hc_num;
__IO uint32_t count = 0U;
uint32_t HcEpType = (USBx_HC(hcnum)->HCCHAR & USB_OTG_HCCHAR_EPTYP) >> 18;
uint32_t ChannelEna = (USBx_HC(hcnum)->HCCHAR & USB_OTG_HCCHAR_CHENA) >> 31;
uint32_t SplitEna = (USBx_HC(hcnum)->HCSPLT & USB_OTG_HCSPLT_SPLITEN) >> 31;
/* In buffer DMA, Channel disable must not be programmed for non-split periodic channels.
At the end of the next uframe/frame (in the worst case), the core generates a channel halted
and disables the channel automatically. */
if ((((USBx->GAHBCFG & USB_OTG_GAHBCFG_DMAEN) == USB_OTG_GAHBCFG_DMAEN) && (SplitEna == 0U)) &&
((ChannelEna == 0U) || (((HcEpType == HCCHAR_ISOC) || (HcEpType == HCCHAR_INTR)))))
{
return HAL_OK;
}
/* Check for space in the request queue to issue the halt. */
if ((HcEpType == HCCHAR_CTRL) || (HcEpType == HCCHAR_BULK))
{
USBx_HC(hcnum)->HCCHAR |= USB_OTG_HCCHAR_CHDIS;
if ((USBx->GAHBCFG & USB_OTG_GAHBCFG_DMAEN) == 0U)
{
if ((USBx->HNPTXSTS & (0xFFU << 16)) == 0U)
{
USBx_HC(hcnum)->HCCHAR &= ~USB_OTG_HCCHAR_CHENA;
USBx_HC(hcnum)->HCCHAR |= USB_OTG_HCCHAR_CHENA;
do
{
count++;
if (count > 1000U)
{
break;
}
} while ((USBx_HC(hcnum)->HCCHAR & USB_OTG_HCCHAR_CHENA) == USB_OTG_HCCHAR_CHENA);
}
else
{
USBx_HC(hcnum)->HCCHAR |= USB_OTG_HCCHAR_CHENA;
}
}
else
{
USBx_HC(hcnum)->HCCHAR |= USB_OTG_HCCHAR_CHENA;
}
}
else
{
USBx_HC(hcnum)->HCCHAR |= USB_OTG_HCCHAR_CHDIS;
if ((USBx_HOST->HPTXSTS & (0xFFU << 16)) == 0U)
{
USBx_HC(hcnum)->HCCHAR &= ~USB_OTG_HCCHAR_CHENA;
USBx_HC(hcnum)->HCCHAR |= USB_OTG_HCCHAR_CHENA;
do
{
count++;
if (count > 1000U)
{
break;
}
} while ((USBx_HC(hcnum)->HCCHAR & USB_OTG_HCCHAR_CHENA) == USB_OTG_HCCHAR_CHENA);
}
else
{
USBx_HC(hcnum)->HCCHAR |= USB_OTG_HCCHAR_CHENA;
}
}
return HAL_OK;
}
/**
* @brief Initiate Do Ping protocol
* @param USBx Selected device
* @param hc_num Host Channel number
* This parameter can be a value from 1 to 15
* @retval HAL state
*/
HAL_StatusTypeDef USB_DoPing(const USB_OTG_GlobalTypeDef *USBx, uint8_t ch_num)
{
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t chnum = (uint32_t)ch_num;
uint32_t num_packets = 1U;
uint32_t tmpreg;
USBx_HC(chnum)->HCTSIZ = ((num_packets << 19) & USB_OTG_HCTSIZ_PKTCNT) |
USB_OTG_HCTSIZ_DOPING;
/* Set host channel enable */
tmpreg = USBx_HC(chnum)->HCCHAR;
tmpreg &= ~USB_OTG_HCCHAR_CHDIS;
tmpreg |= USB_OTG_HCCHAR_CHENA;
USBx_HC(chnum)->HCCHAR = tmpreg;
return HAL_OK;
}
/**
* @brief Stop Host Core
* @param USBx Selected device
* @retval HAL state
*/
HAL_StatusTypeDef USB_StopHost(USB_OTG_GlobalTypeDef *USBx)
{
HAL_StatusTypeDef ret = HAL_OK;
uint32_t USBx_BASE = (uint32_t)USBx;
__IO uint32_t count = 0U;
uint32_t value;
uint32_t i;
(void)USB_DisableGlobalInt(USBx);
/* Flush USB FIFO */
if (USB_FlushTxFifo(USBx, 0x10U) != HAL_OK) /* all Tx FIFOs */
{
ret = HAL_ERROR;
}
if (USB_FlushRxFifo(USBx) != HAL_OK)
{
ret = HAL_ERROR;
}
/* Flush out any leftover queued requests. */
for (i = 0U; i <= 15U; i++)
{
value = USBx_HC(i)->HCCHAR;
value |= USB_OTG_HCCHAR_CHDIS;
value &= ~USB_OTG_HCCHAR_CHENA;
value &= ~USB_OTG_HCCHAR_EPDIR;
USBx_HC(i)->HCCHAR = value;
}
/* Halt all channels to put them into a known state. */
for (i = 0U; i <= 15U; i++)
{
value = USBx_HC(i)->HCCHAR;
value |= USB_OTG_HCCHAR_CHDIS;
value |= USB_OTG_HCCHAR_CHENA;
value &= ~USB_OTG_HCCHAR_EPDIR;
USBx_HC(i)->HCCHAR = value;
do
{
count++;
if (count > 1000U)
{
break;
}
} while ((USBx_HC(i)->HCCHAR & USB_OTG_HCCHAR_CHENA) == USB_OTG_HCCHAR_CHENA);
}
/* Clear any pending Host interrupts */
USBx_HOST->HAINT = CLEAR_INTERRUPT_MASK;
USBx->GINTSTS = CLEAR_INTERRUPT_MASK;
(void)USB_EnableGlobalInt(USBx);
return ret;
}
/**
* @brief USB_ActivateRemoteWakeup active remote wakeup signalling
* @param USBx Selected device
* @retval HAL status
*/
HAL_StatusTypeDef USB_ActivateRemoteWakeup(const USB_OTG_GlobalTypeDef *USBx)
{
uint32_t USBx_BASE = (uint32_t)USBx;
if ((USBx_DEVICE->DSTS & USB_OTG_DSTS_SUSPSTS) == USB_OTG_DSTS_SUSPSTS)
{
/* active Remote wakeup signalling */
USBx_DEVICE->DCTL |= USB_OTG_DCTL_RWUSIG;
}
return HAL_OK;
}
/**
* @brief USB_DeActivateRemoteWakeup de-active remote wakeup signalling
* @param USBx Selected device
* @retval HAL status
*/
HAL_StatusTypeDef USB_DeActivateRemoteWakeup(const USB_OTG_GlobalTypeDef *USBx)
{
uint32_t USBx_BASE = (uint32_t)USBx;
/* active Remote wakeup signalling */
USBx_DEVICE->DCTL &= ~(USB_OTG_DCTL_RWUSIG);
return HAL_OK;
}
#endif /* defined (USB_OTG_FS) */
#if defined (USB)
/**
* @brief Initializes the USB Core
* @param USBx USB Instance
* @param cfg pointer to a USB_CfgTypeDef structure that contains
* the configuration information for the specified USBx peripheral.
* @retval HAL status
*/
HAL_StatusTypeDef USB_CoreInit(USB_TypeDef *USBx, USB_CfgTypeDef cfg)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(USBx);
UNUSED(cfg);
/* NOTE : - This function is not required by USB Device FS peripheral, it is used
only by USB OTG FS peripheral.
- This function is added to ensure compatibility across platforms.
*/
return HAL_OK;
}
/**
* @brief USB_EnableGlobalInt
* Enables the controller's Global Int in the AHB Config reg
* @param USBx Selected device
* @retval HAL status
*/
HAL_StatusTypeDef USB_EnableGlobalInt(USB_TypeDef *USBx)
{
uint32_t winterruptmask;
/* Clear pending interrupts */
USBx->ISTR = 0U;
/* Set winterruptmask variable */
winterruptmask = USB_CNTR_CTRM | USB_CNTR_WKUPM |
USB_CNTR_SUSPM | USB_CNTR_ERRM |
USB_CNTR_SOFM | USB_CNTR_ESOFM |
USB_CNTR_RESETM;
/* Set interrupt mask */
USBx->CNTR = (uint16_t)winterruptmask;
return HAL_OK;
}
/**
* @brief USB_DisableGlobalInt
* Disable the controller's Global Int in the AHB Config reg
* @param USBx Selected device
* @retval HAL status
*/
HAL_StatusTypeDef USB_DisableGlobalInt(USB_TypeDef *USBx)
{
uint32_t winterruptmask;
/* Set winterruptmask variable */
winterruptmask = USB_CNTR_CTRM | USB_CNTR_WKUPM |
USB_CNTR_SUSPM | USB_CNTR_ERRM |
USB_CNTR_SOFM | USB_CNTR_ESOFM |
USB_CNTR_RESETM;
/* Clear interrupt mask */
USBx->CNTR &= (uint16_t)(~winterruptmask);
return HAL_OK;
}
/**
* @brief USB_SetCurrentMode Set functional mode
* @param USBx Selected device
* @param mode current core mode
* This parameter can be one of the these values:
* @arg USB_DEVICE_MODE Peripheral mode
* @retval HAL status
*/
HAL_StatusTypeDef USB_SetCurrentMode(USB_TypeDef *USBx, USB_ModeTypeDef mode)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(USBx);
UNUSED(mode);
/* NOTE : - This function is not required by USB Device FS peripheral, it is used
only by USB OTG FS peripheral.
- This function is added to ensure compatibility across platforms.
*/
return HAL_OK;
}
/**
* @brief USB_DevInit Initializes the USB controller registers
* for device mode
* @param USBx Selected device
* @param cfg pointer to a USB_CfgTypeDef structure that contains
* the configuration information for the specified USBx peripheral.
* @retval HAL status
*/
HAL_StatusTypeDef USB_DevInit(USB_TypeDef *USBx, USB_CfgTypeDef cfg)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(cfg);
/* Init Device */
/* CNTR_FRES = 1 */
USBx->CNTR = (uint16_t)USB_CNTR_FRES;
/* CNTR_FRES = 0 */
USBx->CNTR = 0U;
/* Clear pending interrupts */
USBx->ISTR = 0U;
/*Set Btable Address*/
USBx->BTABLE = BTABLE_ADDRESS;
return HAL_OK;
}
/**
* @brief USB_FlushTxFifo : Flush a Tx FIFO
* @param USBx : Selected device
* @param num : FIFO number
* This parameter can be a value from 1 to 15
15 means Flush all Tx FIFOs
* @retval HAL status
*/
HAL_StatusTypeDef USB_FlushTxFifo(USB_TypeDef const *USBx, uint32_t num)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(USBx);
UNUSED(num);
/* NOTE : - This function is not required by USB Device FS peripheral, it is used
only by USB OTG FS peripheral.
- This function is added to ensure compatibility across platforms.
*/
return HAL_OK;
}
/**
* @brief USB_FlushRxFifo : Flush Rx FIFO
* @param USBx : Selected device
* @retval HAL status
*/
HAL_StatusTypeDef USB_FlushRxFifo(USB_TypeDef const *USBx)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(USBx);
/* NOTE : - This function is not required by USB Device FS peripheral, it is used
only by USB OTG FS peripheral.
- This function is added to ensure compatibility across platforms.
*/
return HAL_OK;
}
#if defined (HAL_PCD_MODULE_ENABLED)
/**
* @brief Activate and configure an endpoint
* @param USBx Selected device
* @param ep pointer to endpoint structure
* @retval HAL status
*/
HAL_StatusTypeDef USB_ActivateEndpoint(USB_TypeDef *USBx, USB_EPTypeDef *ep)
{
HAL_StatusTypeDef ret = HAL_OK;
uint16_t wEpRegVal;
wEpRegVal = PCD_GET_ENDPOINT(USBx, ep->num) & USB_EP_T_MASK;
/* initialize Endpoint */
switch (ep->type)
{
case EP_TYPE_CTRL:
wEpRegVal |= USB_EP_CONTROL;
break;
case EP_TYPE_BULK:
wEpRegVal |= USB_EP_BULK;
break;
case EP_TYPE_INTR:
wEpRegVal |= USB_EP_INTERRUPT;
break;
case EP_TYPE_ISOC:
wEpRegVal |= USB_EP_ISOCHRONOUS;
break;
default:
ret = HAL_ERROR;
break;
}
PCD_SET_ENDPOINT(USBx, ep->num, (wEpRegVal | USB_EP_CTR_RX | USB_EP_CTR_TX));
PCD_SET_EP_ADDRESS(USBx, ep->num, ep->num);
if (ep->doublebuffer == 0U)
{
if (ep->is_in != 0U)
{
/*Set the endpoint Transmit buffer address */
PCD_SET_EP_TX_ADDRESS(USBx, ep->num, ep->pmaadress);
PCD_CLEAR_TX_DTOG(USBx, ep->num);
if (ep->type != EP_TYPE_ISOC)
{
/* Configure NAK status for the Endpoint */
PCD_SET_EP_TX_STATUS(USBx, ep->num, USB_EP_TX_NAK);
}
else
{
/* Configure TX Endpoint to disabled state */
PCD_SET_EP_TX_STATUS(USBx, ep->num, USB_EP_TX_DIS);
}
}
else
{
/* Set the endpoint Receive buffer address */
PCD_SET_EP_RX_ADDRESS(USBx, ep->num, ep->pmaadress);
/* Set the endpoint Receive buffer counter */
PCD_SET_EP_RX_CNT(USBx, ep->num, ep->maxpacket);
PCD_CLEAR_RX_DTOG(USBx, ep->num);
if (ep->num == 0U)
{
/* Configure VALID status for EP0 */
PCD_SET_EP_RX_STATUS(USBx, ep->num, USB_EP_RX_VALID);
}
else
{
/* Configure NAK status for OUT Endpoint */
PCD_SET_EP_RX_STATUS(USBx, ep->num, USB_EP_RX_NAK);
}
}
}
#if (USE_USB_DOUBLE_BUFFER == 1U)
/* Double Buffer */
else
{
if (ep->type == EP_TYPE_BULK)
{
/* Set bulk endpoint as double buffered */
PCD_SET_BULK_EP_DBUF(USBx, ep->num);
}
else
{
/* Set the ISOC endpoint in double buffer mode */
PCD_CLEAR_EP_KIND(USBx, ep->num);
}
/* Set buffer address for double buffered mode */
PCD_SET_EP_DBUF_ADDR(USBx, ep->num, ep->pmaaddr0, ep->pmaaddr1);
if (ep->is_in == 0U)
{
/* Clear the data toggle bits for the endpoint IN/OUT */
PCD_CLEAR_RX_DTOG(USBx, ep->num);
PCD_CLEAR_TX_DTOG(USBx, ep->num);
PCD_SET_EP_RX_STATUS(USBx, ep->num, USB_EP_RX_VALID);
PCD_SET_EP_TX_STATUS(USBx, ep->num, USB_EP_TX_DIS);
}
else
{
/* Clear the data toggle bits for the endpoint IN/OUT */
PCD_CLEAR_RX_DTOG(USBx, ep->num);
PCD_CLEAR_TX_DTOG(USBx, ep->num);
if (ep->type != EP_TYPE_ISOC)
{
/* Configure NAK status for the Endpoint */
PCD_SET_EP_TX_STATUS(USBx, ep->num, USB_EP_TX_NAK);
}
else
{
/* Configure TX Endpoint to disabled state */
PCD_SET_EP_TX_STATUS(USBx, ep->num, USB_EP_TX_DIS);
}
PCD_SET_EP_RX_STATUS(USBx, ep->num, USB_EP_RX_DIS);
}
}
#endif /* (USE_USB_DOUBLE_BUFFER == 1U) */
return ret;
}
/**
* @brief De-activate and de-initialize an endpoint
* @param USBx Selected device
* @param ep pointer to endpoint structure
* @retval HAL status
*/
HAL_StatusTypeDef USB_DeactivateEndpoint(USB_TypeDef *USBx, USB_EPTypeDef *ep)
{
if (ep->doublebuffer == 0U)
{
if (ep->is_in != 0U)
{
PCD_CLEAR_TX_DTOG(USBx, ep->num);
/* Configure DISABLE status for the Endpoint */
PCD_SET_EP_TX_STATUS(USBx, ep->num, USB_EP_TX_DIS);
}
else
{
PCD_CLEAR_RX_DTOG(USBx, ep->num);
/* Configure DISABLE status for the Endpoint */
PCD_SET_EP_RX_STATUS(USBx, ep->num, USB_EP_RX_DIS);
}
}
#if (USE_USB_DOUBLE_BUFFER == 1U)
/* Double Buffer */
else
{
if (ep->is_in == 0U)
{
/* Clear the data toggle bits for the endpoint IN/OUT*/
PCD_CLEAR_RX_DTOG(USBx, ep->num);
PCD_CLEAR_TX_DTOG(USBx, ep->num);
/* Reset value of the data toggle bits for the endpoint out*/
PCD_TX_DTOG(USBx, ep->num);
PCD_SET_EP_RX_STATUS(USBx, ep->num, USB_EP_RX_DIS);
PCD_SET_EP_TX_STATUS(USBx, ep->num, USB_EP_TX_DIS);
}
else
{
/* Clear the data toggle bits for the endpoint IN/OUT*/
PCD_CLEAR_RX_DTOG(USBx, ep->num);
PCD_CLEAR_TX_DTOG(USBx, ep->num);
PCD_RX_DTOG(USBx, ep->num);
/* Configure DISABLE status for the Endpoint*/
PCD_SET_EP_TX_STATUS(USBx, ep->num, USB_EP_TX_DIS);
PCD_SET_EP_RX_STATUS(USBx, ep->num, USB_EP_RX_DIS);
}
}
#endif /* (USE_USB_DOUBLE_BUFFER == 1U) */
return HAL_OK;
}
/**
* @brief USB_EPStartXfer setup and starts a transfer over an EP
* @param USBx Selected device
* @param ep pointer to endpoint structure
* @retval HAL status
*/
HAL_StatusTypeDef USB_EPStartXfer(USB_TypeDef *USBx, USB_EPTypeDef *ep)
{
uint32_t len;
#if (USE_USB_DOUBLE_BUFFER == 1U)
uint16_t pmabuffer;
uint16_t wEPVal;
#endif /* (USE_USB_DOUBLE_BUFFER == 1U) */
/* IN endpoint */
if (ep->is_in == 1U)
{
/*Multi packet transfer*/
if (ep->xfer_len > ep->maxpacket)
{
len = ep->maxpacket;
}
else
{
len = ep->xfer_len;
}
/* configure and validate Tx endpoint */
if (ep->doublebuffer == 0U)
{
USB_WritePMA(USBx, ep->xfer_buff, ep->pmaadress, (uint16_t)len);
PCD_SET_EP_TX_CNT(USBx, ep->num, len);
}
#if (USE_USB_DOUBLE_BUFFER == 1U)
else
{
/* double buffer bulk management */
if (ep->type == EP_TYPE_BULK)
{
if (ep->xfer_len_db > ep->maxpacket)
{
/* enable double buffer */
PCD_SET_BULK_EP_DBUF(USBx, ep->num);
/* each Time to write in PMA xfer_len_db will */
ep->xfer_len_db -= len;
/* Fill the two first buffer in the Buffer0 & Buffer1 */
if ((PCD_GET_ENDPOINT(USBx, ep->num) & USB_EP_DTOG_TX) != 0U)
{
/* Set the Double buffer counter for pmabuffer1 */
PCD_SET_EP_DBUF1_CNT(USBx, ep->num, ep->is_in, len);
pmabuffer = ep->pmaaddr1;
/* Write the user buffer to USB PMA */
USB_WritePMA(USBx, ep->xfer_buff, pmabuffer, (uint16_t)len);
ep->xfer_buff += len;
if (ep->xfer_len_db > ep->maxpacket)
{
ep->xfer_len_db -= len;
}
else
{
len = ep->xfer_len_db;
ep->xfer_len_db = 0U;
}
/* Set the Double buffer counter for pmabuffer0 */
PCD_SET_EP_DBUF0_CNT(USBx, ep->num, ep->is_in, len);
pmabuffer = ep->pmaaddr0;
/* Write the user buffer to USB PMA */
USB_WritePMA(USBx, ep->xfer_buff, pmabuffer, (uint16_t)len);
}
else
{
/* Set the Double buffer counter for pmabuffer0 */
PCD_SET_EP_DBUF0_CNT(USBx, ep->num, ep->is_in, len);
pmabuffer = ep->pmaaddr0;
/* Write the user buffer to USB PMA */
USB_WritePMA(USBx, ep->xfer_buff, pmabuffer, (uint16_t)len);
ep->xfer_buff += len;
if (ep->xfer_len_db > ep->maxpacket)
{
ep->xfer_len_db -= len;
}
else
{
len = ep->xfer_len_db;
ep->xfer_len_db = 0U;
}
/* Set the Double buffer counter for pmabuffer1 */
PCD_SET_EP_DBUF1_CNT(USBx, ep->num, ep->is_in, len);
pmabuffer = ep->pmaaddr1;
/* Write the user buffer to USB PMA */
USB_WritePMA(USBx, ep->xfer_buff, pmabuffer, (uint16_t)len);
}
}
/* auto Switch to single buffer mode when transfer <Mps no need to manage in double buffer */
else
{
len = ep->xfer_len_db;
/* disable double buffer mode for Bulk endpoint */
PCD_CLEAR_BULK_EP_DBUF(USBx, ep->num);
/* Set Tx count with nbre of byte to be transmitted */
PCD_SET_EP_TX_CNT(USBx, ep->num, len);
pmabuffer = ep->pmaaddr0;
/* Write the user buffer to USB PMA */
USB_WritePMA(USBx, ep->xfer_buff, pmabuffer, (uint16_t)len);
}
}
else /* manage isochronous double buffer IN mode */
{
/* each Time to write in PMA xfer_len_db will */
ep->xfer_len_db -= len;
/* Fill the data buffer */
if ((PCD_GET_ENDPOINT(USBx, ep->num) & USB_EP_DTOG_TX) != 0U)
{
/* Set the Double buffer counter for pmabuffer1 */
PCD_SET_EP_DBUF1_CNT(USBx, ep->num, ep->is_in, len);
pmabuffer = ep->pmaaddr1;
/* Write the user buffer to USB PMA */
USB_WritePMA(USBx, ep->xfer_buff, pmabuffer, (uint16_t)len);
}
else
{
/* Set the Double buffer counter for pmabuffer0 */
PCD_SET_EP_DBUF0_CNT(USBx, ep->num, ep->is_in, len);
pmabuffer = ep->pmaaddr0;
/* Write the user buffer to USB PMA */
USB_WritePMA(USBx, ep->xfer_buff, pmabuffer, (uint16_t)len);
}
}
}
#endif /* (USE_USB_DOUBLE_BUFFER == 1U) */
PCD_SET_EP_TX_STATUS(USBx, ep->num, USB_EP_TX_VALID);
}
else /* OUT endpoint */
{
if (ep->doublebuffer == 0U)
{
/* Multi packet transfer */
if (ep->xfer_len > ep->maxpacket)
{
len = ep->maxpacket;
ep->xfer_len -= len;
}
else
{
len = ep->xfer_len;
ep->xfer_len = 0U;
}
/* configure and validate Rx endpoint */
PCD_SET_EP_RX_CNT(USBx, ep->num, len);
}
#if (USE_USB_DOUBLE_BUFFER == 1U)
else
{
/* First Transfer Coming From HAL_PCD_EP_Receive & From ISR */
/* Set the Double buffer counter */
if (ep->type == EP_TYPE_BULK)
{
PCD_SET_EP_DBUF_CNT(USBx, ep->num, ep->is_in, ep->maxpacket);
/* Coming from ISR */
if (ep->xfer_count != 0U)
{
/* update last value to check if there is blocking state */
wEPVal = PCD_GET_ENDPOINT(USBx, ep->num);
/*Blocking State */
if ((((wEPVal & USB_EP_DTOG_RX) != 0U) && ((wEPVal & USB_EP_DTOG_TX) != 0U)) ||
(((wEPVal & USB_EP_DTOG_RX) == 0U) && ((wEPVal & USB_EP_DTOG_TX) == 0U)))
{
PCD_FREE_USER_BUFFER(USBx, ep->num, 0U);
}
}
}
/* iso out double */
else if (ep->type == EP_TYPE_ISOC)
{
/* Multi packet transfer */
if (ep->xfer_len > ep->maxpacket)
{
len = ep->maxpacket;
ep->xfer_len -= len;
}
else
{
len = ep->xfer_len;
ep->xfer_len = 0U;
}
PCD_SET_EP_DBUF_CNT(USBx, ep->num, ep->is_in, len);
}
else
{
return HAL_ERROR;
}
}
#endif /* (USE_USB_DOUBLE_BUFFER == 1U) */
PCD_SET_EP_RX_STATUS(USBx, ep->num, USB_EP_RX_VALID);
}
return HAL_OK;
}
/**
* @brief USB_EPSetStall set a stall condition over an EP
* @param USBx Selected device
* @param ep pointer to endpoint structure
* @retval HAL status
*/
HAL_StatusTypeDef USB_EPSetStall(USB_TypeDef *USBx, USB_EPTypeDef *ep)
{
if (ep->is_in != 0U)
{
PCD_SET_EP_TX_STATUS(USBx, ep->num, USB_EP_TX_STALL);
}
else
{
PCD_SET_EP_RX_STATUS(USBx, ep->num, USB_EP_RX_STALL);
}
return HAL_OK;
}
/**
* @brief USB_EPClearStall Clear a stall condition over an EP
* @param USBx Selected device
* @param ep pointer to endpoint structure
* @retval HAL status
*/
HAL_StatusTypeDef USB_EPClearStall(USB_TypeDef *USBx, USB_EPTypeDef *ep)
{
if (ep->doublebuffer == 0U)
{
if (ep->is_in != 0U)
{
PCD_CLEAR_TX_DTOG(USBx, ep->num);
if (ep->type != EP_TYPE_ISOC)
{
/* Configure NAK status for the Endpoint */
PCD_SET_EP_TX_STATUS(USBx, ep->num, USB_EP_TX_NAK);
}
}
else
{
PCD_CLEAR_RX_DTOG(USBx, ep->num);
/* Configure VALID status for the Endpoint */
PCD_SET_EP_RX_STATUS(USBx, ep->num, USB_EP_RX_VALID);
}
}
return HAL_OK;
}
/**
* @brief USB_EPStoptXfer Stop transfer on an EP
* @param USBx usb device instance
* @param ep pointer to endpoint structure
* @retval HAL status
*/
HAL_StatusTypeDef USB_EPStopXfer(USB_TypeDef *USBx, USB_EPTypeDef *ep)
{
/* IN endpoint */
if (ep->is_in == 1U)
{
if (ep->doublebuffer == 0U)
{
if (ep->type != EP_TYPE_ISOC)
{
/* Configure NAK status for the Endpoint */
PCD_SET_EP_TX_STATUS(USBx, ep->num, USB_EP_TX_NAK);
}
else
{
/* Configure TX Endpoint to disabled state */
PCD_SET_EP_TX_STATUS(USBx, ep->num, USB_EP_TX_DIS);
}
}
}
else /* OUT endpoint */
{
if (ep->doublebuffer == 0U)
{
if (ep->type != EP_TYPE_ISOC)
{
/* Configure NAK status for the Endpoint */
PCD_SET_EP_RX_STATUS(USBx, ep->num, USB_EP_RX_NAK);
}
else
{
/* Configure RX Endpoint to disabled state */
PCD_SET_EP_RX_STATUS(USBx, ep->num, USB_EP_RX_DIS);
}
}
}
return HAL_OK;
}
#endif /* defined (HAL_PCD_MODULE_ENABLED) */
/**
* @brief USB_StopDevice Stop the usb device mode
* @param USBx Selected device
* @retval HAL status
*/
HAL_StatusTypeDef USB_StopDevice(USB_TypeDef *USBx)
{
/* disable all interrupts and force USB reset */
USBx->CNTR = (uint16_t)USB_CNTR_FRES;
/* clear interrupt status register */
USBx->ISTR = 0U;
/* switch-off device */
USBx->CNTR = (uint16_t)(USB_CNTR_FRES | USB_CNTR_PDWN);
return HAL_OK;
}
/**
* @brief USB_SetDevAddress Stop the usb device mode
* @param USBx Selected device
* @param address new device address to be assigned
* This parameter can be a value from 0 to 255
* @retval HAL status
*/
HAL_StatusTypeDef USB_SetDevAddress(USB_TypeDef *USBx, uint8_t address)
{
if (address == 0U)
{
/* set device address and enable function */
USBx->DADDR = (uint16_t)USB_DADDR_EF;
}
return HAL_OK;
}
/**
* @brief USB_DevConnect Connect the USB device by enabling the pull-up/pull-down
* @param USBx Selected device
* @retval HAL status
*/
HAL_StatusTypeDef USB_DevConnect(USB_TypeDef *USBx)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(USBx);
/* NOTE : - This function is not required by USB Device FS peripheral, it is used
only by USB OTG FS peripheral.
- This function is added to ensure compatibility across platforms.
*/
return HAL_OK;
}
/**
* @brief USB_DevDisconnect Disconnect the USB device by disabling the pull-up/pull-down
* @param USBx Selected device
* @retval HAL status
*/
HAL_StatusTypeDef USB_DevDisconnect(USB_TypeDef *USBx)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(USBx);
/* NOTE : - This function is not required by USB Device FS peripheral, it is used
only by USB OTG FS peripheral.
- This function is added to ensure compatibility across platforms.
*/
return HAL_OK;
}
/**
* @brief USB_ReadInterrupts return the global USB interrupt status
* @param USBx Selected device
* @retval USB Global Interrupt status
*/
uint32_t USB_ReadInterrupts(USB_TypeDef const *USBx)
{
uint32_t tmpreg;
tmpreg = USBx->ISTR;
return tmpreg;
}
/**
* @brief USB_ReadDevAllOutEpInterrupt return the USB device OUT endpoints interrupt status
* @param USBx Selected device
* @retval HAL status
*/
uint32_t USB_ReadDevAllOutEpInterrupt(USB_TypeDef *USBx)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(USBx);
/* NOTE : - This function is not required by USB Device FS peripheral, it is used
only by USB OTG FS peripheral.
- This function is added to ensure compatibility across platforms.
*/
return (0);
}
/**
* @brief USB_ReadDevAllInEpInterrupt return the USB device IN endpoints interrupt status
* @param USBx Selected device
* @retval HAL status
*/
uint32_t USB_ReadDevAllInEpInterrupt(USB_TypeDef *USBx)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(USBx);
/* NOTE : - This function is not required by USB Device FS peripheral, it is used
only by USB OTG FS peripheral.
- This function is added to ensure compatibility across platforms.
*/
return (0);
}
/**
* @brief Returns Device OUT EP Interrupt register
* @param USBx Selected device
* @param epnum endpoint number
* This parameter can be a value from 0 to 15
* @retval Device OUT EP Interrupt register
*/
uint32_t USB_ReadDevOutEPInterrupt(USB_TypeDef *USBx, uint8_t epnum)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(USBx);
UNUSED(epnum);
/* NOTE : - This function is not required by USB Device FS peripheral, it is used
only by USB OTG FS peripheral.
- This function is added to ensure compatibility across platforms.
*/
return (0);
}
/**
* @brief Returns Device IN EP Interrupt register
* @param USBx Selected device
* @param epnum endpoint number
* This parameter can be a value from 0 to 15
* @retval Device IN EP Interrupt register
*/
uint32_t USB_ReadDevInEPInterrupt(USB_TypeDef *USBx, uint8_t epnum)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(USBx);
UNUSED(epnum);
/* NOTE : - This function is not required by USB Device FS peripheral, it is used
only by USB OTG FS peripheral.
- This function is added to ensure compatibility across platforms.
*/
return (0);
}
/**
* @brief USB_ClearInterrupts: clear a USB interrupt
* @param USBx Selected device
* @param interrupt flag
* @retval None
*/
void USB_ClearInterrupts(USB_TypeDef *USBx, uint32_t interrupt)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(USBx);
UNUSED(interrupt);
/* NOTE : - This function is not required by USB Device FS peripheral, it is used
only by USB OTG FS peripheral.
- This function is added to ensure compatibility across platforms.
*/
}
/**
* @brief Prepare the EP0 to start the first control setup
* @param USBx Selected device
* @param psetup pointer to setup packet
* @retval HAL status
*/
HAL_StatusTypeDef USB_EP0_OutStart(USB_TypeDef *USBx, uint8_t *psetup)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(USBx);
UNUSED(psetup);
/* NOTE : - This function is not required by USB Device FS peripheral, it is used
only by USB OTG FS peripheral.
- This function is added to ensure compatibility across platforms.
*/
return HAL_OK;
}
/**
* @brief USB_ActivateRemoteWakeup : active remote wakeup signalling
* @param USBx Selected device
* @retval HAL status
*/
HAL_StatusTypeDef USB_ActivateRemoteWakeup(USB_TypeDef *USBx)
{
USBx->CNTR |= (uint16_t)USB_CNTR_RESUME;
return HAL_OK;
}
/**
* @brief USB_DeActivateRemoteWakeup de-active remote wakeup signalling
* @param USBx Selected device
* @retval HAL status
*/
HAL_StatusTypeDef USB_DeActivateRemoteWakeup(USB_TypeDef *USBx)
{
USBx->CNTR &= (uint16_t)(~USB_CNTR_RESUME);
return HAL_OK;
}
/**
* @brief Copy a buffer from user memory area to packet memory area (PMA)
* @param USBx USB peripheral instance register address.
* @param pbUsrBuf pointer to user memory area.
* @param wPMABufAddr address into PMA.
* @param wNBytes no. of bytes to be copied.
* @retval None
*/
void USB_WritePMA(USB_TypeDef const *USBx, uint8_t *pbUsrBuf, uint16_t wPMABufAddr, uint16_t wNBytes)
{
uint32_t n = ((uint32_t)wNBytes + 1U) >> 1;
uint32_t BaseAddr = (uint32_t)USBx;
uint32_t count;
uint16_t WrVal;
__IO uint16_t *pdwVal;
uint8_t *pBuf = pbUsrBuf;
pdwVal = (__IO uint16_t *)(BaseAddr + 0x400U + ((uint32_t)wPMABufAddr * PMA_ACCESS));
for (count = n; count != 0U; count--)
{
WrVal = pBuf[0];
WrVal |= (uint16_t)pBuf[1] << 8;
*pdwVal = (WrVal & 0xFFFFU);
pdwVal++;
#if PMA_ACCESS > 1U
pdwVal++;
#endif /* PMA_ACCESS */
pBuf++;
pBuf++;
}
}
/**
* @brief Copy data from packet memory area (PMA) to user memory buffer
* @param USBx USB peripheral instance register address.
* @param pbUsrBuf pointer to user memory area.
* @param wPMABufAddr address into PMA.
* @param wNBytes no. of bytes to be copied.
* @retval None
*/
void USB_ReadPMA(USB_TypeDef const *USBx, uint8_t *pbUsrBuf, uint16_t wPMABufAddr, uint16_t wNBytes)
{
uint32_t n = (uint32_t)wNBytes >> 1;
uint32_t BaseAddr = (uint32_t)USBx;
uint32_t count;
uint32_t RdVal;
__IO uint16_t *pdwVal;
uint8_t *pBuf = pbUsrBuf;
pdwVal = (__IO uint16_t *)(BaseAddr + 0x400U + ((uint32_t)wPMABufAddr * PMA_ACCESS));
for (count = n; count != 0U; count--)
{
RdVal = *(__IO uint16_t *)pdwVal;
pdwVal++;
*pBuf = (uint8_t)((RdVal >> 0) & 0xFFU);
pBuf++;
*pBuf = (uint8_t)((RdVal >> 8) & 0xFFU);
pBuf++;
#if PMA_ACCESS > 1U
pdwVal++;
#endif /* PMA_ACCESS */
}
if ((wNBytes % 2U) != 0U)
{
RdVal = *pdwVal;
*pBuf = (uint8_t)((RdVal >> 0) & 0xFFU);
}
}
#endif /* defined (USB) */
/**
* @}
*/
/**
* @}
*/
#endif /* defined (USB) || defined (USB_OTG_FS) */
#endif /* defined (HAL_PCD_MODULE_ENABLED) || defined (HAL_HCD_MODULE_ENABLED) */
/**
* @}
*/

View File

@@ -0,0 +1,767 @@
/**
******************************************************************************
* @file stm32f1xx_ll_utils.c
* @author MCD Application Team
* @brief UTILS LL module driver.
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_ll_rcc.h"
#include "stm32f1xx_ll_utils.h"
#include "stm32f1xx_ll_system.h"
#ifdef USE_FULL_ASSERT
#include "stm32_assert.h"
#else
#define assert_param(expr) ((void)0U)
#endif
/** @addtogroup STM32F1xx_LL_Driver
* @{
*/
/** @addtogroup UTILS_LL
* @{
*/
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/** @addtogroup UTILS_LL_Private_Constants
* @{
*/
/* Defines used for PLL range */
#define UTILS_PLL_OUTPUT_MAX RCC_MAX_FREQUENCY /*!< Frequency max for PLL output, in Hz */
#define UTILS_PLL2_OUTPUT_MAX RCC_MAX_FREQUENCY /*!< Frequency max for PLL2 output, in Hz */
/* Defines used for HSE range */
#define UTILS_HSE_FREQUENCY_MIN RCC_HSE_MIN /*!< Frequency min for HSE frequency, in Hz */
#define UTILS_HSE_FREQUENCY_MAX RCC_HSE_MAX /*!< Frequency max for HSE frequency, in Hz */
/* Defines used for FLASH latency according to HCLK Frequency */
#if defined(FLASH_ACR_LATENCY)
#define UTILS_LATENCY1_FREQ 24000000U /*!< SYSCLK frequency to set FLASH latency 1 */
#define UTILS_LATENCY2_FREQ 48000000U /*!< SYSCLK frequency to set FLASH latency 2 */
#else
/*!< No Latency Configuration in this device */
#endif
/**
* @}
*/
/* Private macros ------------------------------------------------------------*/
/** @addtogroup UTILS_LL_Private_Macros
* @{
*/
#define IS_LL_UTILS_SYSCLK_DIV(__VALUE__) (((__VALUE__) == LL_RCC_SYSCLK_DIV_1) \
|| ((__VALUE__) == LL_RCC_SYSCLK_DIV_2) \
|| ((__VALUE__) == LL_RCC_SYSCLK_DIV_4) \
|| ((__VALUE__) == LL_RCC_SYSCLK_DIV_8) \
|| ((__VALUE__) == LL_RCC_SYSCLK_DIV_16) \
|| ((__VALUE__) == LL_RCC_SYSCLK_DIV_64) \
|| ((__VALUE__) == LL_RCC_SYSCLK_DIV_128) \
|| ((__VALUE__) == LL_RCC_SYSCLK_DIV_256) \
|| ((__VALUE__) == LL_RCC_SYSCLK_DIV_512))
#define IS_LL_UTILS_APB1_DIV(__VALUE__) (((__VALUE__) == LL_RCC_APB1_DIV_1) \
|| ((__VALUE__) == LL_RCC_APB1_DIV_2) \
|| ((__VALUE__) == LL_RCC_APB1_DIV_4) \
|| ((__VALUE__) == LL_RCC_APB1_DIV_8) \
|| ((__VALUE__) == LL_RCC_APB1_DIV_16))
#define IS_LL_UTILS_APB2_DIV(__VALUE__) (((__VALUE__) == LL_RCC_APB2_DIV_1) \
|| ((__VALUE__) == LL_RCC_APB2_DIV_2) \
|| ((__VALUE__) == LL_RCC_APB2_DIV_4) \
|| ((__VALUE__) == LL_RCC_APB2_DIV_8) \
|| ((__VALUE__) == LL_RCC_APB2_DIV_16))
#if defined(RCC_CFGR_PLLMULL6_5)
#define IS_LL_UTILS_PLLMUL_VALUE(__VALUE__) (((__VALUE__) == LL_RCC_PLL_MUL_4) \
|| ((__VALUE__) == LL_RCC_PLL_MUL_5) \
|| ((__VALUE__) == LL_RCC_PLL_MUL_6) \
|| ((__VALUE__) == LL_RCC_PLL_MUL_7) \
|| ((__VALUE__) == LL_RCC_PLL_MUL_8) \
|| ((__VALUE__) == LL_RCC_PLL_MUL_9) \
|| ((__VALUE__) == LL_RCC_PLL_MUL_6_5))
#else
#define IS_LL_UTILS_PLLMUL_VALUE(__VALUE__) (((__VALUE__) == LL_RCC_PLL_MUL_2) \
|| ((__VALUE__) == LL_RCC_PLL_MUL_3) \
|| ((__VALUE__) == LL_RCC_PLL_MUL_4) \
|| ((__VALUE__) == LL_RCC_PLL_MUL_5) \
|| ((__VALUE__) == LL_RCC_PLL_MUL_6) \
|| ((__VALUE__) == LL_RCC_PLL_MUL_7) \
|| ((__VALUE__) == LL_RCC_PLL_MUL_8) \
|| ((__VALUE__) == LL_RCC_PLL_MUL_9) \
|| ((__VALUE__) == LL_RCC_PLL_MUL_10) \
|| ((__VALUE__) == LL_RCC_PLL_MUL_11) \
|| ((__VALUE__) == LL_RCC_PLL_MUL_12) \
|| ((__VALUE__) == LL_RCC_PLL_MUL_13) \
|| ((__VALUE__) == LL_RCC_PLL_MUL_14) \
|| ((__VALUE__) == LL_RCC_PLL_MUL_15) \
|| ((__VALUE__) == LL_RCC_PLL_MUL_16))
#endif /* RCC_CFGR_PLLMULL6_5 */
#if defined(RCC_CFGR2_PREDIV1)
#define IS_LL_UTILS_PREDIV_VALUE(__VALUE__) (((__VALUE__) == LL_RCC_PREDIV_DIV_1) || ((__VALUE__) == LL_RCC_PREDIV_DIV_2) || \
((__VALUE__) == LL_RCC_PREDIV_DIV_3) || ((__VALUE__) == LL_RCC_PREDIV_DIV_4) || \
((__VALUE__) == LL_RCC_PREDIV_DIV_5) || ((__VALUE__) == LL_RCC_PREDIV_DIV_6) || \
((__VALUE__) == LL_RCC_PREDIV_DIV_7) || ((__VALUE__) == LL_RCC_PREDIV_DIV_8) || \
((__VALUE__) == LL_RCC_PREDIV_DIV_9) || ((__VALUE__) == LL_RCC_PREDIV_DIV_10) || \
((__VALUE__) == LL_RCC_PREDIV_DIV_11) || ((__VALUE__) == LL_RCC_PREDIV_DIV_12) || \
((__VALUE__) == LL_RCC_PREDIV_DIV_13) || ((__VALUE__) == LL_RCC_PREDIV_DIV_14) || \
((__VALUE__) == LL_RCC_PREDIV_DIV_15) || ((__VALUE__) == LL_RCC_PREDIV_DIV_16))
#else
#define IS_LL_UTILS_PREDIV_VALUE(__VALUE__) (((__VALUE__) == LL_RCC_PREDIV_DIV_1) || ((__VALUE__) == LL_RCC_PREDIV_DIV_2))
#endif /*RCC_PREDIV1_DIV_2_16_SUPPORT*/
#define IS_LL_UTILS_PLL_FREQUENCY(__VALUE__) ((__VALUE__) <= UTILS_PLL_OUTPUT_MAX)
#if defined(RCC_PLL2_SUPPORT)
#define IS_LL_UTILS_PLL2MUL_VALUE(__VALUE__) (((__VALUE__) == LL_RCC_PLL2_MUL_8) \
|| ((__VALUE__) == LL_RCC_PLL2_MUL_9) \
|| ((__VALUE__) == LL_RCC_PLL2_MUL_10) \
|| ((__VALUE__) == LL_RCC_PLL2_MUL_11) \
|| ((__VALUE__) == LL_RCC_PLL2_MUL_12) \
|| ((__VALUE__) == LL_RCC_PLL2_MUL_13) \
|| ((__VALUE__) == LL_RCC_PLL2_MUL_14) \
|| ((__VALUE__) == LL_RCC_PLL2_MUL_16) \
|| ((__VALUE__) == LL_RCC_PLL2_MUL_20))
#define IS_LL_UTILS_PREDIV2_VALUE(__VALUE__) (((__VALUE__) == LL_RCC_HSE_PREDIV2_DIV_1) || ((__VALUE__) == LL_RCC_HSE_PREDIV2_DIV_2) || \
((__VALUE__) == LL_RCC_HSE_PREDIV2_DIV_3) || ((__VALUE__) == LL_RCC_HSE_PREDIV2_DIV_4) || \
((__VALUE__) == LL_RCC_HSE_PREDIV2_DIV_5) || ((__VALUE__) == LL_RCC_HSE_PREDIV2_DIV_6) || \
((__VALUE__) == LL_RCC_HSE_PREDIV2_DIV_7) || ((__VALUE__) == LL_RCC_HSE_PREDIV2_DIV_8) || \
((__VALUE__) == LL_RCC_HSE_PREDIV2_DIV_9) || ((__VALUE__) == LL_RCC_HSE_PREDIV2_DIV_10) || \
((__VALUE__) == LL_RCC_HSE_PREDIV2_DIV_11) || ((__VALUE__) == LL_RCC_HSE_PREDIV2_DIV_12) || \
((__VALUE__) == LL_RCC_HSE_PREDIV2_DIV_13) || ((__VALUE__) == LL_RCC_HSE_PREDIV2_DIV_14) || \
((__VALUE__) == LL_RCC_HSE_PREDIV2_DIV_15) || ((__VALUE__) == LL_RCC_HSE_PREDIV2_DIV_16))
#define IS_LL_UTILS_PLL2_FREQUENCY(__VALUE__) ((__VALUE__) <= UTILS_PLL2_OUTPUT_MAX)
#endif /* RCC_PLL2_SUPPORT */
#define IS_LL_UTILS_HSE_BYPASS(__STATE__) (((__STATE__) == LL_UTILS_HSEBYPASS_ON) \
|| ((__STATE__) == LL_UTILS_HSEBYPASS_OFF))
#define IS_LL_UTILS_HSE_FREQUENCY(__FREQUENCY__) (((__FREQUENCY__) >= UTILS_HSE_FREQUENCY_MIN) && ((__FREQUENCY__) <= UTILS_HSE_FREQUENCY_MAX))
/**
* @}
*/
/* Private function prototypes -----------------------------------------------*/
/** @defgroup UTILS_LL_Private_Functions UTILS Private functions
* @{
*/
static uint32_t UTILS_GetPLLOutputFrequency(uint32_t PLL_InputFrequency,
LL_UTILS_PLLInitTypeDef *UTILS_PLLInitStruct);
static ErrorStatus UTILS_PLL_HSE_ConfigSystemClock(uint32_t PLL_InputFrequency, uint32_t HSEBypass,
LL_UTILS_PLLInitTypeDef *UTILS_PLLInitStruct,
LL_UTILS_ClkInitTypeDef *UTILS_ClkInitStruct);
#if defined(RCC_PLL2_SUPPORT)
static uint32_t UTILS_GetPLL2OutputFrequency(uint32_t PLL2_InputFrequency,
LL_UTILS_PLLInitTypeDef *UTILS_PLL2InitStruct);
#endif /* RCC_PLL2_SUPPORT */
static ErrorStatus UTILS_EnablePLLAndSwitchSystem(uint32_t SYSCLK_Frequency, LL_UTILS_ClkInitTypeDef *UTILS_ClkInitStruct);
static ErrorStatus UTILS_PLL_IsBusy(void);
/**
* @}
*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup UTILS_LL_Exported_Functions
* @{
*/
/** @addtogroup UTILS_LL_EF_DELAY
* @{
*/
/**
* @brief This function configures the Cortex-M SysTick source to have 1ms time base.
* @note When a RTOS is used, it is recommended to avoid changing the Systick
* configuration by calling this function, for a delay use rather osDelay RTOS service.
* @param HCLKFrequency HCLK frequency in Hz
* @note HCLK frequency can be calculated thanks to RCC helper macro or function @ref LL_RCC_GetSystemClocksFreq
* @retval None
*/
void LL_Init1msTick(uint32_t HCLKFrequency)
{
/* Use frequency provided in argument */
LL_InitTick(HCLKFrequency, 1000U);
}
/**
* @brief This function provides accurate delay (in milliseconds) based
* on SysTick counter flag
* @note When a RTOS is used, it is recommended to avoid using blocking delay
* and use rather osDelay service.
* @note To respect 1ms timebase, user should call @ref LL_Init1msTick function which
* will configure Systick to 1ms
* @param Delay specifies the delay time length, in milliseconds.
* @retval None
*/
void LL_mDelay(uint32_t Delay)
{
__IO uint32_t tmp = SysTick->CTRL; /* Clear the COUNTFLAG first */
/* Add this code to indicate that local variable is not used */
((void)tmp);
/* Add a period to guaranty minimum wait */
if (Delay < LL_MAX_DELAY)
{
Delay++;
}
while (Delay)
{
if ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) != 0U)
{
Delay--;
}
}
}
/**
* @}
*/
/** @addtogroup UTILS_EF_SYSTEM
* @brief System Configuration functions
*
@verbatim
===============================================================================
##### System Configuration functions #####
===============================================================================
[..]
System, AHB and APB buses clocks configuration
(+) The maximum frequency of the SYSCLK, HCLK, PCLK1 and PCLK2 is RCC_MAX_FREQUENCY Hz.
@endverbatim
@internal
Depending on the SYSCLK frequency, the flash latency should be adapted accordingly:
(++) +-----------------------------------------------+
(++) | Latency | SYSCLK clock frequency (MHz) |
(++) |---------------|-------------------------------|
(++) |0WS(1CPU cycle)| 0 < SYSCLK <= 24 |
(++) |---------------|-------------------------------|
(++) |1WS(2CPU cycle)| 24 < SYSCLK <= 48 |
(++) |---------------|-------------------------------|
(++) |2WS(3CPU cycle)| 48 < SYSCLK <= 72 |
(++) +-----------------------------------------------+
@endinternal
* @{
*/
/**
* @brief This function sets directly SystemCoreClock CMSIS variable.
* @note Variable can be calculated also through SystemCoreClockUpdate function.
* @param HCLKFrequency HCLK frequency in Hz (can be calculated thanks to RCC helper macro)
* @retval None
*/
void LL_SetSystemCoreClock(uint32_t HCLKFrequency)
{
/* HCLK clock frequency */
SystemCoreClock = HCLKFrequency;
}
/**
* @brief Update number of Flash wait states in line with new frequency and current
voltage range.
* @param Frequency SYSCLK frequency
* @retval An ErrorStatus enumeration value:
* - SUCCESS: Latency has been modified
* - ERROR: Latency cannot be modified
*/
#if defined(FLASH_ACR_LATENCY)
ErrorStatus LL_SetFlashLatency(uint32_t Frequency)
{
uint32_t timeout;
uint32_t getlatency;
uint32_t latency = LL_FLASH_LATENCY_0; /* default value 0WS */
ErrorStatus status = SUCCESS;
/* Frequency cannot be equal to 0 */
if (Frequency == 0U)
{
status = ERROR;
}
else
{
if (Frequency > UTILS_LATENCY2_FREQ)
{
/* 48 < SYSCLK <= 72 => 2WS (3 CPU cycles) */
latency = LL_FLASH_LATENCY_2;
}
else
{
if (Frequency > UTILS_LATENCY1_FREQ)
{
/* 24 < SYSCLK <= 48 => 1WS (2 CPU cycles) */
latency = LL_FLASH_LATENCY_1;
}
else
{
/* else SYSCLK < 24MHz default LL_FLASH_LATENCY_0 0WS */
latency = LL_FLASH_LATENCY_0;
}
}
if (status != ERROR)
{
LL_FLASH_SetLatency(latency);
/* Check that the new number of wait states is taken into account to access the Flash
memory by reading the FLASH_ACR register */
timeout = 2;
do
{
/* Wait for Flash latency to be updated */
getlatency = LL_FLASH_GetLatency();
timeout--;
}
while ((getlatency != latency) && (timeout > 0));
if (getlatency != latency)
{
status = ERROR;
}
else
{
status = SUCCESS;
}
}
}
return status;
}
#endif /* FLASH_ACR_LATENCY */
/**
* @brief This function configures system clock with HSI as clock source of the PLL
* @note The application need to ensure that PLL is disabled.
* @note Function is based on the following formula:
* - PLL output frequency = ((HSI frequency / PREDIV) * PLLMUL)
* - PREDIV: Set to 2 for few devices
* - PLLMUL: The application software must set correctly the PLL multiplication factor to
* not exceed 72MHz
* @note FLASH latency can be modified through this function.
* @param UTILS_PLLInitStruct pointer to a @ref LL_UTILS_PLLInitTypeDef structure that contains
* the configuration information for the PLL.
* @param UTILS_ClkInitStruct pointer to a @ref LL_UTILS_ClkInitTypeDef structure that contains
* the configuration information for the BUS prescalers.
* @retval An ErrorStatus enumeration value:
* - SUCCESS: Max frequency configuration done
* - ERROR: Max frequency configuration not done
*/
ErrorStatus LL_PLL_ConfigSystemClock_HSI(LL_UTILS_PLLInitTypeDef *UTILS_PLLInitStruct,
LL_UTILS_ClkInitTypeDef *UTILS_ClkInitStruct)
{
ErrorStatus status = SUCCESS;
uint32_t pllfreq = 0U;
/* Check if one of the PLL is enabled */
if (UTILS_PLL_IsBusy() == SUCCESS)
{
#if defined(RCC_PLLSRC_PREDIV1_SUPPORT)
/* Check PREDIV value */
assert_param(IS_LL_UTILS_PREDIV_VALUE(UTILS_PLLInitStruct->PLLDiv));
#else
/* Force PREDIV value to 2 */
UTILS_PLLInitStruct->Prediv = LL_RCC_PREDIV_DIV_2;
#endif /*RCC_PLLSRC_PREDIV1_SUPPORT*/
/* Calculate the new PLL output frequency */
pllfreq = UTILS_GetPLLOutputFrequency(HSI_VALUE, UTILS_PLLInitStruct);
/* Enable HSI if not enabled */
if (LL_RCC_HSI_IsReady() != 1U)
{
LL_RCC_HSI_Enable();
while (LL_RCC_HSI_IsReady() != 1U)
{
/* Wait for HSI ready */
}
}
/* Configure PLL */
LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSI_DIV_2, UTILS_PLLInitStruct->PLLMul);
/* Enable PLL and switch system clock to PLL */
status = UTILS_EnablePLLAndSwitchSystem(pllfreq, UTILS_ClkInitStruct);
}
else
{
/* Current PLL configuration cannot be modified */
status = ERROR;
}
return status;
}
/**
* @brief This function configures system clock with HSE as clock source of the PLL
* @note The application need to ensure that PLL is disabled.
* @note Function is based on the following formula:
* - PLL output frequency = ((HSI frequency / PREDIV) * PLLMUL)
* - PREDIV: Set to 2 for few devices
* - PLLMUL: The application software must set correctly the PLL multiplication factor to
* not exceed @ref UTILS_PLL_OUTPUT_MAX
* @note FLASH latency can be modified through this function.
* @param HSEFrequency Value between Min_Data = RCC_HSE_MIN and Max_Data = RCC_HSE_MAX
* @param HSEBypass This parameter can be one of the following values:
* @arg @ref LL_UTILS_HSEBYPASS_ON
* @arg @ref LL_UTILS_HSEBYPASS_OFF
* @param UTILS_PLLInitStruct pointer to a @ref LL_UTILS_PLLInitTypeDef structure that contains
* the configuration information for the PLL.
* @param UTILS_ClkInitStruct pointer to a @ref LL_UTILS_ClkInitTypeDef structure that contains
* the configuration information for the BUS prescalers.
* @retval An ErrorStatus enumeration value:
* - SUCCESS: Max frequency configuration done
* - ERROR: Max frequency configuration not done
*/
ErrorStatus LL_PLL_ConfigSystemClock_HSE(uint32_t HSEFrequency, uint32_t HSEBypass,
LL_UTILS_PLLInitTypeDef *UTILS_PLLInitStruct, LL_UTILS_ClkInitTypeDef *UTILS_ClkInitStruct)
{
ErrorStatus status = SUCCESS;
uint32_t pllfrequency = 0U;
/* Check the parameters */
assert_param(IS_LL_UTILS_HSE_FREQUENCY(HSEFrequency));
assert_param(IS_LL_UTILS_HSE_BYPASS(HSEBypass));
assert_param(IS_LL_UTILS_PREDIV_VALUE(UTILS_PLLInitStruct->Prediv));
/* Calculate the new PLL output frequency */
pllfrequency = UTILS_GetPLLOutputFrequency(HSEFrequency, UTILS_PLLInitStruct);
/* Enable HSE if not enabled */
status = UTILS_PLL_HSE_ConfigSystemClock(HSEFrequency, HSEBypass, UTILS_PLLInitStruct, UTILS_ClkInitStruct);
/* Check if HSE is not enabled*/
if (status == SUCCESS)
{
/* Configure PLL */
LL_RCC_PLL_ConfigDomain_SYS((LL_RCC_PLLSOURCE_HSE | UTILS_PLLInitStruct->Prediv), UTILS_PLLInitStruct->PLLMul);
/* Enable PLL and switch system clock to PLL */
status = UTILS_EnablePLLAndSwitchSystem(pllfrequency, UTILS_ClkInitStruct);
}
return status;
}
#if defined(RCC_PLL2_SUPPORT)
/**
* @brief This function configures system clock with HSE as clock source of the PLL, via PLL2
* @note The application need to ensure that PLL and PLL2 are disabled.
* @note Function is based on the following formula:
* - PLL output frequency = ((((HSE frequency / PREDIV2) * PLL2MUL) / PREDIV) * PLLMUL)
* - PREDIV, PLLMUL, PREDIV2, PLL2MUL: The application software must set correctly the
* PLL multiplication factor to not exceed @ref UTILS_PLL_OUTPUT_MAX
* @note FLASH latency can be modified through this function.
* @param HSEFrequency Value between Min_Data = RCC_HSE_MIN and Max_Data = RCC_HSE_MAX
* @param HSEBypass This parameter can be one of the following values:
* @arg @ref LL_UTILS_HSEBYPASS_ON
* @arg @ref LL_UTILS_HSEBYPASS_OFF
* @param UTILS_PLLInitStruct pointer to a @ref LL_UTILS_PLLInitTypeDef structure that contains
* the configuration information for the PLL.
* @param UTILS_PLL2InitStruct pointer to a @ref LL_UTILS_PLLInitTypeDef structure that contains
* the configuration information for the PLL2.
* @param UTILS_ClkInitStruct pointer to a @ref LL_UTILS_ClkInitTypeDef structure that contains
* the configuration information for the BUS prescalers.
* @retval An ErrorStatus enumeration value:
* - SUCCESS: Max frequency configuration done
* - ERROR: Max frequency configuration not done
*/
ErrorStatus LL_PLL_ConfigSystemClock_PLL2(uint32_t HSEFrequency, uint32_t HSEBypass,
LL_UTILS_PLLInitTypeDef *UTILS_PLLInitStruct,
LL_UTILS_PLLInitTypeDef *UTILS_PLL2InitStruct,
LL_UTILS_ClkInitTypeDef *UTILS_ClkInitStruct)
{
ErrorStatus status = SUCCESS;
uint32_t pllfrequency = 0U;
/* Check the parameters */
assert_param(IS_LL_UTILS_HSE_FREQUENCY(HSEFrequency));
assert_param(IS_LL_UTILS_HSE_BYPASS(HSEBypass));
assert_param(IS_LL_UTILS_PREDIV_VALUE(UTILS_PLLInitStruct->Prediv));
assert_param(IS_LL_UTILS_PREDIV2_VALUE(UTILS_PLL2InitStruct->Prediv));
/* Calculate the new PLL output frequency */
pllfrequency = UTILS_GetPLLOutputFrequency(HSEFrequency, UTILS_PLLInitStruct);
/* Enable HSE if not enabled */
status = UTILS_PLL_HSE_ConfigSystemClock(HSEFrequency, HSEBypass, UTILS_PLLInitStruct, UTILS_ClkInitStruct);
/* Check if HSE is not enabled*/
if (status == SUCCESS)
{
/* Configure PLL */
LL_RCC_PLL_ConfigDomain_PLL2(UTILS_PLL2InitStruct->Prediv, UTILS_PLL2InitStruct->PLLMul);
LL_RCC_PLL_ConfigDomain_SYS((LL_RCC_PLLSOURCE_PLL2 | UTILS_PLLInitStruct->Prediv), UTILS_PLLInitStruct->PLLMul);
/* Calculate the new PLL output frequency */
pllfrequency = UTILS_GetPLL2OutputFrequency(pllfrequency, UTILS_PLL2InitStruct);
/* Enable PLL and switch system clock to PLL */
status = UTILS_EnablePLLAndSwitchSystem(pllfrequency, UTILS_ClkInitStruct);
}
return status;
}
#endif /* RCC_PLL2_SUPPORT */
/**
* @}
*/
/**
* @}
*/
/** @addtogroup UTILS_LL_Private_Functions
* @{
*/
/**
* @brief Function to check that PLL can be modified
* @param PLL_InputFrequency PLL input frequency (in Hz)
* @param UTILS_PLLInitStruct pointer to a @ref LL_UTILS_PLLInitTypeDef structure that contains
* the configuration information for the PLL.
* @retval PLL output frequency (in Hz)
*/
static uint32_t UTILS_GetPLLOutputFrequency(uint32_t PLL_InputFrequency, LL_UTILS_PLLInitTypeDef *UTILS_PLLInitStruct)
{
uint32_t pllfreq = 0U;
/* Check the parameters */
assert_param(IS_LL_UTILS_PLLMUL_VALUE(UTILS_PLLInitStruct->PLLMul));
/* Check different PLL parameters according to RM */
#if defined (RCC_CFGR2_PREDIV1)
pllfreq = __LL_RCC_CALC_PLLCLK_FREQ(PLL_InputFrequency / (UTILS_PLLInitStruct->Prediv + 1U), UTILS_PLLInitStruct->PLLMul);
#else
pllfreq = __LL_RCC_CALC_PLLCLK_FREQ(PLL_InputFrequency / ((UTILS_PLLInitStruct->Prediv >> RCC_CFGR_PLLXTPRE_Pos) + 1U), UTILS_PLLInitStruct->PLLMul);
#endif /*RCC_CFGR2_PREDIV1SRC*/
assert_param(IS_LL_UTILS_PLL_FREQUENCY(pllfreq));
return pllfreq;
}
/**
* @brief This function enable the HSE when it is used by PLL or PLL2
* @note The application need to ensure that PLL is disabled.
* @param HSEFrequency Value between Min_Data = RCC_HSE_MIN and Max_Data = RCC_HSE_MAX
* @param HSEBypass This parameter can be one of the following values:
* @arg @ref LL_UTILS_HSEBYPASS_ON
* @arg @ref LL_UTILS_HSEBYPASS_OFF
* @param UTILS_PLLInitStruct pointer to a @ref LL_UTILS_PLLInitTypeDef structure that contains
* the configuration information for the PLL.
* @param UTILS_ClkInitStruct pointer to a @ref LL_UTILS_ClkInitTypeDef structure that contains
* the configuration information for the BUS prescalers.
* @retval An ErrorStatus enumeration value:
* - SUCCESS: HSE configuration done
* - ERROR: HSE configuration not done
*/
static ErrorStatus UTILS_PLL_HSE_ConfigSystemClock(uint32_t PLL_InputFrequency, uint32_t HSEBypass,
LL_UTILS_PLLInitTypeDef *UTILS_PLLInitStruct,
LL_UTILS_ClkInitTypeDef *UTILS_ClkInitStruct)
{
ErrorStatus status = SUCCESS;
/* Check if one of the PLL is enabled */
if (UTILS_PLL_IsBusy() == SUCCESS)
{
/* Enable HSE if not enabled */
if (LL_RCC_HSE_IsReady() != 1U)
{
/* Check if need to enable HSE bypass feature or not */
if (HSEBypass == LL_UTILS_HSEBYPASS_ON)
{
LL_RCC_HSE_EnableBypass();
}
else
{
LL_RCC_HSE_DisableBypass();
}
/* Enable HSE */
LL_RCC_HSE_Enable();
while (LL_RCC_HSE_IsReady() != 1U)
{
/* Wait for HSE ready */
}
}
}
else
{
/* Current PLL configuration cannot be modified */
status = ERROR;
}
return status;
}
#if defined(RCC_PLL2_SUPPORT)
/**
* @brief Function to check that PLL2 can be modified
* @param PLL2_InputFrequency PLL2 input frequency (in Hz)
* @param UTILS_PLL2InitStruct pointer to a @ref LL_UTILS_PLLInitTypeDef structure that contains
* the configuration information for the PLL.
* @retval PLL2 output frequency (in Hz)
*/
static uint32_t UTILS_GetPLL2OutputFrequency(uint32_t PLL2_InputFrequency, LL_UTILS_PLLInitTypeDef *UTILS_PLL2InitStruct)
{
uint32_t pll2freq = 0U;
/* Check the parameters */
assert_param(IS_LL_UTILS_PLL2MUL_VALUE(UTILS_PLL2InitStruct->PLLMul));
assert_param(IS_LL_UTILS_PREDIV2_VALUE(UTILS_PLL2InitStruct->Prediv));
/* Check different PLL2 parameters according to RM */
pll2freq = __LL_RCC_CALC_PLL2CLK_FREQ(PLL2_InputFrequency, UTILS_PLL2InitStruct->PLLMul, UTILS_PLL2InitStruct->Prediv);
assert_param(IS_LL_UTILS_PLL2_FREQUENCY(pll2freq));
return pll2freq;
}
#endif /* RCC_PLL2_SUPPORT */
/**
* @brief Function to check that PLL can be modified
* @retval An ErrorStatus enumeration value:
* - SUCCESS: PLL modification can be done
* - ERROR: PLL is busy
*/
static ErrorStatus UTILS_PLL_IsBusy(void)
{
ErrorStatus status = SUCCESS;
/* Check if PLL is busy*/
if (LL_RCC_PLL_IsReady() != 0U)
{
/* PLL configuration cannot be modified */
status = ERROR;
}
#if defined(RCC_PLL2_SUPPORT)
/* Check if PLL2 is busy*/
if (LL_RCC_PLL2_IsReady() != 0U)
{
/* PLL2 configuration cannot be modified */
status = ERROR;
}
#endif /* RCC_PLL2_SUPPORT */
#if defined(RCC_PLLI2S_SUPPORT)
/* Check if PLLI2S is busy*/
if (LL_RCC_PLLI2S_IsReady() != 0U)
{
/* PLLI2S configuration cannot be modified */
status = ERROR;
}
#endif /* RCC_PLLI2S_SUPPORT */
return status;
}
/**
* @brief Function to enable PLL and switch system clock to PLL
* @param SYSCLK_Frequency SYSCLK frequency
* @param UTILS_ClkInitStruct pointer to a @ref LL_UTILS_ClkInitTypeDef structure that contains
* the configuration information for the BUS prescalers.
* @retval An ErrorStatus enumeration value:
* - SUCCESS: No problem to switch system to PLL
* - ERROR: Problem to switch system to PLL
*/
static ErrorStatus UTILS_EnablePLLAndSwitchSystem(uint32_t SYSCLK_Frequency, LL_UTILS_ClkInitTypeDef *UTILS_ClkInitStruct)
{
ErrorStatus status = SUCCESS;
#if defined(FLASH_ACR_LATENCY)
uint32_t sysclk_frequency_current = 0U;
#endif /* FLASH_ACR_LATENCY */
assert_param(IS_LL_UTILS_SYSCLK_DIV(UTILS_ClkInitStruct->AHBCLKDivider));
assert_param(IS_LL_UTILS_APB1_DIV(UTILS_ClkInitStruct->APB1CLKDivider));
assert_param(IS_LL_UTILS_APB2_DIV(UTILS_ClkInitStruct->APB2CLKDivider));
#if defined(FLASH_ACR_LATENCY)
/* Calculate current SYSCLK frequency */
sysclk_frequency_current = (SystemCoreClock << AHBPrescTable[LL_RCC_GetAHBPrescaler() >> RCC_CFGR_HPRE_Pos]);
#endif /* FLASH_ACR_LATENCY */
/* Increasing the number of wait states because of higher CPU frequency */
#if defined (FLASH_ACR_LATENCY)
if (sysclk_frequency_current < SYSCLK_Frequency)
{
/* Set FLASH latency to highest latency */
status = LL_SetFlashLatency(SYSCLK_Frequency);
}
#endif /* FLASH_ACR_LATENCY */
/* Update system clock configuration */
if (status == SUCCESS)
{
#if defined(RCC_PLL2_SUPPORT)
if (LL_RCC_PLL_GetMainSource() != LL_RCC_PLLSOURCE_HSI_DIV_2)
{
/* Enable PLL2 */
LL_RCC_PLL2_Enable();
while (LL_RCC_PLL2_IsReady() != 1U)
{
/* Wait for PLL2 ready */
}
}
#endif /* RCC_PLL2_SUPPORT */
/* Enable PLL */
LL_RCC_PLL_Enable();
while (LL_RCC_PLL_IsReady() != 1U)
{
/* Wait for PLL ready */
}
/* Sysclk activation on the main PLL */
LL_RCC_SetAHBPrescaler(UTILS_ClkInitStruct->AHBCLKDivider);
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);
while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL)
{
/* Wait for system clock switch to PLL */
}
/* Set APB1 & APB2 prescaler*/
LL_RCC_SetAPB1Prescaler(UTILS_ClkInitStruct->APB1CLKDivider);
LL_RCC_SetAPB2Prescaler(UTILS_ClkInitStruct->APB2CLKDivider);
}
/* Decreasing the number of wait states because of lower CPU frequency */
#if defined (FLASH_ACR_LATENCY)
if (sysclk_frequency_current > SYSCLK_Frequency)
{
/* Set FLASH latency to lowest latency */
status = LL_SetFlashLatency(SYSCLK_Frequency);
}
#endif /* FLASH_ACR_LATENCY */
/* Update SystemCoreClock variable */
if (status == SUCCESS)
{
LL_SetSystemCoreClock(__LL_RCC_CALC_HCLK_FREQ(SYSCLK_Frequency, UTILS_ClkInitStruct->AHBCLKDivider));
}
return status;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/