Contains the BSP driver for the B-L475E-IOT01 board.
Dependents: mbed-os-example-ble-Thermometer DISCO_L475VG_IOT01-Telegram-BOT DISCO_L475VG_IOT01-sche_cheveux DISCO_L475VG_IOT01-QSPI_FLASH_FILE_SYSTEM ... more
https://os.mbed.com/platforms/ST-Discovery-L475E-IOT01A/
Diff: Drivers/BSP/B-L475E-IOT01/stm32l475e_iot01_qspi.c
- Revision:
- 3:c6b5944187d5
- Child:
- 5:0c70bc6d2dc0
diff -r 87208512ab66 -r c6b5944187d5 Drivers/BSP/B-L475E-IOT01/stm32l475e_iot01_qspi.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Drivers/BSP/B-L475E-IOT01/stm32l475e_iot01_qspi.c Fri Apr 14 11:34:20 2017 +0200 @@ -0,0 +1,1126 @@ +/** + ****************************************************************************** + * @file stm32l475e_iot01_qspi.c + * @author MCD Application Team + * @version V1.0.0 + * @date 17-March-2017 + * @brief This file includes a standard driver for the MX25R6435F QSPI + * memory mounted on STM32L475E IOT01 board. + @verbatim + ============================================================================== + ##### How to use this driver ##### + ============================================================================== + [..] + (#) This driver is used to drive the MX25R6435F QSPI external + memory mounted on STM32L475E IOT01 board. + + (#) This driver need a specific component driver (MX25R6435F) 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. The BSP_QSPI_DeInit() can be used + to deactivate the QSPI interface. + + (#) 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 to the QSPI memory in memory-mapped mode is possible after + the call of the function BSP_QSPI_EnableMemoryMappedMode(). + (++) 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) + (++) Perform erase sector operation using the function BSP_QSPI_Erase_Sector() + which is not blocking. So the function BSP_QSPI_GetStatus() should be used + to check if the memory is busy, and the functions BSP_QSPI_SuspendErase()/ + BSP_QSPI_ResumeErase() can be used to perform other operations during the + sector erase. + (++) Deep power down of the QSPI memory is managed with the call of the functions + BSP_QSPI_EnterDeepPowerDown()/BSP_QSPI_LeaveDeepPowerDown() + @endverbatim + ****************************************************************************** + * @attention + * + * <h2><center>© COPYRIGHT(c) 2017 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32l475e_iot01_qspi.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32L475E_IOT01 + * @{ + */ + +/** @defgroup STM32L475E_IOT01_QSPI QSPI + * @{ + */ + +/* Private constants --------------------------------------------------------*/ +/** @defgroup STM32L475E_IOT01_QSPI_Private_Constants QSPI Private Constants + * @{ + */ +#define QSPI_QUAD_DISABLE 0x0 +#define QSPI_QUAD_ENABLE 0x1 + +#define QSPI_HIGH_PERF_DISABLE 0x0 +#define QSPI_HIGH_PERF_ENABLE 0x1 +/** + * @} + */ +/* Private variables ---------------------------------------------------------*/ + +/** @defgroup STM32L475E_IOT01_QSPI_Private_Variables QSPI Private Variables + * @{ + */ +QSPI_HandleTypeDef QSPIHandle; + +/** + * @} + */ + + +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup STM32L475E_IOT01_QSPI_Private_Functions QSPI Private Functions + * @{ + */ +static uint8_t QSPI_ResetMemory (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_QuadMode (QSPI_HandleTypeDef *hqspi, uint8_t Operation); +static uint8_t QSPI_HighPerfMode (QSPI_HandleTypeDef *hqspi, uint8_t Operation); + +/** + * @} + */ + +/* Exported functions ---------------------------------------------------------*/ + +/** @addtogroup STM32L475E_IOT01_QSPI_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(); + + /* QSPI initialization */ + QSPIHandle.Init.ClockPrescaler = 2; /* QSPI clock = 80MHz / (ClockPrescaler+1) = 26.67MHz */ + QSPIHandle.Init.FifoThreshold = 4; + QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_NONE; + QSPIHandle.Init.FlashSize = POSITION_VAL(MX25R6435F_FLASH_SIZE) - 1; + QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_1_CYCLE; + QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0; + + if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK) + { + return QSPI_ERROR; + } + + /* QSPI memory reset */ + if (QSPI_ResetMemory(&QSPIHandle) != QSPI_OK) + { + return QSPI_NOT_SUPPORTED; + } + + /* QSPI quad enable */ + if (QSPI_QuadMode(&QSPIHandle, QSPI_QUAD_ENABLE) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* High performance mode enable */ + if (QSPI_HighPerfMode(&QSPIHandle, QSPI_HIGH_PERF_ENABLE) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Re-configure the clock for the high performance mode */ + QSPIHandle.Init.ClockPrescaler = 1; /* QSPI clock = 80MHz / (ClockPrescaler+1) = 40MHz */ + + if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK) + { + return QSPI_ERROR; + } + + 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(); + + 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 sCommand; + + /* Initialize the read command */ + sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; + sCommand.Instruction = QUAD_INOUT_READ_CMD; + sCommand.AddressMode = QSPI_ADDRESS_4_LINES; + sCommand.AddressSize = QSPI_ADDRESS_24_BITS; + sCommand.Address = ReadAddr; + sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_4_LINES; + sCommand.AlternateBytesSize = QSPI_ALTERNATE_BYTES_8_BITS; + sCommand.AlternateBytes = MX25R6435F_ALT_BYTES_NO_PE_MODE; + sCommand.DataMode = QSPI_DATA_4_LINES; + sCommand.DummyCycles = MX25R6435F_DUMMY_CYCLES_READ_QUAD; + sCommand.NbData = Size; + sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; + sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 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 sCommand; + uint32_t end_addr, current_size, current_addr; + + /* Calculation of the size between the write address and the end of the page */ + current_size = MX25R6435F_PAGE_SIZE - (WriteAddr % MX25R6435F_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 adress variables */ + current_addr = WriteAddr; + end_addr = WriteAddr + Size; + + /* Initialize the program command */ + sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; + sCommand.Instruction = QUAD_PAGE_PROG_CMD; + sCommand.AddressMode = QSPI_ADDRESS_4_LINES; + sCommand.AddressSize = QSPI_ADDRESS_24_BITS; + sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + sCommand.DataMode = QSPI_DATA_4_LINES; + sCommand.DummyCycles = 0; + sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; + sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Perform the write page by page */ + do + { + sCommand.Address = current_addr; + sCommand.NbData = current_size; + + /* Enable write operations */ + if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Configure the command */ + if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 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 + MX25R6435F_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : MX25R6435F_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 sCommand; + + /* Initialize the erase command */ + sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; + sCommand.Instruction = BLOCK_ERASE_CMD; + sCommand.AddressMode = QSPI_ADDRESS_1_LINE; + sCommand.AddressSize = QSPI_ADDRESS_24_BITS; + sCommand.Address = BlockAddress; + sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + sCommand.DataMode = QSPI_DATA_NONE; + sCommand.DummyCycles = 0; + sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; + sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + sCommand.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, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for end of erase */ + if (QSPI_AutoPollingMemReady(&QSPIHandle, MX25R6435F_BLOCK_ERASE_MAX_TIME) != QSPI_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief Erases the specified sector of the QSPI memory. + * @param Sector : Sector address to erase (0 to 255) + * @retval QSPI memory status + * @note This function is non blocking meaning that sector erase + * operation is started but not completed when the function + * returns. Application has to call BSP_QSPI_GetStatus() + * to know when the device is available again (i.e. erase operation + * completed). + */ +uint8_t BSP_QSPI_Erase_Sector(uint32_t Sector) +{ + QSPI_CommandTypeDef sCommand; + + if (Sector >= (uint32_t)(MX25R6435F_FLASH_SIZE/MX25R6435F_SECTOR_SIZE)) + { + return QSPI_ERROR; + } + + /* Initialize the erase command */ + sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; + sCommand.Instruction = SECTOR_ERASE_CMD; + sCommand.AddressMode = QSPI_ADDRESS_1_LINE; + sCommand.AddressSize = QSPI_ADDRESS_24_BITS; + sCommand.Address = (Sector * MX25R6435F_SECTOR_SIZE); + sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + sCommand.DataMode = QSPI_DATA_NONE; + sCommand.DummyCycles = 0; + sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; + sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + sCommand.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, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_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 sCommand; + + /* Initialize the erase command */ + sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; + sCommand.Instruction = CHIP_ERASE_CMD; + sCommand.AddressMode = QSPI_ADDRESS_NONE; + sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + sCommand.DataMode = QSPI_DATA_NONE; + sCommand.DummyCycles = 0; + sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; + sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + sCommand.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, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for end of erase */ + if (QSPI_AutoPollingMemReady(&QSPIHandle, MX25R6435F_CHIP_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 sCommand; + uint8_t reg; + + /* Initialize the read security register command */ + sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; + sCommand.Instruction = READ_SEC_REG_CMD; + sCommand.AddressMode = QSPI_ADDRESS_NONE; + sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + sCommand.DataMode = QSPI_DATA_1_LINE; + sCommand.DummyCycles = 0; + sCommand.NbData = 1; + sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; + sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Reception of the data */ + if (HAL_QSPI_Receive(&QSPIHandle, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Check the value of the register */ + if ((reg & (MX25R6435F_SECR_P_FAIL | MX25R6435F_SECR_E_FAIL)) != 0) + { + return QSPI_ERROR; + } + else if ((reg & (MX25R6435F_SECR_PSB | MX25R6435F_SECR_ESB)) != 0) + { + return QSPI_SUSPENDED; + } + + /* Initialize the read status register command */ + sCommand.Instruction = READ_STATUS_REG_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Reception of the data */ + if (HAL_QSPI_Receive(&QSPIHandle, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Check the value of the register */ + if ((reg & MX25R6435F_SR_WIP) != 0) + { + return QSPI_BUSY; + } + else + { + return QSPI_OK; + } +} + +/** + * @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 = MX25R6435F_FLASH_SIZE; + pInfo->EraseSectorSize = MX25R6435F_SECTOR_SIZE; + pInfo->EraseSectorsNumber = (MX25R6435F_FLASH_SIZE/MX25R6435F_SECTOR_SIZE); + pInfo->ProgPageSize = MX25R6435F_PAGE_SIZE; + pInfo->ProgPagesNumber = (MX25R6435F_FLASH_SIZE/MX25R6435F_PAGE_SIZE); + + return QSPI_OK; +} + +/** + * @brief Configure the QSPI in memory-mapped mode + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_EnableMemoryMappedMode(void) +{ + QSPI_CommandTypeDef sCommand; + QSPI_MemoryMappedTypeDef sMemMappedCfg; + + /* Configure the command for the read instruction */ + sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; + sCommand.Instruction = QUAD_INOUT_READ_CMD; + sCommand.AddressMode = QSPI_ADDRESS_4_LINES; + sCommand.AddressSize = QSPI_ADDRESS_24_BITS; + sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_4_LINES; + sCommand.AlternateBytesSize = QSPI_ALTERNATE_BYTES_8_BITS; + sCommand.AlternateBytes = MX25R6435F_ALT_BYTES_NO_PE_MODE; + sCommand.DataMode = QSPI_DATA_4_LINES; + sCommand.DummyCycles = MX25R6435F_DUMMY_CYCLES_READ_QUAD; + sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; + sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the memory mapped mode */ + sMemMappedCfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE; + + if (HAL_QSPI_MemoryMapped(&QSPIHandle, &sCommand, &sMemMappedCfg) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function suspends an ongoing erase command. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_SuspendErase(void) +{ + QSPI_CommandTypeDef sCommand; + + /* Check whether the device is busy (erase operation is + in progress). + */ + if (BSP_QSPI_GetStatus() == QSPI_BUSY) + { + /* Initialize the erase command */ + sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; + sCommand.Instruction = PROG_ERASE_SUSPEND_CMD; + sCommand.AddressMode = QSPI_ADDRESS_NONE; + sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + sCommand.DataMode = QSPI_DATA_NONE; + sCommand.DummyCycles = 0; + sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; + sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Send the command */ + if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + if (BSP_QSPI_GetStatus() == QSPI_SUSPENDED) + { + return QSPI_OK; + } + + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function resumes a paused erase command. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_ResumeErase(void) +{ + QSPI_CommandTypeDef sCommand; + + /* Check whether the device is in suspended state */ + if (BSP_QSPI_GetStatus() == QSPI_SUSPENDED) + { + /* Initialize the erase command */ + sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; + sCommand.Instruction = PROG_ERASE_RESUME_CMD; + sCommand.AddressMode = QSPI_ADDRESS_NONE; + sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + sCommand.DataMode = QSPI_DATA_NONE; + sCommand.DummyCycles = 0; + sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; + sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Send the command */ + if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* + When this command is executed, the status register write in progress bit is set to 1, and + the flag status register program erase controller bit is set to 0. This command is ignored + if the device is not in a suspended state. + */ + + if (BSP_QSPI_GetStatus() == QSPI_BUSY) + { + return QSPI_OK; + } + + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function enter the QSPI memory in deep power down mode. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_EnterDeepPowerDown(void) +{ + QSPI_CommandTypeDef sCommand; + + /* Initialize the deep power down command */ + sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; + sCommand.Instruction = DEEP_POWER_DOWN_CMD; + sCommand.AddressMode = QSPI_ADDRESS_NONE; + sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + sCommand.DataMode = QSPI_DATA_NONE; + sCommand.DummyCycles = 0; + sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; + sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Send the command */ + if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* --- Memory takes 10us max to enter deep power down --- */ + /* --- At least 30us should be respected before leaving deep power down --- */ + + return QSPI_OK; +} + +/** + * @brief This function leave the QSPI memory from deep power down mode. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_LeaveDeepPowerDown(void) +{ + QSPI_CommandTypeDef sCommand; + + /* Initialize the erase command */ + sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; + sCommand.Instruction = NO_OPERATION_CMD; + sCommand.AddressMode = QSPI_ADDRESS_NONE; + sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + sCommand.DataMode = QSPI_DATA_NONE; + sCommand.DummyCycles = 0; + sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; + sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Send the command */ + if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* --- A NOP command is sent to the memory, as the nCS should be low for at least 20 ns --- */ + /* --- Memory takes 35us min to leave deep power down --- */ + + return QSPI_OK; +} + +/** + * @brief Initializes the QSPI MSP. + * @retval None + */ +__weak void BSP_QSPI_MspInit(void) +{ + GPIO_InitTypeDef GPIO_InitStruct; + + /* Enable the QuadSPI memory interface clock */ + __HAL_RCC_QSPI_CLK_ENABLE(); + + /* Reset the QuadSPI memory interface */ + __HAL_RCC_QSPI_FORCE_RESET(); + __HAL_RCC_QSPI_RELEASE_RESET(); + + /* Enable GPIO clocks */ + __HAL_RCC_GPIOE_CLK_ENABLE(); + + /* QSPI CLK, CS, D0, D1, D2 and D3 GPIO pins configuration */ + GPIO_InitStruct.Pin = GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 |\ + GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF10_QUADSPI; + HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); +} + +/** + * @brief De-Initializes the QSPI MSP. + * @retval None + */ +__weak void BSP_QSPI_MspDeInit(void) +{ + GPIO_InitTypeDef GPIO_InitStruct; + + /* QSPI CLK, CS, D0-D3 GPIO pins de-configuration */ + __HAL_RCC_GPIOE_CLK_ENABLE(); + GPIO_InitStruct.Pin = GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 |\ + GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + + HAL_GPIO_DeInit(GPIOE, GPIO_InitStruct.Pin); + + /* Reset the QuadSPI memory interface */ + __HAL_RCC_QSPI_FORCE_RESET(); + __HAL_RCC_QSPI_RELEASE_RESET(); + + /* Disable the QuadSPI memory interface clock */ + __HAL_RCC_QSPI_CLK_DISABLE(); +} + +/** + * @} + */ + +/** @addtogroup STM32L475E_IOT01_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 sCommand; + + /* Initialize the reset enable command */ + sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; + sCommand.Instruction = RESET_ENABLE_CMD; + sCommand.AddressMode = QSPI_ADDRESS_NONE; + sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + sCommand.DataMode = QSPI_DATA_NONE; + sCommand.DummyCycles = 0; + sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; + sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Send the command */ + if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Send the reset memory command */ + sCommand.Instruction = RESET_MEMORY_CMD; + if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait the memory is ready */ + if (QSPI_AutoPollingMemReady(&QSPIHandle, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_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 sCommand; + QSPI_AutoPollingTypeDef sConfig; + + /* Enable write operations */ + sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; + sCommand.Instruction = WRITE_ENABLE_CMD; + sCommand.AddressMode = QSPI_ADDRESS_NONE; + sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + sCommand.DataMode = QSPI_DATA_NONE; + sCommand.DummyCycles = 0; + sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; + sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for write enabling */ + sConfig.Match = MX25R6435F_SR_WEL; + sConfig.Mask = MX25R6435F_SR_WEL; + sConfig.MatchMode = QSPI_MATCH_MODE_AND; + sConfig.StatusBytesSize = 1; + sConfig.Interval = 0x10; + sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; + + sCommand.Instruction = READ_STATUS_REG_CMD; + sCommand.DataMode = QSPI_DATA_1_LINE; + + if (HAL_QSPI_AutoPolling(&QSPIHandle, &sCommand, &sConfig, 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 : Timeout for auto-polling + * @retval None + */ +static uint8_t QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi, uint32_t Timeout) +{ + QSPI_CommandTypeDef sCommand; + QSPI_AutoPollingTypeDef sConfig; + + /* Configure automatic polling mode to wait for memory ready */ + sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; + sCommand.Instruction = READ_STATUS_REG_CMD; + sCommand.AddressMode = QSPI_ADDRESS_NONE; + sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + sCommand.DataMode = QSPI_DATA_1_LINE; + sCommand.DummyCycles = 0; + sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; + sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + sConfig.Match = 0; + sConfig.Mask = MX25R6435F_SR_WIP; + sConfig.MatchMode = QSPI_MATCH_MODE_AND; + sConfig.StatusBytesSize = 1; + sConfig.Interval = 0x10; + sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; + + if (HAL_QSPI_AutoPolling(&QSPIHandle, &sCommand, &sConfig, Timeout) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function enables/disables the Quad mode of the memory. + * @param hqspi : QSPI handle + * @param Operation : QSPI_QUAD_ENABLE or QSPI_QUAD_DISABLE mode + * @retval None + */ +static uint8_t QSPI_QuadMode(QSPI_HandleTypeDef *hqspi, uint8_t Operation) +{ + QSPI_CommandTypeDef sCommand; + uint8_t reg; + + /* Read status register */ + sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; + sCommand.Instruction = READ_STATUS_REG_CMD; + sCommand.AddressMode = QSPI_ADDRESS_NONE; + sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + sCommand.DataMode = QSPI_DATA_1_LINE; + sCommand.DummyCycles = 0; + sCommand.NbData = 1; + sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; + sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + if (HAL_QSPI_Receive(&QSPIHandle, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Enable write operations */ + if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Activate/deactivate the Quad mode */ + if (Operation == QSPI_QUAD_ENABLE) + { + SET_BIT(reg, MX25R6435F_SR_QE); + } + else + { + CLEAR_BIT(reg, MX25R6435F_SR_QE); + } + + sCommand.Instruction = WRITE_STATUS_CFG_REG_CMD; + + if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + if (HAL_QSPI_Transmit(&QSPIHandle, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Wait that memory is ready */ + if (QSPI_AutoPollingMemReady(&QSPIHandle, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Check the configuration has been correctly done */ + sCommand.Instruction = READ_STATUS_REG_CMD; + + if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + if (HAL_QSPI_Receive(&QSPIHandle, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + if ((((reg & MX25R6435F_SR_QE) == 0) && (Operation == QSPI_QUAD_ENABLE)) || + (((reg & MX25R6435F_SR_QE) != 0) && (Operation == QSPI_QUAD_DISABLE))) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function enables/disables the high performance mode of the memory. + * @param hqspi : QSPI handle + * @param Operation : QSPI_HIGH_PERF_ENABLE or QSPI_HIGH_PERF_DISABLE high performance mode + * @retval None + */ +static uint8_t QSPI_HighPerfMode(QSPI_HandleTypeDef *hqspi, uint8_t Operation) +{ + QSPI_CommandTypeDef sCommand; + uint8_t reg[3]; + + /* Read status register */ + sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; + sCommand.Instruction = READ_STATUS_REG_CMD; + sCommand.AddressMode = QSPI_ADDRESS_NONE; + sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + sCommand.DataMode = QSPI_DATA_1_LINE; + sCommand.DummyCycles = 0; + sCommand.NbData = 1; + sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; + sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + if (HAL_QSPI_Receive(&QSPIHandle, &(reg[0]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Read configuration registers */ + sCommand.Instruction = READ_CFG_REG_CMD; + sCommand.NbData = 2; + + if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + if (HAL_QSPI_Receive(&QSPIHandle, &(reg[1]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Enable write operations */ + if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Activate/deactivate the Quad mode */ + if (Operation == QSPI_HIGH_PERF_ENABLE) + { + SET_BIT(reg[2], MX25R6435F_CR2_LH_SWITCH); + } + else + { + CLEAR_BIT(reg[2], MX25R6435F_CR2_LH_SWITCH); + } + + sCommand.Instruction = WRITE_STATUS_CFG_REG_CMD; + sCommand.NbData = 3; + + if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + if (HAL_QSPI_Transmit(&QSPIHandle, &(reg[0]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Wait that memory is ready */ + if (QSPI_AutoPollingMemReady(&QSPIHandle, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Check the configuration has been correctly done */ + sCommand.Instruction = READ_CFG_REG_CMD; + sCommand.NbData = 2; + + if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + if (HAL_QSPI_Receive(&QSPIHandle, &(reg[0]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + if ((((reg[1] & MX25R6435F_CR2_LH_SWITCH) == 0) && (Operation == QSPI_HIGH_PERF_ENABLE)) || + (((reg[1] & MX25R6435F_CR2_LH_SWITCH) != 0) && (Operation == QSPI_HIGH_PERF_DISABLE))) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +