Split out code into separate files.
Add support for getting back to boot loader from application.
Signed-off-by: Keith Packard <keithp@keithp.com>
#
ALTOS_SRC = \
ao_interrupt.c \
+ ao_boot_chain.c \
ao_product.c \
ao_romconfig.c \
ao_cmd.c \
#include <ao_event.h>
#include <ao_quadrature.h>
#include <ao_button.h>
+#include <ao_boot.h>
struct ao_task demo_task;
}
+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" },
{ 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 }
};
#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
#
ALTOS_SRC = \
ao_interrupt.c \
+ ao_boot_chain.c \
+ ao_boot_pin.c \
ao_product.c \
ao_romconfig.c \
ao_task.c \
#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_ */
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 <addr>\0Erase block." },
- { ao_block_write, "W <addr>\0Write block. 256 binary bytes follow newline" },
- { ao_block_read, "R <addr>\0Read block. Returns 256 bytes" },
+ { ao_application, "A\0Switch to application" },
{ 0, NULL },
};
// 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;
__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__ = .;
} > 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);
#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_ */
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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);
+}
#include <ao.h>
#include "stm32l.h"
#include <string.h>
+#include <ao_boot.h>
extern void main(void);
extern char __stack__;
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__);