cancel
Showing results for 
Search instead for 
Did you mean: 

External NOR Flash Read address line instead of data

npatil15
Senior

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,
                         &current_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,
                             &sectorBuffer[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,
                                    &sectorBuffer[wordIndex]) != HAL_OK)
                    return false;
            }
            else
            {
                // HAL_NOR_ProgramBuffer expects relative offset
                if (HAL_NOR_ProgramBuffer(&hnor2,
                                          relativeAddr,
                                          &sectorBuffer[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

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
npatil15
Senior

Hello @mƎALLEm ,

I found the issue behind CommandSet reading garbage value. I have custom board in which it has external SRAM and external FLASH using FMC interface, so previously I have configured only external Flash, but now I have configured both SRAM and FLASH which indirectly solved my issue of getting correct value for CommandSet = 0x2.

Where I still need to figure it out, what is impact of not interfacing external SRAM.

Also, I have design function for FLASH Read/Write and both are working as expected.

Thanks,

Nitin

View solution in original post

5 REPLIES 5
npatil15
Senior

Hello,

I have used this test code to confirm Flash is integrated correctly or not.

#define NOR_BANK_ADDR  ((uint32_t)0x64000000) // Change to 0x60000000 if using NE1
#define ADDR_16(offset) ((__IO uint16_t *)(NOR_BANK_ADDR + ((offset) << 1)))

uint16_t q_char = 0, r_char = 0, y_char = 0;
uint16_t cmd;
*ADDR_16(0x000) = 0x00F0;
HAL_Delay(10);

*ADDR_16(0x55) = 0x0098;
HAL_Delay(10);
// 3. Simple Direct Reads (To rule out your NOR_Read function logic)
q_char = *(__IO uint16_t *)(NOR_BANK_ADDR + (0x10 << 1));
r_char = *(__IO uint16_t *)(NOR_BANK_ADDR + (0x11 << 1));
y_char = *(__IO uint16_t *)(NOR_BANK_ADDR + (0x12 << 1));

RESULT = q_char = 'Q', r_char = 'R', y_char = 'Y'

Now I can say flash is integrated correctly, so just there is some logical issue in the code, which may be needed to identify.

 

So it does not seem to be a memory timing access issue but rather to the way haw you are accessing that memory.

Did you do a complete test of the complete 64MB of that Nor Flash?

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
npatil15
Senior

I may need to check does I missed any left shifting like this in example

#define ADDR_16(offset) ((__IO uint16_t *)(NOR_BANK_ADDR + ((offset) << 1)))

 

 

npatil15
Senior

Hello @mƎALLEm ,

Checked the HAL_NOR_Init() and it got issue here, while update varaible hnor->CommandSet = 0x4042

HAL_StatusTypeDef HAL_NOR_Init(NOR_HandleTypeDef *hnor, FMC_NORSRAM_TimingTypeDef *Timing,
                               FMC_NORSRAM_TimingTypeDef *ExtTiming)
{
  uint32_t deviceaddress;
  HAL_StatusTypeDef status = HAL_OK;

  /* Check the NOR handle parameter */
  if (hnor == NULL)
  {
    return HAL_ERROR;
  }

  if (hnor->State == HAL_NOR_STATE_RESET)
  {
    /* Allocate lock resource and initialize it */
    hnor->Lock = HAL_UNLOCKED;

#if (USE_HAL_NOR_REGISTER_CALLBACKS == 1)
    if (hnor->MspInitCallback == NULL)
    {
      hnor->MspInitCallback = HAL_NOR_MspInit;
    }

    /* Init the low level hardware */
    hnor->MspInitCallback(hnor);
#else
    /* Initialize the low level hardware (MSP) */
    HAL_NOR_MspInit(hnor);
#endif /* (USE_HAL_NOR_REGISTER_CALLBACKS) */
  }

  /* Initialize NOR control Interface */
  (void)FMC_NORSRAM_Init(hnor->Instance, &(hnor->Init));

  /* Initialize NOR timing Interface */
  (void)FMC_NORSRAM_Timing_Init(hnor->Instance, Timing, hnor->Init.NSBank);

  /* Initialize NOR extended mode timing Interface */
  (void)FMC_NORSRAM_Extended_Timing_Init(hnor->Extended, ExtTiming,
                                         hnor->Init.NSBank, hnor->Init.ExtendedMode);

  /* Enable the NORSRAM device */
  __FMC_NORSRAM_ENABLE(hnor->Instance, hnor->Init.NSBank);

  /* Initialize NOR Memory Data Width*/
  if (hnor->Init.MemoryDataWidth == FMC_NORSRAM_MEM_BUS_WIDTH_8)
  {
    uwNORMemoryDataWidth = NOR_MEMORY_8B;
  }
  else
  {
    uwNORMemoryDataWidth = NOR_MEMORY_16B;
  }

  /* Initialize the NOR controller state */
  hnor->State = HAL_NOR_STATE_READY;

  /* Select the NOR device address */
  if (hnor->Init.NSBank == FMC_NORSRAM_BANK1)
  {
    deviceaddress = NOR_MEMORY_ADRESS1;
  }
  else if (hnor->Init.NSBank == FMC_NORSRAM_BANK2)
  {
    deviceaddress = NOR_MEMORY_ADRESS2;
  }
  else if (hnor->Init.NSBank == FMC_NORSRAM_BANK3)
  {
    deviceaddress = NOR_MEMORY_ADRESS3;
  }
  else /* FMC_NORSRAM_BANK4 */
  {
    deviceaddress = NOR_MEMORY_ADRESS4;
  }

  if (hnor->Init.WriteOperation == FMC_WRITE_OPERATION_DISABLE)
  {
    (void)FMC_NORSRAM_WriteOperation_Disable(hnor->Instance, hnor->Init.NSBank);

    /* Update the NOR controller state */
    hnor->State = HAL_NOR_STATE_PROTECTED;
  }
  else
  {
    /* Get the value of the command set */
    if (uwNORMemoryDataWidth == NOR_MEMORY_8B)
    {
      NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FIRST_CFI_BYTE),
                NOR_CMD_DATA_CFI);
    }
    else
    {
      NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FIRST_CFI), NOR_CMD_DATA_CFI);
    }

    hnor->CommandSet = *(__IO uint16_t *) NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_ADDRESS_COMMAND_SET);

    status = HAL_NOR_ReturnToReadMode(hnor);
  }

  return status;
}

