I am trying to turn on the Internal LED on my Nucleo-F446RE, but it the LED is always off.
The plan is to set clock for GPIOA on, then set GPIOA_5 to output and then set it to high. Here are the files (C file, Linkerscript, Bashscript for compilation and Flashing).
Blink.c:
// Create references to symbols defined in the linker script
extern unsigned int _data_start;
extern unsigned int _data_end;
extern unsigned int _data_load;
extern unsigned int _bss_start;
extern unsigned int _bss_end;
void startup(); // Function prototype (forward declaration) for startup function
int main(); // Function prototype for main function
// Below we create an array of pointers which would form our vector table
// We use __attribute__ ((section(".vectors"))) to tell the compiler that we want the
// array to be placed in a memory section that we call ".vectors"
unsigned int * vectors[2] __attribute__ ((section(".vectors"))) =
{
(unsigned int *) 0x20020000, // Address of top of stack. 20kB = 1024 x 20 = 20480 bytes = 0x5000
(unsigned int *) startup // Address of the reset handler which is also our startup function
};
// The startup function, address was provided in the vector table
void startup()
{
volatile unsigned int *src, *dest;
// Copy data section values from load time memory address (LMA) to their address in SRAM
for (src = &_data_load, dest = &_data_start; dest < &_data_end; src++, dest++)
*dest = *src;
// Initialize all uninitialized variables (bss section) to 0
for (dest = &_bss_start; dest < &_bss_end; dest++)
*dest = 0;
// Calling the main function
main();
while(1); // Normally main() should never return, but just incase we loop infinitely
}
// LED2 on PA5
#define GPIOA 0x40020000
#define RCC 0x40023800
#define GPIOA_MODER *((volatile char*) GPIOA + 0x0)
#define GPIOA_BSRR *((volatile char*) GPIOA + 0x18)
#define RCC_AHB1ENR *((volatile char*) RCC + 0x30)
int main(){
RCC_AHB1ENR |= (1 << 0);
for(int i = 0; i < 10; i++){ // wait for a few cycles
asm("nop");
}
GPIOA_MODER |= (1 << 10); // set PA5 to output
GPIOA_MODER &= ~(1 << 11);
GPIOA_BSRR = (1 << 5); // set pin high
while(1){}
}
linker.ld:
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K
}
SECTIONS
{
.text : /* Define output file TEXT section */
{
*(.vectors) /* Vector table */
*(.text) /* Program code */
. = ALIGN(4); /* Make sure data that follows are aligned to 4 byte boundary */
*(.rodata) /* Read only, section set asside for constants */
} >rom
.data : /* Define output file DATA section */
{
_data_start = .; /* Get the memory address (VMA) for start of section .data */
*(.data) /* Initialized static and global variable values */
. = ALIGN(4);
_data_end = .; /* Get the memory address (VMA) for end of section .data */
} >ram AT >rom /* After AT we specify the load-time location */
_data_load = LOADADDR(.data); /* Get the load memory address (LMA) for section .data */
.bss : /* Define output file BSS section */
{
_bss_start = .; /* Get memory address of start of bss section */
*(.bss) /* Uninitialized static and global variables */
*(COMMON) /* Uninitialized variables are placed in COMMON section for object files */
. = ALIGN(4);
_bss_end = .; /* Get memory address of end of bss section */
} >ram
}
compile_flash.sh:
arm-none-eabi-gcc -O0 -Wall -c -g -mcpu=cortex-m4 -mthumb blink.c -o blink.o
arm-none-eabi-ld -o blink.elf -T linker.ld blink.o
arm-none-eabi-objcopy blink.elf blink.bin -O binary
arm-none-eabi-nm --numeric-sort blink.elf
st-flash --reset write blink.bin 0x08000000
Sorry for the long code, but I think there should be nothing hidden when you want to help me :)
The problem is that the code is setting the 10th and 11th bit but the datatype is char*.
Changing the Datatype to void* works.
Related
I have already produced a work-around but I have a question about what is happening here.
Setup:
StmCUBEIDE (ver 10)
Stm32F4 on custom board with lan
8Mb extra SDRAM
1Mb FLASH on single boot mode
Default start from 0x08000000
Long story short I have sliced up my memory (flash) into sectors provided in linker. See linker below:
/*
*****************************************************************************
**
** File : LinkerScript.ld
**
** Abstract : Linker script for STM32F4xx Device with
** 1024Kbytes FLASH, 192Kbytes RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used.
**
** Target : STMicroelectronics STM32
**
**
** Distribution: The file is distributed as is, without any warranty
** of any kind.
**
** (c)Copyright Ac6.
** You may use this file as-is or modify it according to the needs of your
** project. Distribution of this file (unmodified or modified) is not
** permitted. Ac6 permit registered System Workbench for MCU users the
** rights to distribute the assembled, compiled & linked contents of this
** file as part of an application binary file, provided that it is built
** using the System Workbench for MCU toolchain.
**
*****************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = 0x20030000; /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 128K; /* required amount of heap */
_Min_Stack_Size = 2K; /* required amount of stack */
/* Specify the memory areas
* reserved sector 0 (16kb sectors)
* flash (bootloader flash) sector 4 & 5 (64kb + 128kb = 192kb)
* sectore stable sector 6 to 8 ( 128 +128 +128 = 384kb)
* sector latest sector 9 to 11 ( 128 +128 +128 = 384kb)
*
*/
MEMORY
{
FLASH_RESERVED (rxw): ORIGIN = 0x08000000, LENGTH = 16K
FLASH_SX (rw) : ORIGIN = 0x08004000, LENGTH = 32K
FLASH_COMMON (rw) : ORIGIN = 0x0800C000, LENGTH = 16K
FLASH_BOOTLOADER (rx) : ORIGIN = 0x08010000, LENGTH = 192K
FLASH_STABLE (rxw) : ORIGIN = 0x08040000, LENGTH = 384K
FLASH_LATEST (rxw) : ORIGIN = 0x080A0000, LENGTH = 384K
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 192K
EXRAM (rwx) : ORIGIN = 0xD0000000, LENGTH = 8192K
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into FLASH_BOOTLOADER */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH_BOOTLOADER
/* keep this section for OTA capabilities*/
.otaComBuff 0x08000000:
{
KEEP(*(.otaComBuff))
} >FLASH_RESERVED = 0x00
/* The program code and other data goes into FLASH_BOOTLOADER */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH_BOOTLOADER
/* sectors for dual boot and reserved data */
.reserved :
{
. = ALIGN(4);
__reserved_start__ = .;
KEEP(*(.reserved*))
. = ALIGN(4);
__reserved_end__ = .;
} >FLASH_RESERVED
ASSERT(LENGTH(FLASH_RESERVED) >= (__reserved_end__ -__reserved_start__), "sector Reserved overflow")
.sx (NOLOAD):
{
. = ALIGN(4);
__sx_start__ = .;
KEEP(*(.sx*))
. = ALIGN(4);
__sx_end__ = .;
} >FLASH_SX
ASSERT(LENGTH(FLASH_SX) >= (__sx_end__ -__sx_start__), "sector sx overflow")
.common :
{
. = ALIGN(4);
__common_start__ = .;
KEEP(*(.common*))
. = ALIGN(4);
__common_end__ = .;
} >FLASH_COMMON
ASSERT(LENGTH(FLASH_COMMON) >= (__common_end__ -__common_start__), "sector common overflow")
.bootloader :
{
. = ALIGN(4);
__bootloader_start__ = .;
KEEP(*(.bootloader*))
. = ALIGN(4);
__bootloader_end__ = .;
} >FLASH_BOOTLOADER
ASSERT(LENGTH(FLASH_BOOTLOADER) >= (__bootloader_end__ -__bootloader_start__), "sector bootloader overflow")
.stable :
{
. = ALIGN(4);
__stable_start__ = .;
KEEP(*(.stable*))
. = ALIGN(4);
__stable_end__ = .;
} >FLASH_STABLE
ASSERT(LENGTH(FLASH_STABLE) >= (__stable_end__ -__stable_start__), "sector stable overflow")
.latest :
{
. = ALIGN(4);
__latest_start__ = .;
KEEP(*(.latest*))
. = ALIGN(4);
__latest_end__ = .;
} >FLASH_LATEST
ASSERT(LENGTH(FLASH_LATEST) >= (__latest_end__ -__latest_start__), "sector latest overflow")
/* Constant data goes into FLASH_BOOTLOADER */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >FLASH_BOOTLOADER
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH_BOOTLOADER
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >FLASH_BOOTLOADER
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >FLASH_BOOTLOADER
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >FLASH_BOOTLOADER
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH_BOOTLOADER
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH_BOOTLOADER
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
/* Uninitialized external data section */
. = ALIGN(4);
.extbss (NOLOAD):
{
/* This is used by the startup in order to initialize the .bss secion */
_extsbss = .; /* define a global symbol at bss start */
__extbss_start__ = _extsbss;
*(.extbss)
*(.extbss*)
*(COMMON)
. = ALIGN(4);
_extebss = .; /* define a global symbol at bss end */
__extbss_end__ = _extebss;
} >EXRAM
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(4);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
PROVIDE ( _max_heap = . );
. = . + _Min_Stack_Size;
. = ALIGN(4);
} >RAM
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}
Next I have in my file:
#include "stm32f4xx_hal.h"
#include "stdint.h"
#include "FreeRTOS.h"
#include "task.h"
#include "error.h"
#include "debug.h"
extern unsigned int __bootloader_start__ ;
extern unsigned int __bootloader_end__ ;
extern unsigned int __sx_start__ ;
extern unsigned int __sx_end__ ;
/*external linker symbols for sector address feching*/
extern unsigned int __stable_start__ ;
extern unsigned int __stable_end__ ;
extern unsigned int __latest_start__ ;
extern unsigned int __latest_end__ ;
/*external linker symbol OTA flash region*/
extern unsigned int __reserved_start__ ;
#define ADR_SectorBootloaderStart ((uint32_t)(&__bootloader_start__))
#define ADR_SectorBootloaderEnd ((uint32_t)(&__bootloader_end_))
#define ADR_SectorSxStart ((uint32_t)(&__sx_start__))
#define ADR_SectorSxEnd ((uint32_t)(&__sx_end__))
#define ADR_SectorStableStart ((uint32_t)(&__stable_start__))
#define ADR_SectorStableEnd ((uint32_t)(&__stable_end__))
#define ADR_SectorLatestStart ((uint32_t)(&__latest_start__))
#define ADR_SectorLatestoEnd ((uint32_t)(&__latest_end__))
/*OTA communiaction sector*/
#define ADR_Reserved ((uint32_t)(&__reserved_start__))
Problem is that only ADR_SectorSxStart returns true address in other variables I get garbage.
On this variables depends flashing logic, for long time function for guarding bootloader sector was not working, after hardcoding addresses into function everything is OK. I need to make the rest of defines work. Any idea why it is that only one variable refers correctly?
Thank you.
#busybee
Map file gets the wrong address too:
.sx 0x0000000008004000 0x0
0x0000000008004000 . = ALIGN (0x4)
0x0000000008004000 __sx_start__ = .
*(.sx*)
0x0000000008004000 . = ALIGN (0x4)
0x0000000008004000 __sx_end__ = .
0x0000000000000001 ASSERT ((LENGTH (FLASH_SX) >= (__sx_end__ - __sx_start__)), sector sx overflow)
.common 0x000000000800c000 0x0
0x000000000800c000 . = ALIGN (0x4)
0x000000000800c000 __common_start__ = .
*(.common*)
0x000000000800c000 . = ALIGN (0x4)
0x000000000800c000 __common_end__ = .
0x0000000000000001 ASSERT ((LENGTH (FLASH_COMMON) >= (__common_end__ - __common_start__)), sector common overflow)
.bootloader 0x0000000008030a54 0x0
0x0000000008030a54 . = ALIGN (0x4)
0x0000000008030a54 __bootloader_start__ = .
*(.bootloader*)
0x0000000008030a54 . = ALIGN (0x4)
0x0000000008030a54 __bootloader_end__ = .
0x0000000000000001 ASSERT ((LENGTH (FLASH_BOOTLOADER) >= (__bootloader_end__ - __bootloader_start__)), sector bootloader overflow)
.stable 0x0000000008040000 0x0
After some time, I have found the answer. As per usual it was in plain .text in front of my eyes.
The thing is that the address of SECTOR_BOOTLOADER is in fact placed correctly telling compiler where to place all .text variables.
When you go carefully line by line, you can see that I have actually created a memory region, FLASH_BOOTLOADER, and then used it as my main program address. This is correct. Then I have placed all my .text variables, using linker, then I created my REGION BOOTLOADER.
This is linker language means that in this region first he will place my variables, incrementing address and then he will place my sector, returning me address of sector not region.
This mistake was made by not understanding linker scripts and naming issue.
STM8, IAR compiler.
Im trying to place changable interrupt vector table(IVT) in RAM(ram_ivt_section or RAM_IVT), stating from 0x00 address.
Prereq: Hardware entry point(base_ivt_section or IVT_TO_RAM block) already replaced and redirects to this RAM addresses.
So, i have next code:
Header.h ===========================================
#define MCU_INTERRUPT_VECTORS_COUNT (32)
typedef void (__interrupt *interrupt_handler_t)(void);
typedef struct {
int8_t value;
int8_t unused_byte;
interrupt_handler_t handler;
}interrupt_vector_t;
extern interrupt_vector_t ram_ivt[MCU_INTERRUPT_VECTORS_COUNT];
Source.c ===========================================
#include "header.h"
extern void __iar_program_start(void);
extern void __iar_unhandled_exception(void);
__interrupt void CallUnhandledException(void) { __iar_unhandled_exception(); }
__interrupt void CallResetHandler(void) { __iar_program_start(); }
interrupt_vector_t ram_ivt[MCU_INTERRUPT_VECTORS_COUNT] #".ram_ivt_sector" = {
{0x82, 0x00, CallResetHandler},
{0x82, 0x00, CallUnhandledException},
{0x82, 0x00, CallUnhandledException},
... repeats 32 times.
Main.c ===========================================
#include "header.h"
int main( void ) {
__enable_interrupt();
__trap();
}
It works fine. On trap, programm falls to unhandled exception.
But, when im trying to modify or read table
Main.c ===========================================
#include "header.h"
int main( void ) {
volatile void* a = &ram_ivt[1].handler;
// Or
ram_ivt[1].handler = 0;
__enable_interrupt();
__trap();
}
Project stops build on linker stage with error:
Error[Lc036]: no block or place matches the pattern "rw data section .ram_ivt_sector in ram_ivt.o symbols: [ram_ivt]"
Linker file:
/////////////////////////////////////////////////////////////////
define symbol __RAM_IVT__ = 0x000000;
// Memory regions
define memory with size = 16M;
define region TinyData = [from 0x00 to 0xFF];
define region NearData = [from 0x0000 to 0x0FFF];
define region NearFuncCode = [from 0x8000 to 0x9000];
define block CSTACK with size = _CSTACK_SIZE {};
define block HEAP with size = _HEAP_SIZE {};
define block IVT_TO_RAM with size = 0x80, alignment = 1 { ro section .base_ivt_section };
define block RAM_IVT with size = 0x80, alignment = 1 { rw section .ram_ivt_section };
define block INTVEC with size = 0x80, alignment = 1 { ro section .intvec };
// Initialization
initialize by copy { rw section .iar.dynexit,
rw section .near.bss,
rw section .near.data,
rw section .near_func.textrw,
rw section .tiny.bss,
rw section .tiny.data,
ro section .tiny.rodata };
initialize by copy with packing = none { section __DLIB_PERTHREAD };
do not initialize { rw section .near.noinit,
rw section .tiny.noinit,
rw section .vregs };
// Keep
keep { rw section .ram_ivt_section };
// Placement
place at address mem: __RAM_IVT__ { block RAM_IVT };
place in TinyData { rw section .vregs,
rw section .tiny.bss,
rw section .tiny.data,
rw section .tiny.noinit,
rw section .tiny.rodata };
place in NearData { block HEAP,
rw section __DLIB_PERTHREAD,
rw section .iar.dynexit,
rw section .near.bss,
rw section .near.data,
rw section .near.noinit,
rw section .near_func.textrw };
place at end of NearData { block CSTACK };
place at start of NearFuncCode { block IVT_TO_RAM };
place in NearFuncCode { block INTVEC,
ro section __DLIB_PERTHREAD_init,
ro section .iar.init_table,
ro section .init_array,
ro section .near.data_init,
ro section .near.rodata,
ro section .near_func.text,
ro section .near_func.textrw_init,
ro section .tiny.data_init,
ro section .tiny.rodata_init };
That was a syntax error in
interrupt_vector_t ram_ivt[MCU_INTERRUPT_VECTORS_COUNT] #".ram_ivt_sector"
ram_ivt_sector must be ram_ivt_section
Thanks #KoynovStas.
As a point of trying to understand the basics, I wrote [or extracted I guess] the following c code and linker script. The resulting binary works and the led blinks without issue. However, while debuging, I found that the bss_start and bss_end symbols both hold a value of 0x20000000. The bss zero fuction is basically skipped. When doing an objdump, I can see
20000000 g O .bss 00000004 timer_delayCount
So the section is 4 bytes long and located at 0x20000000 correclty. And at least bss_start is pointed to the correct memory address. However, bss_end should be pointed at 0x20000004 [I think], not 0x20000000.
I would like to now whey the bss_end symbol is not incremeting after the *(.bss), which I think contains four bytes, is placed.
The micro controller is stm32f103rb, a cortex-m3 chip. I am compling with ARM GNU GCC
My main.c file:
#define _stackInit 0x20005000U
volatile unsigned int * const RCC_APB2ENR = (unsigned int *)0x40021018;
volatile unsigned int * const GPIOA_CRL = (unsigned int *)0x40010800;
volatile unsigned int * const GPIOA_BSR = (unsigned int *)0x40010810;
volatile unsigned int * const GPIOA_BRR = (unsigned int *)0x40010814;
volatile unsigned int * const STK_CTRL = (unsigned int *)0xE000E010;
volatile unsigned int * const STK_LOAD = (unsigned int *)0xE000E014;
volatile unsigned int * const STK_VAL = (unsigned int *)0xE000E018;
volatile unsigned int timer_delayCount;
int main() {
// enable GIOA clock and set PB5 to output
*RCC_APB2ENR |= (unsigned int)0x00000004;
*GPIOA_CRL = (unsigned int)0x44244444;
// COnfigure Systick Timer for 1 millisecond interrupts
*STK_VAL = 0x00;
*STK_LOAD = 7999U; //tick every 1 ms
*STK_CTRL = 0x07;
while (1){
int c, d;
timer_delayCount = 500u;
while(timer_delayCount != 0u);
*GPIOA_BSR = 0x20;
timer_delayCount = 500u;
while(timer_delayCount != 0u);
*GPIOA_BRR = 0x20;
}
}
// Begin and End addresses for the .bss section. Symbols defined in linker script
extern unsigned int __bss_start__;
extern unsigned int __bss_end__;
void __attribute__ ((section(".after_vectors"))) Reset_Handler (void)
{
// Initialize bss section by iterating and clearing word by word.
// It is assumed that the pointers are word aligned.
unsigned int *p = &__bss_start__;
while (p < &__bss_end__) {
*p++ = 0;
}
main();
}
void SysTick_Handler() {
// Decrement to coutner to zero.
if (timer_delayCount != 0u)
{
--timer_delayCount;
}
}
void __attribute__ ((section(".after_vectors"))) Default_Handler(void)
{
while(1);
}
void __attribute__ ((section(".after_vectors"),weak, alias ("Default_Handler"))) NMI_Handler(void);
void __attribute__ ((section(".after_vectors"),weak, alias ("Default_Handler"))) HardFault_Handler(void);
void __attribute__ ((section(".after_vectors"),weak, alias ("Default_Handler"))) MemManage_Handler(void);
void __attribute__ ((section(".after_vectors"),weak, alias ("Default_Handler"))) BusFault_Handler(void);
void __attribute__ ((section(".after_vectors"),weak, alias ("Default_Handler"))) UsageFault_Handler(void);
void __attribute__ ((section(".after_vectors"),weak, alias ("Default_Handler"))) SVC_Handler(void);
void __attribute__ ((section(".after_vectors"),weak, alias ("Default_Handler"))) DebugMon_Handler(void);
void __attribute__ ((section(".after_vectors"),weak, alias ("Default_Handler"))) PendSV_Handler(void);
typedef void(* const pHandler)(void);
// The vector table.
// The linker script to place at correct location in memory.
__attribute__ ((section(".isr_vector"),used)) pHandler __isr_vectors[] =
{
//core exceptions
(pHandler)_stackInit, // Inital Stack Pointer
Reset_Handler, // reset handler
NMI_Handler, // NMI handler
HardFault_Handler, // hard fault handler
MemManage_Handler, // MPU fault handler
BusFault_Handler, // bus fault handler
UsageFault_Handler, // usage fault handler
0x00, // reserved
0x00, // reserved
0x00, // reserved
0x00, // reserved
SVC_Handler, // SVCall handler
DebugMon_Handler, // debug monitor handler
0x00, // reserved
PendSV_Handler, // PendSV handler
SysTick_Handler, // systick handler
};
My linker file:
ENTRY(Reset_Handler)
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K
}
SECTIONS
{
.text : {
*(.isr_vector)
*(.after_vectors)
*(.text)
} > FLASH
.bss : {
__bss_start__ = .; /* symbol for c code to initialize bss section */
*(.bss)
__bss_end__ = .; /* symbol for c code to initialize bss section */
} > RAM
}
Compiler commands:
/opt/gcc-arm-none-eabi-7-2017-q4-major/bin/arm-none-eabi-gcc -c -mcpu=cortex-m3 -mthumb -g blinky-interrupt.c -o blinky-interrupt.o
/opt/gcc-arm-none-eabi-7-2017-q4-major/bin/arm-none-eabi-ld -T blinky-interrupt.ld blinky-interrupt.o -o blinky-interrupt.elf
That's because an unitialized variable goes into COMMON instead of .bss. Had you initialized it with 0, then it'd go into .bss.
Look at the linker map file (if you don't have it, let the linker generate it with -Map), you should see something like this
.bss 0x0000000020000000 0x4 load address 0x00000000080000e0
0x0000000020000000 . = ALIGN (0x4)
0x0000000020000000 __bss_start__ = .
*(.bss)
0x0000000020000000 . = ALIGN (0x4)
0x0000000020000000 __bss_end__ = .
COMMON 0x0000000020000000 0x4 ./src/app/main.o
0x0000000020000000 timer_delayCount
When COMMON is not specified in the linker script, the linker puts it somewhere else, probably dumps it at the end.
A more complete linker script has the following .bss section
.bss :
{
. = ALIGN(4);
__bss_start__ = .;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
} >RAM
Then the COMMON section would go between __bss_start__ and __bss_end__.
FYI, *(.bss*) is there to cover the -fdata-sections option, when each variable gets its own segment, so that the linker can drop unreferenced ones.
I'm debugging an embedded system with the stm32f746vg microcontroller where some speed critical sections of code are loaded in data RAM instead of flash. The rest of the non-critical code is loaded in flash, and the linker puts all of the .text sections in flash by default.
I do this relocation with nasty little function prototypes like this:
int main(void) __attribute__((section(".data")));
This forces main() to be loaded at address 0x2000 0000, which is what I want. Unfortunately, GDB expects main() to be loaded at address 0x0080 0000, where the rest of the program code is. As a result, GDB does not know where the line numbers for main() are. Is there any way to tell GDB "main() is actually at this address" ?
I DO have the newest version of arm-none-eabi-gdb and arm-none-eabi-gcc.
I am running arm-none-eabi-gcc with the -g option.
When I comment out the prototype for main that contains the __attribute__ directive, GDB has no problem finding line numbers.
Below is my linker script:
/* Entry Point */
ENTRY(Reset_Handler)
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
/* Specify the memory areas */
/**
* for the time being, we are going to buffer the image in sram1. sram1 is
* entirely dedicated to buffering images.
* DTCM_RAM will be used for user variables
*/
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
DTCM_SRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
/* RAM1 (xrw) : ORIGIN = 0x20010000, LENGTH = 240K*/
RAM1 (xrw) : ORIGIN = 0x20010000, LENGTH = 245760
RAM2 (xrw) : ORIGIN = 0x2004c000, LENGTH = 16K
ITCM_SRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 16K
}
/* Define output sections */
SECTIONS
{
/* Vectors need to be loaded at the start of flash. */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
/*KEEP (*(.init))*/
/*KEEP (*(.fini))*/
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
_exit = .;
} >FLASH
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >FLASH
/* used by the startup to initialize data */
_sidata = .;
/* Initialized data sections goes into RAM, load LMA copy after code */
.data ORIGIN(DTCM_SRAM) :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} AT > FLASH
__const_data_length__ = SIZEOF(.data);
/* Uninitialized data section */
. = ALIGN(4);
.bss . :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >DTCM_SRAM
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(4);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(4);
} >DTCM_SRAM
/* ram1 section, vars must be located here explicitly */
/* Example: extern int foo(void) __attribute__ ((section (".ram1"))); */
/* No initialization is offered for this section.*/
.ram1 ORIGIN(RAM1) :
{
*(.ram1)
} >RAM1
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}
These are my gcc flags
CFLAGS = -gstabs -Wall -std=gnu99 -ffunction-sections -Wno-unused-variable
CFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork
CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16 -mlong-calls
CFLAGS += -I. -ggdb
CFLAGS += -DHSE_VALUE=$(HSE_VALUE)
CFLAGS += -DUSE_STDPERIPH_DRIVER
You acheive this by placing main() in special code section of your choosing, call it .fast_exec
int main(void) __attribute__((section(".fast_exec")));
Then, in the linker script, place this new section to execute from RAM. It will be copied from FLASH at start-up:
.fast_exec : {
*(.fast_exec)
} > DTCM_SRAM AT> FLASH
You can verify the effect of this, by checking the map file.
Refer to: https://stackoverflow.com/a/15142268/1096140
I have an ARM board with ROM at 0x80000000 and RAM at 0x20000000. Board starts execution of raw binary code at 0x80000000.
I managed to get a simple ARM assembler program running on it, but I have to use C instead of ASM. I know I will need to use some kind of linker script, and then manually copy .data section to RAM and clear .bss, setup stack etc. but I haven't found a reliable solution how to do this yet, especially the linker script (it's very messy in my opinion).
Also, I can't get the linker to output a raw binary instead of ELF, but it's not a big deal as I can use objcopy later.
Thanks in advance.
This example is for STM32F051 MCU:
Very simple application as "blinky" (without delays):
// define used registers
#define RCC_AHB1 *(volatile unsigned int *)(0x40021014)
#define GPIOC_MODER *(volatile unsigned int *)(0x48000800)
#define GPIOC_BSRR *(volatile unsigned int *)(0x48000818)
// main program
void mainApp() {
RCC_AHB1 = 1 << 19; // enable clock for GPIOC
GPIOC_MODER = 1 << (9 * 2); // set output on GPIOC.P9
while (1) {
GPIOC_BSRR = 1 << 9; // set output on GPIOC.P9
GPIOC_BSRR = 1 << (9 + 16); // clear output on GPIOC.P9
}
}
// variables for testing memory initialisation
int x = 10;
int y = 0;
int z;
Here is also very simple startup file written in C (also will work in C++), which start application mainApp and initialise static variables .data initialised from ROM and .bss only set to zero, there are variables initialised to zero and uninitialised variables.
extern void mainApp();
// external variables defined in linker script
// address in FLASH where are stored initial data for .data section
extern unsigned int _data_load;
// defines start and end of .data section in RAM
extern unsigned int _data_start;
extern unsigned int _data_end;
// defines start and end of .bss section in RAM
extern unsigned int _bss_start;
extern unsigned int _bss_end;
void resetHandler() {
unsigned int *src, *dst;
// copy .data area
src = &_data_load;
dst = &_data_start;
while (dst < &_data_end) {
*dst++ = *src++;
}
// clear .bss area
dst = &_bss_start;
while (dst < &_bss_end) {
*dst++ = 0;
}
mainApp();
while(1);
}
// _stacktop is defined in linker script
extern unsigned int _stacktop;
// vector table, will be placed on begin of FLASH memory, is defined in linker script
// only reset vector defined, need add other used vectors (especially NMI)
__attribute__((section(".vectors"), used)) void *isr_vectors[] = {
&_stacktop, // first vector is not vector but initial stack position
(void *)resetHandler, // vector which is called after MCU start
};
And finaly linker script which define location and sizes of memories, sections for vector, program (text), data (.data and .bss) a stacktop
MEMORY {
FLASH(rx) : ORIGIN = 0x08000000, LENGTH = 64K
SRAM(rwx) : ORIGIN = 0x20000000, LENGTH = 8K
}
SECTIONS {
. = ORIGIN(FLASH);
.text : {
*(.vectors)
*(.text)
} >FLASH
. = ORIGIN(SRAM);
.data ALIGN(4) : {
_data_start = .;
*(.data)
. = ALIGN(4);
_data_end = .;
} >SRAM AT >FLASH
.bss ALIGN(4) (NOLOAD) : {
_bss_start = .;
*(.bss)
. = ALIGN(4);
_bss_end = .;
} >SRAM
_stacktop = ORIGIN(SRAM) + LENGTH(SRAM);
_data_load = LOADADDR(.data);
}
Build this with these command (build and link at once):
$ arm-none-eabi-gcc -mcpu=cortex-m0 -mthumb -nostartfiles main.c startup.c -T stm32f051x8.ld -o main.elf
In symbol table is possible to see where are stored data:
$ arm-none-eabi-nm -C -l -n -S main.elf
08000000 00000008 T isr_vectors
08000008 00000034 T mainApp
0800003c 0000005c T resetHandler
08000098 A _data_load
20000000 D _data_start
20000000 00000004 D x
20000004 D _data_end
20000004 B _bss_start
20000004 00000004 B y
20000008 B _bss_end
20000008 00000004 B z
20002000 A _stacktop
Also you can look into listing:
arm-none-eabi-objdump -S main.elf
Raw binary:
arm-none-eabi-objcopy -O binary main.elf main.bin
MEMORY
{
bob : ORIGIN = 0x8000, LENGTH = 0x1000
ted : ORIGIN = 0xA000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > bob
__data_rom_start__ = .;
.data : {
__data_start__ = .;
*(.data*)
} > ted AT > bob
__data_end__ = .;
__data_size__ = __data_end__ - __data_start__;
.bss : {
__bss_start__ = .;
*(.bss*)
} > ted
__bss_end__ = .;
__bss_size__ = __bss_end__ - __bss_start__;
}
of course change the addresses as you see fit. clearly the names of the sections mean nothing, you might try rom and ram if it helps you.
If you were to do something like this
MEMORY
{
rom : ORIGIN = 0x80000000, LENGTH = 0x1000
ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > rom
.bss : { *(.bss*) } > ram
.rodata : { *(.rodata*) } > rom
.data : { *(.data*) } > ram
}
and then objcopy it then you are going to end up with a huge file, even if you only have one instruction of .text and one byte of data. because a binary format has to cover everything as in the memory so it will make a file that is 0x80000000+sizeof(text)-0x20000000. If you had one instruction only in ram and one byte of data then the file would be 0x60000004 bytes or 1.6 gig. leave it as an elf and use objdump -D until you have your linker script worked out THEN make a .bin if you really need one. or make an intel hex or s record and again you can examine it to see if it is all in the same address space before trying a binary.
the first key to your problem is the AT
MEMORY
{
bob : ORIGIN = 0x8000, LENGTH = 0x1000
ted : ORIGIN = 0xA000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > bob
.data : { *(.data*) } > ted AT > bob
.bss : { *(.bss*) } > bob
}
it says I want the .data in the address space ted, but place it in the binary in the bob space. it compiles for the ted address space, but the bits are loaded from bob space. exactly what you want. except you dont know how much .data to copy from rom to ram. you have to be super careful where you place the variables in the more complicated one or it wont work right.