A fork of Erik Olieman's bootloader for the KL05Z32. The bootloader is placed in the 29th sector allowing for 28kB of program memory. The 32nd sector is left empty after the bootloader to allow for use of the non volatile storage without the risk of overwriting it during serial firmware update.

Dependencies:   mbed-dev

Fork of Bootloader_K64F by Erik -

This is a simple boot loader which resides at the end of the flash banks of your uController. It has be ported to work with the KL05Z. Porting the code to another Free scale uController requires the following changes:

Step 1 Change the address of the following function address

If your uController of choice has a flash size other than 32kB then you will likely want to change the addresses of following functions (current addresses displayed).

bootloader.cpp
0x7000 bootloader
0x7080 setupserial
0x70A0 write

FreescaleIAP.cpp
0x7268 erase_sector
0x7300 program_flash
0x7500 flash_size
0x7600 program_word
0x7700 run_command
0x7800 check_boundary
0x7900 check_align
0x7A00 verify_erased
0x7B00 check_error

Step 2 Follow the serial_api HAL file of your target

You will be unable to access anything that you don't define yourself in the bootloader. For this reason you need to create a function for serial. Look up and follow your target's serial_api.c file.

__attribute__((section(".ARM.__at_0x7080"))) static void setupserial(void) {
        //Setup USBRX/USBTX pins (PTB1/PTB2)
        //Enable Port B Clock
        SIM->SCGC5 |= 1 <<SIM_SCGC5_PORTB_SHIFT;                   
        //Select MCGFLLCLK clock
        SIM->SOPT2 |= 1 <<SIM_SOPT2_UART0SRC_SHIFT;
        //Select Pins PB1 & PB2 to their ALT3 function (RX & TX respectively)
        PORTB->PCR[1] = (PORTB->PCR[1] & ~0x700) | (3 << 8);
        PORTB->PCR[2] = (PORTB->PCR[2] & ~0x700) | (3 << 8);
        //Set UART0 Clock to be enabled
        SIM->SCGC4 |= SIM_SCGC4_UART0_MASK;
        //Set UART Baud Rate Register
        //Value's gathered expirimentally   
        UART0->BDH = 1;
        UART0->BDL = 56;   
        //Enable UART0
        UART0->C2 |= (UARTLP_C2_RE_MASK | UARTLP_C2_TE_MASK);
}

To set the correct baudrate you need to determine the right values for BDH & BDL registers for your clock speed. An easy way to do that is by simply printing them with the clock speed that you want like so:

#include "mbed.h"

Serial pc(USBTX, USBrX);

int main()
{
    while (1) {
        pc.printf("BDH: %d \n", UART0->BDH); // print the value of BDH Register
        pc.printf("BDL: %d \n", UART0->BDL); // print the value of BDL Register
        pc.printf("SOPT2: %d \n", SIM->SOPT2); // print the value of SOPT2 Register
        pc.printf("SCGC5: %d \n", SIM->SCGC5); // print the value of SCGC5 Register
        pc.printf("SCGC4: %d \n", SIM->SCGC4); // print the value of SCGC4 Register
        pc.printf("C2: %d \n", UART0->C2); // print the value of C2 Register
        pc.printf("C4: %d \n", UART0->C4); // print the value of C4 Register
        wait(.5);
    }
}

Step 3 Include bootloader.cpp in your first firmware

Before you can update firmware using serial you first must update the firmware using SWD along with the bootloader included in your binary.

#include "mbed.h"
extern void bootloader(void);
//...
main(){
//...
bootloader();
}

Step 4 Include reference to bootloader in serial updates

Once the bootloader is on the uControler you should not include the bootloader in binaries that you want to update over serial. Instead you can access the bootloader by using the following:

#include "mbed.h"

void *(*bootloader)(void) = (void *(*)(void))0x7001; //Address of bootloader + 1 (For some reason)
//...
main(){
//...
bootloader();
}

IF YOU ARE PROGRAMMING USING A PROGRAMMER (SWD OR JTAG) AND NOT SERIAL MAKE SURE TO INCLUDE THE BOOTLOADER OR OTHERWISE IT WILL MOST LIKELY BE ERASED OR OVERWRITTEN

Files at this revision

API Documentation at this revision

Comitter:
Sissors
Date:
Sun Apr 24 12:49:11 2016 +0000
Parent:
10:fb5121bcc468
Child:
12:beaae3757b7d
Commit message:
Undo my accidental failure

Changed in this revision

