External NOR Flash Read address line instead of data
Hello,
I have STM32F7 controller, using Free RTOS, trying to interface external NOR flash, S29GL128S10TFIV13.
So at first, I was trying to do normal read/write operation, but here what I observed,
void FMC_Init()
{
hnor2.Instance = FMC_NORSRAM_DEVICE;
hnor2.Extended = FMC_NORSRAM_EXTENDED_DEVICE;
/* hnor2.Init */
hnor2.Init.NSBank = FMC_NORSRAM_BANK2;
hnor2.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE;
hnor2.Init.MemoryType = FMC_MEMORY_TYPE_NOR;
hnor2.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_16;
hnor2.Init.BurstAccessMode = FMC_BURST_ACCESS_MODE_DISABLE;
hnor2.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW;
hnor2.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS;
hnor2.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE;
hnor2.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE;
hnor2.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE;
hnor2.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE;
hnor2.Init.WriteBurst = FMC_WRITE_BURST_DISABLE;
hnor2.Init.ContinuousClock = FMC_CONTINUOUS_CLOCK_SYNC_ONLY;
hnor2.Init.WriteFifo = FMC_WRITE_FIFO_ENABLE;
hnor2.Init.PageSize = FMC_PAGE_SIZE_NONE;
/* Timing */
Timing.AddressSetupTime = 3;
Timing.AddressHoldTime = 1;
Timing.DataSetupTime = 6;
Timing.BusTurnAroundDuration = 1;
Timing.CLKDivision = 16;
Timing.DataLatency = 17;
Timing.AccessMode = FMC_ACCESS_MODE_A;
/* ExtTiming */
if (HAL_NOR_Init(&hnor2, &Timing, NULL) != HAL_OK)
{
Error_Handler( );
}
}
void Verify_NOR_Flash(void)
{
uint16_t test_data_write[4] = {0x1234, 0x5678, 0x9ABC, 0xDEF0};
uint16_t test_data_read[4] = {0};
if (NOR_Write(0x0150, test_data_write, 4)) {
if (NOR_Read(0x0150, test_data_read, 4)) {
if (test_data_read[0] == 0x1234) {
// SUCCESS: Hardware, Timing, and Logic are all verified.
}
}
}
}
main()
{
MX_FMC_Init();
Verify_NOR_Flash();
}Result:
test_data_read[] = {336, 338, 340, 342} // equivalent to {0x150, 0x152, 0x154, 0x156}So tried to change address but it always read address line instead of data.
Here is code for reference:
// Helper to wait for NOR ready
bool NOR_WaitReady(uint32_t addr, uint32_t timeout_ms)
{
uint32_t tickStart = HAL_GetTick();
HAL_NOR_StatusTypeDef status;
do {
status = HAL_NOR_GetStatus(&hnor2, addr, 1);
if (status == HAL_NOR_STATUS_SUCCESS)
return true;
} while ((HAL_GetTick() - tickStart) < timeout_ms);
return false;
}
// Your sector erase wrapper
bool NOR_EraseSector(uint32_t absSectorAddr)
{
return (HAL_NOR_Erase_Block(&hnor2, absSectorAddr, NOR_BASE_ADDR) == HAL_OK) &&
NOR_WaitReady(absSectorAddr, 5000); // 5s timeout, adjust as needed
}
// Get sector start address (example for uniform sectors)
uint32_t NOR_GetSectorStart(uint32_t addr)
{
return (addr / NOR_SECTOR_SIZE) * NOR_SECTOR_SIZE;
}
// Check address range
bool NOR_IsValidRange(uint32_t addr, uint32_t length_bytes)
{
return (addr + length_bytes) <= 0x00800000; // 8MB for S29GL128S
}
// Read function: reads bytes from NOR using HAL_NOR_Read
bool NOR_Read(uint32_t addr, uint16_t *buffer, uint32_t length_bytes)
{
// hnor2.State = HAL_NOR_STATE_READY;
// HAL_NOR_ReturnToReadMode(&hnor2);
if (!buffer) return false;
// Must be within NOR range
if (!NOR_IsValidRange(addr, length_bytes)) return false;
// NOR is 16-bit word, so check alignment
if (addr % 2 != 0 || length_bytes % 2 != 0)
return false; // enforce word-alignment
// uint16_t *buf16 = (uint16_t *)buffer;
for (uint32_t i = 0; i < length_bytes; i++)
{
uint32_t current_abs_addr = NOR_BASE_ADDR + addr + (i * 2);
if (HAL_NOR_Read(&hnor2,
¤t_abs_addr,
&buffer[i]) != HAL_OK)
{
return false;
}
}
return true;
}
// ----------------- MAIN WRITE FUNCTION -----------------
bool NOR_Write(uint32_t addr, const uint16_t *data, uint32_t length_words)
{
if (!data) return false;
if (addr % 2 != 0) return false;
if (!NOR_IsValidRange(addr, length_words * 2)) return false;
static uint16_t sectorBuffer[NOR_SECTOR_SIZE / 2];
// HAL_NOR_WriteOperation_Enable(&hnor2);
uint32_t remaining = length_words;
uint32_t currentAddr = addr;
uint32_t bufOffset = 0;
while (remaining > 0)
{
uint32_t sectorStart = NOR_GetSectorStart(currentAddr);
uint32_t sectorOffset = currentAddr - sectorStart;
uint32_t absSectorAddr = NOR_BASE_ADDR + sectorStart;
uint32_t wordsInSector = (NOR_SECTOR_SIZE - sectorOffset) / 2;
uint32_t chunkWords = (remaining < wordsInSector) ? remaining : wordsInSector;
/* Read full sector (absolute) */
for (uint32_t i = 0; i < NOR_SECTOR_SIZE / 2; i++)
{
uint32_t absAddr = absSectorAddr + (i * 2);
if (HAL_NOR_Read(&hnor2,
(uint32_t *)absAddr,
§orBuffer[i]) != HAL_OK)
return false;
}
/* Modify buffer */
uint32_t sectorWordOffset = sectorOffset / 2;
for (uint32_t i = 0; i < chunkWords; i++)
{
sectorBuffer[sectorWordOffset + i] = data[bufOffset + i];
}
HAL_NOR_WriteOperation_Enable(&hnor2);
/* 3️⃣ Erase sector (relative) */
if (!NOR_EraseSector(sectorStart))
return false;
/* Program sector */
uint32_t totalWords = NOR_SECTOR_SIZE / 2;
uint32_t wordIndex = 0;
while (wordIndex < totalWords)
{
uint32_t remainingWords = totalWords - wordIndex;
uint32_t programChunk =
(remainingWords > NOR_BUFFER_WORDS) ?
NOR_BUFFER_WORDS : remainingWords;
uint32_t relativeAddr = sectorStart + (wordIndex * 2);
uint32_t absoluteAddr = NOR_BASE_ADDR + relativeAddr;
if (programChunk == 1)
{
// HAL_NOR_Program expects absolute pointer
if (HAL_NOR_Program(&hnor2,
(uint32_t *)absoluteAddr,
§orBuffer[wordIndex]) != HAL_OK)
return false;
}
else
{
// HAL_NOR_ProgramBuffer expects relative offset
if (HAL_NOR_ProgramBuffer(&hnor2,
relativeAddr,
§orBuffer[wordIndex],
programChunk) != HAL_OK)
return false;
}
if (!NOR_WaitReady(absoluteAddr, 5000))
return false;
wordIndex += programChunk;
}
remaining -= chunkWords;
currentAddr += chunkWords * 2;
bufOffset += chunkWords;
}
//HAL_NOR_WriteOperation_Disable(&hnor2);
HAL_NOR_ReturnToReadMode(&hnor2);
return true;
}Note: if I enable "HAL_NOR_WriteOperation_Disable(&hnor2);" after NOR_Write() then in NOR_Read() got this error "state == HAL_NOR_STATE_PROTECTED" so removed it.
Please help me understand what is missing here.
Thanks,
Nitin
