diff --git a/bootloader/README.md b/bootloader/README.md index f5c2d5644de45e063390105e240e1d4ae9aa6864..77a473ff62df02b838f038fd0c896b3dc0f2bd55 100644 --- a/bootloader/README.md +++ b/bootloader/README.md @@ -1,21 +1,53 @@ Fadecandy Bootloader ==================== -This is a simple open source bootloader for the Freescale Kinetis K20 microcontroller. It uses the USB Device Firmware Upgrade (DFU) standard. This bootloader was developed for use with Fadecandy, but it should be portable to other projects using the Kinetis microcontroller family. - -* This bootloader is a work in progress. Doesn't actually work yet! - -Quick facts: - -* Enter the bootloader via serial loopback detect, DFU command from runtime firmware, or if runtime firmware is missing. -* Tested with the open source `dfu-util` package. +This is a simple open source bootloader for the Freescale Kinetis MK20DX128 microcontroller. It uses the USB Device Firmware Upgrade (DFU) standard. This bootloader was developed for use with Fadecandy, but it should be portable with to other projects using chips in the Kinetis microcontroller family. Installing ---------- The bootloader can be installed via JTAG using OpenOCD. If you have an Olimex ARM-USB-OCD adapter, everything's already set up to install the bootloader with "make install". Other JTAG adapters will require changing `openocd.cfg`. +Application Interface +--------------------- + +This section describes the programming interface that exists between the bootloader and the application firmware. + +The bootloader uses the smallest possible protected region on the MK20DX128's flash, a 4KB block. It uses a small amount of RAM for a relocated interrupt vector table, and for a "token" which is used to force entry into the bootloader on system reset. + +When entering the application firmware, the system clocks will already be configured, and the watchdog timer is already enabled with a 10ms timeout, as timed by the system low-power oscillator. + +Interrupts are forwarded from the flash IVT to an IVT in SRAM with the help of trampolines located in bootloader flash. The application's initial IVT, at 0x0000_10F7, is copied to SRAM by the bootloader and includes the application's entry point as its ResetVector. + +The bootloader normally transfers control to the application early in boot, before setting up the USB controller. It will skip this step and run the DFU implementation if any of the following conditions are true: + +* A banner ("FC-Boot\n") printed to the hardware UART at 9600 baud is echoed back within one character-period. (Manual entry by shorting TX and RX) +* An 8-byte entry token ("FC-Boot" + '\0') is found at 0x1FFF_E0F8. (Programmatic entry) +* The application ResetVector does not reside within application flash. (No application is installed) + +Memory address range | Description +-------------------------- | ---------------------------- +0x0000_0000 - 0x0000_0FFF | Bootloader protected flash +0x0000_1000 - 0x0000_10F7 | Application IVT in flash +0x0000_1000 - 0x0001_FFFF | Remainder of application flash +0x1FFF_E000 - 0x1FFF_E0F7 | Interrupt vector table in SRAM +0x1FFF_E0F8 - 0x1FFF_E0FF | Entry token in SRAM +0x1FFF_E100 - 0x2000_1FFF | Remainder of application SRAM + +External Hardware +----------------- + +No external hardware is required for the bootloader to operate. The following pins are used by the bootloader for optional features: + +* PC5 is a status LED, active (high) while the bootloader is in DFU mode. +* PCR16/17 are set up as UART0 briefly during boot, for broadcasting the banner message and testing for manual bootloader entry. + +File Format +----------- + +The DFU file consists of raw 1 kilobyte blocks to be programmed into flash starting at address 0x0000_1000. The file may contain up to 127 blocks. No additional headers or checksums are included. On disk, the standard DFU suffix and CRC are used. During transit, the standard USB CRC is used. + Contact ------- -Micah Elizabeth Scott <<micah@scanlime.org>> \ No newline at end of file +Micah Elizabeth Scott <<micah@scanlime.org>> diff --git a/bootloader/dfu.c b/bootloader/dfu.c index 90695fdc5e2d50a371d472493bd603da6925ee89..dbb2cb8b4cd5f43b5a72109df30bfe7765c7f347 100644 --- a/bootloader/dfu.c +++ b/bootloader/dfu.c @@ -152,6 +152,10 @@ bool dfu_getstatus(uint8_t *status) dfu_state = dfuMANIFEST; break; + case dfuMANIFEST: + dfu_state = dfuIDLE; + break; + default: break; } @@ -194,4 +198,5 @@ bool dfu_abort() void dfu_usb_reset() { debug++; +// watchdog_reboot(); } diff --git a/bootloader/mk20dx128.c b/bootloader/mk20dx128.c index c77475e5ae54a3bb2effb7859e5d111c3ea2cef9..07a52761308fe03830f76b32389e8dc04e4440f2 100644 --- a/bootloader/mk20dx128.c +++ b/bootloader/mk20dx128.c @@ -194,10 +194,11 @@ void ResetHandler(void) uint32_t *src = &_etext; uint32_t *dest = &_sdata; - // Enable watchdog timer + // Enable watchdog timer. Allow settings to be changed later, in case the + // application firmware wants to adjust its settings or disable it. WDOG_UNLOCK = WDOG_UNLOCK_SEQ1; WDOG_UNLOCK = WDOG_UNLOCK_SEQ2; - WDOG_STCTRLH = WDOG_STCTRLH_DISTESTWDOG| WDOG_STCTRLH_WDOGEN | + WDOG_STCTRLH = WDOG_STCTRLH_ALLOWUPDATE | WDOG_STCTRLH_WDOGEN | WDOG_STCTRLH_WAITEN | WDOG_STCTRLH_STOPEN; WDOG_PRESC = 0; WDOG_TOVALH = 0; diff --git a/bootloader/mk20dx128.h b/bootloader/mk20dx128.h index 5b62f3c8467d01648f097c02ceac06fc73601ce1..e20f13cf5b06bb15c9382bfda4c89516c74c8fb6 100644 --- a/bootloader/mk20dx128.h +++ b/bootloader/mk20dx128.h @@ -1610,6 +1610,12 @@ static inline void watchdog_refresh(void) WDOG_REFRESH = 0xB480; } +static inline void watchdog_reboot(void) +{ + // Any invalid write to the WDOG registers will trigger an immediate reboot + WDOG_REFRESH = 0; +} + #ifdef __cplusplus } diff --git a/bootloader/mk20dx128.ld b/bootloader/mk20dx128.ld index 2a25df75f31553bb009afc43b46e4941cd350963..4fe2cebc8d063813929d11fbb0f2f55a2e48f022 100644 --- a/bootloader/mk20dx128.ld +++ b/bootloader/mk20dx128.ld @@ -30,19 +30,24 @@ MEMORY { - FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 128K - RAM (rwx) : ORIGIN = 0x1FFFE000, LENGTH = 16K + /* Boot and application partitions in flash */ + BOOT_FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 4K + APP_FLASH (rx) : ORIGIN = 0x00001000, LENGTH = 124K + + /* Boot and application partitions in RAM */ + BOOT_RAM (rwx) : ORIGIN = 0x1FFFE000, LENGTH = 256 + APP_RAM (rwx) : ORIGIN = 0x1FFFE100, LENGTH = 16128 + + /* Special RAM used for programming flash */ FLEXRAM (rwx) : ORIGIN = 0x14000000, LENGTH = 2K } - SECTIONS { .text : { . = 0; KEEP(*(.vectors)) *(.startup*) - /* TODO: does linker detect startup overflow onto flashconfig? */ . = 0x400; KEEP(*(.flashconfig*)) *(.text*) @@ -57,30 +62,34 @@ SECTIONS KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) __init_array_end = .; - } > FLASH = 0xFF - - .ARM.exidx : { - __exidx_start = .; - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - __exidx_end = .; - } > FLASH + } > BOOT_FLASH = 0xFF _etext = .; + .apptext : { + . = 0; + *(.appvectors) + } > APP_FLASH = 0xFF + + .bootram (NOLOAD) : { + . = 0; + *(.bootram) + } > BOOT_RAM + .usbdescriptortable (NOLOAD) : { /* . = ORIGIN(RAM); */ . = ALIGN(512); *(.usbdescriptortable*) - } > RAM + } > APP_RAM .dmabuffers (NOLOAD) : { . = ALIGN(4); *(.dmabuffers*) - } > RAM + } > APP_RAM .usbbuffers (NOLOAD) : { . = ALIGN(4); *(.usbbuffers*) - } > RAM + } > APP_RAM .flexram (NOLOAD) : { . = ALIGN(4); @@ -93,11 +102,11 @@ SECTIONS *(.data*) . = ALIGN(4); _edata = .; - } > RAM + } > APP_RAM .noinit (NOLOAD) : { *(.noinit*) - } > RAM + } > APP_RAM .bss : { . = ALIGN(4); @@ -107,9 +116,9 @@ SECTIONS . = ALIGN(4); _ebss = .; __bss_end = .; - } > RAM + } > APP_RAM - _estack = ORIGIN(RAM) + LENGTH(RAM); + _estack = ORIGIN(APP_RAM) + LENGTH(APP_RAM); }