cancel
Showing results for 
Search instead for 
Did you mean: 

Problem reading Flash Memory

migmel
Senior

Hello guys,

I am working with a STM32L071CB MCU.

Currently I am trying to backup GPS data to internal memory flash when there is not LTE connection to send later when the LTE service is restored.

Writing data to memory has been done right. I am having problem with reading back the data.

First I am using bank1(start addr 0x08000000) to store the program code and the bank 2 (start addr 0x08010000) to backup data.

The problems I am having are as follow:

If I don't unlock the memory for writing, when I try to read starting the first address of bank2 (page 512), it reads starting the first address of bank 1 (page0).

Now when unlocking the flash, I can read some data right, however some values are still read from page0 and not from page 512 as its supposed to be. Its driving me crazy.

I am attaching the relevant information:

Here is the function to read the flash:

void flashRead (uint32_t readAddr, uint32_t *readBuf, uint16_t wordCnt){

 flashUnlock();   

 while (wordCnt--){

  *readBuf = *(__IO uint32_t *)(readAddr);

  readAddr += 4;

  readBuf++;

 }

 flashLock();  

   

}

Unlock function taken from RM:

void flashUnlock(void){

  /****UNLOCK PELOCK****/

  /* (1) Wait till no operation is on going */

  /* (2) Check if the PELOCK is unlocked */

  /* (3) Perform unlock sequence */

  while ((FLASH->SR & FLASH_SR_BSY) != 0){ /* (1) */

  /* For robust implementation, add here time-out management */

  }

  if ((FLASH->PECR & FLASH_PECR_PELOCK) != 0){ /* (2) */

    FLASH->PEKEYR = FLASH_PEKEY1; /* (3) */

    FLASH->PEKEYR = FLASH_PEKEY2;

  }

   

  /****UNLOCK PRGLOCK****/

  /* (1) Wait till no operation is on going */

  /* (2) Check that the PELOCK is unlocked */

  /* (3) Check if the PRGLOCK is unlocked */

  /* (4) Perform unlock sequence */

  while ((FLASH->SR & FLASH_SR_BSY) != 0){ /* (1) */

  /* For robust implementation, add here time-out management */

  }

  if ((FLASH->PECR & FLASH_PECR_PELOCK) == 0){ /* (2) */

    if ((FLASH->PECR & FLASH_PECR_PRGLOCK) != 0){ /* (3) */

      FLASH->PRGKEYR = FLASH_PRGKEY1; /* (4) */

      FLASH->PRGKEYR = FLASH_PRGKEY2;

    }

  }

       

}

Lock function taken from RM:

void flashLock(void){

  /* (1) Wait till no operation is on going */

  /* (2) Locks the NVM by setting PELOCK in PECR */

  while ((FLASH->SR & FLASH_SR_BSY) != 0){ /* (1) */

  /* For robust implementation, add here time-out management */

  }

  FLASH->PECR |= FLASH_PECR_PELOCK; /* (2) */    

   

}

Here is the data I saved in bank2 page512:

0693W00000Lz2MjQAJ.png0693W00000Lz2L7QAJ.png 

Here is the data stored in flash bank1 page0:

0693W00000Lz2JGQAZ.pngThis is the data I am reading:

Read Buffer:

20000FC0 080000D9 0800119D 08000695

210C000B 792C3010 182CC326 FFFF2501

011B0000 00000000 001B0700 08001273

FFFFFFFF FFFFFFFF 0800119F 08001275 

As you can see, underlined values not are only wrong but they belong to data in the page0 and I don't have any idea how the iteration can fetch these values out of the range of the address.

If this help, I am using multiple interrupts in my program..

Please any help would be greatly appreciated.

1 ACCEPTED SOLUTION

Accepted Solutions
Gsing.2
Associate II
  1. Dont use flash to store gps coordinates as you will run out of write cycles (if you have not considered this yet). You can use rtc backup registers or external memory.
  2. Check if flash is getting unlocked or not before proceeding.(Ususally you dont to unlock for reading purpose)
  3. Use memcpy() to read data from desired address with desired number of bytes to buffer.
  4. Check address you are passing to read and share it too here.
  5. why 0x08000010-2c and 0x08010010-2c have same values(check where you are writing gps data)

Hope it helps.

View solution in original post

8 REPLIES 8
Gsing.2
Associate II
  1. Dont use flash to store gps coordinates as you will run out of write cycles (if you have not considered this yet). You can use rtc backup registers or external memory.
  2. Check if flash is getting unlocked or not before proceeding.(Ususally you dont to unlock for reading purpose)
  3. Use memcpy() to read data from desired address with desired number of bytes to buffer.
  4. Check address you are passing to read and share it too here.
  5. why 0x08000010-2c and 0x08010010-2c have same values(check where you are writing gps data)

Hope it helps.

Hello thank you.

The point 1, yes I have considered it. I don't have options here: RTC registers are not enough, external memory is not available. However this device is kind of use once and and throw it away, so there is not chance of running out of write cycles.

I will try points 2 and 3. Yes, my understanding is that there is no need to unlock flash just for reading.

I just realized the point 5. Have to check it. Weird because if program code is modified the app will colapse

The address I'm passing to the function:

#define PREV_GPS_ADDR 0x08010000

uint32_t* RB;

flashRead ((uint32_t)PREV_GPS_ADDR, RB, 16);

Thanks again

TDK
Guru

From your screenshot, ALL of the values match up with values in 1, not just some. Some of them happen to be the same in both banks.

> If I don't unlock the memory for writing, when I try to read starting the first address of bank2 (page 512), it reads starting the first address of bank 1 (page0).

MCUs aren't prone to erratic behavior. Gotta be something in your program logic that is awry. No need to unlock the flash to read it.

If you feel a post has answered your question, please click "Accept as Solution".

Right, that's a fact. I just cannot figure out what I'm doing wrong

What I have discover is I have all the time been reading starting from 0x08000000. It does not matter which address I use or the method, the program always go to read from page0. The locking/unlocking flash was just a bad judgement, the result is always the same.

As you suggested I used memcpy as below:

void flashRead (const uint32_t *readAddr, uint32_t *readBuf, uint16_t wordCnt){

  memcpy(readBuf, readAddr , wordCnt);

}

The result is the same. There is no way the program read from the address I want it to do...

The writing is fine, just write the data where I want to

Any ide what might be the problem ?

migmel
Senior

Well, I have found the solution. I just used a simple function that returns one address position at a time. Iterate this function thru the range of addresses I want to read (page512).

I will leave it here in case some newbie like me find the same problem:

uint32_t flashRead(uint32_t startAddr){

    return *(__IO uint32_t*)startAddr; 

  }

 uint32_t data[16];

 uint32_t dataAddr = 0x08010000;

  for( int i = 0; i < 16; i++){

     data[i] = flashRead(dataAddr);

     addr+=4;

  }

Thank you all you guys for the help

  1. pointer only hold the address of another value ( Pass an array to pointer in your function i.e Use this.uint32_t* RB[sizeinwords]={0}; instead of uint32_t* RB;)
  2. try replacing direct address instead of Macro.
  3. In memcpy you have to pass number of bytes i.e if you want to read 8 memory locations then your wordCnt should be 8*4=32 (if you have not considered)
  4. There is still no explaination of point 5 from my previous reply. (you should verify why is that and it should not happen)

Point 5 happened because I was trying different addresses. Now I've got the solution

Just to verify I will give it a try to point 3

Thank you for your help.