Bootloader/EthernetInterface.lib Show diff for this revision Revisions of this file
Bootloader/bootloader.h Show diff for this revision Revisions of this file
Bootloader/mbed-rtos.lib Show diff for this revision Revisions of this file
FreescaleIAP/FreescaleIAP.cpp Show annotated file Show diff for this revision Revisions of this file
FreescaleIAP/bootloader.cpp Show diff for this revision Revisions of this file
bootloader.cpp Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- a/Bootloader/EthernetInterface.lib	Sun Apr 24 12:46:37 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-http://mbed.org/users/mbed_official/code/EthernetInterface/#4d7bff17a592
--- a/Bootloader/bootloader.h	Sun Apr 24 12:46:37 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,131 +0,0 @@
-#include "mbed.h"
-#include "EthernetInterface.h"
-#include "rtos.h"
-
-#define START_ADDRESS   0x80000
-#define NUM_SECTORS     120
-#define SECTOR_SIZE     4096
-#define BUFFER_SIZE     1024
-
-
-/*************************************************************/
-//               Bootloader functions
-/*************************************************************/
-int *(*program_flash_boot)(int, char*, unsigned int) = (int *(*)(int, char*, unsigned int))0x795C9;
-int *(*erase_sector_boot)(int) = (int *(*)(int))0x79465;
-void *(*bootloader)(int) = (void *(*)(int))0x79121;
-
-
-/*************************************************************/
-//           Retrieving binary from server
-/*************************************************************/
-void write_flash(void)
-{
-
-    printf("Erasing flash!\r\n");
-    for (int i = 0; i < NUM_SECTORS; i++)
-        erase_sector_boot(START_ADDRESS + i * SECTOR_SIZE);
-
-    printf("Connecting ethernet\r\n");
-    EthernetInterface eth;
-    eth.init(); //Use DHCP
-    eth.connect();
-    printf("IP Address is %s\r\n", eth.getIPAddress());
-    
-    
-    TCPSocketConnection sock;
-    
-    //----------------YOUR SERVER DETAILS-----------------------//
-    sock.connect("192.168.0.18", 80);
-    char http_cmd[] = "GET /loader_test.bin HTTP/1.1\r\nHost: 192.168.0.18 80\r\n\r\n";
-    //----------------YOUR SERVER DETAILS-----------------------//
-    
-    sock.send_all(http_cmd, sizeof(http_cmd)-1);
-    
-    char buffer[BUFFER_SIZE];
-    int received;
-    int binsize;
-    int bufcount;
-    int remaining;
-    int count = 0;
-    
-    //Receive first packet
-    received = sock.receive(buffer, sizeof(buffer));
-    if (received <= 0) {
-        printf("No data received from server\r\n");
-        while(1);
-    }
-    
-    //Search for "Content-Length", if not available, receive more until buffer is full    
-    while(strstr(buffer, "Content-Length: ") == 0) {
-        if (received == sizeof(buffer)) {
-            printf("Could not determine size of bin file\r\n");
-            while(1);
-        } else {
-            received += sock.receive(buffer + received, sizeof(buffer) - received);   
-        }
-    }
-    //Determine size of the file
-    char *temp = strstr(buffer, "Content-Length: ") + 16;   //'16' is size of "Content-Length: "
-    sscanf(temp, "%d", &binsize); 
-    printf("Size of the binary = %d bytes\r\n", binsize);   
-
-    //Search for "\r\n\r\n" (beginning of bin file), if not available, receive more until buffer is full    
-    while(strstr(buffer, "\r\n\r\n") == 0) {
-        if (received == sizeof(buffer)) {
-            printf("Could not find start of bin file\r\n");
-            while(1);
-        } else {
-            received += sock.receive(buffer+received, sizeof(buffer) - received);   
-        }
-    }
-    //Get pointer to begin of the file in the buffer
-    temp = strstr(buffer, "\r\n\r\n") + 4;   //'16' is size of "\r\n\r\n"
-    
-    //See how much of the bin file we already received, and move this to the start of the buffer
-    bufcount = received - ((uint32_t)temp - (uint32_t)buffer);
-    memmove(buffer, temp, bufcount);
-    printf("Received %d bytes\r\n", bufcount);
-    
-    //Start receiving the remaining bin file
-    remaining = binsize - bufcount;
-        
-    while (remaining > 0) {
-        //Completely fill the buffer each time so we can easily write it to flash
-        while (bufcount < sizeof(buffer)) {
-            //Try to receive remainder of the buffer
-            received = sock.receive(&buffer[bufcount], sizeof(buffer)-bufcount);
-            printf("Received %d\r\n", received);
-            if (received <= 0) {
-                printf("Error, should not happen\r\n");
-                while(1);
-            }
-            
-            //Track how much we received and how much is left
-            bufcount += received;
-            remaining -= received;
-            if (remaining == 0) {
-                if (program_flash_boot(count+START_ADDRESS, buffer, sizeof(buffer)) != 0) {
-                    printf("Error @ 0x%X!\r\n", count);
-                    while(1);
-                }
-                count += sizeof(buffer);
-                break;
-            }
-        }
-        //Buffer is full, program it and increase the counter (the counter is a bit redundant, we could get it from the other variables)
-        if (program_flash_boot(count+START_ADDRESS, buffer, sizeof(buffer)) != 0) {
-            printf("Error @ 0x%X!\r\n", count);
-            while(1);
-        }
-        count += sizeof(buffer);
-        bufcount = 0;
-    }
-    printf("Done\r\n");
-    sock.close();
-    
-    eth.disconnect();
-
-    bootloader(count);
-
-}
\ No newline at end of file
--- a/Bootloader/mbed-rtos.lib	Sun Apr 24 12:46:37 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-http://mbed.org/users/mbed_official/code/mbed-rtos/#bdd541595fc5
--- a/FreescaleIAP/FreescaleIAP.cpp	Sun Apr 24 12:46:37 2016 +0000
+++ b/FreescaleIAP/FreescaleIAP.cpp	Sun Apr 24 12:49:11 2016 +0000
@@ -46,7 +46,7 @@
 IAPCode check_error(void);
 IAPCode program_word(int address, char *data);
     
