STM32U585 OSPI hard fault on memory-mapped write
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;
}