2025-08-14 10:45 PM
I am reposting this issue because, while debugging, I've determined that the root cause is related to the Erase operation, not the reboot, as I had initially thought in my previous post.
Previous post: https://community.st.com/t5/stm32-mcus-products/stm32h7-qspi-flash-incorrect-data-after-reboot-initial-write/m-p/830635#M284116
Board: STM32H747I-DISCO
Development Environment: STM32CubeIDE 1.19.0
Library: https://github.com/STMicroelectronics/stm32-mt25ql512abb
My code executes in the following sequence:
1. Initialize QSPI and the MT25QL512ABB flash memory.
2. Erase a 4K block starting from address 0x0.
3. Write 256 bytes (aTxBuffer) to address 0x0.
4. Read back the 256 bytes from address 0x0 into aRxBuffer.
5. Compare aTxBuffer and aRxBuffer.
6. Erase a next 4K block starting from address 0x1000 (4096).
7. Read the 256 bytes from address 0x0 again into aRxBuffer.
8. Compare aTxBuffer and aRxBuffer.
My expectation is that the erase operation in step 6, which targets the 4K block at address 0x1000, should not affect the data previously written at address 0x00.
However, as you can see in the debug screenshot below, the data in aRxBuffer appears to have been erased.
The following links seem to describe cases similar to mine:
https://github.com/leekheee77/kwanhee/issues/1
https://github.com/STMicroelectronics/stm32-external-loader/issues/11
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "quadspi.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <string.h>
#include "mt25ql512abb.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* DUAL_CORE_BOOT_SYNC_SEQUENCE: Define for dual core boot synchronization */
/* demonstration code based on hardware semaphore */
/* This define is present in both CM7/CM4 projects */
/* To comment when developping/debugging on a single core */
#define DUAL_CORE_BOOT_SYNC_SEQUENCE
#if defined(DUAL_CORE_BOOT_SYNC_SEQUENCE)
#ifndef HSEM_ID_0
#define HSEM_ID_0 (0U) /* HW semaphore 0*/
#endif
#endif /* DUAL_CORE_BOOT_SYNC_SEQUENCE */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
#define TEST_BUFFER_SIZE (256)
uint8_t aTxBuffer[TEST_BUFFER_SIZE];
uint8_t aRxBuffer[TEST_BUFFER_SIZE];
MT25QL512ABB_Info_t flashInfo;
uint8_t id[6];
void MT25QL512ABB_Init(void)
{
/* 1. Enter QPI mode */
int32_t flashStatus = MT25QL512ABB_OK;
flashStatus = MT25QL512ABB_EnterQPIMode(&hqspi);
if(flashStatus != MT25QL512ABB_OK)
{
Error_Handler();
}
if(MT25QL512ABB_AutoPollingMemReady(&hqspi, MT25QL512ABB_QPI_MODE, MT25QL512ABB_DUALFLASH_ENABLE) != MT25QL512ABB_OK)
{
Error_Handler();
}
/* 2. Read ID and verify */
flashStatus = MT25QL512ABB_ReadID(&hqspi, MT25QL512ABB_QPI_MODE, id, MT25QL512ABB_DUALFLASH_ENABLE);
if((flashStatus != MT25QL512ABB_OK) || (id[0] != 0x20) || (id[1] != 0x20) || (id[2] != 0xBA) || (id[3] != 0xBA) || (id[4] != 0x20)
|| (id[5] != 0x20))
{
Error_Handler();
}
/* 3. Enter 4-byte address mode */
flashStatus = MT25QL512ABB_Enter4BytesAddressMode(&hqspi, MT25QL512ABB_QPI_MODE);
if(flashStatus != MT25QL512ABB_OK)
{
Error_Handler();
}
if(MT25QL512ABB_AutoPollingMemReady(&hqspi, MT25QL512ABB_QPI_MODE, MT25QL512ABB_DUALFLASH_ENABLE) != MT25QL512ABB_OK)
{
Error_Handler();
}
}
void MT25QL512ABB_Test(void)
{
// 1. Prepare data with a pattern unique to the address
for(uint16_t j = 0;j < TEST_BUFFER_SIZE;j++)
{
aTxBuffer[j] = j;
}
// 2. Erase 1st 4K
MT25QL512ABB_WriteEnable(&hqspi, MT25QL512ABB_QPI_MODE, MT25QL512ABB_DUALFLASH_ENABLE);
MT25QL512ABB_BlockErase(&hqspi, MT25QL512ABB_QPI_MODE, MT25QL512ABB_4BYTES_SIZE, 0x0, MT25QL512ABB_ERASE_4K);
MT25QL512ABB_AutoPollingMemReady(&hqspi, MT25QL512ABB_QPI_MODE, MT25QL512ABB_DUALFLASH_ENABLE);
// 3. Write data to 0x0
MT25QL512ABB_WriteEnable(&hqspi, MT25QL512ABB_QPI_MODE, MT25QL512ABB_DUALFLASH_ENABLE);
MT25QL512ABB_PageProgram(&hqspi, MT25QL512ABB_QPI_MODE, MT25QL512ABB_4BYTES_SIZE, aTxBuffer, 0x0, TEST_BUFFER_SIZE);
MT25QL512ABB_AutoPollingMemReady(&hqspi, MT25QL512ABB_QPI_MODE, MT25QL512ABB_DUALFLASH_ENABLE);
// 4. Read data back from 0x0
MT25QL512ABB_ReadSTR(&hqspi, MT25QL512ABB_QPI_MODE, MT25QL512ABB_4BYTES_SIZE, aRxBuffer, 0x0, TEST_BUFFER_SIZE);
if(memcmp(aTxBuffer, aRxBuffer, TEST_BUFFER_SIZE) != 0)
{
HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_RESET); //error
}
else
{
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);
}
// 5. Erase 2nd 4K
MT25QL512ABB_WriteEnable(&hqspi, MT25QL512ABB_QPI_MODE, MT25QL512ABB_DUALFLASH_ENABLE);
MT25QL512ABB_BlockErase(&hqspi, MT25QL512ABB_QPI_MODE, MT25QL512ABB_4BYTES_SIZE, 0x1000, MT25QL512ABB_ERASE_4K);
MT25QL512ABB_AutoPollingMemReady(&hqspi, MT25QL512ABB_QPI_MODE, MT25QL512ABB_DUALFLASH_ENABLE);
// 6. Read data back from 0x0
MT25QL512ABB_ReadSTR(&hqspi, MT25QL512ABB_QPI_MODE, MT25QL512ABB_4BYTES_SIZE, aRxBuffer, 0x0, TEST_BUFFER_SIZE);
if(memcmp(aTxBuffer, aRxBuffer, TEST_BUFFER_SIZE) != 0)
{
HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_RESET); //error
}
else
{
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);
}
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* USER CODE BEGIN Boot_Mode_Sequence_0 */
#if defined(DUAL_CORE_BOOT_SYNC_SEQUENCE)
int32_t timeout;
#endif /* DUAL_CORE_BOOT_SYNC_SEQUENCE */
/* USER CODE END Boot_Mode_Sequence_0 */
/* USER CODE BEGIN Boot_Mode_Sequence_1 */
#if defined(DUAL_CORE_BOOT_SYNC_SEQUENCE)
/* Wait until CPU2 boots and enters in stop mode or timeout*/
timeout = 0xFFFF;
while((__HAL_RCC_GET_FLAG(RCC_FLAG_D2CKRDY) != RESET) && (timeout-- > 0));
if ( timeout < 0 )
{
Error_Handler();
}
#endif /* DUAL_CORE_BOOT_SYNC_SEQUENCE */
/* USER CODE END Boot_Mode_Sequence_1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN Boot_Mode_Sequence_2 */
#if defined(DUAL_CORE_BOOT_SYNC_SEQUENCE)
/* When system initialization is finished, Cortex-M7 will release Cortex-M4 by means of
HSEM notification */
/*HW semaphore Clock enable*/
__HAL_RCC_HSEM_CLK_ENABLE();
/*Take HSEM */
HAL_HSEM_FastTake(HSEM_ID_0);
/*Release HSEM in order to notify the CPU2(CM4)*/
HAL_HSEM_Release(HSEM_ID_0,0);
/* wait until CPU2 wakes up from stop mode */
timeout = 0xFFFF;
while((__HAL_RCC_GET_FLAG(RCC_FLAG_D2CKRDY) == RESET) && (timeout-- > 0));
if ( timeout < 0 )
{
Error_Handler();
}
#endif /* DUAL_CORE_BOOT_SYNC_SEQUENCE */
/* USER CODE END Boot_Mode_Sequence_2 */
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_QUADSPI_Init();
/* USER CODE BEGIN 2 */
MT25QL512ABB_Init();
MT25QL512ABB_Test();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
QSPI_HandleTypeDef hqspi;
/* QUADSPI init function */
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 */
hqspi.Instance = QUADSPI;
hqspi.Init.ClockPrescaler = 1;
hqspi.Init.FifoThreshold = 1;
hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
hqspi.Init.FlashSize = 26;
hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_3_CYCLE;
hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;
hqspi.Init.DualFlash = QSPI_DUALFLASH_ENABLE;
if (HAL_QSPI_Init(&hqspi) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN QUADSPI_Init 2 */
/* USER CODE END QUADSPI_Init 2 */
}