I am working in a bare-metal ARM project in which I am trying to integrate newlib library. As a beginner, I am trying to make the printf function working first so that I can see the standard output through UART. I have already gone through many on-line documents that describes how to get this done. Instead of blindly following the steps, I did everything myself by learning things from those documents. I made many mistakes in the beginning but fixed them one by one and kept the work progressing.
But now I have stuck with an issue which no one has ever seems to be experienced so far, according to my internet search. Now let me come to the actual, issue.
The printf function is returning without calling my implementation of _write function. When I debug I can see that the printf is invoking other system calls that I have written myself(Like _isatty, _sbrk and _fstat).
These are the system calls that I have implemented in order to resolve the linking issues(undefined references)
extern char __heap_start__;
extern char __heap_end__;
void _exit(int status)
{
while (1);
}
void *_sbrk(int incr)
{
static char *heap_end = &__heap_start__;
char *base = heap_end;
if(heap_end + incr > &__heap_end__)
{
errno = ENOMEM;
return (void *)-1;
}
heap_end += incr;
return base;
}
int _write(int fd, char *buff, int size)
{
int i;
for(i = 0; i < size; i++)
{
UART0_write_char(buff[i]);
}
return i;
}
int _read(int fd, char *buff, int size)
{
return 0;
}
int _open(const char *name, int flags,int mode)
{
return 0;
}
void _close(int fd)
{
}
int _isatty(int fd)
{
return 1;
}
int _fstat(int fd, struct stat *st)
{
st->st_mode = S_IFCHR;
return 0;
}
off_t _lseek(int fd, off_t offset, int whence)
{
return 0;
}
My linker script
STACK_HEAP_BOUNDARY_OFFSET = 0;
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 512K
SRAM (rw) : ORIGIN = 0x40000000, LENGTH = 32K
}
SECTIONS
{
.text :
{
startup.o (.text)
*(.text .txt.*)
*(.glue_7)
*(.glue_7t)
. = ALIGN(4);
} > FLASH
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > FLASH
.ARM :
{
*(.ARM.exidx*)
} >FLASH
.rodata :
{
*(.rodata .rodata.*)
. = ALIGN(4);
} > FLASH
.data :
{
__data_load__ = LOADADDR (.data);
__data_start__ = .;
*(.data .data.*)
. = ALIGN(4);
__data_end__ = .;
} > SRAM AT > FLASH
.bss :
{
__bss_start__ = .;
*(.bss .bss.*)
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
} > SRAM
.heap :
{
__heap_start__ = .;
PROVIDE(end = __heap_start__);
PROVIDE(_heap_start = __heap_start__);
. = . + ((LENGTH(SRAM) - (. - (ORIGIN(SRAM)))) / 2);
. += STACK_HEAP_BOUNDARY_OFFSET;
. = ALIGN(4);
__heap_end__ = .;
PROVIDE(_heap_end = __heap_end__);
} > SRAM
.stack :
{
__stack_start__ = .;
. = . + (LENGTH(SRAM) - (. - (ORIGIN(SRAM))));
. = ALIGN(4);
__stack_end__ = .;
__stack_size__ = __stack_end__ - __stack_start__;
__IRQ_stack_top__ = (__stack_start__ + (__stack_size__ / 2));
} > SRAM
}
My Makefile
TOOLCHAIN_PREFIX:=arm-none-eabi-
CC := $(TOOLCHAIN_PREFIX)gcc
LD := $(TOOLCHAIN_PREFIX)ld
AS := $(TOOLCHAIN_PREFIX)as
AR := $(TOOLCHAIN_PREFIX)ar -cr
OBJCOPY := $(TOOLCHAIN_PREFIX)objcopy
RM := rm -f
TARGET := image.hex
OBJS := startup.o $(patsubst %.c,%.o,$(wildcard *.c))
CFLAGS := -mcpu=arm7tdmi-s -g3 -Wall -I. -gdwarf-2
AS_FLAGS := -mcpu=arm7tdmi-s -g3 -gdwarf-2
LD_FLAGS := -Wl,-Map,$(TARGET:%.hex=%).map -nostartfiles
LD_SCRIPT := lpc2138.ld
all : $(TARGET)
$(TARGET) : $(TARGET:%.hex=%.elf)
$(OBJCOPY) -O ihex $< $#
$(TARGET:%.hex=%.elf) : $(OBJS)
$(CC) -o $# -T $(LD_SCRIPT) $(OBJS) $(LD_FLAGS)
startup.o : startup.s
$(AS) $(AS_FLAGS) -o $# $<
%.o : %.c
$(CC) -c $(CFLAGS) -o $# $<
clean :
$(RM) $(TARGET) $(TARGET:%.hex=%.elf) $(TARGET:%.hex=%).map *.o
Please let me know if any further information is needed from my side. Thank you in advance
EDIT:
Start-up code
/* Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs */
Mode_USR = 0x10
Mode_FIQ = 0x11
Mode_IRQ = 0x12
Mode_SVC = 0x13
Mode_ABT = 0x17
Mode_UND = 0x1B
Mode_SYS = 0x1F
I_Bit = 0x80 /* when I bit is set, IRQ is disabled */
F_Bit = 0x40 /* when F bit is set, FIQ is disabled */
.text
.arm
.global _start
.func _start
_start:
B _reset /* Reset vector */
B _loop /* Undefined Instruction */
B _loop /* Software Interrupt */
B _loop /* Prefetch Abort */
B _loop /* Data Abort */
NOP /* Reserved */
LDR pc, [pc, #-0x0FF0] /* VicVectAddr */
/* LDR pc, _fiq_addr */
B _loop /* FIQ Handler */
_reset:
/* Enable FIQ and IRQ */
MSR CPSR_c,#(Mode_IRQ | I_Bit | F_Bit)
LDR SP, =__IRQ_stack_top__
MSR CPSR_c,#Mode_SVC
/* Relocate the .data section (copy from ROM to RAM) */
LDR r0,=__data_load__
LDR r1,=__data_start__
LDR r2,=__data_end__
_l1:
CMP r1,r2
LDMLTIA r0!,{r3}
STMLTIA r1!,{r3}
BLT _l1
/* Clear the .bss section (zero init) */
LDR r1,=__bss_start__
LDR r2,=__bss_end__
MOV r3,#0
_l2:
CMP r1,r2
STMLTIA r1!,{r3}
BLT _l2
LDR sp,=__stack_end__
LDR FP,=__stack_end__
LDR r0,=main
MOV lr,pc
BX r0
_loop:
B _loop
/* _fiq_addr:
.word VIC_FIQ_handler
*/
.endfunc
.end
Related
I am trying to transmit and receive characters in UART through interrupts in LM3S811 using Qemu Simulation. I wrote this code with the help of this https://www.electronicwings.com/arm7/lpc2148-uart0. I am not sure whether it is correct and it does not work. Could someone suggest how to get the task done.
startup code :
.thumb
.global start
start:
.word 0x20001000
.word main
flash.ld
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00010000
SRAM (rxw) : ORIGIN = 0x20000000, LENGTH = 0x00002000
}
SECTIONS
{
.text : {
*(.vectors);
*(.text);
etext = .;
} > FLASH
.rodata : {
*(.rodata);
} > FLASH
.data : {
sdata = .;
*(.data);
edata = .;
} > SRAM AT > FLASH
.bss: {
sbss = .;
*(.bss);
ebss = .;
} > SRAM
}
main.c
#define UARTDR (*((volatile unsigned int *) 0x4000C000)) // Data register for UART...
#define UARTIFLS (*((volatile unsigned int *) 0x40000034)) // Interrupt identification register...
#define UARTFR (*((volatile unsigned int *) 0x4000C018)) // Register which holds the status of the FIFO...
char rx;
_irq void UART0_Inerrupt(void)
{
int iir_value;
iir_value = UARTIFLS // Interrupt Identification register...
if (iir_value & 0x00) { // If interrupt is received, i.e data is present...
rx = UARTDR;
}
UARTDR = rx; // Write to data register for writing to transmit FIFO...
while ( (UARTFR & 0x20) == 1) continue;
}
int main(void)
{
NVICVectAddr0 = (unsigned) UART0_Inerrupt;
while(1);
}
``
I build a simple OS with three files, but get a ogg problem, the files are here:
loader.s
.extern kernel_main
.global _start
.set MB_ALIGN, 1<<0
.set MB_MEMINFO, 1<<1
.set MB_MAGIC, 0x1BADB002
.set MB_FLAGS, MB_ALIGN | MB_MEMINFO
.set MB_CHECKSUM, - (MB_MAGIC + MB_FLAGS)
.section .multiboot
.align 4
.long MB_MAGIC
.long MB_FLAGS
.long MB_CHECKSUM
.section .bss
.align 16
stack_bottom:
.skip 4096
stack_top:
.section .text
_start:
mov $stack_top, %esp
call kernel_main
hang:
cli
hlt
jmp hang
.size _start, . - _start
and kernel.c
#include <stddef.h>
#include <stdint.h>
const int a = 10;
void kernel_main()
{
uint8_t* video = (uint8_t*) 0xB8000;
const char* hello = "Hello World! From MYOS";
for (size_t i = 0; i < 23; i++)
{
video[2 * i] = hello[i];
video[2 * i + 1] = 0x07;
}
}
and linker.ld
ENTRY(_start);
SECTIONS {
. = 1M;
.rodata BLOCK(4K) : ALIGN(4K)
{
*(.multiboot)
}
.text BLOCK(4K) : ALIGN(4K)
{
*(.text)
}
.rodata BLOCK(4K) : ALIGN(4K)
{
*(.rodata)
}
.data BLOCK(4K) : ALIGN(4K)
{
*(.data)
}
.bss BLOCK(4K) : ALIGN(4K)
{
*(COMMON)
*(.bss)
}
}
and I compile these code:
i686-elf-gcc -std=gnu99 -ffreestanding -g -c start.s -o start.o
i686-elf-gcc -std=gnu99 -ffreestanding -g -c kernel.c -o kernel.o
i686-elf-gcc -ffreestanding -nostdlib -g -T linker.ld start.o kernel.o -o mykernel.elf -lgcc
I run this kernel, but got no multiboot header found.
if I modify kernel.c to:
#include <stddef.h>
#include <stdint.h>
const int a = 10; // Just add this line.
void kernel_main()
{
uint8_t* video = (uint8_t*) 0xB8000;
const char* hello = "Hello World! From MYOS";
for (size_t i = 0; i < 23; i++)
{
video[2 * i] = hello[i];
video[2 * i + 1] = 0x07;
}
}
Its work! Why?
my code here:
void _init(void) {return;}
int main(void)
{
/* STM32F2xx HAL library initialization:
- Configure the Flash prefetch, instruction and Data caches
- Configure the Systick to generate an interrupt each 1 msec
- Set NVIC Group Priority to 4
- Global MSP (MCU Support Package) initialization
*/
HAL_Init();
/* Configure the system clock to 64 MHz */
SystemClock_Config();
/* Enable CRC clock */
__CRC_CLK_ENABLE();
Example_Status = 1;
Example_Status = 2;
Example_Status = 3;
.....
and my gdb on my stm32 using stlink-texane are as follow:
(gdb) s
main () at main.c:74
74 __CRC_CLK_ENABLE();
(gdb) s
77 Example_Status = 3;
(gdb) p Example_status
No symbol "Example_status" in current context.
(gdb) p Example_Status
$1 = 139640994
(gdb) n
74 __CRC_CLK_ENABLE();
(gdb) n
77 Example_Status = 3;
(gdb) n
183 Example_Status = ExampleECCKeyGenSignVerif();
(gdb) p Example_Status
$2 = 139640994
i am wondering why the Example_Status outcome not = 3 ?
and the storage of the variable are
arm-none-eabi-objdump --syms main.o | grep Example_Status
00000000 l d .bss.Example_Status 00000000 .bss.Example_Status
00000000 g O .bss.Example_Status 00000004 Example_Status
and my linker file are here:
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = 0x20010000; /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x000;; /* required amount of heap */
_Min_Stack_Size = 0x000;; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_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) */
*(.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
/* Constant data goes into FLASH */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >FLASH
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >FLASH
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >FLASH
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >FLASH
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH
/* 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
/* 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
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}
This is my first linux project, i would appreicate if someone can help~
thanks
Edited for adding "disassemble /m"
75 Example_Status = 1;
0x080002ac <+24>: and.w r3, r3, #33554432 ; 0x2000000
0x080002b0 <+28>: cmp r3, #0
---Type <return> to continue, or q <return> to quit---
76 Example_Status = 2;
0x080002b2 <+30>: beq.n 0x80002a8 <main+20>
0x080002b4 <+32>: ldr r3, [pc, #60] ; (0x80002f4 <main+96>)
0x080002b6 <+34>: movw r2, #1795 ; 0x703
77 Example_Status = 3;
0x080002b8 <+36>: strb r3, [r0, #8]
0x080002ba <+38>: str r2, [r3, #0]
0x080002bc <+40>: ldr r2, [pc, #44] ; (0x80002ec <main+88>)
//
(gdb) n
75 Example_Status = 1;
(gdb) n
76 Example_Status = 2;
(gdb) p Example_Status
$1 = 140166176
(gdb) s
When compiling, and you want reliable debugging, do not compile with optimization-level higher than 0:
gcc -O0 mycode.c -o mycode.o -c
I made my own bootloader for an STM32L1 board.
My algorithm is simple :
- first, I erase the memory I need to write my new program on my flash.
- then, I write 4 bytes per 4 bytes my new program ( I receive it from the USART of the board)
then i push the RESET button of my card, and nothing happens ...
My new program should blink a LED but nothing happens and I d'ont understand why ...
Do i have to write my own RESET function?
Here is my code if you want to give a try.
void BootLoader(void) {
//clear all ITs
USART_ITConfig_boot( USART1, USART_IT_RXNE, 0);
uint32_t start_adr, end_adr;
uint8_t status, i;
uint8_t buffer[4096];
uint8_t sizeRcv[2];
uint16_t tailleSector = 0x1000;
uint32_t adr;
uint8_t nbSector = 0;
//size fixée en dur
uint16_t k = 0;
uint8_t size1 = 0;
uint8_t size2 = 0;
uint16_t sizeBin = 0;
//taille sector
uint16_t tailleSecteurDec = 4096;
SendString_boot("BOOTLOADER ON.....\r\n", USART2);
//adress
//First Sector
start_adr = WRITE_START_ADDR;
end_adr = start_adr + tailleSector;
//erasing flags
FLASH_ClearFlag_boot(
FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR
| FLASH_FLAG_SIZERR | FLASH_FLAG_OPTVERR
| FLASH_FLAG_OPTVERRUSR | FLASH_FLAG_RDERR);
FLASH_Unlock_boot();
sizeBin = 51400;
nbSector = (uint8_t) (sizeBin / tailleSecteurDec) + 1;
if(nbSector > 30){
SendString_boot("cannot overrite memory : too much sectors used\r\n",USART2);
}
for (i = 0; i <= (127 - 1); i++) {
if(end_adr < 0x0808FFFF){
status = Flash_Erase(start_adr, end_adr);
start_adr = end_adr;
end_adr = end_adr + tailleSector;
SendString_boot(" ERASING SECTOR DONE \r\n", USART2);
}
else{
SendString_boot("END OF FLASH MEMORY\r\n", USART2);
}
}
SendString_boot("ERASING COMPLETE\r\n", USART2);
start_adr = WRITE_START_ADDR;
//receive frames
adr = WRITE_START_ADDR;
do {
SendString_boot("ACK_READY", USART1);
SendString_boot("ACK_READY\r\n", USART2);
//receive 32 bytes
if (sizeBin - k > 4096)
Receive_Data_boot(buffer, 4096);
else
Receive_Data_boot(buffer, sizeBin - k);
//write 32 bytes in memory
if (sizeBin - k > 4096)
status = Flash_Write(adr, buffer, 4096);
else
status = Flash_Write(adr, buffer, sizeBin - k);
//on check si on ecrit bien au bon endroit
//increment cpt
k = k + 4096;
adr = adr + 0x1000;
i++;
//check CRC
//TODO
SendString_boot("...FLASH DONE ON ", USART2);
SendString_boot("\r\n", USART2);
SendString_boot(" SECTOR DONE \r\n", USART2);
} while (k < sizeBin);
SendString_boot("END", USART1);
SendString_boot("ACK_END\r\n", USART2);
FLASH_Lock_boot();
}
The linker script is:
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = 0x20014000; /* end of 96K RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
BOOT (rx) : ORIGIN = 0x0801E000, LENGTH = 8K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K-8K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 80K
MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_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) */
*(.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
/* Constant data goes into FLASH */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >FLASH
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >FLASH
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >FLASH
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >FLASH
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH
/* 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 */
*(.RamFunc) /* .RamFunc sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH
/* 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
/* 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);
} >RAM
/* MEMORY_bank1 section, code must be located here explicitly */
/* Example: extern int foo(void) __attribute__ ((section (".mb1text"))); */
.memory_b1_text :
{
*(.mb1text) /* .mb1text sections (code) */
*(.mb1text*) /* .mb1text* sections (code) */
*(.mb1rodata) /* read-only data (constants) */
*(.mb1rodata*)
} >MEMORY_B1
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.bootsection :
{
. = ALIGN(4);
KEEP(*(.bootsection)) /* Bootloader code */
. = ALIGN(4);
} >BOOT
.ARM.attributes 0 : { *(.ARM.attributes) }
}
Receive_data_boot code :
void Receive_Data_boot(uint8_t * buffer, int size) {
uint16_t i = 0;
do {
buffer[i] = Uart2ReadChar_boot();
i++;
} while (i < size);
}
uint8_t Uart2ReadChar_boot(void) {
while(USART_GetFlagStatus_boot(USART1, USART_FLAG_RXNE) == 0);
return USART_ReceiveData_boot(USART1);
}
uint16_t USART_ReceiveData_boot(USART_TypeDef_boot* USARTx)
{
/* Check the parameters */
assert_param(IS_USART_ALL_PERIPH_BOOT(USARTx));
SendChar_boot((uint8_t)USARTx->DR,USART1);
/* Receive Data */
return ((uint16_t)(USARTx->DR & (uint16_t)0x01FF));
}
To start your new program from FLASH after RESET the following conditions must be satisfied:
Written image contains correct Reset_Handler which will be executed after POR. Typically this is defined in startup.S and ended with something like:
bl SystemInit
bl main
bx lr
Pin BOOT0 of your processor must be set 0.
Example.
From startup.S:
.section .isr_vector,"a",%progbits
.type g_pfnVectors, %object
.size g_pfnVectors, .-g_pfnVectors
g_pfnVectors:
.word _estack
.word Reset_Handler
.word NMI_Handler
.word HardFault_Handler
...
From program assembly listing:
08008fd8 <Reset_Handler>:
.weak Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
/* Copy the data segment initializers from flash to SRAM */
movs r1, #0
8008fd8: 2100 movs r1, #0
From hex-file:
:020000040800F2
:1000000000000220D98F0008F9070008FD0700084A
Note address 0x08008fd9 in hex file (:1000000000000220D98F0008F9070008FD0700084A) that match Reset_Handler with LSB set (Thumb2-mode).
I got some evaluation board with uC STM32F405RG, this micro has ARM Cortext M4 core. Please find reference to the uC :
http://www.st.com/web/catalog/mmc/FM141/SC1169/SS1577/LN1035/PF252144#
I'm using also arm-none-eabi toolchain for linux from below site:
https://launchpad.net/gcc-arm-embedded
After compiling and linking some project I've noticed that linker puts extra padding bytes between mine global variables which are stored in .bss section. Please find short snippet from the map file:
.bss.variable1
0x20002d14 0x15 /path/to/application.o
.bss.variable2
0x20002d29 0x1 /path/to/application.o
.bss.variable3
0x20002d2a 0x1 /path/to/application.o
.bss.variable4
0x20002d2b 0x1 /path/to/application.o
.bss.variable5
0x20002d2c 0x1c /path/to/application.o
.bss.variable6
0x20002d48 0x1 /path/to/application.o
*fill* 0x20002d49 0x3
.bss.variable7
0x20002d4c 0x4 /path/to/application.o
.bss.variable8
0x20002d50 0x8 /path/to/application.o
.bss.variable9
0x20002d58 0x1c /path/to/application.o
.bss.variable10
0x20002d74 0x1 /path/to/application.o
Additionally here is my linker script:
ENTRY(Reset_Handler)
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000 + 256K, LENGTH = 1M - 256K -(3*128K)
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K
}
_stack_size = 16K;
_estack = ORIGIN(RAM) + LENGTH(RAM);
_sstack = _estack - _stack_size;
SECTIONS
{
.text :
{
_stext = .;
KEEP(*(.isr_vector))
. += 8;
*(.text)
*(.text*)
*(.rodata)
*(.rodata*)
*(.glue_7)
*(.glue_7t)
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .;
} >FLASH
.ARM.extab :
{
*(.ARM.extab*)
*(.gnu.linkonce.armextab.*)
} >FLASH
.ARM :
{
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >FLASH
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >FLASH
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >FLASH
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(.fini_array*))
KEEP (*(SORT(.fini_array.*)))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH
_sidata = .;
.data :
{
. = ALIGN(4);
_sdata = .;
*(.data)
*(.data*)
. = ALIGN(4);
_edata = .;
} >RAM AT> FLASH
. = ALIGN(4);
.bss :
{
_sbss = .;
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .;
__bss_end__ = _ebss;
} >RAM
.stack :
{
. += _stack_size;
} >RAM
.memory_b1_text :
{
*(.mb1text) /* .mb1text sections (code) */
*(.mb1text*) /* .mb1text* sections (code) */
*(.mb1rodata) /* read-only data (constants) */
*(.mb1rodata*)
} >MEMORY_B1
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}
Here is type declarations, they're distributed around few header files but I'm putting them here at once:
typedef enum
{
False=0,
True=1
} bool;
typedef enum
{
Unknown,
Data,
Crc
} type3_t;
typedef struct
{
unsigned char data[20];
unsigned char size;
} __attribute__((packed)) type1_t;
typedef enum
{
msg1,
msg2,
msg3
} msg_type_t
typedef struct
{
uint8_t msg;
uint32_t src;
uint32_t dest;
} header_t;
typedef struct
{
header_t header;
uint8_t len;
uint8_t id;
uint8_t idx;
uint8_t type;
} header2_t;
typedef struct
{
header2_t header;
uint8_t* data;
} ex_header_t;
typedef struct
{
msg_type_t type;
union
{
uint8_t * rawData;
header_t header;
ex_header_t ex_header;
} u;
uint8_t val;
} type5_t;
typedef struct
{
uint32_t id;
uint8_t idx;
uint8_t crc[2];
} type8_t;
and application.c file, I left order like in *.c file:
static type5_t variable5;
static type5_t variable9;
static type8_t variable8;
static type3_t variable3 = Unknown;
static type1_t variable1;
static bool variable10 = False;
static unsigned char variable6 = 0;
static bool variable4;
static unsigned char variable2 = 0;
/* few function definitions here */
static void * variable7;
The question is why arm-none-eabi-ld linker is doing so? Why linker cannot put in place of padding bytes, variables which are one byte big(e.g. chars) ? Everything is happening in the same translation unit so I think linker should be able to sort them and utilize more RAM memory. Even if one byte (char) or two bytes variables (short) are not present in the same translation unit, why shouldn't linker take them from other *.o files ?