Keil Logo Arm Logo

STM32: Viewing flash memory contents

Next Thread | Thread List | Previous Thread Start a Thread | Settings

Details Message
Author
B Wilkins
Posted
1-Sep-2016 20:02 GMT
Toolset
ARM
New! STM32: Viewing flash memory contents

Hello folks,

I wish to view the contents of flash memory on STM32L471 (1MB ROM) MCU using Keil ULINK2 debugger (uVision IDE v5.20.0.0), but when I do so the memory viewer (in Debug mode) displays all 0xFF where I expect to find data. I wonder if someone could suggest what I am doing wrong. Here is some background information.

In my Keil uVision project I have (among other files) a C file gsData.c containing a single initialized array, like this:

uint16_t gs[] = {
   38,   // 0x0026
  217,   // 0x00d9
   72,   // 0x0048
    0,   // 0x0000
    4,   // 0x0004
...
}

I use a modified scatter file to divide the flash ROM into a few regions so I can place gsData.o at a specific memory address. I do this because the array gs[] contains data which needs period updating without changing the main program. My scatter file looks like this:

LR_IROM1 0x08000000 0x00100000  {   ; load region size_region
  ER_IROM1 0x08000000 0x00060000 {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  ER_IROM2 0x08060000 0x00004000 {
    gsData.o (+RO)                  ; array gs[] will be located at 0x08060000
  }
...

I verified from the MAP file that gs[] is placed at the location I expect:

    Global Symbols
    Symbol Name                              Value     Ov Type        Size  Object(Section)
    gs                                       0x08060000   Data        1576  gsData.o(.constdata)
...
    Execution Region ER_IROM2 (Base: 0x08060000, Size: 0x00000628, Max: 0x00004000, ABSOLUTE)
    Base Addr    Size         Type   Attr      Idx    E Section Name        Object
    0x08060000   0x00000628   Data   RO        4583     .constdata          gsData.o

Now I compile and download my program to the MCU and enter debug mode in uVision IDE. I press "F5" to run the program to make sure the debugger is connected to the target and in the "Memory 1" window I enter the address 0x08060000 (alternatively the name of the symbol "gs" also works). I find the memory window shows all uninitialized flash at the address I expect to find gs[].

0x08064000: FF FF FF FF FF ...

I don't understand why I am not seeing the contents of the initialized array gs[] as defined in the C file.

Can anyone see what I am doing wrong here?

Thank you!

Author
Clive One
Posted
1-Sep-2016 20:16 GMT
Toolset
ARM
New! RE: STM32: Viewing flash memory contents

I'd use two Load Regions, and define the variable as a "static const"

Author
Per Westermark
Posted
1-Sep-2016 20:45 GMT
Toolset
ARM
New! RE: STM32: Viewing flash memory contents

You most definitely should define it as const data.

If the linker things it's R/W data, then it will store it in the first flash region and then try on startup to copy to this new address just as it does with all other initialized global variables.

Notice that your scatter region says RO. But your data isn't RO, as currently written. Notice that the map file will, for each object file, keep track of code, rw variables, ro variables and zero-initialized variables. So make sure your data fits the correct classification.

Author
B Wilkins
Posted
1-Sep-2016 22:48 GMT
Toolset
ARM
New! RE: STM32: Viewing flash memory contents

Thanks Clive and Per for the prompt suggestions! Here is what I've got now:

const uint16_t gs[] = {
   38,   // 0x0026
  217,   // 0x00d9
   72,   // 0x0048
    0,   // 0x0000
    4,   // 0x0004
...
}

I cannot use 'static' qualifier because array gs[] is defined in gsData.c which I reference in other C files as:

extern const uint16_t gs[];

Using 'static' would limit the scope of gs[] to the current file which then conflicts with 'extern'.

Adding 'const' as above did not resolve my problem so I tried to update the scatter file to use two load regions as suggested by Clive. Here is the modified scatter file:

LR_IROM1 0x08000000 0x00060000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00060000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x20000000 0x00018000  {  ; RW data = SRAM1 = 96kB
   .ANY (+RW +ZI)
  }
  RW_IRAM2 0x10000000 0x00008000  {  ; RW data = SRAM2 = 32kB
   .ANY (+RW +ZI)
  }
}

LR_IROM2 0x08060000 0x000A0000  {    ; load region size_region
  ER_IROM2 0x08060000 0x00004000 {   ; 16kB region to hold gs[]
    gsData.o (+RO)
  }
  ER_IROM3 0x08064000 0x0001C000 {   ; 112kB region to hold nn[]
    nnData.o (+RO)
  }
}

I'm unsuccessful with this modification. The linker complains with:

.\Objects\SensorModule.axf: Error: L6788E: Scatter-loading of execution region ER_IROM3 to execution address [0x08064000,0x0806b3e8) will cause the contents of execution region ER_IROM3 at load-address [0x08060628,0x08067a10) to be corrupted at run-time.

The STM32L471 I am using has 1MB of flash ROM from located from address 0x08000000 to 0x08100000. I tried to "divide" the ROM into two load regions: LR_IROM1: 0x08000000 to 0x0805FFFF containing the main program and LR_IROM2: 0x0806000 to 0x0x08100000 containing the two RO regions at 0x08060000 (16kB) and 0x08064000 (112kB). These two const data RO regions contain data used by the main program which needs to be periodically updated.

I do have two array's gs[] and nn[] (defined similarly in separate C files) of const data that I want to locate at specified addresses.

Obviously the changes I've made to the scatter file are wrong. This is my first time using scatter file so I'm very inexperienced in it.

Any comments are appreciated. In the meantime I'll follow up on the above error and read more of Keil documentation and try to understand it :)

Author
Per Westermark
Posted
1-Sep-2016 23:26 GMT
Toolset
ARM
New! RE: STM32: Viewing flash memory contents

You want the load address to be the same as the execution address.

So in your case give your chip three flash regions. So two flash regions for your two blocks of absolutely located data.

As soon as you have a block of data with a different load address and execution address, the linker will think it needs to store the data at one address and later copy it to another address. And copy to flash doesn't work well at run time.

And when you play like you do, the linker can also get in a situation where it tries to copy one block of data to an address range already used for the initial storage of a different block of data. Then the linker will complain that the scatter-load process will corrupt data.

With three separate flash regions, the linker will not create any configuration to try to copy any data on startup - the flash content will already be stored at the correct address it is expected to be used from.

This wouldn't have been an issue, if your structures had had fixed size so you could just store them directly after each other. But you want to add padding between the 2 data structures to allow later copies to grow.

If I replace '2' with 'two' in the previous sentence, then Keil doesn't accept the post claiming the use of an invalid word 0x57 0x6f 0x64 which isn't even a word...

Damn Keil spam protection that now and then manages really silly false matches... And best of all - when getting the text and screenshots of the error, Keil mails back that they can't reproduce, so the spam filter seems to be nondeterministic.

Author
B Wilkins
Posted
2-Sep-2016 00:01 GMT
Toolset
ARM
New! RE: STM32: Viewing flash memory contents

Thank you, Per! That worked perfectly! :)

