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:
Dot
Date:
Tue Jul 19 00:57:39 2016 +0000
Revision:
20:fdb5c9abc4f2
Parent:
19:8f3f6138bfb9
Initial Working Release

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Sissors 11:a7a0730e20db 1 #include "mbed.h"
Sissors 11:a7a0730e20db 2 #include "FreescaleIAP.h"
Sissors 11:a7a0730e20db 3
Sissors 11:a7a0730e20db 4 //Could be nicer, but for now just erase all preceding sectors
Dot 17:a30cecd2efe8 5 #define NUM_SECTORS 28
Sissors 11:a7a0730e20db 6 #define TIMEOUT 10000000
Sissors 11:a7a0730e20db 7 #define BUFFER_SIZE 16
Sissors 11:a7a0730e20db 8
Sissors 11:a7a0730e20db 9 void setupserial();
Sissors 11:a7a0730e20db 10 void write(char *value);
Dot 12:beaae3757b7d 11 /*KL05 32kB Memmory Map
Dot 12:beaae3757b7d 12 0x0000 : 0x7FFF
Dot 12:beaae3757b7d 13 32 1kB Flash Secotrs
Dot 15:89e2c76e5eed 14 [1:28] Program Memory
Dot 15:89e2c76e5eed 15 [29] Bootloader
Dot 15:89e2c76e5eed 16 [30] IAP
Dot 15:89e2c76e5eed 17 [31] IAP
Dot 12:beaae3757b7d 18 [32] Flash Storage
Dot 15:89e2c76e5eed 19
Dot 15:89e2c76e5eed 20 0x7000 Sector 29 Start Addr
Dot 15:89e2c76e5eed 21 0x7400 Sector 30 Start Addr
Dot 15:89e2c76e5eed 22 0x7800 Sector 31 Start Addr
Dot 15:89e2c76e5eed 23 0x7C00 Sector 32 Start Addr
Sissors 11:a7a0730e20db 24
Dot 15:89e2c76e5eed 25 0x7000 bootloader
Dot 15:89e2c76e5eed 26 0x7080 setupserial
Dot 15:89e2c76e5eed 27 0x70A0 write
Dot 16:30f4c724da60 28 0x7260 erase_sector
Dot 16:30f4c724da60 29 0x7300 program_flash
Dot 16:30f4c724da60 30 0x7500 flash_size
Dot 16:30f4c724da60 31 0x7600 program_word
Dot 16:30f4c724da60 32 0x7700 run_command
Dot 16:30f4c724da60 33 0x7800 check_boundary
Dot 16:30f4c724da60 34 0x7900 check_align
Dot 16:30f4c724da60 35 0x7A00 verify_erased
Dot 16:30f4c724da60 36 0x7B00 check_error
Dot 12:beaae3757b7d 37 */
Dot 12:beaae3757b7d 38 //KL05 Version
Dot 15:89e2c76e5eed 39 __attribute__((section(".ARM.__at_0x7000"))) void bootloader(void)
Sissors 11:a7a0730e20db 40 {
Sissors 11:a7a0730e20db 41 setupserial();
Sissors 11:a7a0730e20db 42 write("\n\n\rBootloader\r\n");
Sissors 11:a7a0730e20db 43 write("Continue? (y/n)");
Sissors 11:a7a0730e20db 44
Sissors 11:a7a0730e20db 45 //Wait until data arrived, if it is 'y', continue
Dot 15:89e2c76e5eed 46 while(!(UART0->S1 & UART0_S1_RDRF_MASK));
Sissors 11:a7a0730e20db 47 if (UART0->D != 'y')
Sissors 11:a7a0730e20db 48 return;
Sissors 11:a7a0730e20db 49
Sissors 11:a7a0730e20db 50 //Erase all sectors we use for the user program
Sissors 11:a7a0730e20db 51 write("Erasing sectors!\r\n");
Sissors 11:a7a0730e20db 52 for (int i = 0; i<NUM_SECTORS; i++)
Sissors 11:a7a0730e20db 53 erase_sector(SECTOR_SIZE * i);
Sissors 11:a7a0730e20db 54
Sissors 11:a7a0730e20db 55 write("Done erasing, send file!\r\n");
Sissors 11:a7a0730e20db 56
Sissors 11:a7a0730e20db 57 char buffer[BUFFER_SIZE];
Sissors 11:a7a0730e20db 58 uint32_t count = 0;
Sissors 11:a7a0730e20db 59 uint8_t buffercount = 0;
Sissors 11:a7a0730e20db 60 uint32_t timeout = 0;
Sissors 11:a7a0730e20db 61
Sissors 11:a7a0730e20db 62 //Wait until data is sent
Dot 15:89e2c76e5eed 63 while(!(UART0->S1 & UART0_S1_RDRF_MASK));
Sissors 11:a7a0730e20db 64
Sissors 11:a7a0730e20db 65 //Data receive loop
Sissors 11:a7a0730e20db 66 while(1) {
Sissors 11:a7a0730e20db 67 //Check if there is new data
Dot 15:89e2c76e5eed 68 if (UART0->S1 & UART0_S1_RDRF_MASK) {
Sissors 11:a7a0730e20db 69 //Place data in buffer
Sissors 11:a7a0730e20db 70 buffer[buffercount] = UART0->D;
Sissors 11:a7a0730e20db 71 buffercount++;
Sissors 11:a7a0730e20db 72
Sissors 11:a7a0730e20db 73 //Reset timeout
Sissors 11:a7a0730e20db 74 timeout = 0;
Sissors 11:a7a0730e20db 75
Sissors 11:a7a0730e20db 76 //We write per BUFFER_SIZE chars
Sissors 11:a7a0730e20db 77 if (buffercount == BUFFER_SIZE) {
Sissors 11:a7a0730e20db 78 //NMI Handler is at bytes 8-9-10-11, we overwrite this to point to bootloader function
Sissors 11:a7a0730e20db 79 if (count == 0) {
Sissors 11:a7a0730e20db 80 buffer[8] = 0x01;
Sissors 11:a7a0730e20db 81 buffer[9] = 0x00;
Sissors 11:a7a0730e20db 82 buffer[10] = 0x01;
Sissors 11:a7a0730e20db 83 buffer[11] = 0x00;
Sissors 11:a7a0730e20db 84 }
Sissors 11:a7a0730e20db 85
Sissors 11:a7a0730e20db 86 //Program the buffer into the flash memory
Sissors 11:a7a0730e20db 87 if (program_flash(count, buffer, BUFFER_SIZE) != 0) {
Sissors 11:a7a0730e20db 88 write("Error!\r\n");
Sissors 11:a7a0730e20db 89 break;
Sissors 11:a7a0730e20db 90 }
Sissors 11:a7a0730e20db 91
Sissors 11:a7a0730e20db 92 //Reset buffercount for next buffer
Sissors 11:a7a0730e20db 93 write("#");
Sissors 11:a7a0730e20db 94 buffercount = 0;
Sissors 11:a7a0730e20db 95 count += BUFFER_SIZE;
Sissors 11:a7a0730e20db 96 }
Sissors 11:a7a0730e20db 97 } else {
Sissors 11:a7a0730e20db 98 //No new data, increase timeout
Dot 12:beaae3757b7d 99 timeout++;
Sissors 11:a7a0730e20db 100 //We have received no new data for a while, assume we are done
Sissors 11:a7a0730e20db 101 if (timeout > TIMEOUT) {
Sissors 11:a7a0730e20db 102 //If there is data left in the buffer, program it
Sissors 11:a7a0730e20db 103 if (buffercount != 0) {
Sissors 11:a7a0730e20db 104 for (int i = buffercount; i<BUFFER_SIZE; i++) {
Sissors 11:a7a0730e20db 105 buffer[i] = 0xFF;
Sissors 11:a7a0730e20db 106 }
Sissors 11:a7a0730e20db 107 program_flash(count, buffer, BUFFER_SIZE);
Sissors 11:a7a0730e20db 108 }
Sissors 11:a7a0730e20db 109 break; //We should be done programming :D
Sissors 11:a7a0730e20db 110 }
Sissors 11:a7a0730e20db 111 }
Sissors 11:a7a0730e20db 112 }
Sissors 11:a7a0730e20db 113 write("Done programming!\r\n");
Sissors 11:a7a0730e20db 114 NVIC_SystemReset();
Sissors 11:a7a0730e20db 115
Sissors 11:a7a0730e20db 116 //Shouldn't arrive here
Sissors 11:a7a0730e20db 117 while(1);
Sissors 11:a7a0730e20db 118 }
Sissors 11:a7a0730e20db 119
Dot 15:89e2c76e5eed 120 __attribute__((section(".ARM.__at_0x7080"))) static void setupserial(void) {
Dot 18:c9396799d565 121 //Setup USBRX/USBTX pins (PTB1/PTB2)
Dot 18:c9396799d565 122 //Disable UART0
Dot 20:fdb5c9abc4f2 123 // UART0->C2 &= ~(UARTLP_C2_RE_MASK | UARTLP_C2_TE_MASK);
Dot 18:c9396799d565 124 //Enable Port B Clock
Dot 18:c9396799d565 125 SIM->SCGC5 |= 1 <<SIM_SCGC5_PORTB_SHIFT;
Dot 18:c9396799d565 126 //Select MCGFLLCLK clock
Dot 18:c9396799d565 127 SIM->SOPT2 |= 1 <<SIM_SOPT2_UART0SRC_SHIFT;
Dot 18:c9396799d565 128 //Select Pins PB1 & PB2 to their ALT3 function (RX & TX respectively)
Dot 19:8f3f6138bfb9 129 PORTB->PCR[1] = (PORTB->PCR[1] & ~0x700) | (3 << 8);
Dot 19:8f3f6138bfb9 130 PORTB->PCR[2] = (PORTB->PCR[2] & ~0x700) | (3 << 8);
Dot 18:c9396799d565 131 //Set UART0 Clock to be enabled
Sissors 11:a7a0730e20db 132 SIM->SCGC4 |= SIM_SCGC4_UART0_MASK;
Dot 16:30f4c724da60 133 // KL05's pclk def
Dot 16:30f4c724da60 134 // uint32_t PCLK = SystemCoreClock * (1u + ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV1_MASK) >> SIM_CLKDIV1_OUTDIV1_SHIFT));
Dot 18:c9396799d565 135 //Set UART Baud Rate Register
Dot 18:c9396799d565 136 // uint32_t PCLK = SystemCoreClock;
Dot 18:c9396799d565 137 // uint16_t DL = PCLK / (16 * 9600); //Want 9600 Baudrate
Dot 18:c9396799d565 138 // UART0->BDH = ((DL >> 8) & 0x1f);
Dot 18:c9396799d565 139 // UART0->BDL = ((DL >> 0) & 0xff);
Dot 18:c9396799d565 140 //Value's gathered expirimentally
Dot 18:c9396799d565 141 UART0->BDH = 1;
Dot 18:c9396799d565 142 UART0->BDL = 56;
Dot 18:c9396799d565 143 //Enable UART0
Dot 16:30f4c724da60 144 UART0->C2 |= (UARTLP_C2_RE_MASK | UARTLP_C2_TE_MASK);
Dot 18:c9396799d565 145 }
Sissors 11:a7a0730e20db 146
Dot 15:89e2c76e5eed 147 __attribute__((section(".ARM.__at_0x70A0"))) static void write(char *value)
Sissors 11:a7a0730e20db 148 {
Sissors 11:a7a0730e20db 149 int i = 0;
Sissors 11:a7a0730e20db 150 //Loop through string and send everything
Sissors 11:a7a0730e20db 151 while(*(value+i) != '\0') {
Dot 15:89e2c76e5eed 152 while(!(UART0->S1 & UART0_S1_TDRE_MASK));
Dot 18:c9396799d565 153 UART0->D = *(value+i);
Sissors 11:a7a0730e20db 154 i++;
Sissors 11:a7a0730e20db 155 }
Sissors 11:a7a0730e20db 156 }