Looks like it doesnt match with any of command set available

#define NOR_INTEL_SHARP_EXT_COMMAND_SET       (uint16_t)0x0001 /* Supported in this driver */
#define NOR_AMD_FUJITSU_COMMAND_SET           (uint16_t)0x0002 /* Supported in this driver */
#define NOR_INTEL_STANDARD_COMMAND_SET        (uint16_t)0x0003 /* Not Supported in this driver */
#define NOR_AMD_FUJITSU_EXT_COMMAND_SET       (uint16_t)0x0004 /* Not Supported in this driver */
#define NOR_WINDBOND_STANDARD_COMMAND_SET     (uint16_t)0x0006 /* Not Supported in this driver */
#define NOR_MITSUBISHI_STANDARD_COMMAND_SET   (uint16_t)0x0100 /* Not Supported in this driver */
#define NOR_MITSUBISHI_EXT_COMMAND_SET        (uint16_t)0x0101 /* Not Supported in this driver */
#define NOR_PAGE_WRITE_COMMAND_SET            (uint16_t)0x0102 /* Not Supported in this driver */
#define NOR_INTEL_PERFORMANCE_COMMAND_SET     (uint16_t)0x0200 /* Not Supported in this driver */
#define NOR_INTEL_DATA_COMMAND_SET            (uint16_t)0x0210 /* Not Supported in this driver */

 Ideally as per this flash S29, it has to return NOR_AMD_FUJITSU_COMMAND_SET, but getting some garbage value.

