From adef945b306a3e4625ddacf276cf433646b4afef Mon Sep 17 00:00:00 2001 From: zhji Date: Sun, 17 Nov 2024 22:04:45 +0800 Subject: [PATCH] [feat] add qspi_flash driver --- bootloader/main.c | 37 +++- driver/board/qspi_flash.c | 387 ++++++++++++++++++++++++++++++++++++++ driver/board/qspi_flash.h | 105 +++++++++++ 3 files changed, 528 insertions(+), 1 deletion(-) create mode 100644 driver/board/qspi_flash.c create mode 100644 driver/board/qspi_flash.h diff --git a/bootloader/main.c b/bootloader/main.c index 6907149..aaf7ab3 100644 --- a/bootloader/main.c +++ b/bootloader/main.c @@ -2,6 +2,7 @@ #include "led.h" #include "uart_log.h" #include "ltimer.h" +#include "qspi_flash.h" #include "stdio.h" void system_init(void) @@ -73,6 +74,7 @@ void system_init(void) led_init(LED_PIN); uart_log_init(); ltimer_init(); + qspi_flash_init(3); /* 200MHz / (3 + 1) = 50MHz */ } void led_blink(void) @@ -81,17 +83,50 @@ void led_blink(void) led_off(LED_PIN); } +uint8_t data[256]; int main(void) { + uint32_t ret; + system_init(); printf("Run start ...\r\n"); printf("SystemCoreClock = %ld\r\n", SystemCoreClock); 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) { uint64_t 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(); ltimer_delay_ms(1000); } diff --git a/driver/board/qspi_flash.c b/driver/board/qspi_flash.c new file mode 100644 index 0000000..2a18ee1 --- /dev/null +++ b/driver/board/qspi_flash.c @@ -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; +} diff --git a/driver/board/qspi_flash.h b/driver/board/qspi_flash.h new file mode 100644 index 0000000..e3661f8 --- /dev/null +++ b/driver/board/qspi_flash.h @@ -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__ */