From ef77ec527dc0459e75cbe7f295a671cbd677e575 Mon Sep 17 00:00:00 2001 From: Renaud Fivet Date: Tue, 24 Nov 2020 10:48:35 +0800 Subject: [PATCH] Entry at reset, C startup, user LED driven by System Tick on STM32F030F4. --- .gitignore | 2 + Makefile | 63 +++++++++++++++++ blink.c | 45 ++++++++++++ boot.c | 25 +++++++ cstartup.c | 61 +++++++++++++++++ f030f4.ld | 196 +++++++++++++++++++++++++++++++++++++++++++++++++++++ init.c | 40 +++++++++++ ledon.c | 37 ++++++++++ ledtick.c | 61 +++++++++++++++++ startup.c | 71 +++++++++++++++++++ success.c | 11 +++ 11 files changed, 612 insertions(+) create mode 100644 Makefile create mode 100644 blink.c create mode 100644 boot.c create mode 100644 cstartup.c create mode 100644 f030f4.ld create mode 100644 init.c create mode 100644 ledon.c create mode 100644 ledtick.c create mode 100644 startup.c create mode 100644 success.c 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 */