diff --git a/.gitignore b/.gitignore index 0ee7235..dd08d26 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ *.ilk *.map *.exp +*.lst # Precompiled Headers *.gch @@ -36,6 +37,7 @@ *.i*86 *.x86_64 *.hex +*.bin # Debug files *.dSYM/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4908a51 --- /dev/null +++ b/Makefile @@ -0,0 +1,63 @@ +# Makefile -- stm32bringup +# Copyright (c) 2020 Renaud Fivet + +### Build environment selection + +ifeq (linux, $(findstring linux, $(MAKE_HOST))) +#GCCDIR = ~/Packages/gcc-arm-none-eabi-9-2019-q4-major + GCCDIR = ~/Packages/gcc-arm-none-eabi-9-2020-q2-update +else +#GCCDIR = "D:/Program Files (x86)/GNU Tools ARM Embedded/9 2019-q4-major" + GCCDIR = "D:/Program Files (x86)/GNU Arm Embedded Toolchain/9 2020-q2-update" +endif + +BINPFX = @$(GCCDIR)/bin/arm-none-eabi- +CC = $(BINPFX)gcc +LD = $(BINPFX)ld +OBJCOPY = $(BINPFX)objcopy +OBJDUMP = $(BINPFX)objdump +SIZE = $(BINPFX)size + +### STM32F030F4P6 based board + +PROJECT = f030f4 +#SRCS = boot.c +#SRCS = ledon.c +#SRCS = blink.c +#SRCS = ledtick.c +#SRCS = cstartup.c +SRCS = startup.c init.c success.c +OBJS = $(SRCS:.c=.o) +CPU = -mthumb -mcpu=cortex-m0 +CFLAGS = $(CPU) -g -Wall -Wextra -Os +LD_SCRIPT = $(PROJECT).ld + +### Build rules + +.PHONY: clean all + +all: $(PROJECT).hex $(PROJECT).bin + +clean: + @echo CLEAN + @rm -f *.o *.elf *.map *.lst *.bin *.hex + +$(PROJECT).elf: $(OBJS) + @echo $@ + $(LD) -T$(LD_SCRIPT) -Map=$(PROJECT).map -cref -o $@ $(OBJS) + $(SIZE) $@ + $(OBJDUMP) -hS $@ > $(PROJECT).lst + +%.elf: %.o + @echo $@ + $(LD) -T$(LD_SCRIPT) -Map=$*.map -cref -o $@ $< + $(SIZE) $@ + $(OBJDUMP) -hS $@ > $*.lst + +%.bin: %.elf + @echo $@ + $(OBJCOPY) -O binary $< $@ + +%.hex: %.elf + @echo $@ + $(OBJCOPY) -O ihex $< $@ diff --git a/blink.c b/blink.c new file mode 100644 index 0000000..170db90 --- /dev/null +++ b/blink.c @@ -0,0 +1,45 @@ +/* blink.c -- user LED blink +** Copyright (c) 2020 Renaud Fivet +*/ + +/* Memory locations defined by linker script */ +extern long __StackTop ; /* &__StackTop points after end of stack */ +void Reset_Handler( void) ; /* Entry point for execution */ + +/* Interrupt vector table: + * 1 Stack Pointer reset value + * 15 System Exceptions + * NN Device specific Interrupts + */ +typedef void (*isr_p)( void) ; +isr_p const isr_vector[ 2] __attribute__((section(".isr_vector"))) = { + (isr_p) &__StackTop, +/* System Exceptions */ + Reset_Handler +} ; + +#define RCC ((volatile long *) 0x40021000) +#define RCC_AHBENR RCC[ 5] +#define RCC_AHBENR_IOPBEN 0x00040000 /* 18: I/O port B clock enable */ + +#define GPIOB ((volatile long *) 0x48000400) +#define GPIOB_MODER GPIOB[ 0] +#define GPIOB_ODR GPIOB[ 5] + +void Reset_Handler( void) { + int delay ; + +/* User LED ON */ + RCC_AHBENR |= RCC_AHBENR_IOPBEN ; /* Enable IOPB periph */ + GPIOB_MODER |= 1 << (1 * 2) ; /* PB1 Output [01], over default 00 */ + /* OTYPER Push-Pull by default */ + /* PB1 output default LOW at reset */ + +/* User LED blink */ + for( ;;) { + for( delay = 1000000 ; delay ; delay--) ; /* delay between toggling */ + GPIOB_ODR ^= 1 << 1 ; /* toggle PB1 (User LED) */ + } +} + +/* end of blink.c */ diff --git a/boot.c b/boot.c new file mode 100644 index 0000000..ff53838 --- /dev/null +++ b/boot.c @@ -0,0 +1,25 @@ +/* boot.c -- entry point at reset +** Copyright (c) 2020 Renaud Fivet +*/ + +/* Memory locations defined by linker script */ +extern long __StackTop ; /* &__StackTop points after end of stack */ +void Reset_Handler( void) ; /* Entry point for execution */ + +/* Interrupt vector table: + * 1 Stack Pointer reset value + * 15 System Exceptions + * NN Device specific Interrupts + */ +typedef void (*isr_p)( void) ; +isr_p const isr_vector[ 2] __attribute__((section(".isr_vector"))) = { + (isr_p) &__StackTop, +/* System Exceptions */ + Reset_Handler +} ; + +void Reset_Handler( void) { + for( ;;) ; +} + +/* end of boot.c */ diff --git a/cstartup.c b/cstartup.c new file mode 100644 index 0000000..7ab17e8 --- /dev/null +++ b/cstartup.c @@ -0,0 +1,61 @@ +/* cstartup.c -- data and bss RAM memory initialization +** Copyright (c) 2020 Renaud Fivet +*/ + +/* Memory locations defined by linker script */ +extern long __StackTop ; /* &__StackTop points after end of stack */ +void Reset_Handler( void) ; /* Entry point for execution */ +extern const long __etext[] ; /* start of initialized data copy in flash */ +extern long __data_start__[] ; +extern long __bss_start__[] ; +extern long __bss_end__ ; /* &__bss_end__ points after end of bss */ + +/* Interrupt vector table: + * 1 Stack Pointer reset value + * 15 System Exceptions + * NN Device specific Interrupts + */ +typedef void (*isr_p)( void) ; +isr_p const isr_vector[ 2] __attribute__((section(".isr_vector"))) = { + (isr_p) &__StackTop, +/* System Exceptions */ + Reset_Handler +} ; + +extern int main( void) ; + +void Reset_Handler( void) { + const long *f ; /* from, source constant data from FLASH */ + long *t ; /* to, destination in RAM */ + +/* Assume: +** __bss_start__ == __data_end__ +** All sections are 4 bytes aligned +*/ + f = __etext ; + for( t = __data_start__ ; t < __bss_start__ ; t += 1) + *t = *f++ ; + + while( t < &__bss_end__) + *t++ = 0 ; + + main() ; + for( ;;) ; +} + +/** Test code: main.c *********************************************************/ + +const char hexa[] = "0123456789abcdef" ; +long first = 1 ; +long i ; + +int main( void) { + static char c = 'a' ; + char *cp = &c ; + + *cp += i ; + i += hexa[ 13] - c + first++ ; + return 0 ; +} + +/* end of cstartup.c */ diff --git a/f030f4.ld b/f030f4.ld new file mode 100644 index 0000000..78b8518 --- /dev/null +++ b/f030f4.ld @@ -0,0 +1,196 @@ +/* Linker script to configure memory regions. + * Need modifying for a specific board. + * FLASH.ORIGIN: starting address of flash + * FLASH.LENGTH: length of flash + * RAM.ORIGIN: starting address of RAM bank 0 + * RAM.LENGTH: length of RAM bank 0 + */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 16K + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 4K +} + +/* Linker script to place sections and symbol values. Should be used together + * with other linker script that defines memory regions FLASH and RAM. + * It references following symbols, which must be defined in code: + * Reset_Handler : Entry of reset handler + * + * It defines following symbols, which code can use without definition: + * __exidx_start + * __exidx_end + * __copy_table_start__ + * __copy_table_end__ + * __zero_table_start__ + * __zero_table_end__ + * __etext + * __data_start__ + * __preinit_array_start + * __preinit_array_end + * __init_array_start + * __init_array_end + * __fini_array_start + * __fini_array_end + * __data_end__ + * __bss_start__ + * __bss_end__ + * __end__ + * end + * __HeapLimit + * __StackLimit + * __StackTop + * __stack + */ +ENTRY(Reset_Handler) + +SECTIONS +{ + .text : + { + KEEP(*(.isr_vector)) + *(.text*) + + *(.init) + *(.fini) + + /* .ctors */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + + /* .dtors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + *(.rodata*) + + *(.eh_frame*) + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + /* To copy multiple ROM to RAM sections, + * uncomment .copy.table section and, + * define __STARTUP_COPY_MULTIPLE in startup_ARMCMx.S */ + /* + .copy.table : + { + . = ALIGN(4); + __copy_table_start__ = .; + LONG (__etext) + LONG (__data_start__) + LONG (__data_end__ - __data_start__) + LONG (__etext2) + LONG (__data2_start__) + LONG (__data2_end__ - __data2_start__) + __copy_table_end__ = .; + } > FLASH + */ + + /* To clear multiple BSS sections, + * uncomment .zero.table section and, + * define __STARTUP_CLEAR_BSS_MULTIPLE in startup_ARMCMx.S */ + /* + .zero.table : + { + . = ALIGN(4); + __zero_table_start__ = .; + LONG (__bss_start__) + LONG (__bss_end__ - __bss_start__) + LONG (__bss2_start__) + LONG (__bss2_end__ - __bss2_start__) + __zero_table_end__ = .; + } > FLASH + */ + + /* Location counter can end up 2byte aligned with narrow Thumb code but + __etext is assumed by startup code to be the LMA of a section in RAM + which must be 4byte aligned */ + __etext = ALIGN (4); + + .data : AT (__etext) + { + __data_start__ = .; + *(vtable) + *(.data*) + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + *(.preinit_array) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + *(SORT(.init_array.*)) + *(.init_array) + PROVIDE_HIDDEN (__init_array_end = .); + + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + *(SORT(.fini_array.*)) + *(.fini_array) + PROVIDE_HIDDEN (__fini_array_end = .); + + *(.jcr) + . = ALIGN(4); + /* All data end */ + __data_end__ = .; + + } > RAM + + .bss : + { + . = ALIGN(4); + __bss_start__ = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + } > RAM + + .heap (COPY): + { + __end__ = .; + PROVIDE(end = .); + *(.heap*) + __HeapLimit = .; + } > RAM + + /* .stack_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later */ + .stack_dummy (COPY): + { + *(.stack*) + } > RAM + + /* Set stack top to end of RAM, and stack limit move down by + * size of stack_dummy section */ + __StackTop = ORIGIN(RAM) + LENGTH(RAM); + __StackLimit = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + PROVIDE(__data_size = __bss_start__ - __data_start__); + PROVIDE(__bss_size = __bss_end__ - __bss_start__); + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") +} diff --git a/init.c b/init.c new file mode 100644 index 0000000..cd223de --- /dev/null +++ b/init.c @@ -0,0 +1,40 @@ +/* init.c -- middleware initialization +** Copyright (c) 2020 Renaud Fivet +*/ + +#define SYSTICK ((volatile long *) 0xE000E010) +#define SYSTICK_CSR SYSTICK[ 0] +#define SYSTICK_RVR SYSTICK[ 1] +#define SYSTICK_CVR SYSTICK[ 2] + +#define RCC ((volatile long *) 0x40021000) +#define RCC_AHBENR RCC[ 5] +#define RCC_AHBENR_IOPBEN 0x00040000 /* 18: I/O port B clock enable */ + +#define GPIOB ((volatile long *) 0x48000400) +#define GPIOB_MODER GPIOB[ 0] +#define GPIOB_ODR GPIOB[ 5] + +int init( void) { +/* By default SYSCLK == HSI [8MHZ] */ + +/* SYSTICK */ + SYSTICK_RVR = 1000000 - 1 ; /* HBA / 8 */ + SYSTICK_CVR = 0 ; + SYSTICK_CSR = 3 ; /* HBA / 8, Interrupt ON, Enable */ + /* SysTick_Handler will execute every 1s from now on */ + +/* User LED ON */ + RCC_AHBENR |= RCC_AHBENR_IOPBEN ; /* Enable IOPB periph */ + GPIOB_MODER |= 1 << (1 * 2) ; /* PB1 Output [01], over default 00 */ + /* OTYPER Push-Pull by default */ + /* PB1 output default LOW at reset */ + + return 0 ; +} + +void SysTick_Handler( void) { + GPIOB_ODR ^= 1 << 1 ; /* Toggle PB1 (User LED) */ +} + +/* end of init.c */ diff --git a/ledon.c b/ledon.c new file mode 100644 index 0000000..028aadb --- /dev/null +++ b/ledon.c @@ -0,0 +1,37 @@ +/* ledon.c -- user LED on +** Copyright (c) 2020 Renaud Fivet +*/ + +/* Memory locations defined by linker script */ +extern long __StackTop ; /* &__StackTop points after end of stack */ +void Reset_Handler( void) ; /* Entry point for execution */ + +/* Interrupt vector table: + * 1 Stack Pointer reset value + * 15 System Exceptions + * NN Device specific Interrupts + */ +typedef void (*isr_p)( void) ; +isr_p const isr_vector[ 2] __attribute__((section(".isr_vector"))) = { + (isr_p) &__StackTop, +/* System Exceptions */ + Reset_Handler +} ; + +#define RCC ((volatile long *) 0x40021000) +#define RCC_AHBENR RCC[ 5] +#define RCC_AHBENR_IOPBEN 0x00040000 /* 18: I/O port B clock enable */ + +#define GPIOB ((volatile long *) 0x48000400) +#define GPIOB_MODER GPIOB[ 0] + +void Reset_Handler( void) { +/* User LED ON */ + RCC_AHBENR |= RCC_AHBENR_IOPBEN ; /* Enable IOPB periph */ + GPIOB_MODER |= 1 << (1 * 2) ; /* PB1 Output [01], over default 00 */ + /* OTYPER Push-Pull by default */ + /* PB1 output default LOW at reset */ + for( ;;) ; +} + +/* end of ledon.c */ diff --git a/ledtick.c b/ledtick.c new file mode 100644 index 0000000..e261752 --- /dev/null +++ b/ledtick.c @@ -0,0 +1,61 @@ +/* ledtick.c -- System Tick driven user LED blink +** Copyright (c) 2020 Renaud Fivet +*/ + +/* Memory locations defined by linker script */ +extern long __StackTop ; /* &__StackTop points after end of stack */ +void Reset_Handler( void) ; /* Entry point for execution */ + +void SysTick_Handler( void) ; + +/* Interrupt vector table: + * 1 Stack Pointer reset value + * 15 System Exceptions + * NN Device specific Interrupts + */ +typedef void (*isr_p)( void) ; +isr_p const isr_vector[ 16] __attribute__((section(".isr_vector"))) = { + (isr_p) &__StackTop, +/* System Exceptions */ + Reset_Handler, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + SysTick_Handler +} ; + +#define SYSTICK ((volatile long *) 0xE000E010) +#define SYSTICK_CSR SYSTICK[ 0] +#define SYSTICK_RVR SYSTICK[ 1] +#define SYSTICK_CVR SYSTICK[ 2] + +#define RCC ((volatile long *) 0x40021000) +#define RCC_AHBENR RCC[ 5] +#define RCC_AHBENR_IOPBEN 0x00040000 /* 18: I/O port B clock enable */ + +#define GPIOB ((volatile long *) 0x48000400) +#define GPIOB_MODER GPIOB[ 0] +#define GPIOB_ODR GPIOB[ 5] + +void Reset_Handler( void) { +/* By default SYSCLK == HSI [8MHZ] */ + +/* SYSTICK */ + SYSTICK_RVR = 1000000 - 1 ; /* HBA / 8 */ + SYSTICK_CVR = 0 ; + SYSTICK_CSR = 3 ; /* HBA / 8, Interrupt ON, Enable */ + /* SysTick_Handler will execute every 1s from now on */ + +/* User LED ON */ + RCC_AHBENR |= RCC_AHBENR_IOPBEN ; /* Enable IOPB periph */ + GPIOB_MODER |= 1 << (1 * 2) ; /* PB1 Output [01], over default 00 */ + /* OTYPER Push-Pull by default */ + /* PB1 output default LOW at reset */ + + for( ;;) + __asm( "WFI") ; /* Wait for interrupt */ +} + +void SysTick_Handler( void) { + GPIOB_ODR ^= 1 << 1 ; /* Toggle PB1 (User LED) */ +} + +/* end of ledtick.c */ diff --git a/startup.c b/startup.c new file mode 100644 index 0000000..052e540 --- /dev/null +++ b/startup.c @@ -0,0 +1,71 @@ +/* startup.c -- entry point at reset and C startup +** Copyright (c) 2020 Renaud Fivet +*/ + +/* Memory locations defined by linker script */ +extern long __StackTop ; /* &__StackTop points after end of stack */ +void Reset_Handler( void) ; /* Entry point for execution */ +extern const long __etext[] ; /* start of initialized data copy in flash */ +extern long __data_start__[] ; +extern long __bss_start__[] ; +extern long __bss_end__ ; /* &__bss_end__ points after end of bss */ + +/* Stubs for System Exception Handler */ +void Default_Handler( void) ; +#define dflt_hndlr( fun) void fun##_Handler( void) \ + __attribute__((weak,alias("Default_Handler"))) +dflt_hndlr( NMI) ; +dflt_hndlr( HardFault) ; +dflt_hndlr( SVCall) ; +dflt_hndlr( PendSV) ; +dflt_hndlr( SysTick) ; + +/* Interrupt vector table: + * 1 Stack Pointer reset value + * 15 System Exceptions + * NN Device specific Interrupts + */ +typedef void (*isr_p)( void) ; +isr_p const isr_vector[ 16] __attribute__((section(".isr_vector"))) = { + (isr_p) &__StackTop, +/* System Exceptions */ + Reset_Handler, + NMI_Handler, + HardFault_Handler, + 0, 0, 0, 0, 0, 0, 0, + SVCall_Handler, + 0, 0, + PendSV_Handler, + SysTick_Handler +} ; + +extern int init( void) ; +extern int main( void) ; + +void Reset_Handler( void) { + const long *f ; /* from, source constant data from FLASH */ + long *t ; /* to, destination in RAM */ + +/* Assume: +** __bss_start__ == __data_end__ +** All sections are 4 bytes aligned +*/ + f = __etext ; + for( t = __data_start__ ; t < __bss_start__ ; t += 1) + *t = *f++ ; + + while( t < &__bss_end__) + *t++ = 0 ; + + if( init() == 0) + main() ; + + for( ;;) + __asm( "WFI") ; /* Wait for interrupt */ +} + +void Default_Handler( void) { + for( ;;) ; +} + +/* end of startup.c */ diff --git a/success.c b/success.c new file mode 100644 index 0000000..6fb0c39 --- /dev/null +++ b/success.c @@ -0,0 +1,11 @@ +/* success.c -- success does nothing, successfully +** Copyright (c) 2020 Renaud Fivet +*/ + +#include + +int main( void) { + return EXIT_SUCCESS ; +} + +/* end of success.c */