-__attribute__((section(".ARM.__at_0x79420"))) IAPCode erase_sector(int address) {
+__attribute__((section(".ARM.__at_0x11000"))) IAPCode erase_sector(int address) {
     #ifdef IAPDEBUG
     printf("IAP: Erasing at %x\r\n", address);
     #endif
@@ -64,7 +64,7 @@
     return check_error();
 }
 
-__attribute__((section(".ARM.__at_0x79420"))) IAPCode program_flash(int address, char *data, unsigned int length) {
+__attribute__((section(".ARM.__at_0x11100"))) IAPCode program_flash(int address, char *data, unsigned int length) {
     #ifdef IAPDEBUG
     printf("IAP: Programming flash at %x with length %d\r\n", address, length);
     #endif
@@ -92,14 +92,14 @@
     return Success;
 }
 
-__attribute__((section(".ARM.__at_0x79420"))) uint32_t flash_size(void) {
+__attribute__((section(".ARM.__at_0x11300"))) uint32_t flash_size(void) {
     uint32_t retval = (SIM->FCFG2 & 0x7F000000u) >> (24-13);
     if (SIM->FCFG2 & (1<<23))           //Possible second flash bank
         retval += (SIM->FCFG2 & 0x007F0000u) >> (16-13);
     return retval;
 }
 
-__attribute__((section(".ARM.__at_0x79420"))) IAPCode program_word(int address, char *data) {
+__attribute__((section(".ARM.__at_0x11400"))) IAPCode program_word(int address, char *data) {
     #ifdef IAPDEBUG
     #ifdef USE_ProgramPhrase
     printf("IAP: Programming word at %x, %d - %d - %d - %d - %d - %d - %d - %d\r\n", address, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
@@ -140,7 +140,7 @@
 }
 
 /* Clear possible flags which are set, run command, wait until done */
-__attribute__((section(".ARM.__at_0x79420"))) inline void run_command(void) {
+__attribute__((section(".ARM.__at_0x11500"))) inline void run_command(void) {
     //Clear possible old errors, start command, wait until done
     __disable_irq();            //Disable IRQs, preventing IRQ routines from trying to access flash (thanks to https://mbed.org/users/mjr/)
     FTFA->FSTAT = FTFA_FSTAT_FPVIOL_MASK | FTFA_FSTAT_ACCERR_MASK | FTFA_FSTAT_RDCOLERR_MASK;
@@ -153,7 +153,7 @@
 
 /* Check if no flash boundary is violated
    Returns true on violation */
-__attribute__((section(".ARM.__at_0x79420"))) bool check_boundary(int address, unsigned int length) {
+__attribute__((section(".ARM.__at_0x11600"))) bool check_boundary(int address, unsigned int length) {
     int temp = (address+length - 1) / SECTOR_SIZE;
     address /= SECTOR_SIZE;
     bool retval = (address != temp);
@@ -166,7 +166,7 @@
 
 /* Check if address is correctly aligned
    Returns true on violation */
-__attribute__((section(".ARM.__at_0x79420"))) bool check_align(int address) {
+__attribute__((section(".ARM.__at_0x11700"))) bool check_align(int address) {
     bool retval = address & 0x03;
     #ifdef IAPDEBUG
     if (retval)
@@ -177,7 +177,7 @@
 
 /* Check if an area of flash memory is erased
    Returns error code or Success (in case of fully erased) */
-__attribute__((section(".ARM.__at_0x79420"))) IAPCode verify_erased(int address, unsigned int length) {
+__attribute__((section(".ARM.__at_0x11800"))) IAPCode verify_erased(int address, unsigned int length) {
     #ifdef IAPDEBUG
     printf("IAP: Verify erased at %x with length %d\r\n", address, length);
     #endif
@@ -209,7 +209,7 @@
 
 /* Check if an error occured 
    Returns error code or Success*/
-__attribute__((section(".ARM.__at_0x79420"))) IAPCode check_error(void) {
+__attribute__((section(".ARM.__at_0x11900"))) IAPCode check_error(void) {
     if (FTFA->FSTAT & FTFA_FSTAT_FPVIOL_MASK) {
         #ifdef IAPDEBUG
         printf("IAP: Protection violation\r\n");
--- a/FreescaleIAP/bootloader.cpp	Sun Apr 24 12:46:37 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-#include "mbed.h"
-#include "FreescaleIAP.h"
-
-//Could be nicer, but for now just erase all preceding sectors
-#define NUM_SECTORS        120
-#define TIMEOUT            10000000
-#define BUFFER_SIZE        16
-
-void setupserial();
-void write(char *value);
-
-__attribute__((section(".ARM.__at_0x79120"))) void bootloader(int size)
-{
-    SysTick->CTRL = 0;
-    __disable_irq();
-
-    setupserial();
-    write("\n\n\rBootloader\r\n");
-    
-    //Erase all sectors we use for the user program
-    write("Erasing sectors!\r\n");
-        
-    for (int i = 0; i<NUM_SECTORS; i++) {
-        write("*");
-        erase_sector(SECTOR_SIZE * i);
-    }
-
-    write("Done erasing, reading file!\r\n");
-
-    
-    char buffer[BUFFER_SIZE];
-    char *source = (char*)0x80000;
-    
-    //Data receive loop
-    for(int count = 0; count<size; count+=BUFFER_SIZE) {
-        for (int i = 0; i<BUFFER_SIZE; i++)
-            buffer[i] = source[i+count];
-        
-        if (program_flash(count, buffer, BUFFER_SIZE) != 0) {
-             write("Error!\r\n");   
-             break;
-        }
-                
-        //Reset buffercount for next buffer
-        write("%");
-    }             
-   
-    write("Done programming!\r\n");
-    NVIC_SystemReset();
-    
-    //Shouldn't arrive here
-    while(1);
-}
-
-__attribute__((section(".ARM.__at_0x79120"))) static void setupserial(void) {
-        //Setup USBTX/USBRX pins (PTB16/PTB17)
-        SIM->SCGC5 |= 1 << SIM_SCGC5_PORTB_SHIFT;
-        PORTB->PCR[16] = (PORTB->PCR[16] & 0x700) | (3 << 8);
-        PORTB->PCR[17] = (PORTB->PCR[17] & 0x700) | (3 << 8);
-
-        //Setup UART (ugly, copied resulting values from mbed serial setup)
-        SIM->SCGC4 |= SIM_SCGC4_UART0_MASK;
-
-        UART0->BDH = 3;
-        UART0->BDL = 13;
-        UART0->C4 = 8;
-        UART0->C2 = 12;  //Enables UART
-
-    }
-
-__attribute__((section(".ARM.__at_0x79120"))) static void write(char *value)
-{
-        int i = 0;
-        //Loop through string and send everything
-        while(*(value+i) != '\0') {
-            while(!(UART0->S1 & UART_S1_TDRE_MASK));
-            UART0->D = *(value+i);
-            i++;
-        }
-    }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bootloader.cpp	Sun Apr 24 12:49:11 2016 +0000
@@ -0,0 +1,120 @@
+#include "mbed.h"
+#include "FreescaleIAP.h"
+
+//Could be nicer, but for now just erase all preceding sectors
+#define NUM_SECTORS        15
+#define TIMEOUT            10000000
+#define BUFFER_SIZE        16
+
+void setupserial();
+void write(char *value);
+
+__attribute__((section(".ARM.__at_0x10000"))) void bootloader(void)
+{
+    setupserial();
+    write("\n\n\rBootloader\r\n");
+    write("Continue? (y/n)");
+    
+    //Wait until data arrived, if it is 'y', continue
+    while(!(UART0->S1 & UART_S1_RDRF_MASK));
+    if (UART0->D != 'y')
+        return;
+    
+    //Erase all sectors we use for the user program
+    write("Erasing sectors!\r\n");
+    for (int i = 0; i<NUM_SECTORS; i++)
+        erase_sector(SECTOR_SIZE * i);
+
+    write("Done erasing, send file!\r\n");
+
+    
+    char buffer[BUFFER_SIZE];
+    uint32_t count = 0;
+    uint8_t buffercount = 0;
+    uint32_t timeout = 0;
+    
+    //Wait until data is sent
+    while(!(UART0->S1 & UART_S1_RDRF_MASK));
+    
+    //Data receive loop
+    while(1) {
+        //Check if there is new data
+        if (UART0->S1 & UART_S1_RDRF_MASK) {
+            //Place data in buffer
+            buffer[buffercount] = UART0->D;
+            buffercount++;
+            
+            //Reset timeout
+            timeout = 0;
+
+            //We write per BUFFER_SIZE chars
+            if (buffercount == BUFFER_SIZE) {
+                //NMI Handler is at bytes 8-9-10-11, we overwrite this to point to bootloader function
+                if (count == 0) {
+                    buffer[8] = 0x01;
+                    buffer[9] = 0x00;
+                    buffer[10] = 0x01;
+                    buffer[11] = 0x00;
+                }
+                
+                //Program the buffer into the flash memory
+                if (program_flash(count, buffer, BUFFER_SIZE) != 0) {
+                    write("Error!\r\n");   
+                    break;
+                }
+                
+                //Reset buffercount for next buffer
+                write("#");
+                buffercount = 0;
+                count += BUFFER_SIZE;
+            }
+        } else {
+            //No new data, increase timeout
+            timeout++;
+            
+            //We have received no new data for a while, assume we are done
+            if (timeout > TIMEOUT) {
+                //If there is data left in the buffer, program it
+                if (buffercount != 0) {
+                    for (int i = buffercount; i<BUFFER_SIZE; i++) {
+                        buffer[i] = 0xFF;
+                    }
+                    program_flash(count, buffer, BUFFER_SIZE);
+                }
+                break;          //We should be done programming :D
+            }
+        }
+    }
+    write("Done programming!\r\n");
+    NVIC_SystemReset();
+    
+    //Shouldn't arrive here
+    while(1);
+}
+
+__attribute__((section(".ARM.__at_0x10080"))) static void setupserial(void) {
+        //Setup USBTX/USBRX pins (PTB16/PTB17)
+        SIM->SCGC5 |= 1 << SIM_SCGC5_PORTB_SHIFT;
+        PORTB->PCR[16] = (PORTB->PCR[16] & 0x700) | (3 << 8);
+        PORTB->PCR[17] = (PORTB->PCR[17] & 0x700) | (3 << 8);
+
+        //Setup UART (ugly, copied resulting values from mbed serial setup)
+        SIM->SCGC4 |= SIM_SCGC4_UART0_MASK;
+
+        UART0->BDH = 3;
+        UART0->BDL = 13;
+        UART0->C4 = 8;
+        UART0->C2 = 12;  //Enables UART
+
+    }
+
+__attribute__((section(".ARM.__at_0x100A0"))) static void write(char *value)
+{
+        int i = 0;
+        //Loop through string and send everything
+        while(*(value+i) != '\0') {
+            while(!(UART0->S1 & UART_S1_TDRE_MASK));
+            UART0->D = *(value+i);
+            i++;
+        }
+    }
--- a/main.cpp	Sun Apr 24 12:46:37 2016 +0000
+++ b/main.cpp	Sun Apr 24 12:49:11 2016 +0000
@@ -1,23 +1,10 @@
 #include "mbed.h"
-#include "bootloader.h"
 
-DigitalIn sw(PTA4);
-DigitalOut LED(LED_BLUE);
+extern void bootloader(void);
 
 int main() 
-{
-    printf("Hello :)\r\n");
-    
-    //Blink LED, and when SW3 is pressed go to bootloader
-    //I don't know atm if the bootloader would work from interrupt context
-    while (1) {
-        LED = !LED;
-        wait(0.25);
-        if (sw == 0) {
-            printf("Entering bootloader\r\n");
-            write_flash();
-        }
-    }
+{   
+    bootloader();
+    while(1);
 }
- 
-
+ 
\ No newline at end of file
--- a/mbed.bld	Sun Apr 24 12:46:37 2016 +0000
+++ b/mbed.bld	Sun Apr 24 12:49:11 2016 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/users/mbed_official/code/mbed/builds/082adc85693f
\ No newline at end of file
+http://mbed.org/users/mbed_official/code/mbed/builds/7e07b6fb45cf
\ No newline at end of file