Please help me what I was missing, its quit long time I'm struggling with this.

Here below is some basic reference

static void MX_FMC_Init(void)
{
  FMC_NORSRAM_TimingTypeDef Timing = {0};

  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_DISABLE;
  hnor2.Init.PageSize = FMC_PAGE_SIZE_NONE;
  /* Timing */
  Timing.AddressSetupTime = 15;
  Timing.AddressHoldTime = 15;
  Timing.DataSetupTime = 255;
  Timing.BusTurnAroundDuration = 15;
  Timing.CLKDivision = 16;
  Timing.DataLatency = 17;
  Timing.AccessMode = FMC_ACCESS_MODE_A;
 
  if (HAL_NOR_Init(&hnor2, &Timing, NULL) != HAL_OK)
  {
    Error_Handler( );
  }
}

static void HAL_FMC_MspInit(void)
{
  GPIO_InitTypeDef GPIO_InitStruct ={0};
  if (FMC_Initialized) {
    return;
  }
  FMC_Initialized = 1;

  /* Peripheral clock enable */
  __HAL_RCC_FMC_CLK_ENABLE();

  /** FMC GPIO Configuration
  PE2   ------> FMC_A23
  PE3   ------> FMC_A19
  PE4   ------> FMC_A20
  PE5   ------> FMC_A21
  PE6   ------> FMC_A22
  PF0   ------> FMC_A0
  PF1   ------> FMC_A1
  PF2   ------> FMC_A2
  PF3   ------> FMC_A3
  PF4   ------> FMC_A4
  PF5   ------> FMC_A5
  PF12   ------> FMC_A6
  PF13   ------> FMC_A7
  PF14   ------> FMC_A8
  PF15   ------> FMC_A9
  PG0   ------> FMC_A10
  PG1   ------> FMC_A11
  PE7   ------> FMC_D4
  PE8   ------> FMC_D5
  PE9   ------> FMC_D6
  PE10   ------> FMC_D7
  PE11   ------> FMC_D8
  PE12   ------> FMC_D9
  PE13   ------> FMC_D10
  PE14   ------> FMC_D11
  PE15   ------> FMC_D12
  PD8   ------> FMC_D13
  PD9   ------> FMC_D14
  PD10   ------> FMC_D15
  PD11   ------> FMC_A16
  PD12   ------> FMC_A17
  PD13   ------> FMC_A18
  PD14   ------> FMC_D0
  PD15   ------> FMC_D1
  PG2   ------> FMC_A12
  PG3   ------> FMC_A13
  PG4   ------> FMC_A14
  PG5   ------> FMC_A15
  PC6   ------> FMC_NWAIT
  PD0   ------> FMC_D2
  PD1   ------> FMC_D3
  PD4   ------> FMC_NOE
  PD5   ------> FMC_NWE
  PG9   ------> FMC_NE2
  */
  GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5
                          |GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9
                          |GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13
                          |GPIO_PIN_14|GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
  HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);

  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
                          |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_12|GPIO_PIN_13
                          |GPIO_PIN_14|GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
  HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
                          |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_9;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
  HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);

  GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
                          |GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15
                          |GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_5;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
  HAL_GPIO_Init(GPIOD, &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_AF9_FMC;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}

 

npatil15
Senior

Hello @mƎALLEm ,

I found the issue behind CommandSet reading garbage value. I have custom board in which it has external SRAM and external FLASH using FMC interface, so previously I have configured only external Flash, but now I have configured both SRAM and FLASH which indirectly solved my issue of getting correct value for CommandSet = 0x2.

Where I still need to figure it out, what is impact of not interfacing external SRAM.

Also, I have design function for FLASH Read/Write and both are working as expected.

Thanks,

Nitin