diff --git a/board/BearPi_STM32L431RC/BSP/Hardware/W25QXX-QSPI/w25qxx.c b/board/BearPi_STM32L431RC/BSP/Hardware/W25QXX-QSPI/w25qxx.c new file mode 100644 index 00000000..765370a3 --- /dev/null +++ b/board/BearPi_STM32L431RC/BSP/Hardware/W25QXX-QSPI/w25qxx.c @@ -0,0 +1,343 @@ +#include "w25qxx.h" +#include "quadspi.h" + +int w25qxx_init(void) +{ + MX_QUADSPI_Init(); + return 0; +} + +int w25qxx_memory_mapped(void) +{ + QSPI_CommandTypeDef cmd = { + // Instruction + .InstructionMode = QSPI_INSTRUCTION_1_LINE, + .Instruction = FAST_READ_DUAL_IO_CMD, + // Address + .AddressMode = QSPI_ADDRESS_2_LINES, + .Address = 0, // NOT USED for memory-mapped mode + .AddressSize = QSPI_ADDRESS_24_BITS, + // AlternateByte + .AlternateByteMode = QSPI_ALTERNATE_BYTES_2_LINES, + .AlternateBytes = 0xF0, // M7-M0 should be set to Fxh + .AlternateBytesSize = QSPI_ALTERNATE_BYTES_8_BITS, + // Dummy + .DummyCycles = 0, + // Data + .DataMode = QSPI_DATA_2_LINES, + .NbData = 0, // NOT USED for memory-mapped mode + // DDR + .DdrMode = QSPI_DDR_MODE_DISABLE, + }; + QSPI_MemoryMappedTypeDef cfg = { + .TimeOutPeriod = 0, + .TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE, + }; + if (HAL_QSPI_GetState(&hqspi) != HAL_QSPI_STATE_BUSY_MEM_MAPPED) { + if (HAL_QSPI_Abort(&hqspi) != HAL_OK) { + return -1; + } + if (HAL_QSPI_MemoryMapped(&hqspi, &cmd, &cfg) != HAL_OK) { + return -1; + } + } + return 0; +} + +uint16_t w25qxx_read_deviceid(void) +{ + uint8_t recv_buf[2] = {0}; + uint16_t device_id = 0; + QSPI_CommandTypeDef cmd = { + // Instruction + .InstructionMode = QSPI_INSTRUCTION_1_LINE, + .Instruction = ManufactDeviceID_CMD, + // Address + .AddressMode = QSPI_ADDRESS_1_LINE, + .Address = 0, + .AddressSize = QSPI_ADDRESS_24_BITS, + // AlternateByte + .AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE, + // Dummy + .DummyCycles = 0, + // Data + .DataMode = QSPI_DATA_1_LINE, + .NbData = 2, + // DDR + .DdrMode = QSPI_DDR_MODE_DISABLE, + }; + if (HAL_QSPI_Abort(&hqspi) != HAL_OK) { + return 0; + } + if (HAL_QSPI_Command(&hqspi, &cmd, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + return 0; + } + if (HAL_QSPI_Receive(&hqspi, recv_buf, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + return 0; + } + device_id = (recv_buf[0] << 8) | recv_buf[1]; + return device_id; +} + +static void w25qxx_wait_busy(void) +{ + uint8_t status; + QSPI_CommandTypeDef cmd = { + // Instruction + .InstructionMode = QSPI_INSTRUCTION_1_LINE, + .Instruction = READ_STATU_REGISTER_1, + // Address + .AddressMode = QSPI_ADDRESS_NONE, + // AlternateByte + .AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE, + // Dummy + .DummyCycles = 0, + // Data + .DataMode = QSPI_DATA_1_LINE, + .NbData = 1, + // DDR + .DdrMode = QSPI_DDR_MODE_DISABLE, + }; + HAL_QSPI_Command(&hqspi, &cmd, HAL_QSPI_TIMEOUT_DEFAULT_VALUE); + do { + HAL_QSPI_Receive(&hqspi, &status, HAL_QSPI_TIMEOUT_DEFAULT_VALUE); + } while ((status & 0x01) == 0x01); +} + +int w25qxx_read(uint8_t *buffer, uint32_t start_addr, uint16_t nbytes) +{ + QSPI_CommandTypeDef cmd = { + // Instruction + .InstructionMode = QSPI_INSTRUCTION_1_LINE, + .Instruction = FAST_READ_DUAL_IO_CMD, + // Address + .AddressMode = QSPI_ADDRESS_2_LINES, + .Address = start_addr, + .AddressSize = QSPI_ADDRESS_24_BITS, + // AlternateByte + .AlternateByteMode = QSPI_ALTERNATE_BYTES_2_LINES, + .AlternateBytes = 0xF0, // M7-M0 should be set to Fxh + .AlternateBytesSize = QSPI_ALTERNATE_BYTES_8_BITS, + // Dummy + .DummyCycles = 0, + // Data + .DataMode = QSPI_DATA_2_LINES, + .NbData = nbytes, + // DDR + .DdrMode = QSPI_DDR_MODE_DISABLE, + }; + if (HAL_QSPI_Abort(&hqspi) != HAL_OK) { + return -1; + } + if (HAL_QSPI_Command(&hqspi, &cmd, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + return -1; + } + if (HAL_QSPI_Receive(&hqspi, buffer, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + return -1; + } + return 0; +} + +static void w25qxx_write_enable(void) +{ + QSPI_CommandTypeDef cmd = { + // Instruction + .InstructionMode = QSPI_INSTRUCTION_1_LINE, + .Instruction = WRITE_ENABLE_CMD, + // Address + .AddressMode = QSPI_ADDRESS_NONE, + // AlternateByte + .AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE, + // Dummy + .DummyCycles = 0, + // Data + .DataMode = QSPI_DATA_NONE, + // DDR + .DdrMode = QSPI_DDR_MODE_DISABLE, + }; + HAL_QSPI_Command(&hqspi, &cmd, HAL_QSPI_TIMEOUT_DEFAULT_VALUE); + // w25qxx_wait_busy(); +} + +static void w25qxx_write_disable(void) +{ + QSPI_CommandTypeDef cmd = { + // Instruction + .InstructionMode = QSPI_INSTRUCTION_1_LINE, + .Instruction = WRITE_DISABLE_CMD, + // Address + .AddressMode = QSPI_ADDRESS_NONE, + // AlternateByte + .AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE, + // Dummy + .DummyCycles = 0, + // Data + .DataMode = QSPI_DATA_NONE, + // DDR + .DdrMode = QSPI_DDR_MODE_DISABLE, + }; + HAL_QSPI_Command(&hqspi, &cmd, HAL_QSPI_TIMEOUT_DEFAULT_VALUE); + // w25qxx_wait_busy(); +} + +int w25qxx_erase_sector(uint32_t sector_addr) +{ + QSPI_CommandTypeDef cmd = { + // Instruction + .InstructionMode = QSPI_INSTRUCTION_1_LINE, + .Instruction = SECTOR_ERASE_CMD, + // Address + .AddressMode = QSPI_ADDRESS_1_LINE, + .Address = sector_addr, + .AddressSize = QSPI_ADDRESS_24_BITS, + // AlternateByte + .AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE, + // Dummy + .DummyCycles = 0, + // Data + .DataMode = QSPI_DATA_NONE, + // DDR + .DdrMode = QSPI_DDR_MODE_DISABLE, + }; + + if (HAL_QSPI_Abort(&hqspi) != HAL_OK) { + return -1; + } + + w25qxx_wait_busy(); + + w25qxx_write_enable(); + + if (HAL_QSPI_Command(&hqspi, &cmd, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + return -1; + } + + w25qxx_wait_busy(); + + return 0; +} + +int w25qxx_erase_chip(void) +{ + QSPI_CommandTypeDef cmd = { + // Instruction + .InstructionMode = QSPI_INSTRUCTION_1_LINE, + .Instruction = CHIP_ERASE_CMD, + // Address + .AddressMode = QSPI_ADDRESS_NONE, + // AlternateByte + .AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE, + // Dummy + .DummyCycles = 0, + // Data + .DataMode = QSPI_DATA_NONE, + // DDR + .DdrMode = QSPI_DDR_MODE_DISABLE, + }; + + if (HAL_QSPI_Abort(&hqspi) != HAL_OK) { + return -1; + } + + w25qxx_wait_busy(); + + w25qxx_write_enable(); + + if (HAL_QSPI_Command(&hqspi, &cmd, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + return -1; + } + + w25qxx_wait_busy(); + + return 0; +} + +int w25qxx_page_program(uint8_t *dat, uint32_t write_addr, uint16_t nbytes) +{ + QSPI_CommandTypeDef cmd = { + // Instruction + .InstructionMode = QSPI_INSTRUCTION_1_LINE, + .Instruction = PAGE_PROGRAM_CMD, + // Address + .AddressMode = QSPI_ADDRESS_1_LINE, + .Address = write_addr, + .AddressSize = QSPI_ADDRESS_24_BITS, + // AlternateByte + .AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE, + // Dummy + .DummyCycles = 0, + // Data + .DataMode = QSPI_DATA_1_LINE, + .NbData = nbytes, + // DDR + .DdrMode = QSPI_DDR_MODE_DISABLE, + }; + + if (HAL_QSPI_Abort(&hqspi) != HAL_OK) { + return -1; + } + + w25qxx_wait_busy(); + + w25qxx_write_enable(); + + if (HAL_QSPI_Command(&hqspi, &cmd, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + return -1; + } + if (HAL_QSPI_Transmit(&hqspi, dat, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + return -1; + } + + w25qxx_wait_busy(); + + return 0; +} + +int w25qxx_reset(void) +{ + QSPI_CommandTypeDef cmd1 = { + // Instruction + .InstructionMode = QSPI_INSTRUCTION_1_LINE, + .Instruction = ENABLE_RESET_CMD, + // Address + .AddressMode = QSPI_ADDRESS_NONE, + // AlternateByte + .AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE, + // Dummy + .DummyCycles = 0, + // Data + .DataMode = QSPI_DATA_NONE, + // DDR + .DdrMode = QSPI_DDR_MODE_DISABLE, + }; + QSPI_CommandTypeDef cmd2 = { + // Instruction + .InstructionMode = QSPI_INSTRUCTION_1_LINE, + .Instruction = RESET_DEVICE_CMD, + // Address + .AddressMode = QSPI_ADDRESS_NONE, + // AlternateByte + .AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE, + // Dummy + .DummyCycles = 0, + // Data + .DataMode = QSPI_DATA_NONE, + // DDR + .DdrMode = QSPI_DDR_MODE_DISABLE, + }; + + if (HAL_QSPI_Abort(&hqspi) != HAL_OK) { + return -1; + } + + if (HAL_QSPI_Command(&hqspi, &cmd1, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + return -1; + } + if (HAL_QSPI_Command(&hqspi, &cmd2, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + return -1; + } + + w25qxx_wait_busy(); + + return 0; +} diff --git a/board/BearPi_STM32L431RC/BSP/Hardware/W25QXX-QSPI/w25qxx.h b/board/BearPi_STM32L431RC/BSP/Hardware/W25QXX-QSPI/w25qxx.h new file mode 100644 index 00000000..b1a2051f --- /dev/null +++ b/board/BearPi_STM32L431RC/BSP/Hardware/W25QXX-QSPI/w25qxx.h @@ -0,0 +1,40 @@ +#ifndef _W25QXX_H_ +#define _W25QXX_H_ +#include "main.h" + +enum { + ManufactDeviceID_CMD = 0x90, + READ_STATU_REGISTER_1 = 0x05, + READ_STATU_REGISTER_2 = 0x35, + WRITE_STATU_REGISTER = 0x01, + READ_DATA_CMD = 0x03, + FAST_READ_CMD = 0x0B, + FAST_READ_DUAL_O_CMD = 0x3B, + FAST_READ_DUAL_IO_CMD = 0xBB, + FAST_READ_QUAD_O_CMD = 0x6B, + FAST_READ_QUAD_IO_CMD = 0xEB, + WRITE_ENABLE_CMD = 0x06, + WRITE_DISABLE_CMD = 0x04, + SECTOR_ERASE_CMD = 0x20, + CHIP_ERASE_CMD = 0xc7, + PAGE_PROGRAM_CMD = 0x02, + QUAD_PAGE_PROGRAM_CMD = 0x32, + BLOCK_ERASE_64KB_CMD = 0xD8, + BLOCK_ERASE_32KB_CMD = 0x52, + ERASE_SUSPEND_CMD = 0x75, + ERASE_RESUME_CMD = 0x7A, + HIGH_PERFORM_MODE_CMD = 0xA3, + ENABLE_RESET_CMD = 0x66, + RESET_DEVICE_CMD = 0x99, +}; + +int w25qxx_init(void); +int w25qxx_memory_mapped(void); +uint16_t w25qxx_read_deviceid(void); +int w25qxx_read(uint8_t* buffer, uint32_t start_addr, uint16_t nbytes); +int w25qxx_erase_sector(uint32_t sector_addr); +int w25qxx_erase_chip(void); +int w25qxx_page_program(uint8_t* dat, uint32_t write_addr, uint16_t nbytes); +int w25qxx_reset(void); + +#endif /* _W25QXX_H_ */