2022-09-12 12:32 PM
I'm trying to follow the OSPI_NOR_MemoryMapped STM32CubeIDE example, but for a different device (W25Q128FV). Write Enable, Read Status, and Erase Sector commands behave as expected, as well as memory-mapped reads. This has been confirmed by monitoring the OSPI lines with a logic analyzer, and comparing against the W25Q128FV datasheet.
The one thing that does not work is memory-mapped writes. No activity occurs on the OSPI lines; a fault occurs on the instruction to write to the OSPI1 address. The Cortex-M33 registers show a precise bus fault at address OCTOSPI1_BASE (0x90000000).
Any suggestions are appreciated.
OSPI_HandleTypeDef ospiHandle = {
.Instance = OCTOSPI1,
.Init = {
.FifoThreshold = 1,
.DualQuad = HAL_OSPI_DUALQUAD_DISABLE,
.MemoryType = HAL_OSPI_MEMTYPE_MACRONIX,
.DeviceSize = 24,
.ChipSelectHighTime = 2,
.FreeRunningClock = HAL_OSPI_FREERUNCLK_DISABLE,
.ClockMode = HAL_OSPI_CLOCK_MODE_0,
.WrapSize = HAL_OSPI_WRAP_NOT_SUPPORTED,
.ClockPrescaler = 256,
.SampleShifting = HAL_OSPI_SAMPLE_SHIFTING_NONE,
.DelayHoldQuarterCycle = HAL_OSPI_DHQC_ENABLE,
.ChipSelectBoundary = 0,
.DelayBlockBypass = HAL_OSPI_DELAY_BLOCK_BYPASSED,
.MaxTran = 0,
.Refresh = 0,
},
Init(void) {
// Enable clock
_HAL_RCC_OSPI1_CLK_ENABLE();
// Enable pins (CS, CLK, QSPI Data 1-4)
...
// Initialize
if (HAL_OSPI_Init(&ospiHandle) != HAL_OK)
{
Error_Handler();
}
// Manager config
OSPIM_CfgTypeDef sOspiManagerCfg = {0};
sOspiManagerCfg.ClkPort = 1;
sOspiManagerCfg.DQSPort = 1;
sOspiManagerCfg.NCSPort = 1;
sOspiManagerCfg.IOLowPort = HAL_OSPIM_IOPORT_1_LOW;
sOspiManagerCfg.IOHighPort = HAL_OSPIM_IOPORT_1_HIGH;
if (HAL_OSPIM_Config(&ospiHandle, &sOspiManagerCfg, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
Error_Handler();
}
HAL_OSPI_DLYB_CfgTypeDef HAL_OSPI_DLYB_Cfg_Struct = {0};
HAL_OSPI_DLYB_Cfg_Struct.Units = 0;
HAL_OSPI_DLYB_Cfg_Struct.PhaseSel = 0;
if (HAL_OSPI_DLYB_SetConfig(&ospiHandle, &HAL_OSPI_DLYB_Cfg_Struct) != HAL_OK)
{
Error_Handler();
}
// Attempted with both Page Program (CMD_PP = 02h) and Quad Page Program (CMD_QPP = 32h); fault occurs with both
static bool EnableMemoryMappedMode(uint8_t readInstruction, uint8_t writeInstruction)
{
// Details of Write Enable function excluded since confirmed to work
SetWriteEnable(self);
OSPI_RegularCmdTypeDef command = {0};
command.OperationType = HAL_OSPI_OPTYPE_WRITE_CFG;
command.FlashId = HAL_OSPI_FLASH_ID_1;
command.Instruction = writeInstruction;
command.AddressSize = HAL_OSPI_ADDRESS_24_BITS;
command.NbData = 1;
switch(writeInstruction)
{
case CMD_QPP:
command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
command.AddressMode = HAL_OSPI_ADDRESS_1_LINE;
command.DataMode = HAL_OSPI_DATA_4_LINES;
break;
case CMD_PP:
default:
command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
command.AddressMode = HAL_OSPI_ADDRESS_1_LINE;
command.DataMode = HAL_OSPI_DATA_1_LINE;
command.Instruction = DEFAULT_CMD_PP;
break;
}
bool success = true;
if (HAL_OSPI_Command(&ospiHandle, &command, OSPI_READY_TIMEOUT) != HAL_OK)
{
success = false;
}
command.OperationType = HAL_OSPI_OPTYPE_READ_CFG;
command.Instruction = readInstruction;
command.AddressSize = HAL_OSPI_ADDRESS_24_BITS;
switch(readInstruction)
{
case CMD_QREAD:
command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
command.AddressMode = HAL_OSPI_ADDRESS_1_LINE;
command.DataMode = HAL_OSPI_DATA_4_LINES;
command.DummyCycles = 8;
break;
case CMD_READ:
default:
command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
command.AddressMode = HAL_OSPI_ADDRESS_1_LINE;
command.DataMode = HAL_OSPI_DATA_1_LINE;
command.DummyCycles = 0;
break;
}
if (HAL_OSPI_Command(&ospiHandle, &command, OSPI_READY_TIMEOUT) != HAL_OK)
{
success = false;
}
OSPI_MemoryMappedTypeDef memMappedCfg = {0};
memMappedCfg.TimeOutActivation = HAL_OSPI_TIMEOUT_COUNTER_ENABLE;
memMappedCfg.TimeOutPeriod = 0xFFFF;
if (HAL_OSPI_MemoryMapped(&ospiHandle, &memMappedCfg) != HAL_OK)
{
success = false;
}
return success;
}
test(void)
{
EraseBlocks(self, 0, 0);
static uint8_t commands[3] = { DEFAULT_CMD_QPP, DEFAULT_CMD_4PP, DEFAULT_CMD_PP };
for(uint32_t i = 0, testW = 0; i < 3 && !found; i++)
{
// Tried PP and READ (not-quad commands) as well
// EnableMemoryMappedMode(CMD_READ, CMD_PP);
EnableMemoryMappedMode(CMD_QREAD, CMD_QPP);
uint32_t testR = 0xFFFFFFFF;
// Verify erase (overwites 0xAA with expected 0xFF)
uint8_t value = 0xAA;
uint8_t * mem_addr = (uint8_t *)(OCTOSPI1_BASE);
value = *mem_addr;
// Hard fault occurs here
*mem_addr = 0xAA;
}
Solved! Go to Solution.
2023-01-31 09:55 AM
Hey BHamm! I am looking at this currently, and have seen the same issue you were seeing. It turns out this is an issue covered by the Errata, specifically item 2.6.1. "Memory-mapped write error response when DQS output is disabled"
Setting the DQSMode field to HAL_OSPI_DQS_ENABLE in the OSPI_RegularCmdTypeDef for the HAL_OSPI_OPTYPE_WRITE_CFG command fixes the issue. ie:
command.DQSMode = HAL_OSPI_DQS_ENABLE;
2022-09-12 12:49 PM
Not clear how well this responds to, and propagates errors, rather than just ploughing forward.
If the memory mapping fails, it will fault.
Suggest unpacking and reviewing OSPI peripheral content.
Enable asserts() and check error/status reporting.
2022-09-12 01:00 PM
Asserts are enabled, and all functions return the HAL_OK status.
2022-09-12 02:08 PM
I've got some QuadSPI Macronix parts running on the NUCLEO-U575ZI-Q
The prescaler here looks very high, and the Winbond's run more like the Micron's, not sure that's the issue here.
Not sure the NOR Flash write mechanics are well suited to memory mapped write, as there are a lot of dependencies, and the device goes out to lunch for a while, in a manner not architected into the STM32
Might try my luck later..
2022-09-12 02:12 PM
Check ConfigMPU() settings, make sure the space isn't designated Read-Only
2022-09-12 02:56 PM
static bool EnableMemoryMappedMode(uint8_t readInstruction, uint8_t writeInstruction)
{
OSPI_RegularCmdTypeDef command = {0};
command.FlashId = HAL_OSPI_FLASH_ID_1;
command.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
command.AddressSize = HAL_OSPI_ADDRESS_24_BITS;
command.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE;
command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
command.DQSMode = HAL_OSPI_DQS_DISABLE;
command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
command.NbData = 1;
command.OperationType = HAL_OSPI_OPTYPE_WRITE_CFG;
command.Instruction = writeInstruction;
switch(writeInstruction)
{
case CMD_QPP:
command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
command.AddressMode = HAL_OSPI_ADDRESS_1_LINE;
command.DataMode = HAL_OSPI_DATA_4_LINES;
break;
case CMD_PP:
default:
command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
command.AddressMode = HAL_OSPI_ADDRESS_1_LINE;
command.DataMode = HAL_OSPI_DATA_1_LINE;
command.Instruction = DEFAULT_CMD_PP;
break;
}
if (HAL_OSPI_Command(&ospiHandle, &command, OSPI_READY_TIMEOUT) != HAL_OK)
{
return(false);
}
command.OperationType = HAL_OSPI_OPTYPE_READ_CFG;
command.Instruction = readInstruction;
switch(readInstruction)
{
case CMD_QREAD:
command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
command.AddressMode = HAL_OSPI_ADDRESS_1_LINE;
command.DataMode = HAL_OSPI_DATA_4_LINES;
command.DummyCycles = 8;
break;
case CMD_READ:
default:
command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
command.AddressMode = HAL_OSPI_ADDRESS_1_LINE;
command.DataMode = HAL_OSPI_DATA_1_LINE;
command.DummyCycles = 0;
break;
}
if (HAL_OSPI_Command(&ospiHandle, &command, OSPI_READY_TIMEOUT) != HAL_OK)
{
return(false);
}
OSPI_MemoryMappedTypeDef memMappedCfg = {0};
memMappedCfg.TimeOutActivation = HAL_OSPI_TIMEOUT_COUNTER_ENABLE;
memMappedCfg.TimeOutPeriod = 80;
if (HAL_OSPI_MemoryMapped(&ospiHandle, &memMappedCfg) != HAL_OK)
{
return(false);
}
return(true);
}
2022-09-13 06:27 AM
Neither the OSPI_NOR_MemoryMapped example or my app appear to have any settings related to the MPU; they're leaving the defaults.
2022-09-13 06:30 AM
No difference, unfortunately. (The extra parameters suggested for writes are only the zero-default options, so there's no difference. I had also confirmed all HAL functions returned HAL_OK, so no difference. I've tried various memMappedCfg.TimeOutPeriod, and actually started out with 80, since that is what the OSPI_NOR_MemoryMapped example uses.)
2022-09-13 06:36 AM
With the prescaler above, or prescaler of 8, memory-mapped reads are successful. I'm unclear if that implies memory-mapped writes should also be successful with those prescaler values.
I tried the Micron configuration, with no change.
The confusing part is that it isn't even attempting communication with the flash device. That implies there is some configuration that is entirely internal to the STM32, and that it may not have anything to do with the chip-specific configuration parameters.
2023-01-31 09:55 AM
Hey BHamm! I am looking at this currently, and have seen the same issue you were seeing. It turns out this is an issue covered by the Errata, specifically item 2.6.1. "Memory-mapped write error response when DQS output is disabled"
Setting the DQSMode field to HAL_OSPI_DQS_ENABLE in the OSPI_RegularCmdTypeDef for the HAL_OSPI_OPTYPE_WRITE_CFG command fixes the issue. ie:
command.DQSMode = HAL_OSPI_DQS_ENABLE;