'Driver QUADSPI W25q128jv on STM32 Project not working, can't seem to write on it
I am trying to initialize my W25Q128jv External Flash in a my project, but I am not able to write on the external flash and I think it could be because of the Memory Mapping Mode but I really don't know.
static void MX_QUADSPI_Init(void)
{
/* USER CODE BEGIN QUADSPI_Init 0 */
/* USER CODE END QUADSPI_Init 0 */
/* USER CODE BEGIN QUADSPI_Init 1 */
/* USER CODE END QUADSPI_Init 1 */
/* QUADSPI parameter configuration*/
hqspi.Instance = QUADSPI;
hqspi.Init.ClockPrescaler = 1;
hqspi.Init.FifoThreshold = 4;
hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
hqspi.Init.FlashSize = 23;
hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_6_CYCLE;
hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;
hqspi.Init.FlashID = QSPI_FLASH_ID_1;
hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;
if (HAL_QSPI_Init(&hqspi) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN QUADSPI_Init 2 */
BSP_QSPI_Init();
/* USER CODE END QUADSPI_Init 2 */
}
Here the driver:
uint8_t BSP_QSPI_Init(void) { QSPI_CommandTypeDef s_command; uint8_t value = W25Q128JV_FSR_QE;
/* QSPI memory reset */ if (QSPI_ResetMemory() != QSPI_OK) { return QSPI_NOT_SUPPORTED; }/* Enable write operations */
if (QSPI_WriteEnable() != QSPI_OK)
{
return QSPI_ERROR;
}
/* Set status register for Quad Enable,the Quad IO2 and IO3 pins are enable */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = WRITE_STATUS_REG2_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.NbData = 1; 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(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } / Transmit the data */ if (HAL_QSPI_Transmit(&hqspi, &value, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; }
/* automatic polling mode to wait for memory ready */ if (QSPI_AutoPollingMemReady(W25Q128JV_WRITE_STATUS_REG_TIME_MS) != QSPI_OK) { return QSPI_ERROR; } BSP_QSPI_MemoryMappedMode(); //BSP_QSPI_Erase(0x90000000, 1000); return QSPI_OK; } /BSP_QSPI_Init/
static uint8_t QSPI_ResetMemory(void) { QSPI_CommandTypeDef s_command;
/* Initialize the reset enable command */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = RESET_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;
/* Send the command */ if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; }
/* Send the reset memory command */ s_command.Instruction = RESET_MEMORY_CMD; if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; }
/* Configure automatic polling mode to wait the memory is ready */ if (QSPI_AutoPollingMemReady(HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) { return QSPI_ERROR; }
return QSPI_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 (QSPI_ERROR);
}
/* Configure automatic polling mode to wait for write enabling ---- */
sConfig.Match = W25Q128JV_FSR_WREN;
sConfig.Mask = W25Q128JV_FSR_WREN;
sConfig.MatchMode = QSPI_MATCH_MODE_AND;
sConfig.StatusBytesSize = 1;
sConfig.Interval = 0x10;
sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
sCommand.Instruction = READ_STATUS_REG1_CMD;
sCommand.DataMode = QSPI_DATA_1_LINE;
sCommand.NbData = 1;
if (HAL_QSPI_AutoPolling(&hqspi, &sCommand, &sConfig, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return (QSPI_ERROR);
}
return (QSPI_OK);
} /* QSPI_WriteEnable */
static uint8_t QSPI_AutoPollingMemReady(uint32_t Timeout) {
QSPI_CommandTypeDef s_command;
QSPI_AutoPollingTypeDef s_config;
/* Configure automatic polling mode to wait for memory ready */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = READ_STATUS_REG1_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;
s_config.Match = 0x00;
s_config.Mask = W25Q128JV_FSR_BUSY;
s_config.MatchMode = QSPI_MATCH_MODE_AND;
s_config.StatusBytesSize = 1;
s_config.Interval = 0x10;
s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
if (HAL_QSPI_AutoPolling(&hqspi, &s_command, &s_config, Timeout) != HAL_OK) {
return (QSPI_ERROR);
}
return (QSPI_OK);
} /* QSPI_AutoPollingMemReady */
static uint8_t BSP_QSPI_Write(const uint8_t * pData, uint32_t WriteAddr, uint32_t Size) {
QSPI_CommandTypeDef s_command;
uint32_t end_addr, current_size, current_addr;
/* Calculation of the size between the write address and the end of the page */
current_addr = 0U;
while (current_addr <= WriteAddr) {
current_addr += W25Q128JV_PAGE_SIZE;
}
current_size = current_addr - WriteAddr;
/* Check if the size of the data is less than the remaining place in the page */
if (current_size > Size) {
current_size = Size;
}
/* Initialize the address variables */
current_addr = WriteAddr;
end_addr = WriteAddr + Size;
/* Initialize the program command */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = QUAD_INPUT_PAGE_PROG_CMD;
s_command.AddressMode = QSPI_ADDRESS_1_LINE;
s_command.AddressSize = QSPI_ADDRESS_24_BITS;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_4_LINES;
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;
/* Perform the write page by page */
do {
s_command.Address = current_addr;
s_command.NbData = current_size;
/* Enable write operations */
QSPI_WriteEnable();
/* Configure the command */
if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return (QSPI_ERROR);
}
/* Transmission of the data */
if (HAL_QSPI_Transmit(&hqspi, (uint8_t *)((uint32_t)pData), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return (QSPI_ERROR);
}
/* Configure automatic polling mode to wait for end of program */
if (QSPI_AutoPollingMemReady(HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) {
return (QSPI_ERROR);
}
/* Update the address and size variables for next page programming */
current_addr += current_size;
pData += current_size;
current_size = ((current_addr + W25Q128JV_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : W25Q128JV_PAGE_SIZE;
} while (current_addr < end_addr);
return (QSPI_OK);
} /* BSP_QSPI_Write */
uint8_t BSP_QSPI_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size) {
QSPI_CommandTypeDef s_command;
/* Initialize the read command */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = READ_CMD;
s_command.AddressMode = QSPI_ADDRESS_1_LINE;
s_command.AddressSize = QSPI_ADDRESS_24_BITS;
s_command.Address = ReadAddr;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_1_LINE;
s_command.DummyCycles = 0;
s_command.NbData = Size;
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(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return (QSPI_ERROR);
}
/* Reception of the data */
if (HAL_QSPI_Receive(&hqspi, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return (QSPI_ERROR);
}
return (QSPI_OK);
} /* BSP_QSPI_Read */
static void BSP_QSPI_MemoryMappedMode(void) {
QSPI_CommandTypeDef s_command;
QSPI_MemoryMappedTypeDef s_mem_mapped_cfg;
/* Configure the command for the read instruction */
s_command.Instruction = QUAD_INOUT_FAST_READ_CMD;
s_command.Address = 0U;
s_command.AlternateBytes = 0xF0;
s_command.AddressSize = QSPI_ADDRESS_24_BITS;
s_command.AlternateBytesSize = QSPI_ALTERNATE_BYTES_8_BITS;
s_command.DummyCycles = W25Q128JV_DUMMY_CYCLES_READ_QUAD;
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.AddressMode = QSPI_ADDRESS_4_LINES;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_4_LINES;
s_command.DataMode = QSPI_DATA_4_LINES;
s_command.NbData = 0U;
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 memory mapped mode */
s_mem_mapped_cfg.TimeOutPeriod = 0;
s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;
if (HAL_QSPI_MemoryMapped(&hqspi, &s_command, &s_mem_mapped_cfg) != HAL_OK) {
Error_Handler();
}
} /* BSP_QSPI_MemoryMappedMode */
static uint8_t BSP_QSPI_Erase(uint32_t Address, uint32_t Size) {
#define TIMEOUTSAFE_MS 1000U
QSPI_CommandTypeDef s_command;
uint16_t Timeout;
/* Initialize the erase command */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
if (Size > W25Q128JV_SECTOR_SIZE) {
s_command.Instruction = BLOCK_64_ERASE_CMD;
} else {
s_command.Instruction = SECTOR_ERASE_CMD;
}
s_command.AddressMode = QSPI_ADDRESS_1_LINE;
s_command.AddressSize = QSPI_ADDRESS_24_BITS;
s_command.Address = Address;
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;
/* Enable write operations */
if (QSPI_WriteEnable() != QSPI_OK) {
return (QSPI_ERROR);
}
/* Send the command */
QSPI_Cplt = 0U;
Timeout = TIMEOUTSAFE_MS;
if (HAL_QSPI_Command_IT(&hqspi, &s_command) != HAL_OK) {
return (QSPI_ERROR);
}
while ((QSPI_Cplt == 0U) && (Timeout > 0U)) {
HAL_Delay(1000);
Timeout--;
}
if (Timeout == 0U) {
return (QSPI_ERROR);
}
if (s_command.Instruction == BLOCK_64_ERASE_CMD) {
Timeout = W25Q128JV_BLOCK_64_ERASE_MAX_TIME;
} else if (s_command.Instruction == BLOCK_32_ERASE_CMD) {
Timeout = W25Q128JV_BLOCK_32_ERASE_MAX_TIME;
} else {
Timeout = W25Q128JV_SECTOR_ERASE_MAX_TIME;
}
/* Configure automatic polling mode to wait for end of erase */
if (QSPI_AutoPollingMemReady(Timeout) != QSPI_OK) {
return (QSPI_ERROR);
}
return (QSPI_OK);
} /* BSP_QSPI_Erase*/
For this project I will need my QUADSPI when I will add TouchGFX to save some items, but for now I am only trying to do a for cycle to verify that it works and its performance
uint32_t *flashbuffer = (uint32_t*)0x90000000;
const uint32_t size = 1000;
int begin = HAL_GetTick();
for(i = 0; i < size; i++)
{
flashbuffer[i]=i;
}
int end = HAL_GetTick();
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
