diff options
Diffstat (limited to 'src/stm')
-rw-r--r-- | src/stm/altos-application.ld | 17 | ||||
-rw-r--r-- | src/stm/altos-loader.ld | 13 | ||||
-rw-r--r-- | src/stm/ao_boot.h | 11 | ||||
-rw-r--r-- | src/stm/ao_boot_chain.c | 62 | ||||
-rw-r--r-- | src/stm/ao_boot_pin.c | 43 | ||||
-rw-r--r-- | src/stm/ao_interrupt.c | 64 |
6 files changed, 147 insertions, 63 deletions
diff --git a/src/stm/altos-application.ld b/src/stm/altos-application.ld index 63a3be00..5110da84 100644 --- a/src/stm/altos-application.ld +++ b/src/stm/altos-application.ld @@ -48,16 +48,27 @@ SECTIONS { __text_end__ = .; } > rom + /* Boot data which must live at the start of ram so that + * the application and bootloader share the same addresses. + * This must be all uninitialized data + */ + .boot : { + __boot_start__ = .; + *(.boot) + . = ALIGN(4); + __boot_end__ = .; + } >ram + /* Data -- relocated to RAM, but written to ROM */ - .data ORIGIN(ram) : AT (ADDR(.ARM.exidx) + SIZEOF (.ARM.exidx)) { + .data : { __data_start__ = .; *(.data) /* initialized data */ __data_end__ = .; - __bss_start__ = .; - } >ram + } >ram AT>rom .bss : { + __bss_start__ = .; *(.bss) *(COMMON) __bss_end__ = .; diff --git a/src/stm/altos-loader.ld b/src/stm/altos-loader.ld index 50a425c7..2e36dce9 100644 --- a/src/stm/altos-loader.ld +++ b/src/stm/altos-loader.ld @@ -48,9 +48,20 @@ SECTIONS { } > rom __text_end__ = .; + /* Boot data which must live at the start of ram so that + * the application and bootloader share the same addresses. + * This must be all uninitialized data + */ + .boot : { + __boot_start__ = .; + *(.boot) + . = ALIGN(4); + __boot_end__ = .; + } >ram + /* Functions placed in RAM (required for flashing) */ .textram : { - __text_ram_start = .; + __text_ram_start__ = .; __data_start__ = .; *(.text.ram) . = ALIGN(4); diff --git a/src/stm/ao_boot.h b/src/stm/ao_boot.h index 863d8e05..3e8c50ba 100644 --- a/src/stm/ao_boot.h +++ b/src/stm/ao_boot.h @@ -19,6 +19,15 @@ #define _AO_BOOT_H_ void -ao_reboot_application(void); +ao_boot_chain(uint32_t *base); + +void +ao_boot_check_pin(void); + +void +ao_boot_check_chain(void); + +void +ao_boot_reboot(uint32_t *base); #endif /* _AO_BOOT_H_ */ diff --git a/src/stm/ao_boot_chain.c b/src/stm/ao_boot_chain.c new file mode 100644 index 00000000..9c63272b --- /dev/null +++ b/src/stm/ao_boot_chain.c @@ -0,0 +1,62 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <ao.h> +#include <ao_boot.h> + +void +ao_boot_chain(uint32_t *base) +{ + uint32_t sp; + uint32_t pc; + + sp = base[0]; + pc = base[1]; + asm ("mov sp, %0" : : "r" (sp)); + asm ("mov lr, %0" : : "r" (pc)); + asm ("bx lr"); +} + +#define AO_BOOT_SIGNAL 0x5a5aa5a5 +#define AO_BOOT_CHECK 0xc3c33c3c + +struct ao_boot { + uint32_t *base; + uint32_t signal; + uint32_t check; +}; + +static struct ao_boot __attribute__ ((section(".boot"))) ao_boot; + +void +ao_boot_check_chain(void) +{ + if (ao_boot.signal == AO_BOOT_SIGNAL && ao_boot.check == AO_BOOT_CHECK) { + ao_boot.signal = 0; + ao_boot.check = 0; + ao_boot_chain(ao_boot.base); + } +} + +void +ao_boot_reboot(uint32_t *base) +{ + ao_boot.base = base; + ao_boot.signal = AO_BOOT_SIGNAL; + ao_boot.check = AO_BOOT_CHECK; + ao_arch_reboot(); +} diff --git a/src/stm/ao_boot_pin.c b/src/stm/ao_boot_pin.c new file mode 100644 index 00000000..03b0214f --- /dev/null +++ b/src/stm/ao_boot_pin.c @@ -0,0 +1,43 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <ao.h> +#include <ao_boot.h> +#include <ao_exti.h> + +void +ao_boot_check_pin(void) +{ + uint16_t v; + + /* Enable power interface clock */ + stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_PWREN); + + /* Enable the input pin */ + ao_enable_input(&AO_BOOT_APPLICATION_GPIO, AO_BOOT_APPLICATION_PIN, + AO_BOOT_APPLICATION_MODE); + + /* Read the value */ + v = stm_gpio_get(&AO_BOOT_APPLICATION_GPIO, AO_BOOT_APPLICATION_PIN); + + /* Reset the chip to turn off the port and the power interface clock */ + ao_gpio_set_mode(&AO_BOOT_APPLICATION_GPIO, AO_BOOT_APPLICATION_PIN, 0); + ao_disable_port(&AO_BOOT_APPLICATION_GPIO); + stm_rcc.apb1enr &= ~(1 << STM_RCC_APB1ENR_PWREN); + if (v == AO_BOOT_APPLICATION_VALUE) + ao_boot_chain(AO_BOOT_APPLICATION_BASE); +} diff --git a/src/stm/ao_interrupt.c b/src/stm/ao_interrupt.c index 9e756219..49156285 100644 --- a/src/stm/ao_interrupt.c +++ b/src/stm/ao_interrupt.c @@ -18,6 +18,7 @@ #include <ao.h> #include "stm32l.h" #include <string.h> +#include <ao_boot.h> extern void main(void); extern char __stack__; @@ -38,67 +39,14 @@ void stm_ignore_isr(void) const void *stm_interrupt_vector[]; -#define BOOT_FETCH(o) (*((uint32_t *) (AO_BOOT_APPLICATION_BASE + (o)))) - -#ifdef AO_BOOT_APPLICATION_PIN -#include <ao_exti.h> - -#define AO_BOOT_APPLICATION 0x5a5aa5a5 -#define AO_BOOT_APPLICATION_CHECK 0xc3c33c3c - -static uint32_t ao_boot_application; -static uint32_t ao_boot_application_check; - -static void -ao_boot_chain(void) { - uint32_t sp; - uint32_t pc; - - sp = BOOT_FETCH(0); - pc = BOOT_FETCH(4); - asm ("mov sp, %0" : : "r" (sp)); - asm ("mov lr, %0" : : "r" (pc)); - asm ("bx lr"); -} - -void -ao_reboot_application(void) +void start(void) { - ao_boot_application = AO_BOOT_APPLICATION; - ao_boot_application_check = AO_BOOT_APPLICATION_CHECK; - ao_arch_reboot(); -} - +#ifdef AO_BOOT_CHAIN + ao_boot_check_chain(); #endif - -void start(void) { -#ifdef AO_BOOT_APPLICATION_PIN - uint16_t v; - - if (ao_boot_application == AO_BOOT_APPLICATION && - ao_boot_application_check == AO_BOOT_APPLICATION_CHECK) { - ao_boot_application = 0; - ao_boot_application_check = 0; - ao_boot_chain(); - } - /* Enable power interface clock */ - stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_PWREN); - - /* Enable the input pin */ - ao_enable_input(&AO_BOOT_APPLICATION_GPIO, AO_BOOT_APPLICATION_PIN, - AO_BOOT_APPLICATION_MODE); - - /* Read the value */ - v = stm_gpio_get(&AO_BOOT_APPLICATION_GPIO, AO_BOOT_APPLICATION_PIN); - - /* Reset the chip to turn off the port and the power interface clock */ - ao_gpio_set_mode(&AO_BOOT_APPLICATION_GPIO, AO_BOOT_APPLICATION_PIN, 0); - ao_disable_port(&AO_BOOT_APPLICATION_GPIO); - stm_rcc.apb1enr &= ~(1 << STM_RCC_APB1ENR_PWREN); - if (v == AO_BOOT_APPLICATION_VALUE) - ao_boot_chain(); +#ifdef AO_BOOT_PIN + ao_boot_check_pin(); #endif - /* Set interrupt vector table offset */ stm_nvic.vto = (uint32_t) &stm_interrupt_vector; memcpy(&__data_start__, &__text_end__, &__data_end__ - &__data_start__); |