This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

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!

Parents
  • 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)
      }
    }
    

Reply
  • 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)
      }
    }
    

Children
No data