BSP files for STM32H747I-Discovery Copy from ST Cube delivery
Dependents: DISCO_H747I_LCD_demo DISCO_H747I_AUDIO_demo
STM32H747I-Discovery/stm32h747i_discovery_qspi.c
- Committer:
- Jerome Coutant
- Date:
- 2019-11-06
- Revision:
- 3:bc403474b366
- Parent:
- 0:146cf26a9bbb
File content as of revision 3:bc403474b366:
/** ****************************************************************************** * @file stm32h747i_discovery_qspi.c * @author MCD Application Team * @brief This file includes a standard driver for the MT25TL01G QSPI * memory mounted on STM32H747I-DISCOVERY board. @verbatim ============================================================================== ##### How to use this driver ##### ============================================================================== [..] (#) This driver is used to drive the MT25TL01G QSPI external memory mounted on STM32H747I-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 "stm32h747i_discovery_qspi.h" /** @addtogroup BSP * @{ */ /** @addtogroup STM32H747I_DISCOVERY * @{ */ /** @defgroup STM32H747I_DISCOVERY_QSPI STM32H747I_DISCOVERY_QSPI * @{ */ /* Private variables ---------------------------------------------------------*/ /** @defgroup STM32H747I_DISCOVERY_QSPI_Private_Variables Private Variables * @{ */ QSPI_HandleTypeDef QSPIHandle; /** * @} */ /* Private functions ---------------------------------------------------------*/ /** @defgroup STM32H747I_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 STM32H747I_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(); } /** * @} */ /** @defgroup STM32H747I_DISCOVERY_QSPI_Private_Functions 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: timeout in ms * @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****/