[feat] add qspi_flash driver
This commit is contained in:
parent
cb66bdd381
commit
adef945b30
@ -2,6 +2,7 @@
|
|||||||
#include "led.h"
|
#include "led.h"
|
||||||
#include "uart_log.h"
|
#include "uart_log.h"
|
||||||
#include "ltimer.h"
|
#include "ltimer.h"
|
||||||
|
#include "qspi_flash.h"
|
||||||
#include "stdio.h"
|
#include "stdio.h"
|
||||||
|
|
||||||
void system_init(void)
|
void system_init(void)
|
||||||
@ -73,6 +74,7 @@ void system_init(void)
|
|||||||
led_init(LED_PIN);
|
led_init(LED_PIN);
|
||||||
uart_log_init();
|
uart_log_init();
|
||||||
ltimer_init();
|
ltimer_init();
|
||||||
|
qspi_flash_init(3); /* 200MHz / (3 + 1) = 50MHz */
|
||||||
}
|
}
|
||||||
|
|
||||||
void led_blink(void)
|
void led_blink(void)
|
||||||
@ -81,17 +83,50 @@ void led_blink(void)
|
|||||||
led_off(LED_PIN);
|
led_off(LED_PIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t data[256];
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
|
uint32_t ret;
|
||||||
|
|
||||||
system_init();
|
system_init();
|
||||||
printf("Run start ...\r\n");
|
printf("Run start ...\r\n");
|
||||||
printf("SystemCoreClock = %ld\r\n", SystemCoreClock);
|
printf("SystemCoreClock = %ld\r\n", SystemCoreClock);
|
||||||
printf("SystemD2Clock = %ld\r\n", SystemD2Clock);
|
printf("SystemD2Clock = %ld\r\n", SystemD2Clock);
|
||||||
|
|
||||||
|
ret = qspi_flash_erase_4kbytes(0);
|
||||||
|
if (ret) {
|
||||||
|
printf("qspi_flash_erase_4k error: 0x%08lX\r\n", ret);
|
||||||
|
} else {
|
||||||
|
printf("qspi_flash_erase_4k ok\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < sizeof(data); i++) {
|
||||||
|
data[i] = (uint8_t)(i & 0xFF);
|
||||||
|
}
|
||||||
|
ret = qspi_flash_write(0, data, sizeof(data));
|
||||||
|
if (ret) {
|
||||||
|
printf("qspi_flash_write error: 0x%08lX\r\n", ret);
|
||||||
|
} else {
|
||||||
|
printf("qspi_flash_write ok\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
uint64_t ms;
|
uint64_t ms;
|
||||||
ms = ltimer_get_ms();
|
ms = ltimer_get_ms();
|
||||||
printf("Hello World, ms = %llu\r\n", ms);
|
printf("Hello World, ms = %llu, tick = %ld\r\n", ms, HAL_GetTick());
|
||||||
|
|
||||||
|
ret = qspi_flash_read(0, data, 30);
|
||||||
|
if (ret) {
|
||||||
|
printf("qspi_flash_read error: 0x%08lX\r\n", ret);
|
||||||
|
} else {
|
||||||
|
printf("qspi_flash_read ok\r\n");
|
||||||
|
for (uint32_t i = 0; i < sizeof(data); i++) {
|
||||||
|
if (i % 16 == 0) {
|
||||||
|
printf("\r\n");
|
||||||
|
}
|
||||||
|
printf("%02X ", data[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
led_blink();
|
led_blink();
|
||||||
ltimer_delay_ms(1000);
|
ltimer_delay_ms(1000);
|
||||||
}
|
}
|
||||||
|
|||||||
387
driver/board/qspi_flash.c
Normal file
387
driver/board/qspi_flash.c
Normal file
@ -0,0 +1,387 @@
|
|||||||
|
#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;
|
||||||
|
}
|
||||||
105
driver/board/qspi_flash.h
Normal file
105
driver/board/qspi_flash.h
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#ifndef __QSPI_FLASH_H__
|
||||||
|
#define __QSPI_FLASH_H__
|
||||||
|
|
||||||
|
#include "stm32h7xx_hal.h"
|
||||||
|
|
||||||
|
/* Definition for QSPI clock resources */
|
||||||
|
#define QSPI_CLK_ENABLE() __HAL_RCC_QSPI_CLK_ENABLE()
|
||||||
|
#define QSPI_CLK_DISABLE() __HAL_RCC_QSPI_CLK_DISABLE()
|
||||||
|
#define QSPI_CLK_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
|
||||||
|
#define QSPI_BK1_CS_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
|
||||||
|
#define QSPI_BK1_D0_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
|
||||||
|
#define QSPI_BK1_D1_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
|
||||||
|
#define QSPI_BK1_D2_GPIO_CLK_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE()
|
||||||
|
#define QSPI_BK1_D3_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
|
||||||
|
|
||||||
|
#define QSPI_MDMA_CLK_ENABLE() __HAL_RCC_MDMA_CLK_ENABLE()
|
||||||
|
|
||||||
|
#define QSPI_FORCE_RESET() __HAL_RCC_QSPI_FORCE_RESET()
|
||||||
|
#define QSPI_RELEASE_RESET() __HAL_RCC_QSPI_RELEASE_RESET()
|
||||||
|
|
||||||
|
/* Definition for QSPI Pins */
|
||||||
|
#define QSPI_CLK_PIN GPIO_PIN_2
|
||||||
|
#define QSPI_CLK_GPIO_PORT GPIOB
|
||||||
|
/* Bank 1 */
|
||||||
|
#define QSPI_BK1_CS_PIN GPIO_PIN_6
|
||||||
|
#define QSPI_BK1_CS_GPIO_PORT GPIOB
|
||||||
|
#define QSPI_BK1_D0_PIN GPIO_PIN_11
|
||||||
|
#define QSPI_BK1_D0_GPIO_PORT GPIOD
|
||||||
|
#define QSPI_BK1_D1_PIN GPIO_PIN_12
|
||||||
|
#define QSPI_BK1_D1_GPIO_PORT GPIOD
|
||||||
|
#define QSPI_BK1_D2_PIN GPIO_PIN_2
|
||||||
|
#define QSPI_BK1_D2_GPIO_PORT GPIOE
|
||||||
|
#define QSPI_BK1_D3_PIN GPIO_PIN_13
|
||||||
|
#define QSPI_BK1_D3_GPIO_PORT GPIOD
|
||||||
|
|
||||||
|
/* W25Q64JV memory */
|
||||||
|
/* Size of the flash */
|
||||||
|
#define QSPI_FLASH_SIZE 22
|
||||||
|
#define QSPI_PAGE_SIZE 256
|
||||||
|
|
||||||
|
/* Reset Operations */
|
||||||
|
#define RESET_ENABLE_CMD 0x66
|
||||||
|
#define RESET_MEMORY_CMD 0x99
|
||||||
|
|
||||||
|
/* Identification Operations */
|
||||||
|
#define READ_ID_CMD 0x9F
|
||||||
|
#define READ_SERIAL_FLASH_DISCO_PARAM_CMD 0x5A
|
||||||
|
|
||||||
|
/* Read Operations */
|
||||||
|
#define READ_CMD 0x03
|
||||||
|
#define FAST_READ_CMD 0x0B
|
||||||
|
#define DUAL_OUT_FAST_READ_CMD 0x3B
|
||||||
|
#define DUAL_INOUT_FAST_READ_CMD 0xBB
|
||||||
|
#define QUAD_OUT_FAST_READ_CMD 0x6B
|
||||||
|
#define QUAD_INOUT_FAST_READ_CMD 0xEB
|
||||||
|
|
||||||
|
/* Write Operations */
|
||||||
|
#define WRITE_ENABLE_CMD 0x06
|
||||||
|
#define WRITE_DISABLE_CMD 0x04
|
||||||
|
|
||||||
|
/* Register Operations */
|
||||||
|
#define READ_STATUS_REG_CMD 0x05
|
||||||
|
#define WRITE_STATUS_REG_CMD 0x01
|
||||||
|
|
||||||
|
/* Program Operations */
|
||||||
|
#define PAGE_PROG_CMD 0x02
|
||||||
|
#define QUAD_IN_FAST_PROG_CMD 0x32
|
||||||
|
|
||||||
|
/* Erase Operations */
|
||||||
|
#define SECTOR_ERASE_CMD 0x20 /* 4K-bytes */
|
||||||
|
#define SUBBLOCK_ERASE_CMD 0x52 /* 32K-bytes */
|
||||||
|
#define BLOCK_ERASE_CMD 0xD8 /* 64K-bytes */
|
||||||
|
#define CHIP_ERASE_CMD 0xC7
|
||||||
|
|
||||||
|
#define PROG_ERASE_RESUME_CMD 0x7A
|
||||||
|
#define PROG_ERASE_SUSPEND_CMD 0x75
|
||||||
|
|
||||||
|
/* Quad Operations */
|
||||||
|
#define ENTER_QUAD_CMD 0x38
|
||||||
|
#define EXIT_QUAD_CMD 0xFF
|
||||||
|
|
||||||
|
/* Default dummy clocks cycles */
|
||||||
|
#define DUMMY_CLOCK_CYCLES_READ 8
|
||||||
|
#define DUMMY_CLOCK_CYCLES_READ_QUAD 8
|
||||||
|
|
||||||
|
/* End address of the QSPI memory */
|
||||||
|
#define QSPI_END_ADDR (1 << (QSPI_FLASH_SIZE + 1))
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void qspi_flash_init(uint32_t div);
|
||||||
|
void qspi_flash_deinit(void);
|
||||||
|
uint32_t qspi_flash_write(uint32_t addr, uint8_t *data, uint32_t length);
|
||||||
|
uint32_t qspi_flash_read(uint32_t addr, uint8_t *data, uint32_t length);
|
||||||
|
uint32_t qspi_flash_erase_4kbytes(uint32_t addr);
|
||||||
|
uint32_t qspi_flash_erase_32kbytes(uint32_t addr);
|
||||||
|
uint32_t qspi_flash_erase_64kbytes(uint32_t addr);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __QSPI_FLASH_H__ */
|
||||||
Loading…
Reference in New Issue
Block a user