stm32h750/driver/board/qspi_flash.c

388 lines
15 KiB
C

#include "qspi_flash.h"
#include "stdio.h"
QSPI_HandleTypeDef QSPIHandle;
/**
* @brief This function polling for release busy status.
* @param hqspi: QSPI handle
* @retval error code
*/
static uint32_t QSPI_WaitforBusyRelease(QSPI_HandleTypeDef *hqspi)
{
QSPI_CommandTypeDef s_command;
QSPI_AutoPollingTypeDef s_config;
/* Configure automatic polling mode to wait for write enabling */
s_config.Match = 0x0;
s_config.Mask = (1 << 0); // BUSY
s_config.MatchMode = QSPI_MATCH_MODE_AND;
s_config.StatusBytesSize = 1;
s_config.Interval = 0x10;
s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
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_1_LINE;
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_AutoPolling(hqspi, &s_command, &s_config, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
printf("%s: function %s, line %d, command \"qspi auto polling for release busy\" failed.\r\n", __FILE__, __FUNCTION__, __LINE__);
return ((2 << 28) | s_config.Mask);
}
return 0;
}
/**
* @brief This function send a Write Enable and wait it is effective.
* @param hqspi: QSPI handle
* @retval None
*/
static uint32_t QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi)
{
QSPI_CommandTypeDef s_command;
QSPI_AutoPollingTypeDef s_config;
/* Enable write operations */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
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) {
printf("%s: function %s, line %d, command \"write enable\" failed.\r\n", __FILE__, __FUNCTION__, __LINE__);
return ((1 << 28) | s_command.Instruction);
}
/* Configure automatic polling mode to wait for write enabling */
s_config.Match = 0x2;
s_config.Mask = (1 << 1) | (1 << 0); // WEL | BUSY
s_config.MatchMode = QSPI_MATCH_MODE_AND;
s_config.StatusBytesSize = 1;
s_config.Interval = 0x10;
s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
s_command.Instruction = READ_STATUS_REG_CMD;
s_command.DataMode = QSPI_DATA_1_LINE;
if (HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
printf("%s: function %s, line %d, command \"qspi auto polling for write enable\" failed.\r\n", __FILE__, __FUNCTION__, __LINE__);
return ((2 << 28) | s_config.Mask);
}
return 0;
}
void qspi_flash_init(uint32_t div)
{
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();
/* Enable DMA clock */
QSPI_MDMA_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);
/* QSPI D1 GPIO pin configuration */
gpio_init_structure.Pin = QSPI_BK1_D1_PIN;
gpio_init_structure.Pull = GPIO_NOPULL;
gpio_init_structure.Alternate = GPIO_AF9_QUADSPI;
HAL_GPIO_Init(QSPI_BK1_D1_GPIO_PORT, &gpio_init_structure);
/* QSPI D2 GPIO pin configuration */
gpio_init_structure.Pin = QSPI_BK1_D2_PIN;
gpio_init_structure.Pull = GPIO_NOPULL;
gpio_init_structure.Alternate = GPIO_AF9_QUADSPI;
HAL_GPIO_Init(QSPI_BK1_D2_GPIO_PORT, &gpio_init_structure);
/* QSPI D3 GPIO pin configuration */
gpio_init_structure.Pin = QSPI_BK1_D3_PIN;
gpio_init_structure.Pull = GPIO_NOPULL;
gpio_init_structure.Alternate = GPIO_AF9_QUADSPI;
HAL_GPIO_Init(QSPI_BK1_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);
/* Initialize QuadSPI structures ------------------------------------------- */
QSPIHandle.Instance = QUADSPI;
/* QSPI initialization */
/* ClockPrescaler set to 1, so QSPI clock = 200MHz / (1+1) = 100MHz */
QSPIHandle.Init.ClockPrescaler = div;
QSPIHandle.Init.FifoThreshold = 32;
QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
QSPIHandle.Init.FlashSize = QSPI_FLASH_SIZE;
QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_3_CYCLE;
QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0;
QSPIHandle.Init.FlashID = QSPI_FLASH_ID_1;
QSPIHandle.Init.DualFlash = QSPI_DUALFLASH_DISABLE;
/* Initialize QuadSPI ------------------------------------------------ */
HAL_QSPI_DeInit(&QSPIHandle);
if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK) {
printf("%s: function %s, line %d, qspi init failed.\r\n", __FILE__, __FUNCTION__, __LINE__);
while (1);
} else {
printf("qspi init succeed.\r\n");
}
}
void qspi_flash_deinit(void)
{
/*##-1- Disable the NVIC for QSPI ###########################################*/
HAL_NVIC_DisableIRQ(QUADSPI_IRQn);
/*##-1- Disable peripherals ################################################*/
/* 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);
/*##-3- Reset peripherals ##################################################*/
/* Reset the QuadSPI memory interface */
QSPI_FORCE_RESET();
QSPI_RELEASE_RESET();
/* Disable the QuadSPI memory interface clock */
QSPI_CLK_DISABLE();
}
uint32_t qspi_flash_write(uint32_t addr, uint8_t *data, uint32_t length)
{
uint32_t ret;
QSPI_CommandTypeDef s_command;
ret = QSPI_WriteEnable(&QSPIHandle);
if (ret) {
return ret;
}
/* Initialize the read volatile configuration register command */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = QUAD_IN_FAST_PROG_CMD;
s_command.AddressMode = QSPI_ADDRESS_1_LINE;
s_command.AddressSize = QSPI_ADDRESS_24_BITS;
s_command.Address = addr;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_4_LINES;
s_command.DummyCycles = 0;
s_command.NbData = length;
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) {
printf("%s: function %s, line %d, command \"QUAD_IN_FAST_PROG_CMD\" failed.\r\n", __FILE__, __FUNCTION__, __LINE__);
return ((1 << 28) | s_command.Instruction);
}
/* Writing of the data */
if (HAL_QSPI_Transmit(&QSPIHandle, data, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
printf("%s: function %s, line %d, command \"HAL_QSPI_Transmit\" failed.\r\n", __FILE__, __FUNCTION__, __LINE__);
return ((3 << 28) | s_command.Instruction);
}
ret = QSPI_WaitforBusyRelease(&QSPIHandle);
if (ret) {
printf("%s: function %s, line %d, command \"busy after write\" failed.\r\n", __FILE__, __FUNCTION__, __LINE__);
return ret;
}
return 0;
}
uint32_t qspi_flash_read(uint32_t addr, uint8_t *data, uint32_t length)
{
QSPI_CommandTypeDef s_command;
/* Initialize the read volatile configuration register command */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = QUAD_OUT_FAST_READ_CMD;
s_command.AddressMode = QSPI_ADDRESS_1_LINE;
s_command.AddressSize = QSPI_ADDRESS_24_BITS;
s_command.Address = addr;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_4_LINES;
s_command.DummyCycles = 8;
s_command.NbData = length;
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) {
printf("%s: function %s, line %d, command \"QUAD_OUT_FAST_READ_CMD\" failed.\r\n", __FILE__, __FUNCTION__, __LINE__);
return ((1 << 28) | s_command.Instruction);
}
/* Reception of the data */
if (HAL_QSPI_Receive(&QSPIHandle, data, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
printf("%s: function %s, line %d, command \"HAL_QSPI_Receive\" failed.\r\n", __FILE__, __FUNCTION__, __LINE__);
return ((3 << 28) | s_command.Instruction);
}
return 0;
}
uint32_t qspi_flash_erase_4kbytes(uint32_t addr)
{
uint32_t ret;
QSPI_CommandTypeDef s_command;
ret = QSPI_WriteEnable(&QSPIHandle);
if (ret) {
return ret;
}
/* Initialize the read volatile configuration register command */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = SECTOR_ERASE_CMD;
s_command.AddressMode = QSPI_ADDRESS_1_LINE;
s_command.AddressSize = QSPI_ADDRESS_24_BITS;
s_command.Address = addr;
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;
/* Configure the command */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
printf("%s: function %s, line %d, command \"SECTOR_ERASE_CMD\" failed.\r\n", __FILE__, __FUNCTION__, __LINE__);
return ((1 << 28) | s_command.Instruction);
}
ret = QSPI_WaitforBusyRelease(&QSPIHandle);
if (ret) {
printf("%s: function %s, line %d, command \"busy after erasen 4K\" failed.\r\n", __FILE__, __FUNCTION__, __LINE__);
return ret;
}
return 0;
}
uint32_t qspi_flash_erase_32kbytes(uint32_t addr)
{
uint32_t ret;
QSPI_CommandTypeDef s_command;
ret = QSPI_WriteEnable(&QSPIHandle);
if (ret) {
return ret;
}
/* Initialize the read volatile configuration register command */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = SUBBLOCK_ERASE_CMD;
s_command.AddressMode = QSPI_ADDRESS_1_LINE;
s_command.AddressSize = QSPI_ADDRESS_24_BITS;
s_command.Address = addr;
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;
/* Configure the command */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
printf("%s: function %s, line %d, command \"SUBBLOCK_ERASE_CMD\" failed.\r\n", __FILE__, __FUNCTION__, __LINE__);
return ((1 << 28) | s_command.Instruction);
}
ret = QSPI_WaitforBusyRelease(&QSPIHandle);
if (ret) {
printf("%s: function %s, line %d, command \"busy after erasen 32K\" failed.\r\n", __FILE__, __FUNCTION__, __LINE__);
return ret;
}
return 0;
}
uint32_t qspi_flash_erase_64kbytes(uint32_t addr)
{
uint32_t ret;
QSPI_CommandTypeDef s_command;
ret = QSPI_WriteEnable(&QSPIHandle);
if (ret) {
return ret;
}
/* Initialize the read volatile configuration register command */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = BLOCK_ERASE_CMD;
s_command.AddressMode = QSPI_ADDRESS_1_LINE;
s_command.AddressSize = QSPI_ADDRESS_24_BITS;
s_command.Address = addr;
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;
/* Configure the command */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
printf("%s: function %s, line %d, command \"SUBBLOCK_ERASE_CMD\" failed.\r\n", __FILE__, __FUNCTION__, __LINE__);
return ((1 << 28) | s_command.Instruction);
}
ret = QSPI_WaitforBusyRelease(&QSPIHandle);
if (ret) {
printf("%s: function %s, line %d, command \"busy after erasen 64K\" failed.\r\n", __FILE__, __FUNCTION__, __LINE__);
return ret;
}
return 0;
}