/** | |
****************************************************************************** | |
* @file stm32h745i_discovery_qspi.c | |
* @author MCD Application Team | |
* @brief This file includes a standard driver for the MT25TL01G QSPI | |
* memory mounted on STM32H745I-DISCOVERY board. | |
@verbatim | |
============================================================================== | |
##### How to use this driver ##### | |
============================================================================== | |
[..] | |
(#) This driver is used to drive the MT25TL01G QSPI external | |
memory mounted on STM32H745I_DISCOVERY board. | |
(#) This driver need a specific component driver (MT25TL01G) to be included with. | |
(#) Initialization steps: | |
(++) Initialize the QPSI external memory using the BSP_QSPI_Init() function. This | |
function includes the MSP layer hardware resources initialization and the | |
QSPI interface with the external memory. | |
(#) QSPI memory operations | |
(++) QSPI memory can be accessed with read/write operations once it is | |
initialized. | |
Read/write operation can be performed with AHB access using the functions | |
BSP_QSPI_Read()/BSP_QSPI_Write(). | |
(++) The function BSP_QSPI_GetInfo() returns the configuration of the QSPI memory. | |
(see the QSPI memory data sheet) | |
(++) Perform erase block operation using the function BSP_QSPI_Erase_Block() and by | |
specifying the block address. You can perform an erase operation of the whole | |
chip by calling the function BSP_QSPI_Erase_Chip(). | |
(++) The function BSP_QSPI_GetStatus() returns the current status of the QSPI memory. | |
(see the QSPI memory data sheet) | |
@endverbatim | |
****************************************************************************** | |
* @attention | |
* | |
* <h2><center>© Copyright (c) 2019 STMicroelectronics. | |
* All rights reserved.</center></h2> | |
* | |
* This software component is licensed by ST under BSD 3-Clause license, | |
* the "License"; You may not use this file except in compliance with the | |
* License. You may obtain a copy of the License at: | |
* opensource.org/licenses/BSD-3-Clause | |
* | |
****************************************************************************** | |
*/ | |
/* Includes ------------------------------------------------------------------*/ | |
#include "stm32h745i_discovery_qspi.h" | |
/** @addtogroup BSP | |
* @{ | |
*/ | |
/** @addtogroup STM32H745I_DISCOVERY | |
* @{ | |
*/ | |
/** @defgroup STM32H745I_DISCOVERY_QSPI STM32H745I_DISCOVERY_QSPI | |
* @{ | |
*/ | |
/* Private variables ---------------------------------------------------------*/ | |
/** @defgroup STM32H745I_DISCOVERY_QSPI_Private_Variables Private Variables | |
* @{ | |
*/ | |
QSPI_HandleTypeDef QSPIHandle; | |
/** | |
* @} | |
*/ | |
/* Private functions ---------------------------------------------------------*/ | |
/** @defgroup STM32H745I_DISCOVERY_QSPI_Private_Functions Private Functions | |
* @{ | |
*/ | |
static uint8_t QSPI_ResetMemory (QSPI_HandleTypeDef *hqspi); | |
static uint8_t QSPI_EnterFourBytesAddress(QSPI_HandleTypeDef *hqspi); | |
static uint8_t QSPI_DummyCyclesCfg (QSPI_HandleTypeDef *hqspi); | |
static uint8_t QSPI_WriteEnable (QSPI_HandleTypeDef *hqspi); | |
static uint8_t QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi, uint32_t Timeout); | |
static uint8_t QSPI_EnterQPI(QSPI_HandleTypeDef *hqspi); | |
/** | |
* @} | |
*/ | |
/** @defgroup STM32H745I_DISCOVERY_QSPI_Exported_Functions Exported Functions | |
* @{ | |
*/ | |
/** | |
* @brief Initializes the QSPI interface. | |
* @retval QSPI memory status | |
*/ | |
uint8_t BSP_QSPI_Init(void) | |
{ | |
QSPIHandle.Instance = QUADSPI; | |
/* Call the DeInit function to reset the driver */ | |
if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
/* System level initialization */ | |
BSP_QSPI_MspInit(&QSPIHandle, NULL); | |
/* QSPI initialization */ | |
/* ClockPrescaler set to 1, so QSPI clock = 200MHz / (1+3) = 50MHz */ | |
QSPIHandle.Init.ClockPrescaler = 3; | |
QSPIHandle.Init.FifoThreshold = 1; | |
QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE; | |
QSPIHandle.Init.FlashSize = POSITION_VAL(MT25TL01G_FLASH_SIZE) - 1; | |
QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_3_CYCLE; | |
QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0; | |
QSPIHandle.Init.FlashID = QSPI_FLASH_ID_2; | |
QSPIHandle.Init.DualFlash = QSPI_DUALFLASH_ENABLE; | |
if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
/* QSPI memory reset */ | |
if (QSPI_ResetMemory(&QSPIHandle) != QSPI_OK) | |
{ | |
return QSPI_NOT_SUPPORTED; | |
} | |
/* Set the QSPI memory in 4-bytes address mode */ | |
if (QSPI_EnterFourBytesAddress(&QSPIHandle) != QSPI_OK) | |
{ | |
return QSPI_NOT_SUPPORTED; | |
} | |
/* Configuration of the dummy cycles on QSPI memory side */ | |
if (QSPI_DummyCyclesCfg(&QSPIHandle) != QSPI_OK) | |
{ | |
return QSPI_NOT_SUPPORTED; | |
} | |
return QSPI_OK; | |
} | |
/** | |
* @brief De-Initializes the QSPI interface. | |
* @retval QSPI memory status | |
*/ | |
uint8_t BSP_QSPI_DeInit(void) | |
{ | |
QSPIHandle.Instance = QUADSPI; | |
/* Call the DeInit function to reset the driver */ | |
if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
/* System level De-initialization */ | |
BSP_QSPI_MspDeInit(&QSPIHandle, NULL); | |
return QSPI_OK; | |
} | |
/** | |
* @brief Reads an amount of data from the QSPI memory. | |
* @param pData: Pointer to data to be read | |
* @param ReadAddr: Read start address | |
* @param Size: Size of data to read | |
* @retval QSPI memory status | |
*/ | |
uint8_t BSP_QSPI_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size) | |
{ | |
QSPI_CommandTypeDef s_command; | |
/* Initialize the read command */ | |
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; | |
s_command.Instruction = QUAD_INOUT_FAST_READ_DTR_CMD; /* DTR QUAD INPUT/OUTPUT FAST READ and 4-BYTE DTR FAST READ commands */ | |
s_command.AddressMode = QSPI_ADDRESS_4_LINES; | |
s_command.AddressSize = QSPI_ADDRESS_32_BITS; | |
s_command.Address = ReadAddr; | |
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; | |
s_command.DataMode = QSPI_DATA_4_LINES; | |
s_command.DummyCycles = MT25TL01G_DUMMY_CYCLES_READ_QUAD_DTR - 1; | |
s_command.NbData = Size; | |
s_command.DdrMode = QSPI_DDR_MODE_ENABLE; | |
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_HALF_CLK_DELAY; | |
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; | |
/* Configure the command */ | |
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
/* Reception of the data */ | |
if (HAL_QSPI_Receive(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
return QSPI_OK; | |
} | |
/** | |
* @brief Writes an amount of data to the QSPI memory. | |
* @param pData: Pointer to data to be written | |
* @param WriteAddr: Write start address | |
* @param Size: Size of data to write | |
* @retval QSPI memory status | |
*/ | |
uint8_t BSP_QSPI_Write(uint8_t* pData, uint32_t WriteAddr, uint32_t Size) | |
{ | |
QSPI_CommandTypeDef s_command; | |
uint32_t end_addr, current_size, current_addr; | |
/* Calculation of the size between the write address and the end of the page */ | |
current_size = MT25TL01G_PAGE_SIZE - (WriteAddr % MT25TL01G_PAGE_SIZE); | |
/* Check if the size of the data is less than the remaining place in the page */ | |
if (current_size > Size) | |
{ | |
current_size = Size; | |
} | |
/* Initialize the address variables */ | |
current_addr = WriteAddr; | |
end_addr = WriteAddr + Size; | |
/* Initialize the program command */ | |
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; | |
s_command.Instruction = QUAD_IN_FAST_PROG_4_BYTE_ADDR_CMD; | |
s_command.AddressMode = QSPI_ADDRESS_4_LINES; | |
s_command.AddressSize = QSPI_ADDRESS_32_BITS; | |
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; | |
s_command.DataMode = QSPI_DATA_4_LINES; | |
s_command.DummyCycles = 0; | |
s_command.DdrMode = QSPI_DDR_MODE_DISABLE; | |
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; | |
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; | |
/* Perform the write page by page */ | |
do | |
{ | |
s_command.Address = current_addr; | |
s_command.NbData = current_size; | |
/* Enable write operations */ | |
if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
/* Configure the command */ | |
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
/* Transmission of the data */ | |
if (HAL_QSPI_Transmit(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
/* Configure automatic polling mode to wait for end of program */ | |
if (QSPI_AutoPollingMemReady(&QSPIHandle, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
/* Update the address and size variables for next page programming */ | |
current_addr += current_size; | |
pData += current_size; | |
current_size = ((current_addr + MT25TL01G_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : MT25TL01G_PAGE_SIZE; | |
} while (current_addr < end_addr); | |
return QSPI_OK; | |
} | |
/** | |
* @brief Erases the specified block of the QSPI memory. | |
* @param BlockAddress: Block address to erase | |
* @retval QSPI memory status | |
*/ | |
uint8_t BSP_QSPI_Erase_Block(uint32_t BlockAddress) | |
{ | |
QSPI_CommandTypeDef s_command; | |
/* Initialize the erase command */ | |
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; | |
s_command.Instruction = SUBSECTOR_ERASE_4_BYTE_ADDR_CMD; | |
s_command.AddressMode = QSPI_ADDRESS_4_LINES; | |
s_command.AddressSize = QSPI_ADDRESS_32_BITS; | |
s_command.Address = BlockAddress; | |
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; | |
s_command.DataMode = QSPI_DATA_NONE; | |
s_command.DummyCycles = 0; | |
s_command.DdrMode = QSPI_DDR_MODE_DISABLE; | |
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; | |
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; | |
/* Enable write operations */ | |
if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
/* Send the command */ | |
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
/* Configure automatic polling mode to wait for end of erase */ | |
if (QSPI_AutoPollingMemReady(&QSPIHandle, MT25TL01G_SUBSECTOR_ERASE_MAX_TIME) != QSPI_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
return QSPI_OK; | |
} | |
/** | |
* @brief Erases the entire QSPI memory. | |
* @retval QSPI memory status | |
*/ | |
uint8_t BSP_QSPI_Erase_Chip(void) | |
{ | |
QSPI_CommandTypeDef s_command; | |
/* Initialize the erase command */ | |
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; | |
s_command.Instruction = DIE_ERASE_CMD; | |
s_command.AddressMode = QSPI_ADDRESS_NONE; | |
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; | |
s_command.DataMode = QSPI_DATA_NONE; | |
s_command.DummyCycles = 0; | |
s_command.DdrMode = QSPI_DDR_MODE_DISABLE; | |
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; | |
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; | |
/* Enable write operations */ | |
if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
/* Send the command */ | |
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
/* Configure automatic polling mode to wait for end of erase */ | |
if (QSPI_AutoPollingMemReady(&QSPIHandle, MT25TL01G_DIE_ERASE_MAX_TIME) != QSPI_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
return QSPI_OK; | |
} | |
/** | |
* @brief Reads current status of the QSPI memory. | |
* @retval QSPI memory status | |
*/ | |
uint8_t BSP_QSPI_GetStatus(void) | |
{ | |
QSPI_CommandTypeDef s_command; | |
uint16_t reg; | |
/* Initialize the read flag status register command */ | |
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; | |
s_command.Instruction = READ_FLAG_STATUS_REG_CMD; | |
s_command.AddressMode = QSPI_ADDRESS_NONE; | |
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; | |
s_command.DataMode = QSPI_DATA_4_LINES; | |
s_command.DummyCycles = 0; | |
s_command.NbData = 1; | |
s_command.DdrMode = QSPI_DDR_MODE_DISABLE; | |
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; | |
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; | |
/* Configure the command */ | |
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
/* Reception of the data */ | |
if (HAL_QSPI_Receive(&QSPIHandle, (uint8_t*)(®), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
/* Check the value of the register */ | |
if ((reg & (MT25TL01G_FSR_PRERR | MT25TL01G_FSR_PGERR | MT25TL01G_FSR_ERERR)) != 0) | |
{ | |
return QSPI_ERROR; | |
} | |
else if ((reg & (MT25TL01G_FSR_PGSUS | MT25TL01G_FSR_ERSUS)) != 0) | |
{ | |
return QSPI_SUSPENDED; | |
} | |
else if ((reg & MT25TL01G_FSR_READY) != 0) | |
{ | |
return QSPI_OK; | |
} | |
else | |
{ | |
return QSPI_BUSY; | |
} | |
} | |
/** | |
* @brief Return the configuration of the QSPI memory. | |
* @param pInfo: pointer on the configuration structure | |
* @retval QSPI memory status | |
*/ | |
uint8_t BSP_QSPI_GetInfo(QSPI_Info* pInfo) | |
{ | |
/* Configure the structure with the memory configuration */ | |
pInfo->FlashSize = MT25TL01G_FLASH_SIZE; | |
pInfo->EraseSectorSize = (2 * MT25TL01G_SUBSECTOR_SIZE); | |
pInfo->ProgPageSize = MT25TL01G_PAGE_SIZE; | |
pInfo->EraseSectorsNumber = (MT25TL01G_FLASH_SIZE/pInfo->EraseSectorSize); | |
pInfo->ProgPagesNumber = (MT25TL01G_FLASH_SIZE/pInfo->ProgPageSize); | |
return QSPI_OK; | |
} | |
/** | |
* @brief Configure the QSPI in memory-mapped mode | |
* @retval QSPI memory status | |
*/ | |
uint8_t BSP_QSPI_EnableMemoryMappedMode(void) | |
{ | |
QSPI_CommandTypeDef s_command; | |
QSPI_MemoryMappedTypeDef s_mem_mapped_cfg; | |
/* Configure the command for the read instruction */ | |
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; | |
s_command.Instruction = QUAD_INOUT_FAST_READ_DTR_CMD; /* DTR QUAD INPUT/OUTPUT FAST READ and 4-BYTE DTR FAST READ commands */ | |
s_command.AddressMode = QSPI_ADDRESS_4_LINES; | |
s_command.AddressSize = QSPI_ADDRESS_32_BITS; | |
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; | |
s_command.DataMode = QSPI_DATA_4_LINES; | |
s_command.DummyCycles = MT25TL01G_DUMMY_CYCLES_READ_QUAD_DTR - 1; | |
s_command.DdrMode = QSPI_DDR_MODE_ENABLE; | |
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_HALF_CLK_DELAY; | |
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; | |
/* Configure the memory mapped mode */ | |
s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE; | |
s_mem_mapped_cfg.TimeOutPeriod = 0; | |
if (HAL_QSPI_MemoryMapped(&QSPIHandle, &s_command, &s_mem_mapped_cfg) != HAL_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
return QSPI_OK; | |
} | |
/** | |
* @brief QSPI MSP Initialization | |
* This function configures the hardware resources used in this example: | |
* - Peripheral's clock enable | |
* - Peripheral's GPIO Configuration | |
* - NVIC configuration for QSPI interrupt | |
* @retval None | |
*/ | |
__weak void BSP_QSPI_MspInit(QSPI_HandleTypeDef *hqspi, void *Params) | |
{ | |
GPIO_InitTypeDef gpio_init_structure; | |
/*##-1- Enable peripherals and GPIO Clocks #################################*/ | |
/* Enable the QuadSPI memory interface clock */ | |
QSPI_CLK_ENABLE(); | |
/* Reset the QuadSPI memory interface */ | |
QSPI_FORCE_RESET(); | |
QSPI_RELEASE_RESET(); | |
/* Enable GPIO clocks */ | |
QSPI_CLK_GPIO_CLK_ENABLE(); | |
QSPI_BK1_CS_GPIO_CLK_ENABLE(); | |
QSPI_BK1_D0_GPIO_CLK_ENABLE(); | |
QSPI_BK1_D1_GPIO_CLK_ENABLE(); | |
QSPI_BK1_D2_GPIO_CLK_ENABLE(); | |
QSPI_BK1_D3_GPIO_CLK_ENABLE(); | |
QSPI_BK2_CS_GPIO_CLK_ENABLE(); | |
QSPI_BK2_D0_GPIO_CLK_ENABLE(); | |
QSPI_BK2_D1_GPIO_CLK_ENABLE(); | |
QSPI_BK2_D2_GPIO_CLK_ENABLE(); | |
QSPI_BK2_D3_GPIO_CLK_ENABLE(); | |
/*##-2- Configure peripheral GPIO ##########################################*/ | |
/* QSPI CLK GPIO pin configuration */ | |
gpio_init_structure.Pin = QSPI_CLK_PIN; | |
gpio_init_structure.Mode = GPIO_MODE_AF_PP; | |
gpio_init_structure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; | |
gpio_init_structure.Pull = GPIO_NOPULL; | |
gpio_init_structure.Alternate = GPIO_AF9_QUADSPI; | |
HAL_GPIO_Init(QSPI_CLK_GPIO_PORT, &gpio_init_structure); | |
/* QSPI CS GPIO pin configuration */ | |
gpio_init_structure.Pin = QSPI_BK1_CS_PIN; | |
gpio_init_structure.Pull = GPIO_PULLUP; | |
gpio_init_structure.Alternate = GPIO_AF10_QUADSPI; | |
HAL_GPIO_Init(QSPI_BK1_CS_GPIO_PORT, &gpio_init_structure); | |
/* QSPI D0 GPIO pin configuration */ | |
gpio_init_structure.Pin = QSPI_BK1_D0_PIN; | |
gpio_init_structure.Pull = GPIO_NOPULL; | |
gpio_init_structure.Alternate = GPIO_AF9_QUADSPI; | |
HAL_GPIO_Init(QSPI_BK1_D0_GPIO_PORT, &gpio_init_structure); | |
gpio_init_structure.Pin = QSPI_BK2_D0_PIN; | |
gpio_init_structure.Alternate = GPIO_AF9_QUADSPI; | |
HAL_GPIO_Init(QSPI_BK2_D0_GPIO_PORT, &gpio_init_structure); | |
/* QSPI D1 GPIO pin configuration */ | |
gpio_init_structure.Pin = QSPI_BK1_D1_PIN; | |
gpio_init_structure.Alternate = GPIO_AF10_QUADSPI; | |
HAL_GPIO_Init(QSPI_BK1_D1_GPIO_PORT, &gpio_init_structure); | |
gpio_init_structure.Pin = QSPI_BK2_D1_PIN; | |
gpio_init_structure.Alternate = GPIO_AF9_QUADSPI; | |
HAL_GPIO_Init(QSPI_BK2_D1_GPIO_PORT, &gpio_init_structure); | |
/* QSPI D2 GPIO pin configuration */ | |
gpio_init_structure.Pin = QSPI_BK1_D2_PIN; | |
gpio_init_structure.Alternate = GPIO_AF9_QUADSPI; | |
HAL_GPIO_Init(QSPI_BK1_D2_GPIO_PORT, &gpio_init_structure); | |
gpio_init_structure.Pin = QSPI_BK2_D2_PIN; | |
HAL_GPIO_Init(QSPI_BK2_D2_GPIO_PORT, &gpio_init_structure); | |
/* QSPI D3 GPIO pin configuration */ | |
gpio_init_structure.Pin = QSPI_BK1_D3_PIN; | |
HAL_GPIO_Init(QSPI_BK1_D3_GPIO_PORT, &gpio_init_structure); | |
gpio_init_structure.Pin = QSPI_BK2_D3_PIN; | |
HAL_GPIO_Init(QSPI_BK2_D3_GPIO_PORT, &gpio_init_structure); | |
/*##-3- Configure the NVIC for QSPI #########################################*/ | |
/* NVIC configuration for QSPI interrupt */ | |
HAL_NVIC_SetPriority(QUADSPI_IRQn, 0x0F, 0); | |
HAL_NVIC_EnableIRQ(QUADSPI_IRQn); | |
} | |
/** | |
* @brief QSPI MSP De-Initialization | |
* This function frees the hardware resources used in this example: | |
* - Disable the Peripheral's clock | |
* - Revert GPIO and NVIC configuration to their default state | |
* @retval None | |
*/ | |
__weak void BSP_QSPI_MspDeInit(QSPI_HandleTypeDef *hqspi, void *Params) | |
{ | |
/*##-1- Disable the NVIC for QSPI ###########################################*/ | |
HAL_NVIC_DisableIRQ(QUADSPI_IRQn); | |
/*##-2- Disable peripherals and GPIO Clocks ################################*/ | |
/* De-Configure QSPI pins */ | |
HAL_GPIO_DeInit(QSPI_CLK_GPIO_PORT, QSPI_CLK_PIN); | |
HAL_GPIO_DeInit(QSPI_BK1_CS_GPIO_PORT, QSPI_BK1_CS_PIN); | |
HAL_GPIO_DeInit(QSPI_BK1_D0_GPIO_PORT, QSPI_BK1_D0_PIN); | |
HAL_GPIO_DeInit(QSPI_BK1_D1_GPIO_PORT, QSPI_BK1_D1_PIN); | |
HAL_GPIO_DeInit(QSPI_BK1_D2_GPIO_PORT, QSPI_BK1_D2_PIN); | |
HAL_GPIO_DeInit(QSPI_BK1_D3_GPIO_PORT, QSPI_BK1_D3_PIN); | |
HAL_GPIO_DeInit(QSPI_BK2_CS_GPIO_PORT, QSPI_BK2_CS_PIN); | |
HAL_GPIO_DeInit(QSPI_BK2_D0_GPIO_PORT, QSPI_BK2_D0_PIN); | |
HAL_GPIO_DeInit(QSPI_BK2_D1_GPIO_PORT, QSPI_BK2_D1_PIN); | |
HAL_GPIO_DeInit(QSPI_BK2_D2_GPIO_PORT, QSPI_BK2_D2_PIN); | |
HAL_GPIO_DeInit(QSPI_BK2_D3_GPIO_PORT, QSPI_BK2_D3_PIN); | |
/*##-3- Reset peripherals ##################################################*/ | |
/* Reset the QuadSPI memory interface */ | |
QSPI_FORCE_RESET(); | |
QSPI_RELEASE_RESET(); | |
/* Disable the QuadSPI memory interface clock */ | |
QSPI_CLK_DISABLE(); | |
} | |
/** | |
* @} | |
*/ | |
/** @addtogroup STM32H745I_DISCOVERY_QSPI_Private_Functions | |
* @{ | |
*/ | |
/** | |
* @brief This function reset the QSPI memory. | |
* @param hqspi: QSPI handle | |
* @retval None | |
*/ | |
static uint8_t QSPI_ResetMemory(QSPI_HandleTypeDef *hqspi) | |
{ | |
QSPI_CommandTypeDef s_command; | |
/* Initialize the reset enable command */ | |
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; | |
s_command.Instruction = RESET_ENABLE_CMD; | |
s_command.AddressMode = QSPI_ADDRESS_NONE; | |
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; | |
s_command.DataMode = QSPI_DATA_NONE; | |
s_command.DummyCycles = 0; | |
s_command.DdrMode = QSPI_DDR_MODE_DISABLE; | |
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; | |
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; | |
/* Send the command */ | |
if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
/* Send the reset memory command */ | |
s_command.Instruction = RESET_MEMORY_CMD; | |
if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; | |
s_command.Instruction = RESET_ENABLE_CMD; | |
/* Send the command */ | |
if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
/* Send the reset memory command */ | |
s_command.Instruction = RESET_MEMORY_CMD; | |
if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
/* Enter QSPI memory in QPI mode */ | |
if(QSPI_EnterQPI(&QSPIHandle) != QSPI_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
/* Configure automatic polling mode to wait the memory is ready */ | |
if (QSPI_AutoPollingMemReady(hqspi, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
return QSPI_OK; | |
} | |
/** | |
* @brief This function set the QSPI memory in 4-byte address mode | |
* @param hqspi: QSPI handle | |
* @retval None | |
*/ | |
static uint8_t QSPI_EnterFourBytesAddress(QSPI_HandleTypeDef *hqspi) | |
{ | |
QSPI_CommandTypeDef s_command; | |
/* Initialize the command */ | |
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; | |
s_command.Instruction = ENTER_4_BYTE_ADDR_MODE_CMD; | |
s_command.AddressMode = QSPI_ADDRESS_NONE; | |
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; | |
s_command.DataMode = QSPI_DATA_NONE; | |
s_command.DummyCycles = 0; | |
s_command.DdrMode = QSPI_DDR_MODE_DISABLE; | |
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; | |
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; | |
/* Enable write operations */ | |
if (QSPI_WriteEnable(hqspi) != QSPI_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
/* Send the command */ | |
if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
/* Configure automatic polling mode to wait the memory is ready */ | |
if (QSPI_AutoPollingMemReady(hqspi, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
return QSPI_OK; | |
} | |
/** | |
* @brief This function configure the dummy cycles on memory side. | |
* @param hqspi: QSPI handle | |
* @retval None | |
*/ | |
static uint8_t QSPI_DummyCyclesCfg(QSPI_HandleTypeDef *hqspi) | |
{ | |
QSPI_CommandTypeDef s_command; | |
uint16_t reg = 0; | |
/* Initialize the read volatile configuration register command */ | |
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; | |
s_command.Instruction = READ_VOL_CFG_REG_CMD; | |
s_command.AddressMode = QSPI_ADDRESS_NONE; | |
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; | |
s_command.DataMode = QSPI_DATA_4_LINES; | |
s_command.DummyCycles = 0; | |
s_command.NbData = 2; | |
s_command.DdrMode = QSPI_DDR_MODE_DISABLE; | |
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; | |
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; | |
/* Configure the command */ | |
if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
/* Reception of the data */ | |
if (HAL_QSPI_Receive(hqspi, (uint8_t *)(®), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
/* Enable write operations */ | |
if (QSPI_WriteEnable(hqspi) != QSPI_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
/* Update volatile configuration register (with new dummy cycles) */ | |
s_command.Instruction = WRITE_VOL_CFG_REG_CMD; | |
MODIFY_REG(reg, 0xF0F0, ((MT25TL01G_DUMMY_CYCLES_READ_QUAD << 4) | | |
(MT25TL01G_DUMMY_CYCLES_READ_QUAD << 12))); | |
/* Configure the write volatile configuration register command */ | |
if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
/* Transmission of the data */ | |
if (HAL_QSPI_Transmit(hqspi, (uint8_t *)(®), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
return QSPI_OK; | |
} | |
/** | |
* @brief This function send a Write Enable and wait it is effective. | |
* @param hqspi: QSPI handle | |
* @retval None | |
*/ | |
static uint8_t QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi) | |
{ | |
QSPI_CommandTypeDef s_command; | |
QSPI_AutoPollingTypeDef s_config; | |
/* Enable write operations */ | |
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; | |
s_command.Instruction = WRITE_ENABLE_CMD; | |
s_command.AddressMode = QSPI_ADDRESS_NONE; | |
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; | |
s_command.DataMode = QSPI_DATA_NONE; | |
s_command.DummyCycles = 0; | |
s_command.DdrMode = QSPI_DDR_MODE_DISABLE; | |
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; | |
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; | |
if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
/* Configure automatic polling mode to wait for write enabling */ | |
s_config.Match = MT25TL01G_SR_WREN | (MT25TL01G_SR_WREN << 8); | |
s_config.Mask = MT25TL01G_SR_WREN | (MT25TL01G_SR_WREN << 8); | |
s_config.MatchMode = QSPI_MATCH_MODE_AND; | |
s_config.StatusBytesSize = 2; | |
s_config.Interval = 0x10; | |
s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; | |
s_command.Instruction = READ_STATUS_REG_CMD; | |
s_command.DataMode = QSPI_DATA_4_LINES; | |
if (HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
return QSPI_OK; | |
} | |
/** | |
* @brief This function read the SR of the memory and wait the EOP. | |
* @param hqspi QSPI handle | |
* @param Timeout Autopolling timeout | |
* @retval None | |
*/ | |
static uint8_t QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi, uint32_t Timeout) | |
{ | |
QSPI_CommandTypeDef s_command; | |
QSPI_AutoPollingTypeDef s_config; | |
/* Configure automatic polling mode to wait for memory ready */ | |
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; | |
s_command.Instruction = READ_STATUS_REG_CMD; | |
s_command.AddressMode = QSPI_ADDRESS_NONE; | |
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; | |
s_command.DataMode = QSPI_DATA_4_LINES; | |
s_command.DummyCycles = 2; | |
s_command.DdrMode = QSPI_DDR_MODE_DISABLE; | |
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; | |
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; | |
s_config.Match = 0; | |
s_config.MatchMode = QSPI_MATCH_MODE_AND; | |
s_config.Interval = 0x10; | |
s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; | |
s_config.Mask = MT25TL01G_SR_WIP | (MT25TL01G_SR_WIP <<8); | |
s_config.StatusBytesSize = 2; | |
if (HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, Timeout) != HAL_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
return QSPI_OK; | |
} | |
/** | |
* @brief This function enter the QPSI memory in QPI mode | |
* @param hqspi QSPI handle | |
* @retval QSPI status | |
*/ | |
static uint8_t QSPI_EnterQPI(QSPI_HandleTypeDef *hqspi) | |
{ | |
QSPI_CommandTypeDef s_command; | |
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; | |
s_command.Instruction = ENTER_QUAD_CMD; | |
s_command.AddressMode = QSPI_ADDRESS_NONE; | |
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; | |
s_command.DataMode = QSPI_DATA_NONE; | |
s_command.DummyCycles = 0; | |
s_command.DdrMode = QSPI_DDR_MODE_DISABLE; | |
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; | |
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; | |
if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) | |
{ | |
return QSPI_ERROR; | |
} | |
return QSPI_OK; | |
} | |
/** | |
* @} | |
*/ | |
/** | |
* @} | |
*/ | |
/** | |
* @} | |
*/ | |
/** | |
* @} | |
*/ | |
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ | |