| /** |
| ****************************************************************************** |
| * @file stm32l4xx_hal_ospi.c |
| * @author MCD Application Team |
| * @brief OSPI HAL module driver. |
| This file provides firmware functions to manage the following |
| functionalities of the OctoSPI interface (OSPI). |
| + Initialization and de-initialization functions |
| + Hyperbus configuration |
| + Indirect functional mode management |
| + Memory-mapped functional mode management |
| + Auto-polling functional mode management |
| + Interrupts and flags management |
| + DMA channel configuration for indirect functional mode |
| + Errors management and abort functionality |
| + IO manager configuration |
| |
| ****************************************************************************** |
| * @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 ##### |
| =============================================================================== |
| [..] |
| *** Initialization *** |
| ====================== |
| [..] |
| As prerequisite, fill in the HAL_OSPI_MspInit() : |
| (+) Enable OctoSPI and OctoSPIM clocks interface with __HAL_RCC_OSPIx_CLK_ENABLE(). |
| (+) Reset OctoSPI Peripheral with __HAL_RCC_OSPIx_FORCE_RESET() and __HAL_RCC_OSPIx_RELEASE_RESET(). |
| (+) Enable the clocks for the OctoSPI GPIOS with __HAL_RCC_GPIOx_CLK_ENABLE(). |
| (+) Configure these OctoSPI pins in alternate mode using HAL_GPIO_Init(). |
| (+) If interrupt or DMA mode is used, enable and configure OctoSPI global |
| interrupt with HAL_NVIC_SetPriority() and HAL_NVIC_EnableIRQ(). |
| (+) If DMA mode is used, enable the clocks for the OctoSPI DMA channel |
| with __HAL_RCC_DMAx_CLK_ENABLE(), configure DMA with HAL_DMA_Init(), |
| link it with OctoSPI handle using __HAL_LINKDMA(), enable and configure |
| DMA channel global interrupt with HAL_NVIC_SetPriority() and HAL_NVIC_EnableIRQ(). |
| [..] |
| Configure the fifo threshold, the dual-quad mode, the memory type, the |
| device size, the CS high time, the free running clock, the clock mode, |
| the wrap size, the clock prescaler, the sample shifting, the hold delay |
| and the CS boundary using the HAL_OSPI_Init() function. |
| [..] |
| When using Hyperbus, configure the RW recovery time, the access time, |
| the write latency and the latency mode using the HAL_OSPI_HyperbusCfg() |
| function. |
| |
| *** Indirect functional mode *** |
| ================================ |
| [..] |
| In regular mode, configure the command sequence using the HAL_OSPI_Command() |
| or HAL_OSPI_Command_IT() functions : |
| (+) Instruction phase : the mode used and if present the size, the instruction |
| opcode and the DTR mode. |
| (+) Address phase : the mode used and if present the size, the address |
| value and the DTR mode. |
| (+) Alternate-bytes phase : the mode used and if present the size, the |
| alternate bytes values and the DTR mode. |
| (+) Dummy-cycles phase : the number of dummy cycles (mode used is same as data phase). |
| (+) Data phase : the mode used and if present the number of bytes and the DTR mode. |
| (+) Data strobe (DQS) mode : the activation (or not) of this mode |
| (+) Sending Instruction Only Once (SIOO) mode : the activation (or not) of this mode. |
| (+) Flash identifier : in dual-quad mode, indicates which flash is concerned |
| (+) Operation type : always common configuration |
| [..] |
| In Hyperbus mode, configure the command sequence using the HAL_OSPI_HyperbusCmd() |
| function : |
| (+) Address space : indicate if the access will be done in register or memory |
| (+) Address size |
| (+) Number of data |
| (+) Data strobe (DQS) mode : the activation (or not) of this mode |
| [..] |
| If no data is required for the command (only for regular mode, not for |
| Hyperbus mode), it is sent directly to the memory : |
| (+) In polling mode, the output of the function is done when the transfer is complete. |
| (+) In interrupt mode, HAL_OSPI_CmdCpltCallback() will be called when the transfer is complete. |
| [..] |
| For the indirect write mode, use HAL_OSPI_Transmit(), HAL_OSPI_Transmit_DMA() or |
| HAL_OSPI_Transmit_IT() after the command configuration : |
| (+) In polling mode, the output of the function is done when the transfer is complete. |
| (+) In interrupt mode, HAL_OSPI_FifoThresholdCallback() will be called when the fifo threshold |
| is reached and HAL_OSPI_TxCpltCallback() will be called when the transfer is complete. |
| (+) In DMA mode, HAL_OSPI_TxHalfCpltCallback() will be called at the half transfer and |
| HAL_OSPI_TxCpltCallback() will be called when the transfer is complete. |
| [..] |
| For the indirect read mode, use HAL_OSPI_Receive(), HAL_OSPI_Receive_DMA() or |
| HAL_OSPI_Receive_IT() after the command configuration : |
| (+) In polling mode, the output of the function is done when the transfer is complete. |
| (+) In interrupt mode, HAL_OSPI_FifoThresholdCallback() will be called when the fifo threshold |
| is reached and HAL_OSPI_RxCpltCallback() will be called when the transfer is complete. |
| (+) In DMA mode, HAL_OSPI_RxHalfCpltCallback() will be called at the half transfer and |
| HAL_OSPI_RxCpltCallback() will be called when the transfer is complete. |
| |
| *** Auto-polling functional mode *** |
| ==================================== |
| [..] |
| Configure the command sequence by the same way than the indirect mode |
| [..] |
| Configure the auto-polling functional mode using the HAL_OSPI_AutoPolling() |
| or HAL_OSPI_AutoPolling_IT() functions : |
| (+) The size of the status bytes, the match value, the mask used, the match mode (OR/AND), |
| the polling interval and the automatic stop activation. |
| [..] |
| After the configuration : |
| (+) In polling mode, the output of the function is done when the status match is reached. The |
| automatic stop is activated to avoid an infinite loop. |
| (+) In interrupt mode, HAL_OSPI_StatusMatchCallback() will be called each time the status match is reached. |
| |
| *** Memory-mapped functional mode *** |
| ===================================== |
| [..] |
| Configure the command sequence by the same way than the indirect mode except |
| for the operation type in regular mode : |
| (+) Operation type equals to read configuration : the command configuration |
| applies to read access in memory-mapped mode |
| (+) Operation type equals to write configuration : the command configuration |
| applies to write access in memory-mapped mode |
| (+) Both read and write configuration should be performed before activating |
| memory-mapped mode |
| [..] |
| Configure the memory-mapped functional mode using the HAL_OSPI_MemoryMapped() |
| functions : |
| (+) The timeout activation and the timeout period. |
| [..] |
| After the configuration, the OctoSPI will be used as soon as an access on the AHB is done on |
| the address range. HAL_OSPI_TimeOutCallback() will be called when the timeout expires. |
| |
| *** Errors management and abort functionality *** |
| ================================================= |
| [..] |
| HAL_OSPI_GetError() function gives the error raised during the last operation. |
| [..] |
| HAL_OSPI_Abort() and HAL_OSPI_AbortIT() functions aborts any on-going operation and |
| flushes the fifo : |
| (+) In polling mode, the output of the function is done when the transfer |
| complete bit is set and the busy bit cleared. |
| (+) In interrupt mode, HAL_OSPI_AbortCpltCallback() will be called when |
| the transfer complete bit is set. |
| |
| *** Control functions *** |
| ========================= |
| [..] |
| HAL_OSPI_GetState() function gives the current state of the HAL OctoSPI driver. |
| [..] |
| HAL_OSPI_SetTimeout() function configures the timeout value used in the driver. |
| [..] |
| HAL_OSPI_SetFifoThreshold() function configures the threshold on the Fifo of the OSPI Peripheral. |
| [..] |
| HAL_OSPI_GetFifoThreshold() function gives the current of the Fifo's threshold |
| |
| *** IO manager configuration functions *** |
| ========================================== |
| [..] |
| HAL_OSPIM_Config() function configures the IO manager for the OctoSPI instance. |
| |
| *** Callback registration *** |
| ============================================= |
| [..] |
| The compilation define USE_HAL_OSPI_REGISTER_CALLBACKS when set to 1 |
| allows the user to configure dynamically the driver callbacks. |
| |
| [..] |
| Use function HAL_OSPI_RegisterCallback() to register a user callback, |
| it allows to register following callbacks: |
| (+) ErrorCallback : callback when error occurs. |
| (+) AbortCpltCallback : callback when abort is completed. |
| (+) FifoThresholdCallback : callback when the fifo threshold is reached. |
| (+) CmdCpltCallback : callback when a command without data is completed. |
| (+) RxCpltCallback : callback when a reception transfer is completed. |
| (+) TxCpltCallback : callback when a transmission transfer is completed. |
| (+) RxHalfCpltCallback : callback when half of the reception transfer is completed. |
| (+) TxHalfCpltCallback : callback when half of the transmission transfer is completed. |
| (+) StatusMatchCallback : callback when a status match occurs. |
| (+) TimeOutCallback : callback when the timeout perioed expires. |
| (+) MspInitCallback : OSPI MspInit. |
| (+) MspDeInitCallback : OSPI MspDeInit. |
| [..] |
| This function takes as parameters the HAL peripheral handle, the Callback ID |
| and a pointer to the user callback function. |
| |
| [..] |
| Use function HAL_OSPI_UnRegisterCallback() to reset a callback to the default |
| weak (overridden) function. It allows to reset following callbacks: |
| (+) ErrorCallback : callback when error occurs. |
| (+) AbortCpltCallback : callback when abort is completed. |
| (+) FifoThresholdCallback : callback when the fifo threshold is reached. |
| (+) CmdCpltCallback : callback when a command without data is completed. |
| (+) RxCpltCallback : callback when a reception transfer is completed. |
| (+) TxCpltCallback : callback when a transmission transfer is completed. |
| (+) RxHalfCpltCallback : callback when half of the reception transfer is completed. |
| (+) TxHalfCpltCallback : callback when half of the transmission transfer is completed. |
| (+) StatusMatchCallback : callback when a status match occurs. |
| (+) TimeOutCallback : callback when the timeout perioed expires. |
| (+) MspInitCallback : OSPI MspInit. |
| (+) MspDeInitCallback : OSPI MspDeInit. |
| [..] |
| This function) takes as parameters the HAL peripheral handle and the Callback ID. |
| |
| [..] |
| By default, after the HAL_OSPI_Init() and if the state is HAL_OSPI_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_OSPI_Init() |
| and HAL_OSPI_DeInit() only when these callbacks are null (not registered beforehand). |
| If not, MspInit or MspDeInit are not null, the HAL_OSPI_Init() and HAL_OSPI_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_OSPI_RegisterCallback() before calling HAL_OSPI_DeInit() |
| or HAL_OSPI_Init() function. |
| |
| [..] |
| When The compilation define USE_HAL_OSPI_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 "stm32l4xx_hal.h" |
| |
| #if defined(OCTOSPI) || defined(OCTOSPI1) || defined(OCTOSPI2) |
| |
| /** @addtogroup STM32L4xx_HAL_Driver |
| * @{ |
| */ |
| |
| /** @defgroup OSPI OSPI |
| * @brief OSPI HAL module driver |
| * @{ |
| */ |
| |
| #ifdef HAL_OSPI_MODULE_ENABLED |
| |
| /** |
| @cond 0 |
| */ |
| /* Private typedef -----------------------------------------------------------*/ |
| |
| /* Private define ------------------------------------------------------------*/ |
| #define OSPI_FUNCTIONAL_MODE_INDIRECT_WRITE ((uint32_t)0x00000000) /*!< Indirect write mode */ |
| #define OSPI_FUNCTIONAL_MODE_INDIRECT_READ ((uint32_t)OCTOSPI_CR_FMODE_0) /*!< Indirect read mode */ |
| #define OSPI_FUNCTIONAL_MODE_AUTO_POLLING ((uint32_t)OCTOSPI_CR_FMODE_1) /*!< Automatic polling mode */ |
| #define OSPI_FUNCTIONAL_MODE_MEMORY_MAPPED ((uint32_t)OCTOSPI_CR_FMODE) /*!< Memory-mapped mode */ |
| |
| #define OSPI_CFG_STATE_MASK 0x00000004U |
| #define OSPI_BUSY_STATE_MASK 0x00000008U |
| |
| #define OSPI_NB_INSTANCE 2U |
| #define OSPI_IOM_NB_PORTS 2U |
| #define OSPI_IOM_PORT_MASK 0x1U |
| |
| /* Private macro -------------------------------------------------------------*/ |
| #define IS_OSPI_FUNCTIONAL_MODE(MODE) (((MODE) == OSPI_FUNCTIONAL_MODE_INDIRECT_WRITE) || \ |
| ((MODE) == OSPI_FUNCTIONAL_MODE_INDIRECT_READ) || \ |
| ((MODE) == OSPI_FUNCTIONAL_MODE_AUTO_POLLING) || \ |
| ((MODE) == OSPI_FUNCTIONAL_MODE_MEMORY_MAPPED)) |
| |
| /* Private variables ---------------------------------------------------------*/ |
| |
| /* Private function prototypes -----------------------------------------------*/ |
| static void OSPI_DMACplt(DMA_HandleTypeDef *hdma); |
| static void OSPI_DMAHalfCplt(DMA_HandleTypeDef *hdma); |
| static void OSPI_DMAError(DMA_HandleTypeDef *hdma); |
| static void OSPI_DMAAbortCplt(DMA_HandleTypeDef *hdma); |
| static HAL_StatusTypeDef OSPI_WaitFlagStateUntilTimeout(OSPI_HandleTypeDef *hospi, uint32_t Flag, FlagStatus State, |
| uint32_t Tickstart, uint32_t Timeout); |
| static HAL_StatusTypeDef OSPI_ConfigCmd(OSPI_HandleTypeDef *hospi, OSPI_RegularCmdTypeDef *cmd); |
| static HAL_StatusTypeDef OSPIM_GetConfig(uint8_t instance_nb, OSPIM_CfgTypeDef *cfg); |
| /** |
| @endcond |
| */ |
| |
| /* Exported functions --------------------------------------------------------*/ |
| |
| /** @defgroup OSPI_Exported_Functions OSPI Exported Functions |
| * @{ |
| */ |
| |
| /** @defgroup OSPI_Exported_Functions_Group1 Initialization/de-initialization functions |
| * @brief Initialization and Configuration functions |
| * |
| @verbatim |
| =============================================================================== |
| ##### Initialization and Configuration functions ##### |
| =============================================================================== |
| [..] |
| This subsection provides a set of functions allowing to : |
| (+) Initialize the OctoSPI. |
| (+) De-initialize the OctoSPI. |
| |
| @endverbatim |
| * @{ |
| */ |
| |
| /** |
| * @brief Initialize the OSPI mode according to the specified parameters |
| * in the OSPI_InitTypeDef and initialize the associated handle. |
| * @param hospi : OSPI handle |
| * @retval HAL status |
| */ |
| HAL_StatusTypeDef HAL_OSPI_Init(OSPI_HandleTypeDef *hospi) |
| { |
| HAL_StatusTypeDef status = HAL_OK; |
| uint32_t tickstart = HAL_GetTick(); |
| |
| /* Check the OSPI handle allocation */ |
| if (hospi == NULL) |
| { |
| status = HAL_ERROR; |
| /* No error code can be set set as the handler is null */ |
| } |
| else |
| { |
| /* Check the parameters of the initialization structure */ |
| assert_param(IS_OSPI_FIFO_THRESHOLD(hospi->Init.FifoThreshold)); |
| assert_param(IS_OSPI_DUALQUAD_MODE(hospi->Init.DualQuad)); |
| assert_param(IS_OSPI_MEMORY_TYPE(hospi->Init.MemoryType)); |
| assert_param(IS_OSPI_DEVICE_SIZE(hospi->Init.DeviceSize)); |
| assert_param(IS_OSPI_CS_HIGH_TIME(hospi->Init.ChipSelectHighTime)); |
| assert_param(IS_OSPI_FREE_RUN_CLK(hospi->Init.FreeRunningClock)); |
| assert_param(IS_OSPI_CLOCK_MODE(hospi->Init.ClockMode)); |
| assert_param(IS_OSPI_CLK_PRESCALER(hospi->Init.ClockPrescaler)); |
| assert_param(IS_OSPI_SAMPLE_SHIFTING(hospi->Init.SampleShifting)); |
| assert_param(IS_OSPI_DHQC(hospi->Init.DelayHoldQuarterCycle)); |
| assert_param(IS_OSPI_CS_BOUNDARY(hospi->Init.ChipSelectBoundary)); |
| assert_param(IS_OSPI_DLYBYP(hospi->Init.DelayBlockBypass)); |
| #if defined (OCTOSPI_DCR3_MAXTRAN) |
| assert_param(IS_OSPI_MAXTRAN(hospi->Init.MaxTran)); |
| #endif |
| |
| /* Initialize error code */ |
| hospi->ErrorCode = HAL_OSPI_ERROR_NONE; |
| |
| /* Check if the state is the reset state */ |
| if (hospi->State == HAL_OSPI_STATE_RESET) |
| { |
| #if defined (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) |
| /* Reset Callback pointers in HAL_OSPI_STATE_RESET only */ |
| hospi->ErrorCallback = HAL_OSPI_ErrorCallback; |
| hospi->AbortCpltCallback = HAL_OSPI_AbortCpltCallback; |
| hospi->FifoThresholdCallback = HAL_OSPI_FifoThresholdCallback; |
| hospi->CmdCpltCallback = HAL_OSPI_CmdCpltCallback; |
| hospi->RxCpltCallback = HAL_OSPI_RxCpltCallback; |
| hospi->TxCpltCallback = HAL_OSPI_TxCpltCallback; |
| hospi->RxHalfCpltCallback = HAL_OSPI_RxHalfCpltCallback; |
| hospi->TxHalfCpltCallback = HAL_OSPI_TxHalfCpltCallback; |
| hospi->StatusMatchCallback = HAL_OSPI_StatusMatchCallback; |
| hospi->TimeOutCallback = HAL_OSPI_TimeOutCallback; |
| |
| if (hospi->MspInitCallback == NULL) |
| { |
| hospi->MspInitCallback = HAL_OSPI_MspInit; |
| } |
| |
| /* Init the low level hardware */ |
| hospi->MspInitCallback(hospi); |
| #else |
| /* Initialization of the low level hardware */ |
| HAL_OSPI_MspInit(hospi); |
| #endif /* defined (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) */ |
| |
| /* Configure the default timeout for the OSPI memory access */ |
| (void)HAL_OSPI_SetTimeout(hospi, HAL_OSPI_TIMEOUT_DEFAULT_VALUE); |
| |
| /* Configure memory type, device size, chip select high time, delay block bypass, |
| free running clock, clock mode */ |
| MODIFY_REG(hospi->Instance->DCR1, |
| (OCTOSPI_DCR1_MTYP | OCTOSPI_DCR1_DEVSIZE | OCTOSPI_DCR1_CSHT | OCTOSPI_DCR1_DLYBYP | |
| OCTOSPI_DCR1_FRCK | OCTOSPI_DCR1_CKMODE), |
| (hospi->Init.MemoryType | ((hospi->Init.DeviceSize - 1U) << OCTOSPI_DCR1_DEVSIZE_Pos) | |
| ((hospi->Init.ChipSelectHighTime - 1U) << OCTOSPI_DCR1_CSHT_Pos) | |
| hospi->Init.DelayBlockBypass | hospi->Init.ClockMode)); |
| |
| #if defined (OCTOSPI_DCR3_MAXTRAN) |
| /* Configure chip select boundary and maximum transfer */ |
| hospi->Instance->DCR3 = ((hospi->Init.ChipSelectBoundary << OCTOSPI_DCR3_CSBOUND_Pos) | |
| (hospi->Init.MaxTran << OCTOSPI_DCR3_MAXTRAN_Pos)); |
| #else |
| /* Configure chip select boundary */ |
| hospi->Instance->DCR3 = (hospi->Init.ChipSelectBoundary << OCTOSPI_DCR3_CSBOUND_Pos); |
| #endif |
| |
| #if defined (OCTOSPI_DCR4_REFRESH) |
| /* Configure refresh */ |
| hospi->Instance->DCR4 = hospi->Init.Refresh; |
| #endif |
| |
| /* Configure FIFO threshold */ |
| MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_FTHRES, ((hospi->Init.FifoThreshold - 1U) << OCTOSPI_CR_FTHRES_Pos)); |
| |
| /* Wait till busy flag is reset */ |
| status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_BUSY, RESET, tickstart, hospi->Timeout); |
| |
| if (status == HAL_OK) |
| { |
| /* Configure clock prescaler */ |
| MODIFY_REG(hospi->Instance->DCR2, OCTOSPI_DCR2_PRESCALER, |
| ((hospi->Init.ClockPrescaler - 1U) << OCTOSPI_DCR2_PRESCALER_Pos)); |
| |
| /* Configure Dual Quad mode */ |
| MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_DQM, hospi->Init.DualQuad); |
| |
| /* Configure sample shifting and delay hold quarter cycle */ |
| MODIFY_REG(hospi->Instance->TCR, (OCTOSPI_TCR_SSHIFT | OCTOSPI_TCR_DHQC), |
| (hospi->Init.SampleShifting | hospi->Init.DelayHoldQuarterCycle)); |
| |
| /* Enable OctoSPI */ |
| __HAL_OSPI_ENABLE(hospi); |
| |
| /* Enable free running clock if needed : must be done after OSPI enable */ |
| if (hospi->Init.FreeRunningClock == HAL_OSPI_FREERUNCLK_ENABLE) |
| { |
| SET_BIT(hospi->Instance->DCR1, OCTOSPI_DCR1_FRCK); |
| } |
| |
| /* Initialize the OSPI state */ |
| if (hospi->Init.MemoryType == HAL_OSPI_MEMTYPE_HYPERBUS) |
| { |
| hospi->State = HAL_OSPI_STATE_HYPERBUS_INIT; |
| } |
| else |
| { |
| hospi->State = HAL_OSPI_STATE_READY; |
| } |
| } |
| } |
| } |
| |
| /* Return function status */ |
| return status; |
| } |
| |
| /** |
| * @brief Initialize the OSPI MSP. |
| * @param hospi : OSPI handle |
| * @retval None |
| */ |
| __weak void HAL_OSPI_MspInit(OSPI_HandleTypeDef *hospi) |
| { |
| /* Prevent unused argument(s) compilation warning */ |
| UNUSED(hospi); |
| |
| /* NOTE : This function should not be modified, when the callback is needed, |
| the HAL_OSPI_MspInit can be implemented in the user file |
| */ |
| } |
| |
| /** |
| * @brief De-Initialize the OSPI peripheral. |
| * @param hospi : OSPI handle |
| * @retval HAL status |
| */ |
| HAL_StatusTypeDef HAL_OSPI_DeInit(OSPI_HandleTypeDef *hospi) |
| { |
| HAL_StatusTypeDef status = HAL_OK; |
| |
| /* Check the OSPI handle allocation */ |
| if (hospi == NULL) |
| { |
| status = HAL_ERROR; |
| /* No error code can be set set as the handler is null */ |
| } |
| else |
| { |
| /* Disable OctoSPI */ |
| __HAL_OSPI_DISABLE(hospi); |
| |
| /* Disable free running clock if needed : must be done after OSPI disable */ |
| CLEAR_BIT(hospi->Instance->DCR1, OCTOSPI_DCR1_FRCK); |
| |
| #if defined (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) |
| if (hospi->MspDeInitCallback == NULL) |
| { |
| hospi->MspDeInitCallback = HAL_OSPI_MspDeInit; |
| } |
| |
| /* DeInit the low level hardware */ |
| hospi->MspDeInitCallback(hospi); |
| #else |
| /* De-initialize the low-level hardware */ |
| HAL_OSPI_MspDeInit(hospi); |
| #endif /* (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) */ |
| |
| /* Reset the driver state */ |
| hospi->State = HAL_OSPI_STATE_RESET; |
| } |
| |
| return status; |
| } |
| |
| /** |
| * @brief DeInitialize the OSPI MSP. |
| * @param hospi : OSPI handle |
| * @retval None |
| */ |
| __weak void HAL_OSPI_MspDeInit(OSPI_HandleTypeDef *hospi) |
| { |
| /* Prevent unused argument(s) compilation warning */ |
| UNUSED(hospi); |
| |
| /* NOTE : This function should not be modified, when the callback is needed, |
| the HAL_OSPI_MspDeInit can be implemented in the user file |
| */ |
| } |
| |
| /** |
| * @} |
| */ |
| |
| /** @defgroup OSPI_Exported_Functions_Group2 Input and Output operation functions |
| * @brief OSPI Transmit/Receive functions |
| * |
| @verbatim |
| =============================================================================== |
| ##### IO operation functions ##### |
| =============================================================================== |
| [..] |
| This subsection provides a set of functions allowing to : |
| (+) Handle the interrupts. |
| (+) Handle the command sequence (regular and Hyperbus). |
| (+) Handle the Hyperbus configuration. |
| (+) Transmit data in blocking, interrupt or DMA mode. |
| (+) Receive data in blocking, interrupt or DMA mode. |
| (+) Manage the auto-polling functional mode. |
| (+) Manage the memory-mapped functional mode. |
| |
| @endverbatim |
| * @{ |
| */ |
| |
| /** |
| * @brief Handle OSPI interrupt request. |
| * @param hospi : OSPI handle |
| * @retval None |
| */ |
| void HAL_OSPI_IRQHandler(OSPI_HandleTypeDef *hospi) |
| { |
| __IO uint32_t *data_reg = &hospi->Instance->DR; |
| uint32_t flag = hospi->Instance->SR; |
| uint32_t itsource = hospi->Instance->CR; |
| uint32_t currentstate = hospi->State; |
| |
| /* OctoSPI fifo threshold interrupt occurred -------------------------------*/ |
| if (((flag & HAL_OSPI_FLAG_FT) != 0U) && ((itsource & HAL_OSPI_IT_FT) != 0U)) |
| { |
| if (currentstate == HAL_OSPI_STATE_BUSY_TX) |
| { |
| /* Write a data in the fifo */ |
| *((__IO uint8_t *)data_reg) = *hospi->pBuffPtr; |
| hospi->pBuffPtr++; |
| hospi->XferCount--; |
| } |
| else if (currentstate == HAL_OSPI_STATE_BUSY_RX) |
| { |
| /* Read a data from the fifo */ |
| *hospi->pBuffPtr = *((__IO uint8_t *)data_reg); |
| hospi->pBuffPtr++; |
| hospi->XferCount--; |
| } |
| else |
| { |
| /* Nothing to do */ |
| } |
| |
| if (hospi->XferCount == 0U) |
| { |
| /* All data have been received or transmitted for the transfer */ |
| /* Disable fifo threshold interrupt */ |
| __HAL_OSPI_DISABLE_IT(hospi, HAL_OSPI_IT_FT); |
| } |
| |
| /* Fifo threshold callback */ |
| #if defined (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) |
| hospi->FifoThresholdCallback(hospi); |
| #else |
| HAL_OSPI_FifoThresholdCallback(hospi); |
| #endif /* (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U)*/ |
| } |
| /* OctoSPI transfer complete interrupt occurred ----------------------------*/ |
| else if (((flag & HAL_OSPI_FLAG_TC) != 0U) && ((itsource & HAL_OSPI_IT_TC) != 0U)) |
| { |
| if (currentstate == HAL_OSPI_STATE_BUSY_RX) |
| { |
| if ((hospi->XferCount > 0U) && ((flag & OCTOSPI_SR_FLEVEL) != 0U)) |
| { |
| /* Read the last data received in the fifo */ |
| *hospi->pBuffPtr = *((__IO uint8_t *)data_reg); |
| hospi->pBuffPtr++; |
| hospi->XferCount--; |
| } |
| else if (hospi->XferCount == 0U) |
| { |
| /* Clear flag */ |
| hospi->Instance->FCR = HAL_OSPI_FLAG_TC; |
| |
| /* Disable the interrupts */ |
| __HAL_OSPI_DISABLE_IT(hospi, HAL_OSPI_IT_TC | HAL_OSPI_IT_FT | HAL_OSPI_IT_TE); |
| |
| /* Update state */ |
| hospi->State = HAL_OSPI_STATE_READY; |
| |
| /* RX complete callback */ |
| #if defined (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) |
| hospi->RxCpltCallback(hospi); |
| #else |
| HAL_OSPI_RxCpltCallback(hospi); |
| #endif /* (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) */ |
| } |
| else |
| { |
| /* Nothing to do */ |
| } |
| } |
| else |
| { |
| /* Clear flag */ |
| hospi->Instance->FCR = HAL_OSPI_FLAG_TC; |
| |
| /* Disable the interrupts */ |
| __HAL_OSPI_DISABLE_IT(hospi, HAL_OSPI_IT_TC | HAL_OSPI_IT_FT | HAL_OSPI_IT_TE); |
| |
| /* Update state */ |
| hospi->State = HAL_OSPI_STATE_READY; |
| |
| if (currentstate == HAL_OSPI_STATE_BUSY_TX) |
| { |
| /* TX complete callback */ |
| #if defined (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) |
| hospi->TxCpltCallback(hospi); |
| #else |
| HAL_OSPI_TxCpltCallback(hospi); |
| #endif /* defined (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) */ |
| } |
| else if (currentstate == HAL_OSPI_STATE_BUSY_CMD) |
| { |
| /* Command complete callback */ |
| #if defined (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) |
| hospi->CmdCpltCallback(hospi); |
| #else |
| HAL_OSPI_CmdCpltCallback(hospi); |
| #endif /* (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) */ |
| } |
| else if (currentstate == HAL_OSPI_STATE_ABORT) |
| { |
| if (hospi->ErrorCode == HAL_OSPI_ERROR_NONE) |
| { |
| /* Abort called by the user */ |
| /* Abort complete callback */ |
| #if defined (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) |
| hospi->AbortCpltCallback(hospi); |
| #else |
| HAL_OSPI_AbortCpltCallback(hospi); |
| #endif /* defined (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U)*/ |
| } |
| else |
| { |
| /* Abort due to an error (eg : DMA error) */ |
| /* Error callback */ |
| #if defined (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) |
| hospi->ErrorCallback(hospi); |
| #else |
| HAL_OSPI_ErrorCallback(hospi); |
| #endif /* (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) */ |
| } |
| } |
| else |
| { |
| /* Nothing to do */ |
| } |
| } |
| } |
| /* OctoSPI status match interrupt occurred ---------------------------------*/ |
| else if (((flag & HAL_OSPI_FLAG_SM) != 0U) && ((itsource & HAL_OSPI_IT_SM) != 0U)) |
| { |
| /* Clear flag */ |
| hospi->Instance->FCR = HAL_OSPI_FLAG_SM; |
| |
| /* Check if automatic poll mode stop is activated */ |
| if ((hospi->Instance->CR & OCTOSPI_CR_APMS) != 0U) |
| { |
| /* Disable the interrupts */ |
| __HAL_OSPI_DISABLE_IT(hospi, HAL_OSPI_IT_SM | HAL_OSPI_IT_TE); |
| |
| /* Update state */ |
| hospi->State = HAL_OSPI_STATE_READY; |
| } |
| |
| /* Status match callback */ |
| #if defined (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) |
| hospi->StatusMatchCallback(hospi); |
| #else |
| HAL_OSPI_StatusMatchCallback(hospi); |
| #endif /* (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) */ |
| } |
| /* OctoSPI transfer error interrupt occurred -------------------------------*/ |
| else if (((flag & HAL_OSPI_FLAG_TE) != 0U) && ((itsource & HAL_OSPI_IT_TE) != 0U)) |
| { |
| /* Clear flag */ |
| hospi->Instance->FCR = HAL_OSPI_FLAG_TE; |
| |
| /* Disable all interrupts */ |
| __HAL_OSPI_DISABLE_IT(hospi, (HAL_OSPI_IT_TO | HAL_OSPI_IT_SM | HAL_OSPI_IT_FT | HAL_OSPI_IT_TC | HAL_OSPI_IT_TE)); |
| |
| /* Set error code */ |
| hospi->ErrorCode = HAL_OSPI_ERROR_TRANSFER; |
| |
| /* Check if the DMA is enabled */ |
| if ((hospi->Instance->CR & OCTOSPI_CR_DMAEN) != 0U) |
| { |
| /* Disable the DMA transfer on the OctoSPI side */ |
| CLEAR_BIT(hospi->Instance->CR, OCTOSPI_CR_DMAEN); |
| |
| /* Disable the DMA transfer on the DMA side */ |
| hospi->hdma->XferAbortCallback = OSPI_DMAAbortCplt; |
| if (HAL_DMA_Abort_IT(hospi->hdma) != HAL_OK) |
| { |
| /* Update state */ |
| hospi->State = HAL_OSPI_STATE_READY; |
| |
| /* Error callback */ |
| #if defined (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) |
| hospi->ErrorCallback(hospi); |
| #else |
| HAL_OSPI_ErrorCallback(hospi); |
| #endif /* (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U)*/ |
| } |
| } |
| else |
| { |
| /* Update state */ |
| hospi->State = HAL_OSPI_STATE_READY; |
| |
| /* Error callback */ |
| #if defined (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) |
| hospi->ErrorCallback(hospi); |
| #else |
| HAL_OSPI_ErrorCallback(hospi); |
| #endif /* (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) */ |
| } |
| } |
| /* OctoSPI timeout interrupt occurred --------------------------------------*/ |
| else if (((flag & HAL_OSPI_FLAG_TO) != 0U) && ((itsource & HAL_OSPI_IT_TO) != 0U)) |
| { |
| /* Clear flag */ |
| hospi->Instance->FCR = HAL_OSPI_FLAG_TO; |
| |
| /* Timeout callback */ |
| #if defined (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) |
| hospi->TimeOutCallback(hospi); |
| #else |
| HAL_OSPI_TimeOutCallback(hospi); |
| #endif /* (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) */ |
| } |
| else |
| { |
| /* Nothing to do */ |
| } |
| } |
| |
| /** |
| * @brief Set the command configuration. |
| * @param hospi : OSPI handle |
| * @param cmd : structure that contains the command configuration information |
| * @param Timeout : Timeout duration |
| * @retval HAL status |
| */ |
| HAL_StatusTypeDef HAL_OSPI_Command(OSPI_HandleTypeDef *hospi, OSPI_RegularCmdTypeDef *cmd, uint32_t Timeout) |
| { |
| HAL_StatusTypeDef status; |
| uint32_t state; |
| uint32_t tickstart = HAL_GetTick(); |
| |
| /* Check the parameters of the command structure */ |
| assert_param(IS_OSPI_OPERATION_TYPE(cmd->OperationType)); |
| |
| if (hospi->Init.DualQuad == HAL_OSPI_DUALQUAD_DISABLE) |
| { |
| assert_param(IS_OSPI_FLASH_ID(cmd->FlashId)); |
| } |
| |
| assert_param(IS_OSPI_INSTRUCTION_MODE(cmd->InstructionMode)); |
| if (cmd->InstructionMode != HAL_OSPI_INSTRUCTION_NONE) |
| { |
| assert_param(IS_OSPI_INSTRUCTION_SIZE(cmd->InstructionSize)); |
| assert_param(IS_OSPI_INSTRUCTION_DTR_MODE(cmd->InstructionDtrMode)); |
| } |
| |
| assert_param(IS_OSPI_ADDRESS_MODE(cmd->AddressMode)); |
| if (cmd->AddressMode != HAL_OSPI_ADDRESS_NONE) |
| { |
| assert_param(IS_OSPI_ADDRESS_SIZE(cmd->AddressSize)); |
| assert_param(IS_OSPI_ADDRESS_DTR_MODE(cmd->AddressDtrMode)); |
| } |
| |
| assert_param(IS_OSPI_ALT_BYTES_MODE(cmd->AlternateBytesMode)); |
| if (cmd->AlternateBytesMode != HAL_OSPI_ALTERNATE_BYTES_NONE) |
| { |
| assert_param(IS_OSPI_ALT_BYTES_SIZE(cmd->AlternateBytesSize)); |
| assert_param(IS_OSPI_ALT_BYTES_DTR_MODE(cmd->AlternateBytesDtrMode)); |
| } |
| |
| assert_param(IS_OSPI_DATA_MODE(cmd->DataMode)); |
| if (cmd->DataMode != HAL_OSPI_DATA_NONE) |
| { |
| if (cmd->OperationType == HAL_OSPI_OPTYPE_COMMON_CFG) |
| { |
| assert_param(IS_OSPI_NUMBER_DATA(cmd->NbData)); |
| } |
| assert_param(IS_OSPI_DATA_DTR_MODE(cmd->DataDtrMode)); |
| assert_param(IS_OSPI_DUMMY_CYCLES(cmd->DummyCycles)); |
| } |
| |
| assert_param(IS_OSPI_DQS_MODE(cmd->DQSMode)); |
| assert_param(IS_OSPI_SIOO_MODE(cmd->SIOOMode)); |
| |
| /* Check the state of the driver */ |
| state = hospi->State; |
| if (((state == HAL_OSPI_STATE_READY) && (hospi->Init.MemoryType != HAL_OSPI_MEMTYPE_HYPERBUS)) || |
| ((state == HAL_OSPI_STATE_READ_CMD_CFG) && (cmd->OperationType == HAL_OSPI_OPTYPE_WRITE_CFG)) || |
| ((state == HAL_OSPI_STATE_WRITE_CMD_CFG) && (cmd->OperationType == HAL_OSPI_OPTYPE_READ_CFG))) |
| { |
| /* Wait till busy flag is reset */ |
| status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_BUSY, RESET, tickstart, Timeout); |
| |
| if (status == HAL_OK) |
| { |
| /* Initialize error code */ |
| hospi->ErrorCode = HAL_OSPI_ERROR_NONE; |
| |
| /* Configure the registers */ |
| status = OSPI_ConfigCmd(hospi, cmd); |
| |
| if (status == HAL_OK) |
| { |
| if (cmd->DataMode == HAL_OSPI_DATA_NONE) |
| { |
| /* When there is no data phase, the transfer start as soon as the configuration is done |
| so wait until TC flag is set to go back in idle state */ |
| status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_TC, SET, tickstart, Timeout); |
| |
| __HAL_OSPI_CLEAR_FLAG(hospi, HAL_OSPI_FLAG_TC); |
| } |
| else |
| { |
| /* Update the state */ |
| if (cmd->OperationType == HAL_OSPI_OPTYPE_COMMON_CFG) |
| { |
| hospi->State = HAL_OSPI_STATE_CMD_CFG; |
| } |
| else if (cmd->OperationType == HAL_OSPI_OPTYPE_READ_CFG) |
| { |
| if (hospi->State == HAL_OSPI_STATE_WRITE_CMD_CFG) |
| { |
| hospi->State = HAL_OSPI_STATE_CMD_CFG; |
| } |
| else |
| { |
| hospi->State = HAL_OSPI_STATE_READ_CMD_CFG; |
| } |
| } |
| else |
| { |
| if (hospi->State == HAL_OSPI_STATE_READ_CMD_CFG) |
| { |
| hospi->State = HAL_OSPI_STATE_CMD_CFG; |
| } |
| else |
| { |
| hospi->State = HAL_OSPI_STATE_WRITE_CMD_CFG; |
| } |
| } |
| } |
| } |
| } |
| } |
| else |
| { |
| status = HAL_ERROR; |
| hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; |
| } |
| |
| /* Return function status */ |
| return status; |
| } |
| |
| /** |
| * @brief Set the command configuration in interrupt mode. |
| * @param hospi : OSPI handle |
| * @param cmd : structure that contains the command configuration information |
| * @note This function is used only in Indirect Read or Write Modes |
| * @retval HAL status |
| */ |
| HAL_StatusTypeDef HAL_OSPI_Command_IT(OSPI_HandleTypeDef *hospi, OSPI_RegularCmdTypeDef *cmd) |
| { |
| HAL_StatusTypeDef status; |
| uint32_t tickstart = HAL_GetTick(); |
| |
| /* Check the parameters of the command structure */ |
| assert_param(IS_OSPI_OPERATION_TYPE(cmd->OperationType)); |
| |
| if (hospi->Init.DualQuad == HAL_OSPI_DUALQUAD_DISABLE) |
| { |
| assert_param(IS_OSPI_FLASH_ID(cmd->FlashId)); |
| } |
| |
| assert_param(IS_OSPI_INSTRUCTION_MODE(cmd->InstructionMode)); |
| if (cmd->InstructionMode != HAL_OSPI_INSTRUCTION_NONE) |
| { |
| assert_param(IS_OSPI_INSTRUCTION_SIZE(cmd->InstructionSize)); |
| assert_param(IS_OSPI_INSTRUCTION_DTR_MODE(cmd->InstructionDtrMode)); |
| } |
| |
| assert_param(IS_OSPI_ADDRESS_MODE(cmd->AddressMode)); |
| if (cmd->AddressMode != HAL_OSPI_ADDRESS_NONE) |
| { |
| assert_param(IS_OSPI_ADDRESS_SIZE(cmd->AddressSize)); |
| assert_param(IS_OSPI_ADDRESS_DTR_MODE(cmd->AddressDtrMode)); |
| } |
| |
| assert_param(IS_OSPI_ALT_BYTES_MODE(cmd->AlternateBytesMode)); |
| if (cmd->AlternateBytesMode != HAL_OSPI_ALTERNATE_BYTES_NONE) |
| { |
| assert_param(IS_OSPI_ALT_BYTES_SIZE(cmd->AlternateBytesSize)); |
| assert_param(IS_OSPI_ALT_BYTES_DTR_MODE(cmd->AlternateBytesDtrMode)); |
| } |
| |
| assert_param(IS_OSPI_DATA_MODE(cmd->DataMode)); |
| if (cmd->DataMode != HAL_OSPI_DATA_NONE) |
| { |
| assert_param(IS_OSPI_NUMBER_DATA(cmd->NbData)); |
| assert_param(IS_OSPI_DATA_DTR_MODE(cmd->DataDtrMode)); |
| assert_param(IS_OSPI_DUMMY_CYCLES(cmd->DummyCycles)); |
| } |
| |
| assert_param(IS_OSPI_DQS_MODE(cmd->DQSMode)); |
| assert_param(IS_OSPI_SIOO_MODE(cmd->SIOOMode)); |
| |
| /* Check the state of the driver */ |
| if ((hospi->State == HAL_OSPI_STATE_READY) && (cmd->OperationType == HAL_OSPI_OPTYPE_COMMON_CFG) && |
| (cmd->DataMode == HAL_OSPI_DATA_NONE) && (hospi->Init.MemoryType != HAL_OSPI_MEMTYPE_HYPERBUS)) |
| { |
| /* Wait till busy flag is reset */ |
| status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_BUSY, RESET, tickstart, hospi->Timeout); |
| |
| if (status == HAL_OK) |
| { |
| /* Initialize error code */ |
| hospi->ErrorCode = HAL_OSPI_ERROR_NONE; |
| |
| /* Clear flags related to interrupt */ |
| __HAL_OSPI_CLEAR_FLAG(hospi, HAL_OSPI_FLAG_TE | HAL_OSPI_FLAG_TC); |
| |
| /* Configure the registers */ |
| status = OSPI_ConfigCmd(hospi, cmd); |
| |
| if (status == HAL_OK) |
| { |
| /* Update the state */ |
| hospi->State = HAL_OSPI_STATE_BUSY_CMD; |
| |
| /* Enable the transfer complete and transfer error interrupts */ |
| __HAL_OSPI_ENABLE_IT(hospi, HAL_OSPI_IT_TC | HAL_OSPI_IT_TE); |
| } |
| } |
| } |
| else |
| { |
| status = HAL_ERROR; |
| hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; |
| } |
| |
| /* Return function status */ |
| return status; |
| } |
| |
| /** |
| * @brief Configure the Hyperbus parameters. |
| * @param hospi : OSPI handle |
| * @param cfg : Structure containing the Hyperbus configuration |
| * @param Timeout : Timeout duration |
| * @retval HAL status |
| */ |
| HAL_StatusTypeDef HAL_OSPI_HyperbusCfg(OSPI_HandleTypeDef *hospi, OSPI_HyperbusCfgTypeDef *cfg, uint32_t Timeout) |
| { |
| HAL_StatusTypeDef status; |
| uint32_t state; |
| uint32_t tickstart = HAL_GetTick(); |
| |
| /* Check the parameters of the hyperbus configuration structure */ |
| assert_param(IS_OSPI_RW_RECOVERY_TIME(cfg->RWRecoveryTime)); |
| assert_param(IS_OSPI_ACCESS_TIME(cfg->AccessTime)); |
| assert_param(IS_OSPI_WRITE_ZERO_LATENCY(cfg->WriteZeroLatency)); |
| assert_param(IS_OSPI_LATENCY_MODE(cfg->LatencyMode)); |
| |
| /* Check the state of the driver */ |
| state = hospi->State; |
| if ((state == HAL_OSPI_STATE_HYPERBUS_INIT) || (state == HAL_OSPI_STATE_READY)) |
| { |
| /* Wait till busy flag is reset */ |
| status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_BUSY, RESET, tickstart, Timeout); |
| |
| if (status == HAL_OK) |
| { |
| /* Configure Hyperbus configuration Latency register */ |
| WRITE_REG(hospi->Instance->HLCR, ((cfg->RWRecoveryTime << OCTOSPI_HLCR_TRWR_Pos) | |
| (cfg->AccessTime << OCTOSPI_HLCR_TACC_Pos) | |
| cfg->WriteZeroLatency | cfg->LatencyMode)); |
| |
| /* Update the state */ |
| hospi->State = HAL_OSPI_STATE_READY; |
| } |
| } |
| else |
| { |
| status = HAL_ERROR; |
| hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; |
| } |
| |
| /* Return function status */ |
| return status; |
| } |
| |
| /** |
| * @brief Set the Hyperbus command configuration. |
| * @param hospi : OSPI handle |
| * @param cmd : Structure containing the Hyperbus command |
| * @param Timeout : Timeout duration |
| * @retval HAL status |
| */ |
| HAL_StatusTypeDef HAL_OSPI_HyperbusCmd(OSPI_HandleTypeDef *hospi, OSPI_HyperbusCmdTypeDef *cmd, uint32_t Timeout) |
| { |
| HAL_StatusTypeDef status; |
| uint32_t tickstart = HAL_GetTick(); |
| |
| /* Check the parameters of the hyperbus command structure */ |
| assert_param(IS_OSPI_ADDRESS_SPACE(cmd->AddressSpace)); |
| assert_param(IS_OSPI_ADDRESS_SIZE(cmd->AddressSize)); |
| assert_param(IS_OSPI_NUMBER_DATA(cmd->NbData)); |
| assert_param(IS_OSPI_DQS_MODE(cmd->DQSMode)); |
| |
| /* Check the state of the driver */ |
| if ((hospi->State == HAL_OSPI_STATE_READY) && (hospi->Init.MemoryType == HAL_OSPI_MEMTYPE_HYPERBUS)) |
| { |
| /* Wait till busy flag is reset */ |
| status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_BUSY, RESET, tickstart, Timeout); |
| |
| if (status == HAL_OK) |
| { |
| /* Re-initialize the value of the functional mode */ |
| MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_FMODE, 0U); |
| |
| /* Configure the address space in the DCR1 register */ |
| MODIFY_REG(hospi->Instance->DCR1, OCTOSPI_DCR1_MTYP_0, cmd->AddressSpace); |
| |
| /* Configure the CCR and WCCR registers with the address size and the following configuration : |
| - DQS signal enabled (used as RWDS) |
| - DTR mode enabled on address and data |
| - address and data on 8 lines */ |
| WRITE_REG(hospi->Instance->CCR, (cmd->DQSMode | OCTOSPI_CCR_DDTR | OCTOSPI_CCR_DMODE_2 | |
| cmd->AddressSize | OCTOSPI_CCR_ADDTR | OCTOSPI_CCR_ADMODE_2)); |
| WRITE_REG(hospi->Instance->WCCR, (cmd->DQSMode | OCTOSPI_WCCR_DDTR | OCTOSPI_WCCR_DMODE_2 | |
| cmd->AddressSize | OCTOSPI_WCCR_ADDTR | OCTOSPI_WCCR_ADMODE_2)); |
| |
| /* Configure the DLR register with the number of data */ |
| WRITE_REG(hospi->Instance->DLR, (cmd->NbData - 1U)); |
| |
| /* Configure the AR register with the address value */ |
| WRITE_REG(hospi->Instance->AR, cmd->Address); |
| |
| /* Update the state */ |
| hospi->State = HAL_OSPI_STATE_CMD_CFG; |
| } |
| } |
| else |
| { |
| status = HAL_ERROR; |
| hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; |
| } |
| |
| /* Return function status */ |
| return status; |
| } |
| |
| /** |
| * @brief Transmit an amount of data in blocking mode. |
| * @param hospi : OSPI handle |
| * @param pData : pointer to data buffer |
| * @param Timeout : Timeout duration |
| * @note This function is used only in Indirect Write Mode |
| * @retval HAL status |
| */ |
| HAL_StatusTypeDef HAL_OSPI_Transmit(OSPI_HandleTypeDef *hospi, uint8_t *pData, uint32_t Timeout) |
| { |
| HAL_StatusTypeDef status; |
| uint32_t tickstart = HAL_GetTick(); |
| __IO uint32_t *data_reg = &hospi->Instance->DR; |
| |
| /* Check the data pointer allocation */ |
| if (pData == NULL) |
| { |
| status = HAL_ERROR; |
| hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_PARAM; |
| } |
| else |
| { |
| /* Check the state */ |
| if (hospi->State == HAL_OSPI_STATE_CMD_CFG) |
| { |
| /* Configure counters and size */ |
| hospi->XferCount = READ_REG(hospi->Instance->DLR) + 1U; |
| hospi->XferSize = hospi->XferCount; |
| hospi->pBuffPtr = pData; |
| |
| /* Configure CR register with functional mode as indirect write */ |
| MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_FMODE, OSPI_FUNCTIONAL_MODE_INDIRECT_WRITE); |
| |
| do |
| { |
| /* Wait till fifo threshold flag is set to send data */ |
| status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_FT, SET, tickstart, Timeout); |
| |
| if (status != HAL_OK) |
| { |
| break; |
| } |
| |
| *((__IO uint8_t *)data_reg) = *hospi->pBuffPtr; |
| hospi->pBuffPtr++; |
| hospi->XferCount--; |
| } |
| while (hospi->XferCount > 0U); |
| |
| if (status == HAL_OK) |
| { |
| /* Wait till transfer complete flag is set to go back in idle state */ |
| status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_TC, SET, tickstart, Timeout); |
| |
| if (status == HAL_OK) |
| { |
| /* Clear transfer complete flag */ |
| __HAL_OSPI_CLEAR_FLAG(hospi, HAL_OSPI_FLAG_TC); |
| |
| /* Update state */ |
| hospi->State = HAL_OSPI_STATE_READY; |
| } |
| } |
| } |
| else |
| { |
| status = HAL_ERROR; |
| hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; |
| } |
| } |
| |
| /* Return function status */ |
| return status; |
| } |
| |
| /** |
| * @brief Receive an amount of data in blocking mode. |
| * @param hospi : OSPI handle |
| * @param pData : pointer to data buffer |
| * @param Timeout : Timeout duration |
| * @note This function is used only in Indirect Read Mode |
| * @retval HAL status |
| */ |
| HAL_StatusTypeDef HAL_OSPI_Receive(OSPI_HandleTypeDef *hospi, uint8_t *pData, uint32_t Timeout) |
| { |
| HAL_StatusTypeDef status; |
| uint32_t tickstart = HAL_GetTick(); |
| __IO uint32_t *data_reg = &hospi->Instance->DR; |
| uint32_t addr_reg = hospi->Instance->AR; |
| uint32_t ir_reg = hospi->Instance->IR; |
| |
| /* Check the data pointer allocation */ |
| if (pData == NULL) |
| { |
| status = HAL_ERROR; |
| hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_PARAM; |
| } |
| else |
| { |
| /* Check the state */ |
| if (hospi->State == HAL_OSPI_STATE_CMD_CFG) |
| { |
| /* Configure counters and size */ |
| hospi->XferCount = READ_REG(hospi->Instance->DLR) + 1U; |
| hospi->XferSize = hospi->XferCount; |
| hospi->pBuffPtr = pData; |
| |
| /* Configure CR register with functional mode as indirect read */ |
| MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_FMODE, OSPI_FUNCTIONAL_MODE_INDIRECT_READ); |
| |
| /* Trig the transfer by re-writing address or instruction register */ |
| if (hospi->Init.MemoryType == HAL_OSPI_MEMTYPE_HYPERBUS) |
| { |
| WRITE_REG(hospi->Instance->AR, addr_reg); |
| } |
| else |
| { |
| if (READ_BIT(hospi->Instance->CCR, OCTOSPI_CCR_ADMODE) != HAL_OSPI_ADDRESS_NONE) |
| { |
| WRITE_REG(hospi->Instance->AR, addr_reg); |
| } |
| else |
| { |
| WRITE_REG(hospi->Instance->IR, ir_reg); |
| } |
| } |
| |
| do |
| { |
| /* Wait till fifo threshold or transfer complete flags are set to read received data */ |
| status = OSPI_WaitFlagStateUntilTimeout(hospi, (HAL_OSPI_FLAG_FT | HAL_OSPI_FLAG_TC), SET, tickstart, Timeout); |
| |
| if (status != HAL_OK) |
| { |
| break; |
| } |
| |
| *hospi->pBuffPtr = *((__IO uint8_t *)data_reg); |
| hospi->pBuffPtr++; |
| hospi->XferCount--; |
| } |
| while (hospi->XferCount > 0U); |
| |
| if (status == HAL_OK) |
| { |
| /* Wait till transfer complete flag is set to go back in idle state */ |
| status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_TC, SET, tickstart, Timeout); |
| |
| if (status == HAL_OK) |
| { |
| /* Clear transfer complete flag */ |
| __HAL_OSPI_CLEAR_FLAG(hospi, HAL_OSPI_FLAG_TC); |
| |
| /* Update state */ |
| hospi->State = HAL_OSPI_STATE_READY; |
| } |
| } |
| } |
| else |
| { |
| status = HAL_ERROR; |
| hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; |
| } |
| } |
| |
| /* Return function status */ |
| return status; |
| } |
| |
| /** |
| * @brief Send an amount of data in non-blocking mode with interrupt. |
| * @param hospi : OSPI handle |
| * @param pData : pointer to data buffer |
| * @note This function is used only in Indirect Write Mode |
| * @retval HAL status |
| */ |
| HAL_StatusTypeDef HAL_OSPI_Transmit_IT(OSPI_HandleTypeDef *hospi, uint8_t *pData) |
| { |
| HAL_StatusTypeDef status = HAL_OK; |
| |
| /* Check the data pointer allocation */ |
| if (pData == NULL) |
| { |
| status = HAL_ERROR; |
| hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_PARAM; |
| } |
| else |
| { |
| /* Check the state */ |
| if (hospi->State == HAL_OSPI_STATE_CMD_CFG) |
| { |
| /* Configure counters and size */ |
| hospi->XferCount = READ_REG(hospi->Instance->DLR) + 1U; |
| hospi->XferSize = hospi->XferCount; |
| hospi->pBuffPtr = pData; |
| |
| /* Configure CR register with functional mode as indirect write */ |
| MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_FMODE, OSPI_FUNCTIONAL_MODE_INDIRECT_WRITE); |
| |
| /* Clear flags related to interrupt */ |
| __HAL_OSPI_CLEAR_FLAG(hospi, HAL_OSPI_FLAG_TE | HAL_OSPI_FLAG_TC); |
| |
| /* Update the state */ |
| hospi->State = HAL_OSPI_STATE_BUSY_TX; |
| |
| /* Enable the transfer complete, fifo threshold and transfer error interrupts */ |
| __HAL_OSPI_ENABLE_IT(hospi, HAL_OSPI_IT_TC | HAL_OSPI_IT_FT | HAL_OSPI_IT_TE); |
| } |
| else |
| { |
| status = HAL_ERROR; |
| hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; |
| } |
| } |
| |
| /* Return function status */ |
| return status; |
| } |
| |
| /** |
| * @brief Receive an amount of data in non-blocking mode with interrupt. |
| * @param hospi : OSPI handle |
| * @param pData : pointer to data buffer |
| * @note This function is used only in Indirect Read Mode |
| * @retval HAL status |
| */ |
| HAL_StatusTypeDef HAL_OSPI_Receive_IT(OSPI_HandleTypeDef *hospi, uint8_t *pData) |
| { |
| HAL_StatusTypeDef status = HAL_OK; |
| uint32_t addr_reg = hospi->Instance->AR; |
| uint32_t ir_reg = hospi->Instance->IR; |
| |
| /* Check the data pointer allocation */ |
| if (pData == NULL) |
| { |
| status = HAL_ERROR; |
| hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_PARAM; |
| } |
| else |
| { |
| /* Check the state */ |
| if (hospi->State == HAL_OSPI_STATE_CMD_CFG) |
| { |
| /* Configure counters and size */ |
| hospi->XferCount = READ_REG(hospi->Instance->DLR) + 1U; |
| hospi->XferSize = hospi->XferCount; |
| hospi->pBuffPtr = pData; |
| |
| /* Configure CR register with functional mode as indirect read */ |
| MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_FMODE, OSPI_FUNCTIONAL_MODE_INDIRECT_READ); |
| |
| /* Clear flags related to interrupt */ |
| __HAL_OSPI_CLEAR_FLAG(hospi, HAL_OSPI_FLAG_TE | HAL_OSPI_FLAG_TC); |
| |
| /* Update the state */ |
| hospi->State = HAL_OSPI_STATE_BUSY_RX; |
| |
| /* Enable the transfer complete, fifo threshold and transfer error interrupts */ |
| __HAL_OSPI_ENABLE_IT(hospi, HAL_OSPI_IT_TC | HAL_OSPI_IT_FT | HAL_OSPI_IT_TE); |
| |
| /* Trig the transfer by re-writing address or instruction register */ |
| if (hospi->Init.MemoryType == HAL_OSPI_MEMTYPE_HYPERBUS) |
| { |
| WRITE_REG(hospi->Instance->AR, addr_reg); |
| } |
| else |
| { |
| if (READ_BIT(hospi->Instance->CCR, OCTOSPI_CCR_ADMODE) != HAL_OSPI_ADDRESS_NONE) |
| { |
| WRITE_REG(hospi->Instance->AR, addr_reg); |
| } |
| else |
| { |
| WRITE_REG(hospi->Instance->IR, ir_reg); |
| } |
| } |
| } |
| else |
| { |
| status = HAL_ERROR; |
| hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; |
| } |
| } |
| |
| /* Return function status */ |
| return status; |
| } |
| |
| /** |
| * @brief Send an amount of data in non-blocking mode with DMA. |
| * @param hospi : OSPI handle |
| * @param pData : pointer to data buffer |
| * @note This function is used only in Indirect Write Mode |
| * @note If DMA peripheral access is configured as halfword, the number |
| * of data and the fifo threshold should be aligned on halfword |
| * @note If DMA peripheral access is configured as word, the number |
| * of data and the fifo threshold should be aligned on word |
| * @retval HAL status |
| */ |
| HAL_StatusTypeDef HAL_OSPI_Transmit_DMA(OSPI_HandleTypeDef *hospi, uint8_t *pData) |
| { |
| HAL_StatusTypeDef status = HAL_OK; |
| uint32_t data_size = hospi->Instance->DLR + 1U; |
| |
| /* Check the data pointer allocation */ |
| if (pData == NULL) |
| { |
| status = HAL_ERROR; |
| hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_PARAM; |
| } |
| else |
| { |
| /* Check the state */ |
| if (hospi->State == HAL_OSPI_STATE_CMD_CFG) |
| { |
| /* Configure counters and size */ |
| if (hospi->hdma->Init.PeriphDataAlignment == DMA_PDATAALIGN_BYTE) |
| { |
| hospi->XferCount = data_size; |
| } |
| else if (hospi->hdma->Init.PeriphDataAlignment == DMA_PDATAALIGN_HALFWORD) |
| { |
| if (((data_size % 2U) != 0U) || ((hospi->Init.FifoThreshold % 2U) != 0U)) |
| { |
| /* The number of data or the fifo threshold is not aligned on halfword |
| => no transfer possible with DMA peripheral access configured as halfword */ |
| hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_PARAM; |
| status = HAL_ERROR; |
| } |
| else |
| { |
| hospi->XferCount = (data_size >> 1); |
| } |
| } |
| else if (hospi->hdma->Init.PeriphDataAlignment == DMA_PDATAALIGN_WORD) |
| { |
| if (((data_size % 4U) != 0U) || ((hospi->Init.FifoThreshold % 4U) != 0U)) |
| { |
| /* The number of data or the fifo threshold is not aligned on word |
| => no transfer possible with DMA peripheral access configured as word */ |
| hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_PARAM; |
| status = HAL_ERROR; |
| } |
| else |
| { |
| hospi->XferCount = (data_size >> 2); |
| } |
| } |
| else |
| { |
| /* Nothing to do */ |
| } |
| |
| if (status == HAL_OK) |
| { |
| hospi->XferSize = hospi->XferCount; |
| hospi->pBuffPtr = pData; |
| |
| /* Configure CR register with functional mode as indirect write */ |
| MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_FMODE, OSPI_FUNCTIONAL_MODE_INDIRECT_WRITE); |
| |
| /* Clear flags related to interrupt */ |
| __HAL_OSPI_CLEAR_FLAG(hospi, HAL_OSPI_FLAG_TE | HAL_OSPI_FLAG_TC); |
| |
| /* Update the state */ |
| hospi->State = HAL_OSPI_STATE_BUSY_TX; |
| |
| /* Set the DMA transfer complete callback */ |
| hospi->hdma->XferCpltCallback = OSPI_DMACplt; |
| |
| /* Set the DMA Half transfer complete callback */ |
| hospi->hdma->XferHalfCpltCallback = OSPI_DMAHalfCplt; |
| |
| /* Set the DMA error callback */ |
| hospi->hdma->XferErrorCallback = OSPI_DMAError; |
| |
| /* Clear the DMA abort callback */ |
| hospi->hdma->XferAbortCallback = NULL; |
| |
| /* Configure the direction of the DMA */ |
| hospi->hdma->Init.Direction = DMA_MEMORY_TO_PERIPH; |
| MODIFY_REG(hospi->hdma->Instance->CCR, DMA_CCR_DIR, hospi->hdma->Init.Direction); |
| |
| /* Enable the transmit DMA Channel */ |
| if (HAL_DMA_Start_IT(hospi->hdma, (uint32_t)pData, (uint32_t)&hospi->Instance->DR, hospi->XferSize) == HAL_OK) |
| { |
| /* Enable the transfer error interrupt */ |
| __HAL_OSPI_ENABLE_IT(hospi, HAL_OSPI_IT_TE); |
| |
| /* Enable the DMA transfer by setting the DMAEN bit */ |
| SET_BIT(hospi->Instance->CR, OCTOSPI_CR_DMAEN); |
| } |
| else |
| { |
| status = HAL_ERROR; |
| hospi->ErrorCode = HAL_OSPI_ERROR_DMA; |
| hospi->State = HAL_OSPI_STATE_READY; |
| } |
| } |
| } |
| else |
| { |
| status = HAL_ERROR; |
| hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; |
| } |
| } |
| |
| /* Return function status */ |
| return status; |
| } |
| |
| /** |
| * @brief Receive an amount of data in non-blocking mode with DMA. |
| * @param hospi : OSPI handle |
| * @param pData : pointer to data buffer. |
| * @note This function is used only in Indirect Read Mode |
| * @note If DMA peripheral access is configured as halfword, the number |
| * of data and the fifo threshold should be aligned on halfword |
| * @note If DMA peripheral access is configured as word, the number |
| * of data and the fifo threshold should be aligned on word |
| * @retval HAL status |
| */ |
| HAL_StatusTypeDef HAL_OSPI_Receive_DMA(OSPI_HandleTypeDef *hospi, uint8_t *pData) |
| { |
| HAL_StatusTypeDef status = HAL_OK; |
| uint32_t data_size = hospi->Instance->DLR + 1U; |
| uint32_t addr_reg = hospi->Instance->AR; |
| uint32_t ir_reg = hospi->Instance->IR; |
| /* Check the data pointer allocation */ |
| if (pData == NULL) |
| { |
| status = HAL_ERROR; |
| hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_PARAM; |
| } |
| else |
| { |
| /* Check the state */ |
| if (hospi->State == HAL_OSPI_STATE_CMD_CFG) |
| { |
| /* Configure counters and size */ |
| if (hospi->hdma->Init.PeriphDataAlignment == DMA_PDATAALIGN_BYTE) |
| { |
| hospi->XferCount = data_size; |
| } |
| else if (hospi->hdma->Init.PeriphDataAlignment == DMA_PDATAALIGN_HALFWORD) |
| { |
| if (((data_size % 2U) != 0U) || ((hospi->Init.FifoThreshold % 2U) != 0U)) |
| { |
| /* The number of data or the fifo threshold is not aligned on halfword |
| => no transfer possible with DMA peripheral access configured as halfword */ |
| hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_PARAM; |
| status = HAL_ERROR; |
| } |
| else |
| { |
| hospi->XferCount = (data_size >> 1); |
| } |
| } |
| else if (hospi->hdma->Init.PeriphDataAlignment == DMA_PDATAALIGN_WORD) |
| { |
| if (((data_size % 4U) != 0U) || ((hospi->Init.FifoThreshold % 4U) != 0U)) |
| { |
| /* The number of data or the fifo threshold is not aligned on word |
| => no transfer possible with DMA peripheral access configured as word */ |
| hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_PARAM; |
| status = HAL_ERROR; |
| } |
| else |
| { |
| hospi->XferCount = (data_size >> 2); |
| } |
| } |
| else |
| { |
| /* Nothing to do */ |
| } |
| |
| if (status == HAL_OK) |
| { |
| hospi->XferSize = hospi->XferCount; |
| hospi->pBuffPtr = pData; |
| |
| /* Configure CR register with functional mode as indirect read */ |
| MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_FMODE, OSPI_FUNCTIONAL_MODE_INDIRECT_READ); |
| |
| /* Clear flags related to interrupt */ |
| __HAL_OSPI_CLEAR_FLAG(hospi, HAL_OSPI_FLAG_TE | HAL_OSPI_FLAG_TC); |
| |
| /* Update the state */ |
| hospi->State = HAL_OSPI_STATE_BUSY_RX; |
| |
| /* Set the DMA transfer complete callback */ |
| hospi->hdma->XferCpltCallback = OSPI_DMACplt; |
| |
| /* Set the DMA Half transfer complete callback */ |
| hospi->hdma->XferHalfCpltCallback = OSPI_DMAHalfCplt; |
| |
| /* Set the DMA error callback */ |
| hospi->hdma->XferErrorCallback = OSPI_DMAError; |
| |
| /* Clear the DMA abort callback */ |
| hospi->hdma->XferAbortCallback = NULL; |
| |
| /* Configure the direction of the DMA */ |
| hospi->hdma->Init.Direction = DMA_PERIPH_TO_MEMORY; |
| MODIFY_REG(hospi->hdma->Instance->CCR, DMA_CCR_DIR, hospi->hdma->Init.Direction); |
| |
| /* Enable the transmit DMA Channel */ |
| if (HAL_DMA_Start_IT(hospi->hdma, (uint32_t)&hospi->Instance->DR, (uint32_t)pData, hospi->XferSize) == HAL_OK) |
| { |
| /* Enable the transfer error interrupt */ |
| __HAL_OSPI_ENABLE_IT(hospi, HAL_OSPI_IT_TE); |
| |
| /* Trig the transfer by re-writing address or instruction register */ |
| if (hospi->Init.MemoryType == HAL_OSPI_MEMTYPE_HYPERBUS) |
| { |
| WRITE_REG(hospi->Instance->AR, addr_reg); |
| } |
| else |
| { |
| if (READ_BIT(hospi->Instance->CCR, OCTOSPI_CCR_ADMODE) != HAL_OSPI_ADDRESS_NONE) |
| { |
| WRITE_REG(hospi->Instance->AR, addr_reg); |
| } |
| else |
| { |
| WRITE_REG(hospi->Instance->IR, ir_reg); |
| } |
| } |
| |
| /* Enable the DMA transfer by setting the DMAEN bit */ |
| SET_BIT(hospi->Instance->CR, OCTOSPI_CR_DMAEN); |
| } |
| else |
| { |
| status = HAL_ERROR; |
| hospi->ErrorCode = HAL_OSPI_ERROR_DMA; |
| hospi->State = HAL_OSPI_STATE_READY; |
| } |
| } |
| } |
| else |
| { |
| status = HAL_ERROR; |
| hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; |
| } |
| } |
| |
| /* Return function status */ |
| return status; |
| } |
| |
| /** |
| * @brief Configure the OSPI Automatic Polling Mode in blocking mode. |
| * @param hospi : OSPI handle |
| * @param cfg : structure that contains the polling configuration information. |
| * @param Timeout : Timeout duration |
| * @note This function is used only in Automatic Polling Mode |
| * @note This function should not be used when the memory is in octal mode (see Errata Sheet) |
| * @retval HAL status |
| */ |
| HAL_StatusTypeDef HAL_OSPI_AutoPolling(OSPI_HandleTypeDef *hospi, OSPI_AutoPollingTypeDef *cfg, uint32_t Timeout) |
| { |
| HAL_StatusTypeDef status; |
| uint32_t tickstart = HAL_GetTick(); |
| uint32_t addr_reg = hospi->Instance->AR; |
| uint32_t ir_reg = hospi->Instance->IR; |
| #ifdef USE_FULL_ASSERT |
| uint32_t dlr_reg = hospi->Instance->DLR; |
| #endif /* USE_FULL_ASSERT */ |
| |
| /* Check the parameters of the autopolling configuration structure */ |
| assert_param(IS_OSPI_MATCH_MODE(cfg->MatchMode)); |
| assert_param(IS_OSPI_AUTOMATIC_STOP(cfg->AutomaticStop)); |
| assert_param(IS_OSPI_INTERVAL(cfg->Interval)); |
| assert_param(IS_OSPI_STATUS_BYTES_SIZE(dlr_reg + 1U)); |
| |
| /* Check the state */ |
| if ((hospi->State == HAL_OSPI_STATE_CMD_CFG) && (cfg->AutomaticStop == HAL_OSPI_AUTOMATIC_STOP_ENABLE)) |
| { |
| /* Wait till busy flag is reset */ |
| status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_BUSY, RESET, tickstart, Timeout); |
| |
| if (status == HAL_OK) |
| { |
| /* Configure registers */ |
| WRITE_REG(hospi->Instance->PSMAR, cfg->Match); |
| WRITE_REG(hospi->Instance->PSMKR, cfg->Mask); |
| WRITE_REG(hospi->Instance->PIR, cfg->Interval); |
| MODIFY_REG(hospi->Instance->CR, (OCTOSPI_CR_PMM | OCTOSPI_CR_APMS | OCTOSPI_CR_FMODE), |
| (cfg->MatchMode | cfg->AutomaticStop | OSPI_FUNCTIONAL_MODE_AUTO_POLLING)); |
| |
| /* Trig the transfer by re-writing address or instruction register */ |
| if (hospi->Init.MemoryType == HAL_OSPI_MEMTYPE_HYPERBUS) |
| { |
| WRITE_REG(hospi->Instance->AR, addr_reg); |
| } |
| else |
| { |
| if (READ_BIT(hospi->Instance->CCR, OCTOSPI_CCR_ADMODE) != HAL_OSPI_ADDRESS_NONE) |
| { |
| WRITE_REG(hospi->Instance->AR, addr_reg); |
| } |
| else |
| { |
| WRITE_REG(hospi->Instance->IR, ir_reg); |
| } |
| } |
| |
| /* Wait till status match flag is set to go back in idle state */ |
| status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_SM, SET, tickstart, Timeout); |
| |
| if (status == HAL_OK) |
| { |
| /* Clear status match flag */ |
| __HAL_OSPI_CLEAR_FLAG(hospi, HAL_OSPI_FLAG_SM); |
| |
| /* Update state */ |
| hospi->State = HAL_OSPI_STATE_READY; |
| } |
| } |
| } |
| else |
| { |
| status = HAL_ERROR; |
| hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; |
| } |
| |
| /* Return function status */ |
| return status; |
| } |
| |
| /** |
| * @brief Configure the OSPI Automatic Polling Mode in non-blocking mode. |
| * @param hospi : OSPI handle |
| * @param cfg : structure that contains the polling configuration information. |
| * @note This function is used only in Automatic Polling Mode |
| * @note This function should not be used when the memory is in octal mode (see Errata Sheet) |
| * @retval HAL status |
| */ |
| HAL_StatusTypeDef HAL_OSPI_AutoPolling_IT(OSPI_HandleTypeDef *hospi, OSPI_AutoPollingTypeDef *cfg) |
| { |
| HAL_StatusTypeDef status; |
| uint32_t tickstart = HAL_GetTick(); |
| uint32_t addr_reg = hospi->Instance->AR; |
| uint32_t ir_reg = hospi->Instance->IR; |
| #ifdef USE_FULL_ASSERT |
| uint32_t dlr_reg = hospi->Instance->DLR; |
| #endif /* USE_FULL_ASSERT */ |
| |
| /* Check the parameters of the autopolling configuration structure */ |
| assert_param(IS_OSPI_MATCH_MODE(cfg->MatchMode)); |
| assert_param(IS_OSPI_AUTOMATIC_STOP(cfg->AutomaticStop)); |
| assert_param(IS_OSPI_INTERVAL(cfg->Interval)); |
| assert_param(IS_OSPI_STATUS_BYTES_SIZE(dlr_reg + 1U)); |
| |
| /* Check the state */ |
| if (hospi->State == HAL_OSPI_STATE_CMD_CFG) |
| { |
| /* Wait till busy flag is reset */ |
| status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_BUSY, RESET, tickstart, hospi->Timeout); |
| |
| if (status == HAL_OK) |
| { |
| /* Configure registers */ |
| WRITE_REG(hospi->Instance->PSMAR, cfg->Match); |
| WRITE_REG(hospi->Instance->PSMKR, cfg->Mask); |
| WRITE_REG(hospi->Instance->PIR, cfg->Interval); |
| MODIFY_REG(hospi->Instance->CR, (OCTOSPI_CR_PMM | OCTOSPI_CR_APMS | OCTOSPI_CR_FMODE), |
| (cfg->MatchMode | cfg->AutomaticStop | OSPI_FUNCTIONAL_MODE_AUTO_POLLING)); |
| |
| /* Clear flags related to interrupt */ |
| __HAL_OSPI_CLEAR_FLAG(hospi, HAL_OSPI_FLAG_TE | HAL_OSPI_FLAG_SM); |
| |
| /* Update state */ |
| hospi->State = HAL_OSPI_STATE_BUSY_AUTO_POLLING; |
| |
| /* Enable the status match and transfer error interrupts */ |
| __HAL_OSPI_ENABLE_IT(hospi, HAL_OSPI_IT_SM | HAL_OSPI_IT_TE); |
| |
| /* Trig the transfer by re-writing address or instruction register */ |
| if (hospi->Init.MemoryType == HAL_OSPI_MEMTYPE_HYPERBUS) |
| { |
| WRITE_REG(hospi->Instance->AR, addr_reg); |
| } |
| else |
| { |
| if (READ_BIT(hospi->Instance->CCR, OCTOSPI_CCR_ADMODE) != HAL_OSPI_ADDRESS_NONE) |
| { |
| WRITE_REG(hospi->Instance->AR, addr_reg); |
| } |
| else |
| { |
| WRITE_REG(hospi->Instance->IR, ir_reg); |
| } |
| } |
| } |
| } |
| else |
| { |
| status = HAL_ERROR; |
| hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; |
| } |
| |
| /* Return function status */ |
| return status; |
| } |
| |
| /** |
| * @brief Configure the Memory Mapped mode. |
| * @param hospi : OSPI handle |
| * @param cfg : structure that contains the memory mapped configuration information. |
| * @note This function is used only in Memory mapped Mode |
| * @retval HAL status |
| */ |
| HAL_StatusTypeDef HAL_OSPI_MemoryMapped(OSPI_HandleTypeDef *hospi, OSPI_MemoryMappedTypeDef *cfg) |
| { |
| HAL_StatusTypeDef status; |
| uint32_t tickstart = HAL_GetTick(); |
| |
| /* Check the parameters of the memory-mapped configuration structure */ |
| assert_param(IS_OSPI_TIMEOUT_ACTIVATION(cfg->TimeOutActivation)); |
| |
| /* Check the state */ |
| if (hospi->State == HAL_OSPI_STATE_CMD_CFG) |
| { |
| /* Wait till busy flag is reset */ |
| status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_BUSY, RESET, tickstart, hospi->Timeout); |
| |
| if (status == HAL_OK) |
| { |
| /* Update state */ |
| hospi->State = HAL_OSPI_STATE_BUSY_MEM_MAPPED; |
| |
| if (cfg->TimeOutActivation == HAL_OSPI_TIMEOUT_COUNTER_ENABLE) |
| { |
| assert_param(IS_OSPI_TIMEOUT_PERIOD(cfg->TimeOutPeriod)); |
| |
| /* Configure register */ |
| WRITE_REG(hospi->Instance->LPTR, cfg->TimeOutPeriod); |
| |
| /* Clear flags related to interrupt */ |
| __HAL_OSPI_CLEAR_FLAG(hospi, HAL_OSPI_FLAG_TO); |
| |
| /* Enable the timeout interrupt */ |
| __HAL_OSPI_ENABLE_IT(hospi, HAL_OSPI_IT_TO); |
| } |
| |
| /* Configure CR register with functional mode as memory-mapped */ |
| MODIFY_REG(hospi->Instance->CR, (OCTOSPI_CR_TCEN | OCTOSPI_CR_FMODE), |
| (cfg->TimeOutActivation | OSPI_FUNCTIONAL_MODE_MEMORY_MAPPED)); |
| } |
| } |
| else |
| { |
| status = HAL_ERROR; |
| hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; |
| } |
| |
| /* Return function status */ |
| return status; |
| } |
| |
| /** |
| * @brief Transfer Error callback. |
| * @param hospi : OSPI handle |
| * @retval None |
| */ |
| __weak void HAL_OSPI_ErrorCallback(OSPI_HandleTypeDef *hospi) |
| { |
| /* Prevent unused argument(s) compilation warning */ |
| UNUSED(hospi); |
| |
| /* NOTE : This function should not be modified, when the callback is needed, |
| the HAL_OSPI_ErrorCallback could be implemented in the user file |
| */ |
| } |
| |
| /** |
| * @brief Abort completed callback. |
| * @param hospi : OSPI handle |
| * @retval None |
| */ |
| __weak void HAL_OSPI_AbortCpltCallback(OSPI_HandleTypeDef *hospi) |
| { |
| /* Prevent unused argument(s) compilation warning */ |
| UNUSED(hospi); |
| |
| /* NOTE: This function should not be modified, when the callback is needed, |
| the HAL_OSPI_AbortCpltCallback could be implemented in the user file |
| */ |
| } |
| |
| /** |
| * @brief FIFO Threshold callback. |
| * @param hospi : OSPI handle |
| * @retval None |
| */ |
| __weak void HAL_OSPI_FifoThresholdCallback(OSPI_HandleTypeDef *hospi) |
| { |
| /* Prevent unused argument(s) compilation warning */ |
| UNUSED(hospi); |
| |
| /* NOTE : This function should not be modified, when the callback is needed, |
| the HAL_OSPI_FIFOThresholdCallback could be implemented in the user file |
| */ |
| } |
| |
| /** |
| * @brief Command completed callback. |
| * @param hospi : OSPI handle |
| * @retval None |
| */ |
| __weak void HAL_OSPI_CmdCpltCallback(OSPI_HandleTypeDef *hospi) |
| { |
| /* Prevent unused argument(s) compilation warning */ |
| UNUSED(hospi); |
| |
| /* NOTE: This function should not be modified, when the callback is needed, |
| the HAL_OSPI_CmdCpltCallback could be implemented in the user file |
| */ |
| } |
| |
| /** |
| * @brief Rx Transfer completed callback. |
| * @param hospi : OSPI handle |
| * @retval None |
| */ |
| __weak void HAL_OSPI_RxCpltCallback(OSPI_HandleTypeDef *hospi) |
| { |
| /* Prevent unused argument(s) compilation warning */ |
| UNUSED(hospi); |
| |
| /* NOTE: This function should not be modified, when the callback is needed, |
| the HAL_OSPI_RxCpltCallback could be implemented in the user file |
| */ |
| } |
| |
| /** |
| * @brief Tx Transfer completed callback. |
| * @param hospi : OSPI handle |
| * @retval None |
| */ |
| __weak void HAL_OSPI_TxCpltCallback(OSPI_HandleTypeDef *hospi) |
| { |
| /* Prevent unused argument(s) compilation warning */ |
| UNUSED(hospi); |
| |
| /* NOTE: This function should not be modified, when the callback is needed, |
| the HAL_OSPI_TxCpltCallback could be implemented in the user file |
| */ |
| } |
| |
| /** |
| * @brief Rx Half Transfer completed callback. |
| * @param hospi : OSPI handle |
| * @retval None |
| */ |
| __weak void HAL_OSPI_RxHalfCpltCallback(OSPI_HandleTypeDef *hospi) |
| { |
| /* Prevent unused argument(s) compilation warning */ |
| UNUSED(hospi); |
| |
| /* NOTE: This function should not be modified, when the callback is needed, |
| the HAL_OSPI_RxHalfCpltCallback could be implemented in the user file |
| */ |
| } |
| |
| /** |
| * @brief Tx Half Transfer completed callback. |
| * @param hospi : OSPI handle |
| * @retval None |
| */ |
| __weak void HAL_OSPI_TxHalfCpltCallback(OSPI_HandleTypeDef *hospi) |
| { |
| /* Prevent unused argument(s) compilation warning */ |
| UNUSED(hospi); |
| |
| /* NOTE: This function should not be modified, when the callback is needed, |
| the HAL_OSPI_TxHalfCpltCallback could be implemented in the user file |
| */ |
| } |
| |
| /** |
| * @brief Status Match callback. |
| * @param hospi : OSPI handle |
| * @retval None |
| */ |
| __weak void HAL_OSPI_StatusMatchCallback(OSPI_HandleTypeDef *hospi) |
| { |
| /* Prevent unused argument(s) compilation warning */ |
| UNUSED(hospi); |
| |
| /* NOTE : This function should not be modified, when the callback is needed, |
| the HAL_OSPI_StatusMatchCallback could be implemented in the user file |
| */ |
| } |
| |
| /** |
| * @brief Timeout callback. |
| * @param hospi : OSPI handle |
| * @retval None |
| */ |
| __weak void HAL_OSPI_TimeOutCallback(OSPI_HandleTypeDef *hospi) |
| { |
| /* Prevent unused argument(s) compilation warning */ |
| UNUSED(hospi); |
| |
| /* NOTE : This function should not be modified, when the callback is needed, |
| the HAL_OSPI_TimeOutCallback could be implemented in the user file |
| */ |
| } |
| |
| #if defined (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) |
| /** |
| * @brief Register a User OSPI Callback |
| * To be used to override the weak predefined callback |
| * @param hospi : OSPI handle |
| * @param CallbackID : ID of the callback to be registered |
| * This parameter can be one of the following values: |
| * @arg @ref HAL_OSPI_ERROR_CB_ID OSPI Error Callback ID |
| * @arg @ref HAL_OSPI_ABORT_CB_ID OSPI Abort Callback ID |
| * @arg @ref HAL_OSPI_FIFO_THRESHOLD_CB_ID OSPI FIFO Threshold Callback ID |
| * @arg @ref HAL_OSPI_CMD_CPLT_CB_ID OSPI Command Complete Callback ID |
| * @arg @ref HAL_OSPI_RX_CPLT_CB_ID OSPI Rx Complete Callback ID |
| * @arg @ref HAL_OSPI_TX_CPLT_CB_ID OSPI Tx Complete Callback ID |
| * @arg @ref HAL_OSPI_RX_HALF_CPLT_CB_ID OSPI Rx Half Complete Callback ID |
| * @arg @ref HAL_OSPI_TX_HALF_CPLT_CB_ID OSPI Tx Half Complete Callback ID |
| * @arg @ref HAL_OSPI_STATUS_MATCH_CB_ID OSPI Status Match Callback ID |
| * @arg @ref HAL_OSPI_TIMEOUT_CB_ID OSPI Timeout Callback ID |
| * @arg @ref HAL_OSPI_MSP_INIT_CB_ID OSPI MspInit callback ID |
| * @arg @ref HAL_OSPI_MSP_DEINIT_CB_ID OSPI MspDeInit callback ID |
| * @param pCallback : pointer to the Callback function |
| * @retval status |
| */ |
| HAL_StatusTypeDef HAL_OSPI_RegisterCallback(OSPI_HandleTypeDef *hospi, HAL_OSPI_CallbackIDTypeDef CallbackID, |
| pOSPI_CallbackTypeDef pCallback) |
| { |
| HAL_StatusTypeDef status = HAL_OK; |
| |
| if (pCallback == NULL) |
| { |
| /* Update the error code */ |
| hospi->ErrorCode |= HAL_OSPI_ERROR_INVALID_CALLBACK; |
| return HAL_ERROR; |
| } |
| |
| if (hospi->State == HAL_OSPI_STATE_READY) |
| { |
| switch (CallbackID) |
| { |
| case HAL_OSPI_ERROR_CB_ID : |
| hospi->ErrorCallback = pCallback; |
| break; |
| case HAL_OSPI_ABORT_CB_ID : |
| hospi->AbortCpltCallback = pCallback; |
| break; |
| case HAL_OSPI_FIFO_THRESHOLD_CB_ID : |
| hospi->FifoThresholdCallback = pCallback; |
| break; |
| case HAL_OSPI_CMD_CPLT_CB_ID : |
| hospi->CmdCpltCallback = pCallback; |
| break; |
| case HAL_OSPI_RX_CPLT_CB_ID : |
| hospi->RxCpltCallback = pCallback; |
| break; |
| case HAL_OSPI_TX_CPLT_CB_ID : |
| hospi->TxCpltCallback = pCallback; |
| break; |
| case HAL_OSPI_RX_HALF_CPLT_CB_ID : |
| hospi->RxHalfCpltCallback = pCallback; |
| break; |
| case HAL_OSPI_TX_HALF_CPLT_CB_ID : |
| hospi->TxHalfCpltCallback = pCallback; |
| break; |
| case HAL_OSPI_STATUS_MATCH_CB_ID : |
| hospi->StatusMatchCallback = pCallback; |
| break; |
| case HAL_OSPI_TIMEOUT_CB_ID : |
| hospi->TimeOutCallback = pCallback; |
| break; |
| case HAL_OSPI_MSP_INIT_CB_ID : |
| hospi->MspInitCallback = pCallback; |
| break; |
| case HAL_OSPI_MSP_DEINIT_CB_ID : |
| hospi->MspDeInitCallback = pCallback; |
| break; |
| default : |
| /* Update the error code */ |
| hospi->ErrorCode |= HAL_OSPI_ERROR_INVALID_CALLBACK; |
| /* update return status */ |
| status = HAL_ERROR; |
| break; |
| } |
| } |
| else if (hospi->State == HAL_OSPI_STATE_RESET) |
| { |
| switch (CallbackID) |
| { |
| case HAL_OSPI_MSP_INIT_CB_ID : |
| hospi->MspInitCallback = pCallback; |
| break; |
| case HAL_OSPI_MSP_DEINIT_CB_ID : |
| hospi->MspDeInitCallback = pCallback; |
| break; |
| default : |
| /* Update the error code */ |
| hospi->ErrorCode |= HAL_OSPI_ERROR_INVALID_CALLBACK; |
| /* update return status */ |
| status = HAL_ERROR; |
| break; |
| } |
| } |
| else |
| { |
| /* Update the error code */ |
| hospi->ErrorCode |= HAL_OSPI_ERROR_INVALID_CALLBACK; |
| /* update return status */ |
| status = HAL_ERROR; |
| } |
| |
| return status; |
| } |
| |
| /** |
| * @brief Unregister a User OSPI Callback |
| * OSPI Callback is redirected to the weak predefined callback |
| * @param hospi : OSPI handle |
| * @param CallbackID : ID of the callback to be unregistered |
| * This parameter can be one of the following values: |
| * @arg @ref HAL_OSPI_ERROR_CB_ID OSPI Error Callback ID |
| * @arg @ref HAL_OSPI_ABORT_CB_ID OSPI Abort Callback ID |
| * @arg @ref HAL_OSPI_FIFO_THRESHOLD_CB_ID OSPI FIFO Threshold Callback ID |
| * @arg @ref HAL_OSPI_CMD_CPLT_CB_ID OSPI Command Complete Callback ID |
| * @arg @ref HAL_OSPI_RX_CPLT_CB_ID OSPI Rx Complete Callback ID |
| * @arg @ref HAL_OSPI_TX_CPLT_CB_ID OSPI Tx Complete Callback ID |
| * @arg @ref HAL_OSPI_RX_HALF_CPLT_CB_ID OSPI Rx Half Complete Callback ID |
| * @arg @ref HAL_OSPI_TX_HALF_CPLT_CB_ID OSPI Tx Half Complete Callback ID |
| * @arg @ref HAL_OSPI_STATUS_MATCH_CB_ID OSPI Status Match Callback ID |
| * @arg @ref HAL_OSPI_TIMEOUT_CB_ID OSPI Timeout Callback ID |
| * @arg @ref HAL_OSPI_MSP_INIT_CB_ID OSPI MspInit callback ID |
| * @arg @ref HAL_OSPI_MSP_DEINIT_CB_ID OSPI MspDeInit callback ID |
| * @retval status |
| */ |
| HAL_StatusTypeDef HAL_OSPI_UnRegisterCallback(OSPI_HandleTypeDef *hospi, HAL_OSPI_CallbackIDTypeDef CallbackID) |
| { |
| HAL_StatusTypeDef status = HAL_OK; |
| |
| if (hospi->State == HAL_OSPI_STATE_READY) |
| { |
| switch (CallbackID) |
| { |
| case HAL_OSPI_ERROR_CB_ID : |
| hospi->ErrorCallback = HAL_OSPI_ErrorCallback; |
| break; |
| case HAL_OSPI_ABORT_CB_ID : |
| hospi->AbortCpltCallback = HAL_OSPI_AbortCpltCallback; |
| break; |
| case HAL_OSPI_FIFO_THRESHOLD_CB_ID : |
| hospi->FifoThresholdCallback = HAL_OSPI_FifoThresholdCallback; |
| break; |
| case HAL_OSPI_CMD_CPLT_CB_ID : |
| hospi->CmdCpltCallback = HAL_OSPI_CmdCpltCallback; |
| break; |
| case HAL_OSPI_RX_CPLT_CB_ID : |
| hospi->RxCpltCallback = HAL_OSPI_RxCpltCallback; |
| break; |
| case HAL_OSPI_TX_CPLT_CB_ID : |
| hospi->TxCpltCallback = HAL_OSPI_TxCpltCallback; |
| break; |
| case HAL_OSPI_RX_HALF_CPLT_CB_ID : |
| hospi->RxHalfCpltCallback = HAL_OSPI_RxHalfCpltCallback; |
| break; |
| case HAL_OSPI_TX_HALF_CPLT_CB_ID : |
| hospi->TxHalfCpltCallback = HAL_OSPI_TxHalfCpltCallback; |
| break; |
| case HAL_OSPI_STATUS_MATCH_CB_ID : |
| hospi->StatusMatchCallback = HAL_OSPI_StatusMatchCallback; |
| break; |
| case HAL_OSPI_TIMEOUT_CB_ID : |
| hospi->TimeOutCallback = HAL_OSPI_TimeOutCallback; |
| break; |
| case HAL_OSPI_MSP_INIT_CB_ID : |
| hospi->MspInitCallback = HAL_OSPI_MspInit; |
| break; |
| case HAL_OSPI_MSP_DEINIT_CB_ID : |
| hospi->MspDeInitCallback = HAL_OSPI_MspDeInit; |
| break; |
| default : |
| /* Update the error code */ |
| hospi->ErrorCode |= HAL_OSPI_ERROR_INVALID_CALLBACK; |
| /* update return status */ |
| status = HAL_ERROR; |
| break; |
| } |
| } |
| else if (hospi->State == HAL_OSPI_STATE_RESET) |
| { |
| switch (CallbackID) |
| { |
| case HAL_OSPI_MSP_INIT_CB_ID : |
| hospi->MspInitCallback = HAL_OSPI_MspInit; |
| break; |
| case HAL_OSPI_MSP_DEINIT_CB_ID : |
| hospi->MspDeInitCallback = HAL_OSPI_MspDeInit; |
| break; |
| default : |
| /* Update the error code */ |
| hospi->ErrorCode |= HAL_OSPI_ERROR_INVALID_CALLBACK; |
| /* update return status */ |
| status = HAL_ERROR; |
| break; |
| } |
| } |
| else |
| { |
| /* Update the error code */ |
| hospi->ErrorCode |= HAL_OSPI_ERROR_INVALID_CALLBACK; |
| /* update return status */ |
| status = HAL_ERROR; |
| } |
| |
| return status; |
| } |
| #endif /* defined (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) */ |
| |
| /** |
| * @} |
| */ |
| |
| /** @defgroup OSPI_Exported_Functions_Group3 Peripheral Control and State functions |
| * @brief OSPI control and State functions |
| * |
| @verbatim |
| =============================================================================== |
| ##### Peripheral Control and State functions ##### |
| =============================================================================== |
| [..] |
| This subsection provides a set of functions allowing to : |
| (+) Check in run-time the state of the driver. |
| (+) Check the error code set during last operation. |
| (+) Abort any operation. |
| (+) Manage the Fifo threshold. |
| (+) Configure the timeout duration used in the driver. |
| |
| @endverbatim |
| * @{ |
| */ |
| |
| /** |
| * @brief Abort the current transmission. |
| * @param hospi : OSPI handle |
| * @retval HAL status |
| */ |
| HAL_StatusTypeDef HAL_OSPI_Abort(OSPI_HandleTypeDef *hospi) |
| { |
| HAL_StatusTypeDef status = HAL_OK; |
| uint32_t state; |
| uint32_t tickstart = HAL_GetTick(); |
| |
| /* Check if the state is in one of the busy or configured states */ |
| state = hospi->State; |
| if (((state & OSPI_BUSY_STATE_MASK) != 0U) || ((state & OSPI_CFG_STATE_MASK) != 0U)) |
| { |
| /* Check if the DMA is enabled */ |
| if ((hospi->Instance->CR & OCTOSPI_CR_DMAEN) != 0U) |
| { |
| /* Disable the DMA transfer on the OctoSPI side */ |
| CLEAR_BIT(hospi->Instance->CR, OCTOSPI_CR_DMAEN); |
| |
| /* Disable the DMA transfer on the DMA side */ |
| status = HAL_DMA_Abort(hospi->hdma); |
| if (status != HAL_OK) |
| { |
| hospi->ErrorCode = HAL_OSPI_ERROR_DMA; |
| } |
| } |
| |
| if (__HAL_OSPI_GET_FLAG(hospi, HAL_OSPI_FLAG_BUSY) != RESET) |
| { |
| /* Perform an abort of the OctoSPI */ |
| SET_BIT(hospi->Instance->CR, OCTOSPI_CR_ABORT); |
| |
| /* Wait until the transfer complete flag is set to go back in idle state */ |
| status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_TC, SET, tickstart, hospi->Timeout); |
| |
| if (status == HAL_OK) |
| { |
| /* Clear transfer complete flag */ |
| __HAL_OSPI_CLEAR_FLAG(hospi, HAL_OSPI_FLAG_TC); |
| |
| /* Wait until the busy flag is reset to go back in idle state */ |
| status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_BUSY, RESET, tickstart, hospi->Timeout); |
| |
| if (status == HAL_OK) |
| { |
| /* Update state */ |
| hospi->State = HAL_OSPI_STATE_READY; |
| } |
| } |
| } |
| else |
| { |
| /* Update state */ |
| hospi->State = HAL_OSPI_STATE_READY; |
| } |
| } |
| else |
| { |
| status = HAL_ERROR; |
| hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; |
| } |
| |
| /* Return function status */ |
| return status; |
| } |
| |
| /** |
| * @brief Abort the current transmission (non-blocking function) |
| * @param hospi : OSPI handle |
| * @retval HAL status |
| */ |
| HAL_StatusTypeDef HAL_OSPI_Abort_IT(OSPI_HandleTypeDef *hospi) |
| { |
| HAL_StatusTypeDef status = HAL_OK; |
| uint32_t state; |
| |
| /* Check if the state is in one of the busy or configured states */ |
| state = hospi->State; |
| if (((state & OSPI_BUSY_STATE_MASK) != 0U) || ((state & OSPI_CFG_STATE_MASK) != 0U)) |
| { |
| /* Disable all interrupts */ |
| __HAL_OSPI_DISABLE_IT(hospi, (HAL_OSPI_IT_TO | HAL_OSPI_IT_SM | HAL_OSPI_IT_FT | HAL_OSPI_IT_TC | HAL_OSPI_IT_TE)); |
| |
| /* Update state */ |
| hospi->State = HAL_OSPI_STATE_ABORT; |
| |
| /* Check if the DMA is enabled */ |
| if ((hospi->Instance->CR & OCTOSPI_CR_DMAEN) != 0U) |
| { |
| /* Disable the DMA transfer on the OctoSPI side */ |
| CLEAR_BIT(hospi->Instance->CR, OCTOSPI_CR_DMAEN); |
| |
| /* Disable the DMA transfer on the DMA side */ |
| hospi->hdma->XferAbortCallback = OSPI_DMAAbortCplt; |
| if (HAL_DMA_Abort_IT(hospi->hdma) != HAL_OK) |
| { |
| /* Update state */ |
| hospi->State = HAL_OSPI_STATE_READY; |
| |
| /* Abort callback */ |
| #if defined (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) |
| hospi->AbortCpltCallback(hospi); |
| #else |
| HAL_OSPI_AbortCpltCallback(hospi); |
| #endif /* (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U)*/ |
| } |
| } |
| else |
| { |
| if (__HAL_OSPI_GET_FLAG(hospi, HAL_OSPI_FLAG_BUSY) != RESET) |
| { |
| /* Clear transfer complete flag */ |
| __HAL_OSPI_CLEAR_FLAG(hospi, HAL_OSPI_FLAG_TC); |
| |
| /* Enable the transfer complete interrupts */ |
| __HAL_OSPI_ENABLE_IT(hospi, HAL_OSPI_IT_TC); |
| |
| /* Perform an abort of the OctoSPI */ |
| SET_BIT(hospi->Instance->CR, OCTOSPI_CR_ABORT); |
| } |
| else |
| { |
| /* Update state */ |
| hospi->State = HAL_OSPI_STATE_READY; |
| |
| /* Abort callback */ |
| #if defined (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) |
| hospi->AbortCpltCallback(hospi); |
| #else |
| HAL_OSPI_AbortCpltCallback(hospi); |
| #endif /* (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) */ |
| } |
| } |
| } |
| else |
| { |
| status = HAL_ERROR; |
| hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; |
| } |
| |
| /* Return function status */ |
| return status; |
| } |
| |
| /** @brief Set OSPI Fifo threshold. |
| * @param hospi : OSPI handle. |
| * @param Threshold : Threshold of the Fifo. |
| * @retval HAL status |
| */ |
| HAL_StatusTypeDef HAL_OSPI_SetFifoThreshold(OSPI_HandleTypeDef *hospi, uint32_t Threshold) |
| { |
| HAL_StatusTypeDef status = HAL_OK; |
| |
| /* Check the state */ |
| if ((hospi->State & OSPI_BUSY_STATE_MASK) == 0U) |
| { |
| /* Synchronize initialization structure with the new fifo threshold value */ |
| hospi->Init.FifoThreshold = Threshold; |
| |
| /* Configure new fifo threshold */ |
| MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_FTHRES, ((hospi->Init.FifoThreshold - 1U) << OCTOSPI_CR_FTHRES_Pos)); |
| |
| } |
| else |
| { |
| status = HAL_ERROR; |
| hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; |
| } |
| |
| /* Return function status */ |
| return status; |
| } |
| |
| /** @brief Get OSPI Fifo threshold. |
| * @param hospi : OSPI handle. |
| * @retval Fifo threshold |
| */ |
| uint32_t HAL_OSPI_GetFifoThreshold(const OSPI_HandleTypeDef *hospi) |
| { |
| return ((READ_BIT(hospi->Instance->CR, OCTOSPI_CR_FTHRES) >> OCTOSPI_CR_FTHRES_Pos) + 1U); |
| } |
| |
| /** @brief Set OSPI timeout. |
| * @param hospi : OSPI handle. |
| * @param Timeout : Timeout for the memory access. |
| * @retval None |
| */ |
| HAL_StatusTypeDef HAL_OSPI_SetTimeout(OSPI_HandleTypeDef *hospi, uint32_t Timeout) |
| { |
| hospi->Timeout = Timeout; |
| return HAL_OK; |
| } |
| |
| /** |
| * @brief Return the OSPI error code. |
| * @param hospi : OSPI handle |
| * @retval OSPI Error Code |
| */ |
| uint32_t HAL_OSPI_GetError(const OSPI_HandleTypeDef *hospi) |
| { |
| return hospi->ErrorCode; |
| } |
| |
| /** |
| * @brief Return the OSPI handle state. |
| * @param hospi : OSPI handle |
| * @retval HAL state |
| */ |
| uint32_t HAL_OSPI_GetState(const OSPI_HandleTypeDef *hospi) |
| { |
| /* Return OSPI handle state */ |
| return hospi->State; |
| } |
| |
| /** |
| * @} |
| */ |
| |
| /** @defgroup OSPI_Exported_Functions_Group4 IO Manager configuration function |
| * @brief OSPI IO Manager configuration function |
| * |
| @verbatim |
| =============================================================================== |
| ##### IO Manager configuration function ##### |
| =============================================================================== |
| [..] |
| This subsection provides a set of functions allowing to : |
| (+) Configure the IO manager. |
| |
| @endverbatim |
| * @{ |
| */ |
| |
| /** |
| * @brief Configure the OctoSPI IO manager. |
| * @param hospi : OSPI handle |
| * @param cfg : Configuration of the IO Manager for the instance |
| * @param Timeout : Timeout duration |
| * @retval HAL status |
| */ |
| HAL_StatusTypeDef HAL_OSPIM_Config(OSPI_HandleTypeDef *hospi, OSPIM_CfgTypeDef *cfg, uint32_t Timeout) |
| { |
| HAL_StatusTypeDef status = HAL_OK; |
| uint32_t instance; |
| uint8_t index; |
| uint8_t ospi_enabled = 0U; |
| uint8_t other_instance; |
| OSPIM_CfgTypeDef IOM_cfg[OSPI_NB_INSTANCE]; |
| |
| /* Prevent unused argument(s) compilation warning */ |
| UNUSED(Timeout); |
| |
| /* Check the parameters of the OctoSPI IO Manager configuration structure */ |
| assert_param(IS_OSPIM_PORT(cfg->ClkPort)); |
| assert_param(IS_OSPIM_DQS_PORT(cfg->DQSPort)); |
| assert_param(IS_OSPIM_PORT(cfg->NCSPort)); |
| assert_param(IS_OSPIM_IO_PORT(cfg->IOLowPort)); |
| assert_param(IS_OSPIM_IO_PORT(cfg->IOHighPort)); |
| #if defined (OCTOSPIM_CR_MUXEN) |
| assert_param(IS_OSPIM_REQ2ACKTIME(cfg->Req2AckTime)); |
| #endif |
| |
| if (hospi->Instance == OCTOSPI1) |
| { |
| instance = 0U; |
| other_instance = 1U; |
| } |
| else |
| { |
| instance = 1U; |
| other_instance = 0U; |
| } |
| |
| /**************** Get current configuration of the instances ****************/ |
| for (index = 0U; index < OSPI_NB_INSTANCE; index++) |
| { |
| if (OSPIM_GetConfig(index + 1U, &(IOM_cfg[index])) != HAL_OK) |
| { |
| status = HAL_ERROR; |
| hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_PARAM; |
| } |
| } |
| |
| if (status == HAL_OK) |
| { |
| /********** Disable both OctoSPI to configure OctoSPI IO Manager **********/ |
| if ((OCTOSPI1->CR & OCTOSPI_CR_EN) != 0U) |
| { |
| CLEAR_BIT(OCTOSPI1->CR, OCTOSPI_CR_EN); |
| ospi_enabled |= 0x1U; |
| } |
| if ((OCTOSPI2->CR & OCTOSPI_CR_EN) != 0U) |
| { |
| CLEAR_BIT(OCTOSPI2->CR, OCTOSPI_CR_EN); |
| ospi_enabled |= 0x2U; |
| } |
| |
| /***************** Deactivation of previous configuration *****************/ |
| CLEAR_BIT(OCTOSPIM->PCR[(IOM_cfg[instance].NCSPort - 1U)], OCTOSPIM_PCR_NCSEN); |
| #if defined (OCTOSPIM_CR_MUXEN) |
| if ((OCTOSPIM->CR & OCTOSPIM_CR_MUXEN) != 0U) |
| { |
| /* De-multiplexing should be performed */ |
| CLEAR_BIT(OCTOSPIM->CR, OCTOSPIM_CR_MUXEN); |
| |
| if (other_instance == 1U) |
| { |
| SET_BIT(OCTOSPIM->PCR[(IOM_cfg[other_instance].ClkPort - 1U)], OCTOSPIM_PCR_CLKSRC); |
| if (IOM_cfg[other_instance].DQSPort != 0U) |
| { |
| SET_BIT(OCTOSPIM->PCR[(IOM_cfg[other_instance].DQSPort - 1U)], OCTOSPIM_PCR_DQSSRC); |
| } |
| if (IOM_cfg[other_instance].IOLowPort != HAL_OSPIM_IOPORT_NONE) |
| { |
| SET_BIT(OCTOSPIM->PCR[((IOM_cfg[other_instance].IOLowPort - 1U)& OSPI_IOM_PORT_MASK)], \ |
| OCTOSPIM_PCR_IOLSRC_1); |
| } |
| if (IOM_cfg[other_instance].IOHighPort != HAL_OSPIM_IOPORT_NONE) |
| { |
| SET_BIT(OCTOSPIM->PCR[((IOM_cfg[other_instance].IOHighPort - 1U)& OSPI_IOM_PORT_MASK)], \ |
| OCTOSPIM_PCR_IOHSRC_1); |
| } |
| } |
| } |
| else |
| { |
| #endif |
| if (IOM_cfg[instance].ClkPort != 0U) |
| { |
| CLEAR_BIT(OCTOSPIM->PCR[(IOM_cfg[instance].ClkPort - 1U)], OCTOSPIM_PCR_CLKEN); |
| if (IOM_cfg[instance].DQSPort != 0U) |
| { |
| CLEAR_BIT(OCTOSPIM->PCR[(IOM_cfg[instance].DQSPort - 1U)], OCTOSPIM_PCR_DQSEN); |
| } |
| if (IOM_cfg[instance].IOLowPort != HAL_OSPIM_IOPORT_NONE) |
| { |
| CLEAR_BIT(OCTOSPIM->PCR[((IOM_cfg[instance].IOLowPort - 1U)& OSPI_IOM_PORT_MASK)], OCTOSPIM_PCR_IOLEN); |
| } |
| if (IOM_cfg[instance].IOHighPort != HAL_OSPIM_IOPORT_NONE) |
| { |
| CLEAR_BIT(OCTOSPIM->PCR[((IOM_cfg[instance].IOHighPort - 1U)& OSPI_IOM_PORT_MASK)], OCTOSPIM_PCR_IOHEN); |
| } |
| } |
| #if defined (OCTOSPIM_CR_MUXEN) |
| } |
| #endif |
| |
| /********************* Deactivation of other instance *********************/ |
| if ((cfg->ClkPort == IOM_cfg[other_instance].ClkPort) || (cfg->NCSPort == IOM_cfg[other_instance].NCSPort) || |
| ((cfg->DQSPort == IOM_cfg[other_instance].DQSPort) && (cfg->DQSPort != 0U)) || |
| (cfg->IOLowPort == IOM_cfg[other_instance].IOLowPort) || |
| (cfg->IOHighPort == IOM_cfg[other_instance].IOHighPort)) |
| { |
| #if defined (OCTOSPIM_CR_MUXEN) |
| if ((cfg->ClkPort == IOM_cfg[other_instance].ClkPort) && |
| (cfg->DQSPort == IOM_cfg[other_instance].DQSPort) && |
| (cfg->IOLowPort == IOM_cfg[other_instance].IOLowPort) && |
| (cfg->IOHighPort == IOM_cfg[other_instance].IOHighPort)) |
| { |
| /* Multiplexing should be performed */ |
| SET_BIT(OCTOSPIM->CR, OCTOSPIM_CR_MUXEN); |
| } |
| else |
| { |
| #endif |
| CLEAR_BIT(OCTOSPIM->PCR[(IOM_cfg[other_instance].ClkPort - 1U)], OCTOSPIM_PCR_CLKEN); |
| if (IOM_cfg[other_instance].DQSPort != 0U) |
| { |
| CLEAR_BIT(OCTOSPIM->PCR[(IOM_cfg[other_instance].DQSPort - 1U)], OCTOSPIM_PCR_DQSEN); |
| } |
| CLEAR_BIT(OCTOSPIM->PCR[(IOM_cfg[other_instance].NCSPort - 1U)], OCTOSPIM_PCR_NCSEN); |
| if (IOM_cfg[other_instance].IOLowPort != HAL_OSPIM_IOPORT_NONE) |
| { |
| CLEAR_BIT(OCTOSPIM->PCR[((IOM_cfg[other_instance].IOLowPort - 1U)& OSPI_IOM_PORT_MASK)], |
| OCTOSPIM_PCR_IOLEN); |
| } |
| if (IOM_cfg[other_instance].IOHighPort != HAL_OSPIM_IOPORT_NONE) |
| { |
| CLEAR_BIT(OCTOSPIM->PCR[((IOM_cfg[other_instance].IOHighPort - 1U)& OSPI_IOM_PORT_MASK)], |
| OCTOSPIM_PCR_IOHEN); |
| } |
| #if defined (OCTOSPIM_CR_MUXEN) |
| } |
| #endif |
| } |
| |
| /******************** Activation of new configuration *********************/ |
| MODIFY_REG(OCTOSPIM->PCR[(cfg->NCSPort - 1U)], (OCTOSPIM_PCR_NCSEN | OCTOSPIM_PCR_NCSSRC), |
| (OCTOSPIM_PCR_NCSEN | (instance << OCTOSPIM_PCR_NCSSRC_Pos))); |
| |
| #if defined (OCTOSPIM_CR_MUXEN) |
| if ((cfg->Req2AckTime - 1U) > ((OCTOSPIM->CR & OCTOSPIM_CR_REQ2ACK_TIME) >> OCTOSPIM_CR_REQ2ACK_TIME_Pos)) |
| { |
| MODIFY_REG(OCTOSPIM->CR, OCTOSPIM_CR_REQ2ACK_TIME, ((cfg->Req2AckTime - 1U) << OCTOSPIM_CR_REQ2ACK_TIME_Pos)); |
| } |
| |
| if ((OCTOSPIM->CR & OCTOSPIM_CR_MUXEN) != 0U) |
| { |
| MODIFY_REG(OCTOSPIM->PCR[(cfg->ClkPort - 1U)], (OCTOSPIM_PCR_CLKEN | OCTOSPIM_PCR_CLKSRC), OCTOSPIM_PCR_CLKEN); |
| if (cfg->DQSPort != 0U) |
| { |
| MODIFY_REG(OCTOSPIM->PCR[(cfg->DQSPort - 1U)], (OCTOSPIM_PCR_DQSEN | OCTOSPIM_PCR_DQSSRC), OCTOSPIM_PCR_DQSEN); |
| } |
| |
| if ((cfg->IOLowPort & OCTOSPIM_PCR_IOLEN) != 0U) |
| { |
| MODIFY_REG(OCTOSPIM->PCR[((cfg->IOLowPort - 1U)& OSPI_IOM_PORT_MASK)], |
| (OCTOSPIM_PCR_IOLEN | OCTOSPIM_PCR_IOLSRC), OCTOSPIM_PCR_IOLEN); |
| } |
| else if (cfg->IOLowPort != HAL_OSPIM_IOPORT_NONE) |
| { |
| MODIFY_REG(OCTOSPIM->PCR[((cfg->IOLowPort - 1U)& OSPI_IOM_PORT_MASK)], |
| (OCTOSPIM_PCR_IOHEN | OCTOSPIM_PCR_IOHSRC), OCTOSPIM_PCR_IOHEN); |
| } |
| else |
| { |
| /* Nothing to do */ |
| } |
| |
| if ((cfg->IOHighPort & OCTOSPIM_PCR_IOLEN) != 0U) |
| { |
| MODIFY_REG(OCTOSPIM->PCR[((cfg->IOHighPort - 1U)& OSPI_IOM_PORT_MASK)], |
| (OCTOSPIM_PCR_IOLEN | OCTOSPIM_PCR_IOLSRC), (OCTOSPIM_PCR_IOLEN | OCTOSPIM_PCR_IOLSRC_0)); |
| } |
| else if (cfg->IOHighPort != HAL_OSPIM_IOPORT_NONE) |
| { |
| MODIFY_REG(OCTOSPIM->PCR[((cfg->IOHighPort - 1U)& OSPI_IOM_PORT_MASK)], |
| (OCTOSPIM_PCR_IOHEN | OCTOSPIM_PCR_IOHSRC), (OCTOSPIM_PCR_IOHEN | OCTOSPIM_PCR_IOHSRC_0)); |
| } |
| else |
| { |
| /* Nothing to do */ |
| } |
| } |
| else |
| { |
| #endif |
| MODIFY_REG(OCTOSPIM->PCR[(cfg->ClkPort - 1U)], (OCTOSPIM_PCR_CLKEN | OCTOSPIM_PCR_CLKSRC), |
| (OCTOSPIM_PCR_CLKEN | (instance << OCTOSPIM_PCR_CLKSRC_Pos))); |
| if (cfg->DQSPort != 0U) |
| { |
| MODIFY_REG(OCTOSPIM->PCR[(cfg->DQSPort - 1U)], (OCTOSPIM_PCR_DQSEN | OCTOSPIM_PCR_DQSSRC), |
| (OCTOSPIM_PCR_DQSEN | (instance << OCTOSPIM_PCR_DQSSRC_Pos))); |
| } |
| |
| if ((cfg->IOLowPort & OCTOSPIM_PCR_IOLEN) != 0U) |
| { |
| MODIFY_REG(OCTOSPIM->PCR[((cfg->IOLowPort - 1U)& OSPI_IOM_PORT_MASK)], |
| (OCTOSPIM_PCR_IOLEN | OCTOSPIM_PCR_IOLSRC), |
| (OCTOSPIM_PCR_IOLEN | (instance << (OCTOSPIM_PCR_IOLSRC_Pos + 1U)))); |
| } |
| else if (cfg->IOLowPort != HAL_OSPIM_IOPORT_NONE) |
| { |
| MODIFY_REG(OCTOSPIM->PCR[((cfg->IOLowPort - 1U)& OSPI_IOM_PORT_MASK)], |
| (OCTOSPIM_PCR_IOHEN | OCTOSPIM_PCR_IOHSRC), |
| (OCTOSPIM_PCR_IOHEN | (instance << (OCTOSPIM_PCR_IOHSRC_Pos + 1U)))); |
| } |
| else |
| { |
| /* Nothing to do */ |
| } |
| |
| if ((cfg->IOHighPort & OCTOSPIM_PCR_IOLEN) != 0U) |
| { |
| MODIFY_REG(OCTOSPIM->PCR[((cfg->IOHighPort - 1U)& OSPI_IOM_PORT_MASK)], |
| (OCTOSPIM_PCR_IOLEN | OCTOSPIM_PCR_IOLSRC), |
| (OCTOSPIM_PCR_IOLEN | OCTOSPIM_PCR_IOLSRC_0 | (instance << (OCTOSPIM_PCR_IOLSRC_Pos + 1U)))); |
| } |
| else if (cfg->IOHighPort != HAL_OSPIM_IOPORT_NONE) |
| { |
| MODIFY_REG(OCTOSPIM->PCR[((cfg->IOHighPort - 1U)& OSPI_IOM_PORT_MASK)], |
| (OCTOSPIM_PCR_IOHEN | OCTOSPIM_PCR_IOHSRC), |
| (OCTOSPIM_PCR_IOHEN | OCTOSPIM_PCR_IOHSRC_0 | (instance << (OCTOSPIM_PCR_IOHSRC_Pos + 1U)))); |
| } |
| else |
| { |
| /* Nothing to do */ |
| } |
| #if defined (OCTOSPIM_CR_MUXEN) |
| } |
| #endif |
| |
| /******* Re-enable both OctoSPI after configure OctoSPI IO Manager ********/ |
| if ((ospi_enabled & 0x1U) != 0U) |
| { |
| SET_BIT(OCTOSPI1->CR, OCTOSPI_CR_EN); |
| } |
| if ((ospi_enabled & 0x2U) != 0U) |
| { |
| SET_BIT(OCTOSPI2->CR, OCTOSPI_CR_EN); |
| } |
| } |
| |
| /* Return function status */ |
| return status; |
| } |
| |
| /** |
| * @} |
| */ |
| |
| /** |
| @cond 0 |
| */ |
| /** |
| * @brief DMA OSPI process complete callback. |
| * @param hdma : DMA handle |
| * @retval None |
| */ |
| static void OSPI_DMACplt(DMA_HandleTypeDef *hdma) |
| { |
| OSPI_HandleTypeDef *hospi = (OSPI_HandleTypeDef *)(hdma->Parent); |
| hospi->XferCount = 0; |
| |
| /* Disable the DMA transfer on the OctoSPI side */ |
| CLEAR_BIT(hospi->Instance->CR, OCTOSPI_CR_DMAEN); |
| |
| /* Disable the DMA channel */ |
| __HAL_DMA_DISABLE(hdma); |
| |
| /* Enable the OSPI transfer complete Interrupt */ |
| __HAL_OSPI_ENABLE_IT(hospi, HAL_OSPI_IT_TC); |
| } |
| |
| /** |
| * @brief DMA OSPI process half complete callback. |
| * @param hdma : DMA handle |
| * @retval None |
| */ |
| static void OSPI_DMAHalfCplt(DMA_HandleTypeDef *hdma) |
| { |
| OSPI_HandleTypeDef *hospi = (OSPI_HandleTypeDef *)(hdma->Parent); |
| hospi->XferCount = (hospi->XferCount >> 1); |
| |
| if (hospi->State == HAL_OSPI_STATE_BUSY_RX) |
| { |
| #if defined (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) |
| hospi->RxHalfCpltCallback(hospi); |
| #else |
| HAL_OSPI_RxHalfCpltCallback(hospi); |
| #endif /*(USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) */ |
| } |
| else |
| { |
| #if defined (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) |
| hospi->TxHalfCpltCallback(hospi); |
| #else |
| HAL_OSPI_TxHalfCpltCallback(hospi); |
| #endif /* (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U)*/ |
| } |
| } |
| |
| /** |
| * @brief DMA OSPI communication error callback. |
| * @param hdma : DMA handle |
| * @retval None |
| */ |
| static void OSPI_DMAError(DMA_HandleTypeDef *hdma) |
| { |
| OSPI_HandleTypeDef *hospi = (OSPI_HandleTypeDef *)(hdma->Parent); |
| hospi->XferCount = 0; |
| hospi->ErrorCode = HAL_OSPI_ERROR_DMA; |
| |
| /* Disable the DMA transfer on the OctoSPI side */ |
| CLEAR_BIT(hospi->Instance->CR, OCTOSPI_CR_DMAEN); |
| |
| /* Abort the OctoSPI */ |
| if (HAL_OSPI_Abort_IT(hospi) != HAL_OK) |
| { |
| /* Disable the interrupts */ |
| __HAL_OSPI_DISABLE_IT(hospi, HAL_OSPI_IT_TC | HAL_OSPI_IT_FT | HAL_OSPI_IT_TE); |
| |
| /* Update state */ |
| hospi->State = HAL_OSPI_STATE_READY; |
| |
| /* Error callback */ |
| #if defined (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) |
| hospi->ErrorCallback(hospi); |
| #else |
| HAL_OSPI_ErrorCallback(hospi); |
| #endif /*(USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) */ |
| } |
| } |
| |
| /** |
| * @brief DMA OSPI abort complete callback. |
| * @param hdma : DMA handle |
| * @retval None |
| */ |
| static void OSPI_DMAAbortCplt(DMA_HandleTypeDef *hdma) |
| { |
| OSPI_HandleTypeDef *hospi = (OSPI_HandleTypeDef *)(hdma->Parent); |
| hospi->XferCount = 0; |
| |
| /* Check the state */ |
| if (hospi->State == HAL_OSPI_STATE_ABORT) |
| { |
| /* DMA abort called by OctoSPI abort */ |
| if (__HAL_OSPI_GET_FLAG(hospi, HAL_OSPI_FLAG_BUSY) != RESET) |
| { |
| /* Clear transfer complete flag */ |
| __HAL_OSPI_CLEAR_FLAG(hospi, HAL_OSPI_FLAG_TC); |
| |
| /* Enable the transfer complete interrupts */ |
| __HAL_OSPI_ENABLE_IT(hospi, HAL_OSPI_IT_TC); |
| |
| /* Perform an abort of the OctoSPI */ |
| SET_BIT(hospi->Instance->CR, OCTOSPI_CR_ABORT); |
| } |
| else |
| { |
| /* Update state */ |
| hospi->State = HAL_OSPI_STATE_READY; |
| |
| /* Abort callback */ |
| #if defined (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) |
| hospi->AbortCpltCallback(hospi); |
| #else |
| HAL_OSPI_AbortCpltCallback(hospi); |
| #endif /* (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) */ |
| } |
| } |
| else |
| { |
| /* DMA abort called due to a transfer error interrupt */ |
| /* Update state */ |
| hospi->State = HAL_OSPI_STATE_READY; |
| |
| /* Error callback */ |
| #if defined (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U) |
| hospi->ErrorCallback(hospi); |
| #else |
| HAL_OSPI_ErrorCallback(hospi); |
| #endif /* (USE_HAL_OSPI_REGISTER_CALLBACKS) && (USE_HAL_OSPI_REGISTER_CALLBACKS == 1U)*/ |
| } |
| } |
| |
| /** |
| * @brief Wait for a flag state until timeout. |
| * @param hospi : OSPI handle |
| * @param Flag : Flag checked |
| * @param State : Value of the flag expected |
| * @param Timeout : Duration of the timeout |
| * @param Tickstart : Tick start value |
| * @retval HAL status |
| */ |
| static HAL_StatusTypeDef OSPI_WaitFlagStateUntilTimeout(OSPI_HandleTypeDef *hospi, uint32_t Flag, |
| FlagStatus State, uint32_t Tickstart, uint32_t Timeout) |
| { |
| /* Wait until flag is in expected state */ |
| while ((__HAL_OSPI_GET_FLAG(hospi, Flag)) != State) |
| { |
| /* Check for the Timeout */ |
| if (Timeout != HAL_MAX_DELAY) |
| { |
| if (((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U)) |
| { |
| hospi->State = HAL_OSPI_STATE_ERROR; |
| hospi->ErrorCode |= HAL_OSPI_ERROR_TIMEOUT; |
| |
| return HAL_ERROR; |
| } |
| } |
| } |
| return HAL_OK; |
| } |
| |
| /** |
| * @brief Configure the registers for the regular command mode. |
| * @param hospi : OSPI handle |
| * @param cmd : structure that contains the command configuration information |
| * @retval HAL status |
| */ |
| static HAL_StatusTypeDef OSPI_ConfigCmd(OSPI_HandleTypeDef *hospi, OSPI_RegularCmdTypeDef *cmd) |
| { |
| HAL_StatusTypeDef status = HAL_OK; |
| __IO uint32_t *ccr_reg; |
| __IO uint32_t *tcr_reg; |
| __IO uint32_t *ir_reg; |
| __IO uint32_t *abr_reg; |
| |
| /* Re-initialize the value of the functional mode */ |
| MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_FMODE, 0U); |
| |
| /* Configure the flash ID */ |
| if (hospi->Init.DualQuad == HAL_OSPI_DUALQUAD_DISABLE) |
| { |
| MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_FSEL, cmd->FlashId); |
| } |
| |
| if (cmd->OperationType == HAL_OSPI_OPTYPE_WRITE_CFG) |
| { |
| ccr_reg = &(hospi->Instance->WCCR); |
| tcr_reg = &(hospi->Instance->WTCR); |
| ir_reg = &(hospi->Instance->WIR); |
| abr_reg = &(hospi->Instance->WABR); |
| } |
| else |
| { |
| ccr_reg = &(hospi->Instance->CCR); |
| tcr_reg = &(hospi->Instance->TCR); |
| ir_reg = &(hospi->Instance->IR); |
| abr_reg = &(hospi->Instance->ABR); |
| } |
| |
| /* Configure the CCR register with DQS and SIOO modes */ |
| *ccr_reg = (cmd->DQSMode | cmd->SIOOMode); |
| |
| if (cmd->AlternateBytesMode != HAL_OSPI_ALTERNATE_BYTES_NONE) |
| { |
| /* Configure the ABR register with alternate bytes value */ |
| *abr_reg = cmd->AlternateBytes; |
| |
| /* Configure the CCR register with alternate bytes communication parameters */ |
| MODIFY_REG((*ccr_reg), (OCTOSPI_CCR_ABMODE | OCTOSPI_CCR_ABDTR | OCTOSPI_CCR_ABSIZE), |
| (cmd->AlternateBytesMode | cmd->AlternateBytesDtrMode | cmd->AlternateBytesSize)); |
| } |
| |
| /* Configure the TCR register with the number of dummy cycles */ |
| MODIFY_REG((*tcr_reg), OCTOSPI_TCR_DCYC, cmd->DummyCycles); |
| |
| if (cmd->DataMode != HAL_OSPI_DATA_NONE) |
| { |
| if (cmd->OperationType == HAL_OSPI_OPTYPE_COMMON_CFG) |
| { |
| /* Configure the DLR register with the number of data */ |
| hospi->Instance->DLR = (cmd->NbData - 1U); |
| } |
| } |
| |
| if (cmd->InstructionMode != HAL_OSPI_INSTRUCTION_NONE) |
| { |
| if (cmd->AddressMode != HAL_OSPI_ADDRESS_NONE) |
| { |
| if (cmd->DataMode != HAL_OSPI_DATA_NONE) |
| { |
| /* ---- Command with instruction, address and data ---- */ |
| |
| /* Configure the CCR register with all communication parameters */ |
| MODIFY_REG((*ccr_reg), (OCTOSPI_CCR_IMODE | OCTOSPI_CCR_IDTR | OCTOSPI_CCR_ISIZE | |
| OCTOSPI_CCR_ADMODE | OCTOSPI_CCR_ADDTR | OCTOSPI_CCR_ADSIZE | |
| OCTOSPI_CCR_DMODE | OCTOSPI_CCR_DDTR), |
| (cmd->InstructionMode | cmd->InstructionDtrMode | cmd->InstructionSize | |
| cmd->AddressMode | cmd->AddressDtrMode | cmd->AddressSize | |
| cmd->DataMode | cmd->DataDtrMode)); |
| } |
| else |
| { |
| /* ---- Command with instruction and address ---- */ |
| |
| /* Configure the CCR register with all communication parameters */ |
| MODIFY_REG((*ccr_reg), (OCTOSPI_CCR_IMODE | OCTOSPI_CCR_IDTR | OCTOSPI_CCR_ISIZE | |
| OCTOSPI_CCR_ADMODE | OCTOSPI_CCR_ADDTR | OCTOSPI_CCR_ADSIZE), |
| (cmd->InstructionMode | cmd->InstructionDtrMode | cmd->InstructionSize | |
| cmd->AddressMode | cmd->AddressDtrMode | cmd->AddressSize)); |
| |
| /* The DHQC bit is linked with DDTR bit which should be activated */ |
| if ((hospi->Init.DelayHoldQuarterCycle == HAL_OSPI_DHQC_ENABLE) && |
| (cmd->InstructionDtrMode == HAL_OSPI_INSTRUCTION_DTR_ENABLE)) |
| { |
| MODIFY_REG((*ccr_reg), OCTOSPI_CCR_DDTR, HAL_OSPI_DATA_DTR_ENABLE); |
| } |
| } |
| |
| /* Configure the IR register with the instruction value */ |
| *ir_reg = cmd->Instruction; |
| |
| /* Configure the AR register with the address value */ |
| hospi->Instance->AR = cmd->Address; |
| } |
| else |
| { |
| if (cmd->DataMode != HAL_OSPI_DATA_NONE) |
| { |
| /* ---- Command with instruction and data ---- */ |
| |
| /* Configure the CCR register with all communication parameters */ |
| MODIFY_REG((*ccr_reg), (OCTOSPI_CCR_IMODE | OCTOSPI_CCR_IDTR | OCTOSPI_CCR_ISIZE | |
| OCTOSPI_CCR_DMODE | OCTOSPI_CCR_DDTR), |
| (cmd->InstructionMode | cmd->InstructionDtrMode | cmd->InstructionSize | |
| cmd->DataMode | cmd->DataDtrMode)); |
| } |
| else |
| { |
| /* ---- Command with only instruction ---- */ |
| |
| /* Configure the CCR register with all communication parameters */ |
| MODIFY_REG((*ccr_reg), (OCTOSPI_CCR_IMODE | OCTOSPI_CCR_IDTR | OCTOSPI_CCR_ISIZE), |
| (cmd->InstructionMode | cmd->InstructionDtrMode | cmd->InstructionSize)); |
| |
| /* The DHQC bit is linked with DDTR bit which should be activated */ |
| if ((hospi->Init.DelayHoldQuarterCycle == HAL_OSPI_DHQC_ENABLE) && |
| (cmd->InstructionDtrMode == HAL_OSPI_INSTRUCTION_DTR_ENABLE)) |
| { |
| MODIFY_REG((*ccr_reg), OCTOSPI_CCR_DDTR, HAL_OSPI_DATA_DTR_ENABLE); |
| } |
| } |
| |
| /* Configure the IR register with the instruction value */ |
| *ir_reg = cmd->Instruction; |
| |
| } |
| } |
| else |
| { |
| if (cmd->AddressMode != HAL_OSPI_ADDRESS_NONE) |
| { |
| if (cmd->DataMode != HAL_OSPI_DATA_NONE) |
| { |
| /* ---- Command with address and data ---- */ |
| |
| /* Configure the CCR register with all communication parameters */ |
| MODIFY_REG((*ccr_reg), (OCTOSPI_CCR_ADMODE | OCTOSPI_CCR_ADDTR | OCTOSPI_CCR_ADSIZE | |
| OCTOSPI_CCR_DMODE | OCTOSPI_CCR_DDTR), |
| (cmd->AddressMode | cmd->AddressDtrMode | cmd->AddressSize | cmd->DataMode | |
| cmd->DataDtrMode)); |
| } |
| else |
| { |
| /* ---- Command with only address ---- */ |
| |
| /* Configure the CCR register with all communication parameters */ |
| MODIFY_REG((*ccr_reg), (OCTOSPI_CCR_ADMODE | OCTOSPI_CCR_ADDTR | OCTOSPI_CCR_ADSIZE), |
| (cmd->AddressMode | cmd->AddressDtrMode | cmd->AddressSize)); |
| } |
| |
| /* Configure the AR register with the instruction value */ |
| hospi->Instance->AR = cmd->Address; |
| } |
| else |
| { |
| /* ---- Invalid command configuration (no instruction, no address) ---- */ |
| status = HAL_ERROR; |
| hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_PARAM; |
| } |
| } |
| |
| /* Return function status */ |
| return status; |
| } |
| |
| /** |
| * @brief Get the current IOM configuration for an OctoSPI instance. |
| * @param instance_nb : number of the instance |
| * @param cfg : configuration of the IO Manager for the instance |
| * @retval HAL status |
| */ |
| static HAL_StatusTypeDef OSPIM_GetConfig(uint8_t instance_nb, OSPIM_CfgTypeDef *cfg) |
| { |
| HAL_StatusTypeDef status = HAL_OK; |
| uint32_t reg; |
| uint32_t value = 0U; |
| uint32_t index; |
| |
| if ((instance_nb == 0U) || (instance_nb > OSPI_NB_INSTANCE) || (cfg == NULL)) |
| { |
| /* Invalid parameter -> error returned */ |
| status = HAL_ERROR; |
| } |
| else |
| { |
| /* Initialize the structure */ |
| cfg->ClkPort = 0U; |
| cfg->DQSPort = 0U; |
| cfg->NCSPort = 0U; |
| cfg->IOLowPort = 0U; |
| cfg->IOHighPort = 0U; |
| |
| if (instance_nb == 2U) |
| { |
| #if defined (OCTOSPIM_CR_MUXEN) |
| if ((OCTOSPIM->CR & OCTOSPIM_CR_MUXEN) == 0U) |
| { |
| #endif |
| value = (OCTOSPIM_PCR_CLKSRC | OCTOSPIM_PCR_DQSSRC | OCTOSPIM_PCR_NCSSRC |
| | OCTOSPIM_PCR_IOLSRC_1 | OCTOSPIM_PCR_IOHSRC_1); |
| #if defined (OCTOSPIM_CR_MUXEN) |
| } |
| else |
| { |
| value = OCTOSPIM_PCR_NCSSRC; |
| } |
| #endif |
| } |
| |
| /* Get the information about the instance */ |
| for (index = 0U; index < OSPI_IOM_NB_PORTS; index ++) |
| { |
| reg = OCTOSPIM->PCR[index]; |
| |
| if ((reg & OCTOSPIM_PCR_CLKEN) != 0U) |
| { |
| /* The clock is enabled on this port */ |
| if ((reg & OCTOSPIM_PCR_CLKSRC) == (value & OCTOSPIM_PCR_CLKSRC)) |
| { |
| /* The clock correspond to the instance passed as parameter */ |
| cfg->ClkPort = index + 1U; |
| } |
| } |
| |
| if ((reg & OCTOSPIM_PCR_DQSEN) != 0U) |
| { |
| /* The DQS is enabled on this port */ |
| if ((reg & OCTOSPIM_PCR_DQSSRC) == (value & OCTOSPIM_PCR_DQSSRC)) |
| { |
| /* The DQS correspond to the instance passed as parameter */ |
| cfg->DQSPort = index + 1U; |
| } |
| } |
| |
| if ((reg & OCTOSPIM_PCR_NCSEN) != 0U) |
| { |
| /* The nCS is enabled on this port */ |
| if ((reg & OCTOSPIM_PCR_NCSSRC) == (value & OCTOSPIM_PCR_NCSSRC)) |
| { |
| /* The nCS correspond to the instance passed as parameter */ |
| cfg->NCSPort = index + 1U; |
| } |
| } |
| |
| if ((reg & OCTOSPIM_PCR_IOLEN) != 0U) |
| { |
| /* The IO Low is enabled on this port */ |
| if ((reg & OCTOSPIM_PCR_IOLSRC_1) == (value & OCTOSPIM_PCR_IOLSRC_1)) |
| { |
| /* The IO Low correspond to the instance passed as parameter */ |
| if ((reg & OCTOSPIM_PCR_IOLSRC_0) == 0U) |
| { |
| cfg->IOLowPort = (OCTOSPIM_PCR_IOLEN | (index + 1U)); |
| } |
| else |
| { |
| cfg->IOLowPort = (OCTOSPIM_PCR_IOHEN | (index + 1U)); |
| } |
| } |
| } |
| |
| if ((reg & OCTOSPIM_PCR_IOHEN) != 0U) |
| { |
| /* The IO High is enabled on this port */ |
| if ((reg & OCTOSPIM_PCR_IOHSRC_1) == (value & OCTOSPIM_PCR_IOHSRC_1)) |
| { |
| /* The IO High correspond to the instance passed as parameter */ |
| if ((reg & OCTOSPIM_PCR_IOHSRC_0) == 0U) |
| { |
| cfg->IOHighPort = (OCTOSPIM_PCR_IOLEN | (index + 1U)); |
| } |
| else |
| { |
| cfg->IOHighPort = (OCTOSPIM_PCR_IOHEN | (index + 1U)); |
| } |
| } |
| } |
| } |
| } |
| |
| /* Return function status */ |
| return status; |
| } |
| |
| /** |
| @endcond |
| */ |
| |
| /** |
| * @} |
| */ |
| |
| #endif /* HAL_OSPI_MODULE_ENABLED */ |
| |
| /** |
| * @} |
| */ |
| |
| /** |
| * @} |
| */ |
| |
| #endif /* OCTOSPI || OCTOSPI1 || OCTOSPI2 */ |