From: Keith Packard Date: Mon, 11 Mar 2013 20:21:04 +0000 (-0700) Subject: altos: Clean up boot loader support X-Git-Tag: 1.2.1~55 X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=commitdiff_plain;h=b1a43ce313c85cb7f8f16f7f0647d9d4320ba692 altos: Clean up boot loader support Split out code into separate files. Add support for getting back to boot loader from application. Signed-off-by: Keith Packard --- diff --git a/src/stm-demo/Makefile b/src/stm-demo/Makefile index ab12f47b..e6cd55e4 100644 --- a/src/stm-demo/Makefile +++ b/src/stm-demo/Makefile @@ -17,6 +17,7 @@ INC = \ # ALTOS_SRC = \ ao_interrupt.c \ + ao_boot_chain.c \ ao_product.c \ ao_romconfig.c \ ao_cmd.c \ diff --git a/src/stm-demo/ao_demo.c b/src/stm-demo/ao_demo.c index 9ee0be03..ec572fdc 100644 --- a/src/stm-demo/ao_demo.c +++ b/src/stm-demo/ao_demo.c @@ -20,6 +20,7 @@ #include #include #include +#include struct ao_task demo_task; @@ -168,6 +169,13 @@ ao_event(void) } +static void +ao_boot_loader(void) +{ + flush(); + ao_boot_reboot((uint32_t *) 0); +} + __code struct ao_cmds ao_demo_cmds[] = { { ao_dma_test, "D\0DMA test" }, { ao_spi_write, "W\0SPI write" }, @@ -175,6 +183,7 @@ __code struct ao_cmds ao_demo_cmds[] = { { ao_i2c_write, "i\0I2C write" }, { ao_temp, "t\0Show temp" }, { ao_event, "e\0Monitor event queue" }, + { ao_boot_loader, "L\0Reboot to boot loader" }, { 0, NULL } }; diff --git a/src/stm-demo/ao_pins.h b/src/stm-demo/ao_pins.h index 07b4a19d..40e48a36 100644 --- a/src/stm-demo/ao_pins.h +++ b/src/stm-demo/ao_pins.h @@ -68,6 +68,8 @@ #define HAS_BEEP 0 #define PACKET_HAS_SLAVE 0 +#define AO_BOOT_CHAIN 1 + #define LOW_LEVEL_DEBUG 1 #define LED_PORT_ENABLE STM_RCC_AHBENR_GPIOBEN diff --git a/src/stm-flash/Makefile b/src/stm-flash/Makefile index 3c7b4966..e4a2f321 100644 --- a/src/stm-flash/Makefile +++ b/src/stm-flash/Makefile @@ -17,6 +17,8 @@ INC = \ # ALTOS_SRC = \ ao_interrupt.c \ + ao_boot_chain.c \ + ao_boot_pin.c \ ao_product.c \ ao_romconfig.c \ ao_task.c \ diff --git a/src/stm-flash/ao_pins.h b/src/stm-flash/ao_pins.h index ca53d844..382ef353 100644 --- a/src/stm-flash/ao_pins.h +++ b/src/stm-flash/ao_pins.h @@ -65,10 +65,13 @@ #define HAS_TASK_INFO 0 #define HAS_VERSION 0 +#define AO_BOOT_CHAIN 1 +#define AO_BOOT_PIN 1 + #define AO_BOOT_APPLICATION_GPIO stm_gpioa #define AO_BOOT_APPLICATION_PIN 0 #define AO_BOOT_APPLICATION_VALUE 1 #define AO_BOOT_APPLICATION_MODE 0 -#define AO_BOOT_APPLICATION_BASE 0x2000 +#define AO_BOOT_APPLICATION_BASE ((uint32_t *) 0x2000) #endif /* _AO_PINS_H_ */ diff --git a/src/stm-flash/ao_stm_flash.c b/src/stm-flash/ao_stm_flash.c index e2d7ec65..2988a937 100644 --- a/src/stm-flash/ao_stm_flash.c +++ b/src/stm-flash/ao_stm_flash.c @@ -32,89 +32,8 @@ ao_application(void) ao_boot_reboot(AO_BOOT_APPLICATION_BASE); } -static uint32_t -ao_cmd_hex32(void) -{ - __pdata uint8_t r = ao_cmd_lex_error; - int8_t n; - uint32_t v = 0; - - ao_cmd_white(); - for(;;) { - n = ao_cmd_hexchar(ao_cmd_lex_c); - if (n < 0) - break; - v = (v << 4) | n; - r = ao_cmd_success; - ao_cmd_lex(); - } - if (r != ao_cmd_success) - ao_cmd_status = r; - return v; -} - -void -ao_block_erase(void) -{ - uint32_t addr = ao_cmd_hex32(); - uint32_t *p = (uint32_t *) addr; - - ao_flash_erase_page(p); -} - -void -ao_block_write(void) -{ - uint32_t addr = ao_cmd_hex32(); - uint32_t *p = (uint32_t *) addr; - union { - uint8_t data8[256]; - uint32_t data32[64]; - } u; - uint16_t i; - - if (addr < 0x08002000 || 0x08200000 <= addr) { - puts("Invalid address"); - return; - } - for (i = 0; i < 256; i++) - u.data8[i] = i; - ao_flash_page(p, u.data32); -} - -static void -puthex(uint8_t c) -{ - c &= 0xf; - if (c < 10) - c += '0'; - else - c += 'a' - 10; - putchar (c); -} - -void -ao_block_read(void) -{ - uint32_t addr = ao_cmd_hex32(); - uint8_t *p = (uint8_t *) addr; - uint16_t i; - uint8_t c; - - for (i = 0; i < 256; i++) { - c = *p++; - puthex(c); - puthex(c>>4); - if ((i & 0xf) == 0xf) - putchar('\n'); - } -} - __code struct ao_cmds ao_flash_cmds[] = { - { ao_application, "a\0Switch to application" }, - { ao_block_erase, "e \0Erase block." }, - { ao_block_write, "W \0Write block. 256 binary bytes follow newline" }, - { ao_block_read, "R \0Read block. Returns 256 bytes" }, + { ao_application, "A\0Switch to application" }, { 0, NULL }, }; @@ -132,7 +51,6 @@ main(void) // ao_exti_init(); ao_usb_init(); - ao_cmd_register(&ao_flash_cmds[0]); ao_cmd_register(&ao_flash_cmds[0]); ao_start_scheduler(); return 0; 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 + * + * 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 +#include + +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 + * + * 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 +#include +#include + +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 #include "stm32l.h" #include +#include 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 - -#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__);