From your description I'm understanding the meaning of "load address" and "execution address" in this context and it starts to make perfect sense: so clear now that if these addresses aren't the same the const data will be stored in one location and copied elsewhere before execution.

The scatter loading mechanism is powerful; thanks for describing a lot of what the linker is doing when processing this file. I hope to understand it well.

Also, you are correct that I wanted to define a maximum size for the regions to allow flexibility for the const data to grow. It's only a small amount of data now (< 2kB) but I wanted to reserve a 16kB region for future expansion.

Here is the final scatter file for anyone wondering the solution:

LR_IROM1 0x08000000 0x00060000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00060000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x20000000 0x00018000  {  ; RW data = SRAM1 = 96kB
   .ANY (+RW +ZI)
  }
  RW_IRAM2 0x10000000 0x00008000  {  ; RW data = SRAM2 = 32kB
   .ANY (+RW +ZI)
  }
}

LR_IROM2 0x08060000 0x00004000   {   ; load region size_region
  ER_IROM2 0x08060000 0x00004000 {   ; load address = execution address, 16kB region to hold gs[]
    gsData.o (+RO)
  }
}

LR_IROM3 0x08064000 0x0001C000  {    ; load region size_region
  ER_IROM3 0x08064000 0x0001C000 {   ; load address = execution address, 112kB region to hold nn[]
    nnData.o (+RO)
  }
}

Next Thread | Thread List | Previous Thread Start a Thread | Settings

Keil logo

Arm logo
Important information

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies.

Change Settings

Privacy Policy Update

ARM’s Privacy Policy has been updated. By continuing to use our site, you consent to ARM’s Privacy Policy. Please review our Privacy Policy to learn more about our collection, use and transfers
of your data.