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

Committer:
Sissors
Date:
Fri Mar 13 21:47:01 2015 +0000
Revision:
5:1345007a5fc3
Parent:
4:8d109a566486
Child:
6:76c37fd3780a
Deleted bit too much in clean up

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Sissors 2:8c44f28c122c 1 #include "mbed.h"
Sissors 2:8c44f28c122c 2 #include "FreescaleIAP.h"
Sissors 2:8c44f28c122c 3
Sissors 2:8c44f28c122c 4 //Could be nicer, but for now just erase all preceding sectors
Sissors 3:8c39a7751758 5 #define NUM_SECTORS 15
Sissors 2:8c44f28c122c 6 #define TIMEOUT 10000000
Sissors 4:8d109a566486 7 #define BUFFER_SIZE 16
Sissors 2:8c44f28c122c 8
Sissors 2:8c44f28c122c 9 void setupserial();
Sissors 2:8c44f28c122c 10 void write(char *value);
Sissors 2:8c44f28c122c 11 char getserial(void);
Sissors 1:782a3ddc329e 12
Sissors 2:8c44f28c122c 13 __attribute__((section(".ARM.__at_0x10000"))) void bootloader(void)
Sissors 2:8c44f28c122c 14 {
Sissors 1:782a3ddc329e 15 setupserial();
Sissors 2:8c44f28c122c 16 write("\n\n\rBootloader\r\n");
Sissors 2:8c44f28c122c 17 write("Continue? (y/n)");
Sissors 4:8d109a566486 18
Sissors 4:8d109a566486 19 //Wait until data arrived, if it is 'y', continue
Sissors 2:8c44f28c122c 20 while(!(UART0->S1 & UART_S1_RDRF_MASK));
Sissors 2:8c44f28c122c 21 if (UART0->D != 'y')
Sissors 2:8c44f28c122c 22 return;
Sissors 4:8d109a566486 23
Sissors 4:8d109a566486 24 //Erase all sectors we use for the user program
Sissors 2:8c44f28c122c 25 write("Erasing sectors!\r\n");
Sissors 2:8c44f28c122c 26 for (int i = 0; i<NUM_SECTORS; i++)
Sissors 2:8c44f28c122c 27 erase_sector(SECTOR_SIZE * i);
Sissors 2:8c44f28c122c 28
Sissors 2:8c44f28c122c 29 write("Done erasing, send file!\r\n");
Sissors 4:8d109a566486 30
Sissors 1:782a3ddc329e 31
Sissors 4:8d109a566486 32 char buffer[BUFFER_SIZE];
Sissors 2:8c44f28c122c 33 uint32_t count = 0;
Sissors 2:8c44f28c122c 34 uint8_t buffercount = 0;
Sissors 2:8c44f28c122c 35 uint32_t timeout = 0;
Sissors 4:8d109a566486 36
Sissors 5:1345007a5fc3 37 //Wait until data is sent
Sissors 5:1345007a5fc3 38 while(!(UART0->S1 & UART_S1_RDRF_MASK));
Sissors 5:1345007a5fc3 39
Sissors 4:8d109a566486 40 //Data receive loop
Sissors 1:782a3ddc329e 41 while(1) {
Sissors 2:8c44f28c122c 42 //Check if there is new data
Sissors 2:8c44f28c122c 43 if (UART0->S1 & UART_S1_RDRF_MASK) {
Sissors 4:8d109a566486 44 //Place data in buffer
Sissors 2:8c44f28c122c 45 buffer[buffercount] = UART0->D;
Sissors 2:8c44f28c122c 46 buffercount++;
Sissors 4:8d109a566486 47
Sissors 4:8d109a566486 48 //Reset timeout
Sissors 4:8d109a566486 49 timeout = 0;
Sissors 2:8c44f28c122c 50
Sissors 4:8d109a566486 51 //We write per BUFFER_SIZE chars
Sissors 4:8d109a566486 52 if (buffercount == BUFFER_SIZE) {
Sissors 4:8d109a566486 53 //NMI Handler is at bytes 8-9-10-11, we overwrite this to point to bootloader function
Sissors 4:8d109a566486 54 if (count == 0) {
Sissors 4:8d109a566486 55 buffer[8] = 0x01;
Sissors 4:8d109a566486 56 buffer[9] = 0x00;
Sissors 4:8d109a566486 57 buffer[10] = 0x01;
Sissors 4:8d109a566486 58 buffer[11] = 0x00;
Sissors 4:8d109a566486 59 }
Sissors 4:8d109a566486 60
Sissors 4:8d109a566486 61 //Program the buffer into the flash memory
Sissors 4:8d109a566486 62 if (program_flash(count, buffer, BUFFER_SIZE) != 0) {
Sissors 2:8c44f28c122c 63 write("Error!\r\n");
Sissors 2:8c44f28c122c 64 break;
Sissors 2:8c44f28c122c 65 }
Sissors 4:8d109a566486 66
Sissors 4:8d109a566486 67 //Reset buffercount for next buffer
Sissors 4:8d109a566486 68 write("#");
Sissors 2:8c44f28c122c 69 buffercount = 0;
Sissors 4:8d109a566486 70 count += BUFFER_SIZE;
Sissors 2:8c44f28c122c 71 }
Sissors 2:8c44f28c122c 72 } else {
Sissors 2:8c44f28c122c 73 //No new data, increase timeout
Sissors 2:8c44f28c122c 74 timeout++;
Sissors 4:8d109a566486 75
Sissors 4:8d109a566486 76 //We have received no new data for a while, assume we are done
Sissors 2:8c44f28c122c 77 if (timeout > TIMEOUT) {
Sissors 4:8d109a566486 78 //If there is data left in the buffer, program it
Sissors 2:8c44f28c122c 79 if (buffercount != 0) {
Sissors 4:8d109a566486 80 for (int i = buffercount; i<BUFFER_SIZE; i++) {
Sissors 2:8c44f28c122c 81 buffer[i] = 0xFF;
Sissors 4:8d109a566486 82 }
Sissors 4:8d109a566486 83 program_flash(count, buffer, BUFFER_SIZE);
Sissors 2:8c44f28c122c 84 }
Sissors 2:8c44f28c122c 85 break; //We should be done programming :D
Sissors 2:8c44f28c122c 86 }
Sissors 2:8c44f28c122c 87 }
Sissors 1:782a3ddc329e 88 }
Sissors 2:8c44f28c122c 89 write("Done programming!\r\n");
Sissors 4:8d109a566486 90 NVIC_SystemReset();
Sissors 4:8d109a566486 91
Sissors 4:8d109a566486 92 //Shouldn't arrive here
Sissors 4:8d109a566486 93 while(1);
Sissors 1:782a3ddc329e 94 }
Sissors 1:782a3ddc329e 95
Sissors 4:8d109a566486 96 __attribute__((section(".ARM.__at_0x10080"))) static void setupserial(void) {
Sissors 2:8c44f28c122c 97 //Setup USBTX/USBRX pins (PTB16/PTB17)
Sissors 2:8c44f28c122c 98 SIM->SCGC5 |= 1 << SIM_SCGC5_PORTB_SHIFT;
Sissors 2:8c44f28c122c 99 PORTB->PCR[16] = (PORTB->PCR[16] & 0x700) | (3 << 8);
Sissors 2:8c44f28c122c 100 PORTB->PCR[17] = (PORTB->PCR[17] & 0x700) | (3 << 8);
Sissors 2:8c44f28c122c 101
Sissors 2:8c44f28c122c 102 //Setup UART (ugly, copied resulting values from mbed serial setup)
Sissors 2:8c44f28c122c 103 SIM->SCGC4 |= SIM_SCGC4_UART0_MASK;
Sissors 4:8d109a566486 104
Sissors 3:8c39a7751758 105 UART0->BDH = 3;
Sissors 3:8c39a7751758 106 UART0->BDL = 13;
Sissors 2:8c44f28c122c 107 UART0->C4 = 8;
Sissors 2:8c44f28c122c 108 UART0->C2 = 12; //Enables UART
Sissors 2:8c44f28c122c 109
Sissors 2:8c44f28c122c 110 }
Sissors 1:782a3ddc329e 111
Sissors 4:8d109a566486 112 __attribute__((section(".ARM.__at_0x100A0"))) static void write(char *value)
Sissors 4:8d109a566486 113 {
Sissors 2:8c44f28c122c 114 int i = 0;
Sissors 4:8d109a566486 115 //Loop through string and send everything
Sissors 2:8c44f28c122c 116 while(*(value+i) != '\0') {
Sissors 2:8c44f28c122c 117 while(!(UART0->S1 & UART_S1_TDRE_MASK));
Sissors 2:8c44f28c122c 118 UART0->D = *(value+i);
Sissors 2:8c44f28c122c 119 i++;
Sissors 2:8c44f28c122c 120 }
Sissors 2:8c44f28c122c 121 }