ARM bare-metal program compilation -control flash writes - compilation

I'm trying to compile some C code to run on an ARMv6 simulator, with FLASH memory starting # 0x0 and RAM starting at 0x800000. Right now, I can pass binary files off the the simulator just fine...
However, I want the instructions generated to not include any writes to flash memory, and only operate within RAM memory (after copying RAM). Is this possible?
I am using the GNU toolchain to compile.
This is my current linker script:
MEMORY
{
rom(rx) : ORIGIN = 0x00000000, LENGTH = 0x00800000
ram(!rx) : ORIGIN = 0x40000000, LENGTH = 0x00800000
h : ORIGIN = 0x40000000, LENGTH = 0x00400000
}
SECTIONS
{
.text : { *(.text*) } > rom
.bss : { *(.bss*) } > ram
.heap : { *(.heap*) } > h
}
end = ORIGIN(h) + LENGTH(h);
_stacktop = ORIGIN(ram) + LENGTH(ram);

Your build linker script (normally a .ld file) determines the locations of your device's memory and how the linker sections are mapped to that. Your link map should not include writable sections in read-only memory, that will fail.
[Added after linker script added to question]
You linker script seems unusual in lacking a .data section:
.data : { *(.data) } > ram
Without that it is not clear what the linker will do with static initialised data.
Also your question states that the RAM starts at 0x800000, but the linker script clearly locates it at 0x40000000. Perhaps this misunderstanding of your memory map is leading you to erroneously believe that writes to the ROM region are occurring?

Related

How to debug code copied from FLASH to RAM in Atmel Studio?

I have a custom boot loader program. The loader must be able to program any part of the flash, including upgrading itself. To accomplish this, the loader startup code copies the whole program from flash into RAM and then jumps to main().
The program works fine, but I can't get the debugger to set breakpoints. The specific error message that I get is "Unable to set requested breakpoint on target". Reading the state of variables and single stepping DOES seem to work.
How can I get the debugger to work in this setup?
Development Environment: Atmel Studio 7
Processor: ATSAME70 (This is an ARM Cortex M7)
Compiler: GCC
Tool: Atmel-ICE
Interface: SWD (Serial Wire Debug)
The relevant portions of the linker script look like this...
/* Memory Spaces Definitions */
MEMORY
{
rom (rx) : ORIGIN = 0x00400000, LENGTH = 0x00004000 /* rom, 2097152K */
ram (rwx) : ORIGIN = 0x20400000, LENGTH = 0x00060000 /* ram, 393216K */
}
SECTIONS
{
.reset : {
. = ALIGN(4);
KEEP("Device_Startup/startup.o"(.text))
KEEP(*(.reset_code))
} > rom
PROVIDE(_exit = .);
.text :
{
. = ALIGN(4);
_rom_to_ram_copy_vma_start = .;
KEEP(*(.vectors .vectors.*))
*(.text .text.* .gnu.linkonce.t.*)
...
...
_rom_to_ram_copy_vma_end = .;
} > ram AT > rom
_rom_to_ram_copy_lma_start = LOADADDR(.text);
}
The program coplies everthing between _rom_to_ram_copy_vma_start and _rom_to_ram_copy_vma_end into RAM and then jumps to main in RAM.
Given that I used "ram AT > rom" in the linker script one would think that the debugger should know that the code is in RAM and should have no problem setting the breakpoint there.

Why is gcc placing my global data in the wrong address?

I am trying to compile an app for a custom OS I'm writing for the ARM Cortex M0+. The app is written in C. I have a global variable, int newInt = 4; defined at the very top of my code. The rest of the app just calls a print function to print out the value of that variable. However, it kept crashing. To check it, I instead printed out the address of the variable, newInt. It was well outside of the valid memory map of the chip, hence why it crashed.
My linker script is simple:
SECTIONS
{
. = 0x20001580;
.text :
{
_text = .;
*(.text)
_etext = .;
}
.data :
{
_data = .;
KEEP(*(.data))
_edata = .;
}
.bss :
{
_bss = .;
*(.bss)
_ebss = .;
}
}
Now, the .text segment is placed correctly, starting at 0x20001580. However, the address of my global variable, which SHOULD be somewhere around that value (0x20001580 or so, plus the code size, which is around 40 bytes), is actually placed at 0x18060, which as far as I'm concerned is a totally random address. So, whenever I try to access newInt's value, the code tries to access an out of range memory address, and it fails.
Shouldn't newInt be placed in the .data segment? If so, why would the .data segment be at such an odd location, given my linker script?
This might be relevant to other people later:
The problem lay in my linking process. In order to make it work, I had to compile my app using the -c flag, to get the correct output file. THEN link against the output of gcc. I tried to do compilation and linking in one step and something went awry when that was done.

