STM32/ARM Cortex-M3 HOWTO: Development under Ubuntu (Debian)

The mini example part two.

However we still has to much in the main.c file, there is no real good reason to have the NVIC part there.

So let's move the NVIC "array" out from the main.c and into a assembly file. (As a little bonus this will give us more control).

This is all that is left in main.c.

Filename: main.c

int main(void)
{
    int i=0;

    while(1)
    {
        i++;
    }
}

But let's look in the assembly file and see where we will find the NVIC data. Please also note that this file actually is a scaled downed version of a more advanced one found in standard peripheral library from ST, that I will use later.

Filename: startup_stm32f10x.s

    .syntax unified
    .cpu cortex-m3
    .fpu softvfp
    .thumb

    .global  Default_Handler
    .global  g_pfnVectors
    .global  .isr_vector


    .section  .text.Default_Handler,"ax",%progbits 
Default_Handler: 
Infinite_Loop: 
    nop
    b  Infinite_Loop 
    .size  Default_Handler, .-Default_Handler 


    .section  .isr_vector,"a",%progbits
    .type  g_pfnVectors, %object
    .size  g_pfnVectors, .-g_pfnVectors
    
#SP 0x20000000+0x4FFC = 20 476 ~ 20k RAM    
g_pfnVectors:
  .word  0x20004FFC 
  .word  main 
  .word  Default_Handler
  .word  Default_Handler
   

So if we compare g_pfnVectors with the old myvectors (the NVIC arrays).

unsigned int * myvectors[4] __attribute__ ((section("vectors")))= {
    (unsigned int *)    STACK_TOP,         // stack pointer
    (unsigned int *)    main,              // code entry point
    (unsigned int *)    nmi_handler,       // NMI handler (not really)
    (unsigned int *)    hardfault_handler  // hard fault handler (let's hope not)
};


    .section  .isr_vector,"a",%progbits
    .type  g_pfnVectors, %object
    .size  g_pfnVectors, .-g_pfnVectors

g_pfnVectors:
    .word  0x20004FFC 
    .word  main 
    .word  Default_Handler
    .word  Default_Handler

We will see that it is only the syntax that change, they really do exactly the same. But for this to be true we must however also change the linker file, stm32.ld, since we need to tell the linker to use another array at address 0x0.

Filename: stm32.ld

MEMORY
{
    ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
    rom (rx) :  ORIGIN = 0x00000000, LENGTH = 128K
}
SECTIONS
{
    .  = 0x0;           /* From 0x00000000 */
    .text : 
    {
        *(.isr_vector)  /* Vector table */
        *(.text.*)      /* Program code */
        *(.text)        /* Program code */
        *(.rodata)      /* Read only data */
    } >rom

    .  = 0x20000000;    /* From 0x20000000 */      
    .data : 
    {
        *(.data)        /* Data memory */
    } >ram AT > rom

    .bss : 
    {
        *(.bss)         /* Zero-filled run time allocate data memory */
    } >ram AT > rom
}  

If we compare with the old version, you can see that vectors is now called .isr_vector.

.  = 0x0;         /* From 0x00000000 */
.text : 
{
    *(vectors)    /* Vector table */

...

.  = 0x0;           /* From 0x00000000 */
.text : 
{
    *(.isr_vector)  /* Vector table */
    *(.text.*)      /* Program code */

The linker will look for .section in the assembler file, and in this case .isr_vector points at g_pfnVectors that holds the NVIC data.

Another thing is that we also moved the error handling away from the c-file, and into the assembler file (but let's save that for later).

Then we need to modify the Makefile so that the assembler file will be compiled and linked in with the rest.

Filename: Makefile

CC      = arm-none-eabi-gcc
LD      = arm-none-eabi-ld -v
AR      = arm-none-eabi-ar
AS      = arm-none-eabi-as
CP      = arm-none-eabi-objcopy
OD      = arm-none-eabi-objdump
  
CFLAGS  =  -I./ -c -fno-common -O0 -g -mcpu=cortex-m3 -mthumb  
AFLAGS  = -ahls -mcpu=cortex-m3 -mthumb 
LFLAGS  = -Tstm32.ld -nostartfiles
CPFLAGS = -Obinary
ODFLAGS = -S

all: test

clean:
	-rm main.lst main.o main.elf main.lst main.bin startup_stm32f10x.lst startup_stm32f10x.o

test: main.elf
	@ echo "...copying"
	$(CP) $(CPFLAGS) main.elf main.bin
	$(OD) $(ODFLAGS) main.elf > main.lst

main.elf: main.o startup_stm32f10x.o stm32.ld  
	@ echo "..linking"
	$(LD) $(LFLAGS) -o main.elf main.o startup_stm32f10x.o

main.o: main.c
	@ echo ".compiling"
	$(CC) $(CFLAGS) main.c

startup_stm32f10x.o: startup_stm32f10x.s
	@ echo ".assembling"
	$(AS) $(AFLAGS) -o startup_stm32f10x.o startup_stm32f10x.s > startup_stm32f10x.lst

Now we have a nice little foundation that we can expand in whatever direction we want to :)

Fatal error: Uncaught Error: Call to a member function link_ext() on null in /customers/9/b/5/fun-tech.se/httpd.www/stm32/class.page.php:62 Stack trace: #0 /customers/9/b/5/fun-tech.se/httpd.www/stm32/OlimexBlinky/mini2.php(125): page->getFoot() #1 {main} thrown in /customers/9/b/5/fun-tech.se/httpd.www/stm32/class.page.php on line 62