From 51e018433c00b4fe8021d16583606850cf91c289 Mon Sep 17 00:00:00 2001
From: Micah Elizabeth Scott <micah@scanlime.org>
Date: Mon, 7 Oct 2013 19:08:25 -0700
Subject: [PATCH] Start to specify the programmatic interface between
 bootloader and app

---
 bootloader/README.md    | 50 +++++++++++++++++++++++++++++++++--------
 bootloader/dfu.c        |  5 +++++
 bootloader/mk20dx128.c  |  5 +++--
 bootloader/mk20dx128.h  |  6 +++++
 bootloader/mk20dx128.ld | 45 ++++++++++++++++++++++---------------
 5 files changed, 82 insertions(+), 29 deletions(-)

diff --git a/bootloader/README.md b/bootloader/README.md
index f5c2d56..77a473f 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 90695fd..dbb2cb8 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 c77475e..07a5276 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 5b62f3c..e20f13c 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 2a25df7..4fe2ceb 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);
 }
 
 
-- 
GitLab