2024-07-05 05:51 AM
I'm working on a project where I use the STM32U5A9 microcontroller to control the W25Q128JV flash memory. I wrote a library to interact with this flash memory, but unfortunately I can't get it set up correctly.
The problem is that commands are sent incorrectly when this piece of code in the enableQuadMode function is executed:
CS_ENABLE();
OSPI_RegularCmdTypeDef sCommand = {0};
uint8_t reg;
HAL_StatusTypeDef res;
sCommand.OperationType = READ_STATUS_REG_CMD;
sCommand.FlashId = HAL_OSPI_FLASH_ID_1;
sCommand.DQSMode = HAL_OSPI_DQS_DISABLE;
sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
sCommand.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
sCommand.Instruction = READ_STATUS_REG2_CMD;
sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE;
sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
sCommand.DataMode = HAL_OSPI_DATA_NONE;
sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
sCommand.DummyCycles = 0;
sCommand.NbData = 1;
res = HAL_OSPI_Command(&hospi1, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
if(res != HAL_OK) {
return res;
}
the logic analyzer displays this:
Maybe any of you have faced a similar problem or can suggest some steps to solve it? Any help or guidance would be greatly appreciated!
Thanks in advance!
Settings OCTOSPI:
void MX_OCTOSPI1_Init(void)
{
/* USER CODE BEGIN OCTOSPI1_Init 0 */
/* USER CODE END OCTOSPI1_Init 0 */
OSPIM_CfgTypeDef sOspiManagerCfg = {0};
HAL_OSPI_DLYB_CfgTypeDef HAL_OSPI_DLYB_Cfg_Struct = {0};
/* USER CODE BEGIN OCTOSPI1_Init 1 */
/* USER CODE END OCTOSPI1_Init 1 */
hospi1.Instance = OCTOSPI1;
hospi1.Init.FifoThreshold = 1;
hospi1.Init.DualQuad = HAL_OSPI_DUALQUAD_DISABLE;
hospi1.Init.MemoryType = HAL_OSPI_MEMTYPE_MICRON;
hospi1.Init.DeviceSize = 24;
hospi1.Init.ChipSelectHighTime = 1;
hospi1.Init.FreeRunningClock = HAL_OSPI_FREERUNCLK_DISABLE;
hospi1.Init.ClockMode = HAL_OSPI_CLOCK_MODE_0;
hospi1.Init.WrapSize = HAL_OSPI_WRAP_NOT_SUPPORTED;
hospi1.Init.ClockPrescaler = 64-1;
hospi1.Init.SampleShifting = HAL_OSPI_SAMPLE_SHIFTING_NONE;
hospi1.Init.DelayHoldQuarterCycle = HAL_OSPI_DHQC_DISABLE;
hospi1.Init.ChipSelectBoundary = 0;
hospi1.Init.DelayBlockBypass = HAL_OSPI_DELAY_BLOCK_BYPASSED;
hospi1.Init.MaxTran = 0;
hospi1.Init.Refresh = 0;
if (HAL_OSPI_Init(&hospi1) != HAL_OK)
{
Error_Handler();
}
sOspiManagerCfg.ClkPort = 1;
sOspiManagerCfg.IOLowPort = HAL_OSPIM_IOPORT_1_LOW;
sOspiManagerCfg.Req2AckTime = 1;
if (HAL_OSPIM_Config(&hospi1, &sOspiManagerCfg, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
Error_Handler();
}
HAL_OSPI_DLYB_Cfg_Struct.Units = 0;
HAL_OSPI_DLYB_Cfg_Struct.PhaseSel = 0;
if (HAL_OSPI_DLYB_SetConfig(&hospi1, &HAL_OSPI_DLYB_Cfg_Struct) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN OCTOSPI1_Init 2 */
/* USER CODE END OCTOSPI1_Init 2 */
}
My code:
/*
* external_flash_driver.c
*
* Created on: Jun 11, 2024
* Author: nhrabets
*/
#include "main.h"
#include "octospi.h"
#include "external_flash_driver.h"
#define CS_ENABLE() HAL_GPIO_WritePin(QSPI_CS_GPIO_Port, QSPI_CS_Pin, 0)
#define CS_DISABLE() HAL_GPIO_WritePin(QSPI_CS_GPIO_Port, QSPI_CS_Pin, 1)
static uint8_t writeEnable(void)
{
CS_ENABLE();
OSPI_RegularCmdTypeDef sCommand = {0};
OSPI_AutoPollingTypeDef sConfig = {0};
HAL_StatusTypeDef res;
sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;
sCommand.FlashId = HAL_OSPI_FLASH_ID_1;
sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
sCommand.Instruction = WRITE_ENABLE_CMD;
sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
sCommand.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE;
sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
sCommand.DataMode = HAL_OSPI_DATA_NONE;
sCommand.DummyCycles = 0;
sCommand.DQSMode = HAL_OSPI_DQS_DISABLE;
sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
res = HAL_OSPI_Command(&hospi1, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
if(res != HAL_OK) {
return res;
}
CS_DISABLE();
return HAL_OK;
}
static uint8_t enableQuadMode(void)
{
CS_ENABLE();
OSPI_RegularCmdTypeDef sCommand = {0};
uint8_t reg;
HAL_StatusTypeDef res;
sCommand.OperationType = READ_STATUS_REG_CMD;
sCommand.FlashId = HAL_OSPI_FLASH_ID_1;
sCommand.DQSMode = HAL_OSPI_DQS_DISABLE;
sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
sCommand.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
sCommand.Instruction = READ_STATUS_REG2_CMD;
sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE;
sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
sCommand.DataMode = HAL_OSPI_DATA_NONE;
sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
sCommand.DummyCycles = 0;
sCommand.NbData = 1;
res = HAL_OSPI_Command(&hospi1, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
if(res != HAL_OK) {
return res;
}
res = HAL_OSPI_Receive(&hospi1, ®, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
if(res != HAL_OK) {
return res;
}
sCommand.DataMode = HAL_OSPI_DATA_NONE;
sCommand.Instruction = VOLATILE_SR_WRITE_ENABLE;
res = HAL_OSPI_Command(&hospi1, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
if(res != HAL_OK) {
return res;
}
sCommand.DataMode = HAL_OSPI_DATA_1_LINE;
sCommand.Instruction = WRITE_STATUS_REG2_CMD;
reg |= 0x02;
res = HAL_OSPI_Command(&hospi1, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
if(res != HAL_OK) {
return res;
}
res = HAL_OSPI_Transmit(&hospi1, ®, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
if(res != HAL_OK) {
return res;
}
CS_DISABLE();
return HAL_OK;
}
static uint8_t qspiConfiguration(void)
{
CS_ENABLE();
OSPI_RegularCmdTypeDef sCommand = {0};
HAL_StatusTypeDef res;
uint8_t reg;
sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
sCommand.Instruction = READ_STATUS_REG3_CMD;
sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE;
sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
sCommand.DataMode = HAL_OSPI_DATA_1_LINE;
sCommand.DummyCycles = 0;
sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
sCommand.NbData = 1;
res = HAL_OSPI_Command(&hospi1, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
if(res != HAL_OK) {
return res;
}
res = HAL_OSPI_Receive(&hospi1, ®, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
if(res != HAL_OK) {
return res;
}
sCommand.Instruction = WRITE_STATUS_REG3_CMD;
reg &= 0x9F;
res = HAL_OSPI_Command(&hospi1, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
if(res != HAL_OK) {
return res;
}
res = HAL_OSPI_Transmit(&hospi1, ®, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
if(res != HAL_OK) {
return res;
}
CS_DISABLE();
return HAL_OK;
}
uint8_t EFD_init(void)
{
if(enableQuadMode() != HAL_OK) {
return HAL_ERROR;
}
if(writeEnable() != HAL_OK) {
return HAL_ERROR;
}
if(qspiConfiguration() != HAL_OK) {
return HAL_ERROR;
}
HAL_Delay(100);
return HAL_OK;
}
uint8_t EFD_eraseChip(void)
{
CS_ENABLE();
OSPI_RegularCmdTypeDef sCommand = {0};
HAL_StatusTypeDef res;
if(writeEnable() != HAL_OK) {
return HAL_ERROR;
}
sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
sCommand.Instruction = CHIP_ERASE_CMD;
sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE;
sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
sCommand.DataMode = HAL_OSPI_DATA_NONE;
sCommand.DummyCycles = 0;
sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
res = HAL_OSPI_Command(&hospi1, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
if(res != HAL_OK) {
return HAL_ERROR;
}
CS_DISABLE();
return HAL_OK;
}
uint8_t EFD_writeData(uint8_t* pBuffer, uint32_t address, uint32_t bufferSize)
{
CS_ENABLE();
OSPI_RegularCmdTypeDef sCommand = {0};
HAL_StatusTypeDef res;
uint32_t endAddr;
uint32_t currentSize;
uint32_t currentAddr = 0;
while(currentAddr <= address) {
currentAddr += MEMORY_PAGE_SIZE;
}
currentSize = currentAddr - address;
if(currentSize > bufferSize) {
currentSize = bufferSize;
}
currentAddr = address;
endAddr = address + bufferSize;
sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
sCommand.Instruction = QUAD_IN_FAST_PROG_CMD;
sCommand.AddressMode = HAL_OSPI_ADDRESS_1_LINE;
sCommand.AddressSize = HAL_OSPI_ADDRESS_24_BITS;
sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
sCommand.DataMode = HAL_OSPI_DATA_1_LINE;
sCommand.NbData = bufferSize;
sCommand.Address = address;
sCommand.DummyCycles = 0;
do {
sCommand.Address = currentAddr;
sCommand.NbData = currentSize;
if(currentSize == 0) {
return HAL_OK;
}
if(writeEnable() != HAL_OK) {
return HAL_ERROR;
}
res = HAL_OSPI_Command(&hospi1, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
if(res != HAL_OK) {
return HAL_ERROR;
}
res = HAL_OSPI_Transmit(&hospi1, pBuffer, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
if(res != HAL_OK) {
return HAL_ERROR;
}
currentAddr += currentSize;
pBuffer += currentSize;
currentSize = ((currentAddr + MEMORY_PAGE_SIZE) > endAddr) ?
(endAddr - currentAddr) : MEMORY_PAGE_SIZE;
} while(currentAddr <= endAddr);
CS_DISABLE();
return HAL_OK;
}
uint8_t EFD_readData(uint8_t* pBuffer, uint32_t address, uint32_t bufferSize)
{
CS_ENABLE();
OSPI_RegularCmdTypeDef sCommand = {0};
HAL_StatusTypeDef res;
sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
sCommand.Instruction = QUAD_OUT_FAST_READ_CMD;
sCommand.AddressMode = HAL_OSPI_ADDRESS_4_LINES;
sCommand.AddressSize = HAL_OSPI_ADDRESS_24_BITS;
sCommand.Address = address;
sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
sCommand.DataMode = HAL_OSPI_DATA_4_LINES;
sCommand.DummyCycles = 0;
sCommand.NbData = bufferSize;
sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
res = HAL_OSPI_Command(&hospi1, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
if(res != HAL_OK) {
return HAL_ERROR;
}
res = HAL_OSPI_Receive(&hospi1, pBuffer, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
if(res != HAL_OK) {
return HAL_ERROR;
}
CS_DISABLE();
return HAL_OK;
}
2024-07-05 10:32 AM
Not clear what you see vs expect.
Certainly an excessive amount of whitespace, like you've not directly pasted from the original source
sCommand.OperationType = READ_STATUS_REG_CMD; // << NO !! THIS IS NOT THE COMMAND
Lot of code missing on nearly every subroutine using sCommand
sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;
sCommand.FlashId = HAL_OSPI_FLASH_ID_1;
sCommand.DQSMode = HAL_OSPI_DQS_DISABLE;
sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
...
2024-07-05 10:38 AM
Related to this poster, or strange coincident? https://community.st.com/t5/stm32-mcus-embedded-software/connecting-w25q128jv-via-octospi-in-quadspi-mode-on-stm32u5a9/td-p/693688
2024-07-05 10:41 AM
Why on Earth are you driving the Chip Select manually? Chose the wrong pin in fabricated PCB?
Please enumerate the pins use in your implementation
2024-07-06 06:03 AM
Thank you for your response.
Yes, on the board I am using, the Chip Select is chosen incorrectly. Can this significantly affect the operation if I control it manually?
Pinout:
OCTOSPIM_P1_IO3 - PF6
OCTOSPIM_P1_IO2 - PF7
OCTOSPIM_P1_IO0 - PF8
OCTOSPIM_P1_IO1 - PF9
OCTOSPIM_P1_CLK - PF10
CS - PF11
2024-07-06 07:08 AM
>>Can this significantly affect the operation if I control it manually?
Well it will preclude XIP / Memory Mapped mode operation.
2024-07-07 09:44 AM
Soldered a jumper and set CS in .ioc, but it always remains in the high state. What could this be related to? Could you possibly provide an example? That would be really helpful.
2024-07-07 11:38 AM
Wired it to what/how exactly, I've got zero visibility here. Are you scoping the right pins?
Still as a GPIO, or to a pin designated for OCTO SPI NCS?
Writing comprehensive examples gets to be actual work.
2024-07-09 04:02 PM
Ok, I`m trying to send data by sending instruction 0x32 Quad Input Page Program but during HAL_OSPI_Transmit function executing I have problem that hospi->State = HAL_OSPI_STATE_WRITE_CMD_CFG but in function we have the checking if (hospi->State == HAL_OSPI_STATE_CMD_CFG) and I got error. What I need to do to write data to this Flash? Can you give me some information for workflow to do this process with this config (STm32U5 + W25Q32JVSIQ)?
2024-07-10 06:58 AM
Wow, that's a bit of a dog's breakfast of random cut-n-paste. Couple of hours of work to fix that mess.
For things to work everything needs to be consistent and correct. When not in 4-4-4 you can't send things in 4-4-4. Winbond's need the QE bit in Status Registers to enable the extending bit pins. When writing registers / memory or erasing, need to wait for operations to complete.
PA4:AF3 NCS
PF10:AF3 CLK
PF8:AF10 D0
PF9:AF10 D1
PF7:AF10 D2
PF6:AF10 D3
https://github.com/cturvey/stm32extldr/tree/main/u5_w25q32