STM32 ExtRAM GCC-MAP file

I use STM32F417 with external 512*16 RAM under FreeRTOS. When I see a MAP file the address of used memory are still in the internal RAM.
RTOS Heap def:
> static unsigned char ucHeap[ 60*1024 ]__attribute__ > ((section(".ExRam")));
arm-gcc-link.ld file:
> rom (rx) : ORIGIN = 0x08000000, LENGTH = 0x00100000
> ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00020000
>ram2 (rwx) : ORIGIN = 0x60000000, LENGTH = 0x00100000
>...
>ExRam (NOLOAD): { *(.ExRam.) } > ram2
>...
MAP File:
> .ExRam 0x60000000 0xf000
>*(.ExRam.)
>.ExRam 0x60000000 0xf000 ..\obj\heap_4.o
>
> .ARM.extab *(.ARM.extab * .gnu.linkonce.armextab.*)
> 0x6000f000 __exidx_start = .
Variable , Why not in 0x6000000 area?:
>.bss 0x200053ac 0x2c ..\obj\tcp_in.o
>.bss 0x200053d8 0x4 ..\obj\raw.o
>.bss 0x200053dc 0x10 ..\obj\ip_addr.o
>.bss 0x200053ec 0x100 ..\obj\ssl_ciphersuites.o
>.bss 0x200054ec 0x678 ..\obj\dns.o
>.bss 0x20005b64 0x8 ..\obj\lwip_timers.o
The heap is used by malloc to allocate memory dynamically, at run time. The linker creates the map file at build time, before your code is running. The linker knows only about variables that are defined at compile time. The linker has no knowledge of how the heap will be used at run-time. Therefore the map file cannot possibly itemize the variables that may be created in the heap.
The variables that are listed in the map file in the .bss and .data sections are defined at compile time and statically allocated. They don't appear in the heap because that is not what the heap is for.
OK,
I found that in the MAP file are not listed variables located in the extRAM heap. It means that object listed in RAM are lower size if there are variables located in the heap in extRAM but are not listed under heap address (0x6000000) same way like variables/object located in the internal RAM.

What is the IAR equiavlent of the gcc linker NOLOAD directive?

The gcc linker has a directive called NOLOAD that allows a section to be linked but not loaded in the final output. This directive is placed in the linker scatter file (see the example below). Is there an equivalent linker directive for IAR Workbench? I'm currently using IAR Embedded Workbench for ARM V7.20.2.
MEMORY
{
rom (rx) : ORIGIN = 0x00000000, LENGTH = 0x00010000
ram (rwx) : ORIGIN = 0x10000000, LENGTH = 0x00008000
}
SECTIONS
{
.my_section (NOLOAD):
{
*my_funcs.o(.text*)
} > rom

Put gcc libs .data in specific section?

I'm trying to switch to the GNU GCC compiler for our embedded system, but I'm having trouble linking the project as the memory layout of our chip is split:
RAM section 1: 0x10000-0x12FFF
RAM section 2: 0x18000-0x1BFFF
The data from our project can fit in section 1, but the data linked from the gcc libs doesn't. Map file extract:
.data 0x00012974 0x3c4 c:/tools/gnucr16_v1.1.3-elf/cr16-elf/bin/../lib/gcc/cr16-elf/4.5.1-GNUCR16_v1.1.3/../../../../cr16-elf/lib\libc.a(lib_a-impure.o)
0x00012974 _impure_ptr
.data 0x00012d7c 0x410 c:/tools/gnucr16_v1.1.3-elf/cr16-elf/bin/../lib/gcc/cr16-elf/4.5.1-GNUCR16_v1.1.3/../../../../cr16-elf/lib\libc.a(lib_a-mallocr.o)
0x00012d7c __malloc_av_
0x00013184 __malloc_trim_threshold
0x00013188 __malloc_sbrk_base
Is it possible to put the .data section from the libs in the 2nd section? I've tried different thing without success... Linker script extract:
MEMORY
{
SHARED1 : org = 0x10000, len = 0x3000
SHARED2 : org = 0x18000, len = 0x4000
}
SECTIONS
{
.data 0x12004 : { *(.data); } >SHARED1
.data2 0x19000 : { libc*(.data); } >SHARED2
}
SECTIONS
{
.section_name:
{
*lib_a-impure.o (.data); //That is the syntax to access sections of object files
} >SHARED1
}
More info here: http://www.embedded.com/design/mcus-processors-and-socs/4026080/Building-Bare-Metal-ARM-Systems-with-GNU-Part-3

Resources