diff --git a/QSPI_Drivers/AT25SF128A/quadspi.c b/QSPI_Drivers/AT25SF128A/quadspi.c new file mode 100644 index 0000000..6e8dba6 --- /dev/null +++ b/QSPI_Drivers/AT25SF128A/quadspi.c @@ -0,0 +1,404 @@ +/* USER CODE BEGIN 0 */ +static uint8_t QSPI_WriteEnable(void); +static uint8_t QSPI_AutoPollingMemReady(uint32_t Timeout); +static uint8_t QSPI_Configuration(void); +static uint8_t QSPI_ResetChip(void); +/* USER CODE END 0 */ + +/* USER CODE BEGIN 1 */ + +/* QUADSPI init function */ +uint8_t CSP_QUADSPI_Init(void) +{ + // Prepare QSPI peripheral for ST-Link Utility operations + hqspi.Instance = QUADSPI; + if (HAL_QSPI_DeInit(&hqspi) != HAL_OK) + { + return HAL_ERROR; + } + + MX_QUADSPI_Init(); + + if (QSPI_ResetChip() != HAL_OK) + { + return HAL_ERROR; + } + + HAL_Delay(1); + + if (QSPI_AutoPollingMemReady() != HAL_OK) + { + return HAL_ERROR; + } + + if (QSPI_WriteEnable() != HAL_OK) + { + return HAL_ERROR; + } + + if (QSPI_Configuration() != HAL_OK) + { + return HAL_ERROR; + } + + return HAL_OK; +} + +uint8_t CSP_QSPI_Erase_Chip(void) +{ + QSPI_CommandTypeDef sCommand; + + if (QSPI_WriteEnable() != HAL_OK) + { + return HAL_ERROR; + } + + // Erasing Sequence + sCommand.Instruction = CHIP_ERASE_CMD; + sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; + sCommand.AddressSize = QSPI_ADDRESS_24_BITS; + sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; + sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + sCommand.AddressMode = QSPI_ADDRESS_NONE; + sCommand.Address = 0; + sCommand.DataMode = QSPI_DATA_NONE; + sCommand.DummyCycles = 0; + + if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return HAL_ERROR; + } + + if (QSPI_AutoPollingMemReady() != HAL_OK) + { + return HAL_ERROR; + } + + return HAL_OK; +} + +static uint8_t QSPI_AutoPollingMemReady(void) +{ + QSPI_CommandTypeDef sCommand; + QSPI_AutoPollingTypeDef sConfig; + + // Configure automatic polling mode to wait for memory ready + sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; + sCommand.Instruction = READ_STATUS_REG_1_CMD; + sCommand.AddressMode = QSPI_ADDRESS_NONE; + sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + sCommand.DataMode = QSPI_DATA_1_LINE; + sCommand.DummyCycles = 0; + sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; + sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + sConfig.Match = 0x00; + sConfig.Mask = 0x01; + sConfig.MatchMode = QSPI_MATCH_MODE_AND; + sConfig.StatusBytesSize = 1; + sConfig.Interval = 0x10; + sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; + + if (HAL_QSPI_AutoPolling(&hqspi, &sCommand, &sConfig, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return HAL_ERROR; + } + + return HAL_OK; +} + +static uint8_t QSPI_WriteEnable(void) +{ + QSPI_CommandTypeDef sCommand; + QSPI_AutoPollingTypeDef sConfig; + + // Enable write operations + sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; + sCommand.Instruction = WRITE_ENABLE_CMD; + sCommand.AddressMode = QSPI_ADDRESS_NONE; + sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + sCommand.DataMode = QSPI_DATA_NONE; + sCommand.DummyCycles = 0; + sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; + sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return HAL_ERROR; + } + + // Configure automatic polling mode to wait for write enabling + sConfig.Match = 0x02; + sConfig.Mask = 0x02; + sConfig.MatchMode = QSPI_MATCH_MODE_AND; + sConfig.StatusBytesSize = 1; + sConfig.Interval = 0x10; + sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; + + sCommand.Instruction = READ_STATUS_REG_1_CMD; + sCommand.DataMode = QSPI_DATA_1_LINE; + if (HAL_QSPI_AutoPolling(&hqspi, &sCommand, &sConfig, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return HAL_ERROR; + } + + return HAL_OK; +} + +// Enable quad mode +uint8_t QSPI_Configuration(void) +{ + QSPI_CommandTypeDef sCommand; + uint8_t reg; + + // Read status register + sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; + sCommand.Instruction = READ_STATUS_REG_2_CMD; + sCommand.AddressMode = QSPI_ADDRESS_NONE; + sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + sCommand.DataMode = QSPI_DATA_1_LINE; + sCommand.DummyCycles = 0; + sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; + sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + sCommand.NbData = 1; + + if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return HAL_ERROR; + } + if (HAL_QSPI_Receive(&hqspi, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return HAL_ERROR; + } + + // Modify buffer to enable quad mode + reg |= 0x02; + + sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; + sCommand.AddressSize = QSPI_ADDRESS_24_BITS; + sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; + sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + sCommand.Instruction = WRITE_STATUS_REG_2_CMD; + sCommand.AddressMode = QSPI_ADDRESS_NONE; + sCommand.DataMode = QSPI_DATA_1_LINE; + sCommand.DummyCycles = 0; + sCommand.NbData = 1; + + if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return HAL_ERROR; + } + if (HAL_QSPI_Transmit(&hqspi, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + Error_Handler(); + return HAL_ERROR; + } + + return HAL_OK; +} + +uint8_t CSP_QSPI_EraseSector(uint32_t EraseStartAddress, uint32_t EraseEndAddress) +{ + QSPI_CommandTypeDef sCommand; + + EraseStartAddress = EraseStartAddress - EraseStartAddress % MEMORY_SECTOR_SIZE; + + // Erasing Sequence + sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; + sCommand.AddressSize = QSPI_ADDRESS_24_BITS; + sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; + sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + sCommand.Instruction = SECTOR_ERASE_CMD; + sCommand.AddressMode = QSPI_ADDRESS_1_LINE; + + sCommand.DataMode = QSPI_DATA_NONE; + sCommand.DummyCycles = 0; + + while (EraseEndAddress >= EraseStartAddress) + { + sCommand.Address = (EraseStartAddress & 0x0FFFFFFF); + + if (QSPI_WriteEnable() != HAL_OK) + { + return HAL_ERROR; + } + + if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return HAL_ERROR; + } + EraseStartAddress += MEMORY_SECTOR_SIZE; + + if (QSPI_AutoPollingMemReady() != HAL_OK) + { + return HAL_ERROR; + } + } + + return HAL_OK; +} + +uint8_t CSP_QSPI_WriteMemory(uint8_t *buffer, uint32_t address, uint32_t buffer_size) +{ + QSPI_CommandTypeDef sCommand; + uint32_t end_addr, current_size, current_addr; + + // Calculation of the size between the write address and the end of the page + current_addr = 0; + while (current_addr <= address) + { + current_addr += MEMORY_PAGE_SIZE; + } + current_size = current_addr - address; + + // Check if the size of the data is less than the remaining place in the page + if (current_size > buffer_size) + { + current_size = buffer_size; + } + + // Initialize the adress variables + current_addr = address; + end_addr = address + buffer_size; + + sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; + sCommand.AddressSize = QSPI_ADDRESS_24_BITS; + sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; + sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + sCommand.Instruction = QUAD_PROG_CMD; + sCommand.AddressMode = QSPI_ADDRESS_1_LINE; + sCommand.DataMode = QSPI_DATA_4_LINES; + sCommand.DummyCycles = 0; + + // Perform the write page by page + do + { + sCommand.Address = current_addr; + sCommand.NbData = current_size; + + if (current_size == 0) + { + return HAL_OK; + } + + // Enable write operations + if (QSPI_WriteEnable() != HAL_OK) + { + return HAL_ERROR; + } + + // Configure the command + if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return HAL_ERROR; + } + + // Transmission of the data + if (HAL_QSPI_Transmit(&hqspi, buffer, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return HAL_ERROR; + } + + // Configure automatic polling mode to wait for end of program + if (QSPI_AutoPollingMemReady() != HAL_OK) + { + return HAL_ERROR; + } + + // Update the address and size variables for next page programming + current_addr += current_size; + buffer += current_size; + current_size = ((current_addr + MEMORY_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : MEMORY_PAGE_SIZE; + } while (current_addr <= end_addr); + + return HAL_OK; +} + + +uint8_t CSP_QSPI_EnableMemoryMappedMode(void) +{ + QSPI_CommandTypeDef sCommand; + QSPI_MemoryMappedTypeDef sMemMappedCfg; + + // Enable Memory-Mapped mode + sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; + sCommand.AddressSize = QSPI_ADDRESS_24_BITS; + sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; + sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + sCommand.AddressMode = QSPI_ADDRESS_4_LINES; + sCommand.DataMode = QSPI_DATA_4_LINES; + sCommand.NbData = 0; + sCommand.Address = 0; + sCommand.Instruction = QUAD_INOUT_FAST_READ_CMD; + sCommand.DummyCycles = DUMMY_CLOCK_CYCLES_MEMORY_MAPPED_MODE; + + sMemMappedCfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE; + + if (HAL_QSPI_MemoryMapped(&hqspi, &sCommand, &sMemMappedCfg) != HAL_OK) + { + return HAL_ERROR; + } + + return HAL_OK; +} + +static uint8_t QSPI_ResetChip() +{ + QSPI_CommandTypeDef sCommand; + uint32_t temp = 0; + + // Erasing Sequence + sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; + sCommand.AddressSize = QSPI_ADDRESS_24_BITS; + sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; + sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + sCommand.Instruction = RESET_ENABLE_CMD; + sCommand.AddressMode = QSPI_ADDRESS_NONE; + sCommand.Address = 0; + sCommand.DataMode = QSPI_DATA_NONE; + sCommand.DummyCycles = 0; + + if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return HAL_ERROR; + } + for (temp = 0; temp < 0x2f; temp++) + { + __NOP(); + } + + sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; + sCommand.AddressSize = QSPI_ADDRESS_24_BITS; + sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; + sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + sCommand.Instruction = RESET_EXECUTE_CMD; + sCommand.AddressMode = QSPI_ADDRESS_NONE; + sCommand.Address = 0; + sCommand.DataMode = QSPI_DATA_NONE; + sCommand.DummyCycles = 0; + + if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return HAL_ERROR; + } + + return HAL_OK; +} +/* USER CODE END 1 */ diff --git a/QSPI_Drivers/AT25SF128A/quadspi.h b/QSPI_Drivers/AT25SF128A/quadspi.h new file mode 100644 index 0000000..8753afc --- /dev/null +++ b/QSPI_Drivers/AT25SF128A/quadspi.h @@ -0,0 +1,44 @@ +/* USER CODE BEGIN Private defines */ + +uint8_t CSP_QUADSPI_Init(void); +uint8_t CSP_QSPI_EraseSector(uint32_t EraseStartAddress, uint32_t EraseEndAddress); +uint8_t CSP_QSPI_WriteMemory(uint8_t* buffer, uint32_t address, uint32_t buffer_size); +uint8_t CSP_QSPI_EnableMemoryMappedMode(void); +uint8_t CSP_QSPI_Erase_Chip (void); + +/* USER CODE END Private defines */ + + + +/* USER CODE BEGIN Prototypes */ + +/*AT25SF128A memory parameters*/ +#define MEMORY_FLASH_SIZE 0x1000000 /// 16 MBytes, 128 MBits +#define MEMORY_BLOCK_SIZE 0x10000 /// 64 KBytes, 256 blocks +#define MEMORY_SECTOR_SIZE 0x1000 /// 4 kBytes, 4096 sectors +#define MEMORY_PAGE_SIZE 0x100 /// 256 bytes, 65536 pages + +/*AT25SF128A commands */ +#define WRITE_ENABLE_CMD 0x06 +#define RESET_ENABLE_CMD 0x66 +#define RESET_EXECUTE_CMD 0x99 + +#define READ_STATUS_REG_1_CMD 0x05 +#define READ_STATUS_REG_2_CMD 0x35 +#define READ_STATUS_REG_3_CMD 0x15 +#define WRITE_STATUS_REG_1_CMD 0x01 +#define WRITE_STATUS_REG_2_CMD 0x31 +#define WRITE_STATUS_REG_3_CMD 0x11 + +#define SUBSECTOR_ERASE_CMD 0x20 +#define SECTOR_ERASE_CMD 0xD8 +#define CHIP_ERASE_CMD 0xC7 + +#define QUAD_OUT_FAST_READ_CMD 0x6B +#define QUAD_INOUT_FAST_READ_CMD 0xEB +#define QUAD_PROG_CMD 0x32 + +#define DUMMY_CLOCK_CYCLES_READ_QUAD 8 +#define DUMMY_CLOCK_CYCLES_MEMORY_MAPPED_MODE 6 + +/* USER CODE END Prototypes */ \ No newline at end of file