Communicating with QSPI nor-flash via OctoSPI (OSPI) [STM32H730VBT6]
Hello, I have a very basic setup of OSPI1 on STM32H730VBT and I am trying to read the 1st Status Register of the Winbond W25Q128JV.
Environment
- STM32CubeMX: 6.5.0
- STM32Cube_FW_H7_V1.10.0
- STM32CubeIDE Version: 1.9.0 Build: 12015_20220302_0855 (UTC)
Hardware
A custom board with STM32H730VBT and Winbond W25Q128JV connected via OSPI1.
Code
Generated OSPI init code
void MX_OCTOSPI1_Init(void)
{
/* USER CODE BEGIN OCTOSPI1_Init 0 */
/* USER CODE END OCTOSPI1_Init 0 */
OSPIM_CfgTypeDef sOspiManagerCfg = {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 = 1; /* HCLK3 is already 65MHz */
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.NCSPort = 1;
sOspiManagerCfg.DQSPort = 0;
sOspiManagerCfg.IOLowPort = HAL_OSPIM_IOPORT_1_LOW;
sOspiManagerCfg.IOHighPort = HAL_OSPIM_IOPORT_NONE;
sOspiManagerCfg.Req2AckTime = 1; /* required when full assert is enabled... */
if (HAL_OSPIM_Config(&hospi1, &sOspiManagerCfg, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN OCTOSPI1_Init 2 */
/* USER CODE END OCTOSPI1_Init 2 */
}
void HAL_OSPI_MspInit(OSPI_HandleTypeDef* ospiHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
if(ospiHandle->Instance==OCTOSPI1)
{
/* USER CODE BEGIN OCTOSPI1_MspInit 0 */
/* USER CODE END OCTOSPI1_MspInit 0 */
/** Initializes the peripherals clock
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_OSPI;
PeriphClkInitStruct.OspiClockSelection = RCC_OSPICLKSOURCE_D1HCLK;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
/* OCTOSPI1 clock enable */
__HAL_RCC_OCTOSPIM_CLK_ENABLE();
__HAL_RCC_OSPI1_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/**OCTOSPI1 GPIO Configuration
PE2 ------> OCTOSPIM_P1_IO2
PB2 ------> OCTOSPIM_P1_CLK
PD11 ------> OCTOSPIM_P1_IO0
PD13 ------> OCTOSPIM_P1_IO3
PC10 ------> OCTOSPIM_P1_IO1
PB6 ------> OCTOSPIM_P1_NCS
*/
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF9_OCTOSPIM_P1;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF9_OCTOSPIM_P1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF9_OCTOSPIM_P1;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF9_OCTOSPIM_P1;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF10_OCTOSPIM_P1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* USER CODE BEGIN OCTOSPI1_MspInit 1 */
/* USER CODE END OCTOSPI1_MspInit 1 */
}
}PS: `sOspiManagerCfg` init is slightly modified to not produce an error when full assert is enabled but `Req2AckTime` is not set by the STM32CubeMX.
Status Register 1 (SR1) read code
uint8_t reg = 0U;
OSPI_RegularCmdTypeDef cmd = {
.Instruction = 0x05,
.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE,
.DataMode = HAL_OSPI_DATA_1_LINE,
.AddressMode = HAL_OSPI_ADDRESS_NONE,
.NbData = 1U,
.DummyCycles = 0U
};
hal_ret = HAL_OSPI_Command(&hospi1, &cmd, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
if (hal_ret != HAL_OK) {
return hal_ret;
}
hal_ret = HAL_OSPI_Receive(&hospi1, ®, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
if (hal_ret != HAL_OK) {
return hal_ret;
}
return HAL_OK;Current
- Missing CLK on PB2
- Not HAL errors
- The SR1 read as `0x00`
Expected
- PB2 CLK signal
- Non zero SR1
Everything works perfectly when using QSPI on STM32H750 (same board, same clock configuration output [doesn't exceed < Max 133MHz for O/QSPI]). However, when Octo-SPI (OSPI) is used, then nothing is being read. It looks like the CLK signal is not present.
Any ideas what can be tried out?
