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.
Fork of Bootloader_K64F by
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
bootloader.cpp@13:d187850a6f6f, 2016-07-16 (annotated)
- Committer:
- Dot
- Date:
- Sat Jul 16 18:20:22 2016 +0000
- Revision:
- 13:d187850a6f6f
- Parent:
- 12:beaae3757b7d
- Child:
- 14:5df65dc9d98e
Brought in UART0_S1_RDRF_MASK & UART0_S1_TDRE_MASK definitions.
Who changed what in which revision?
User | Revision | Line number | New 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 | 12:beaae3757b7d | 5 | #define NUM_SECTORS 30 |
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 | /*KL64 Memory Locations |
Dot | 12:beaae3757b7d | 12 | 0x10000 |
Dot | 12:beaae3757b7d | 13 | 0x10080 |
Dot | 12:beaae3757b7d | 14 | 0x100A0 |
Dot | 12:beaae3757b7d | 15 | */ |
Dot | 12:beaae3757b7d | 16 | /*KL05 32kB Memmory Map |
Dot | 12:beaae3757b7d | 17 | 0x0000 : 0x7FFF |
Dot | 12:beaae3757b7d | 18 | 32 1kB Flash Secotrs |
Dot | 12:beaae3757b7d | 19 | [1:30] Program Memory |
Dot | 12:beaae3757b7d | 20 | [31] Bootloader |
Dot | 12:beaae3757b7d | 21 | [32] Flash Storage |
Dot | 12:beaae3757b7d | 22 | 0x7C00 Sector 31 Start Addr |
Dot | 12:beaae3757b7d | 23 | 0x7800 Sector 32 Start Addr |
Sissors | 11:a7a0730e20db | 24 | |
Dot | 12:beaae3757b7d | 25 | 0x7C00 bootloader |
Dot | 12:beaae3757b7d | 26 | 0x7C80 setupserial |
Dot | 12:beaae3757b7d | 27 | 0x7CA0 |
Dot | 12:beaae3757b7d | 28 | */ |
Dot | 13:d187850a6f6f | 29 | #define UART_S1_RDRF_MASK 0x20u |
Dot | 13:d187850a6f6f | 30 | #define UART_S1_TDRE_MASK 0x80u |
Dot | 13:d187850a6f6f | 31 | |
Dot | 12:beaae3757b7d | 32 | //KL05 Version |
Dot | 12:beaae3757b7d | 33 | __attribute__((section(".ARM.__at_0x7C00"))) void bootloader(void) |
Sissors | 11:a7a0730e20db | 34 | { |
Sissors | 11:a7a0730e20db | 35 | setupserial(); |
Sissors | 11:a7a0730e20db | 36 | write("\n\n\rBootloader\r\n"); |
Sissors | 11:a7a0730e20db | 37 | write("Continue? (y/n)"); |
Sissors | 11:a7a0730e20db | 38 | |
Sissors | 11:a7a0730e20db | 39 | //Wait until data arrived, if it is 'y', continue |
Sissors | 11:a7a0730e20db | 40 | while(!(UART0->S1 & UART_S1_RDRF_MASK)); |
Sissors | 11:a7a0730e20db | 41 | if (UART0->D != 'y') |
Sissors | 11:a7a0730e20db | 42 | return; |
Sissors | 11:a7a0730e20db | 43 | |
Sissors | 11:a7a0730e20db | 44 | //Erase all sectors we use for the user program |
Sissors | 11:a7a0730e20db | 45 | write("Erasing sectors!\r\n"); |
Sissors | 11:a7a0730e20db | 46 | for (int i = 0; i<NUM_SECTORS; i++) |
Sissors | 11:a7a0730e20db | 47 | erase_sector(SECTOR_SIZE * i); |
Sissors | 11:a7a0730e20db | 48 | |
Sissors | 11:a7a0730e20db | 49 | write("Done erasing, send file!\r\n"); |
Sissors | 11:a7a0730e20db | 50 | |
Sissors | 11:a7a0730e20db | 51 | |
Sissors | 11:a7a0730e20db | 52 | char buffer[BUFFER_SIZE]; |
Sissors | 11:a7a0730e20db | 53 | uint32_t count = 0; |
Sissors | 11:a7a0730e20db | 54 | uint8_t buffercount = 0; |
Sissors | 11:a7a0730e20db | 55 | uint32_t timeout = 0; |
Sissors | 11:a7a0730e20db | 56 | |
Sissors | 11:a7a0730e20db | 57 | //Wait until data is sent |
Sissors | 11:a7a0730e20db | 58 | while(!(UART0->S1 & UART_S1_RDRF_MASK)); |
Sissors | 11:a7a0730e20db | 59 | |
Sissors | 11:a7a0730e20db | 60 | //Data receive loop |
Sissors | 11:a7a0730e20db | 61 | while(1) { |
Sissors | 11:a7a0730e20db | 62 | //Check if there is new data |
Sissors | 11:a7a0730e20db | 63 | if (UART0->S1 & UART_S1_RDRF_MASK) { |
Sissors | 11:a7a0730e20db | 64 | //Place data in buffer |
Sissors | 11:a7a0730e20db | 65 | buffer[buffercount] = UART0->D; |
Sissors | 11:a7a0730e20db | 66 | buffercount++; |
Sissors | 11:a7a0730e20db | 67 | |
Sissors | 11:a7a0730e20db | 68 | //Reset timeout |
Sissors | 11:a7a0730e20db | 69 | timeout = 0; |
Sissors | 11:a7a0730e20db | 70 | |
Sissors | 11:a7a0730e20db | 71 | //We write per BUFFER_SIZE chars |
Sissors | 11:a7a0730e20db | 72 | if (buffercount == BUFFER_SIZE) { |
Sissors | 11:a7a0730e20db | 73 | //NMI Handler is at bytes 8-9-10-11, we overwrite this to point to bootloader function |
Sissors | 11:a7a0730e20db | 74 | if (count == 0) { |
Sissors | 11:a7a0730e20db | 75 | buffer[8] = 0x01; |
Sissors | 11:a7a0730e20db | 76 | buffer[9] = 0x00; |
Sissors | 11:a7a0730e20db | 77 | buffer[10] = 0x01; |
Sissors | 11:a7a0730e20db | 78 | buffer[11] = 0x00; |
Sissors | 11:a7a0730e20db | 79 | } |
Sissors | 11:a7a0730e20db | 80 | |
Sissors | 11:a7a0730e20db | 81 | //Program the buffer into the flash memory |
Sissors | 11:a7a0730e20db | 82 | if (program_flash(count, buffer, BUFFER_SIZE) != 0) { |
Sissors | 11:a7a0730e20db | 83 | write("Error!\r\n"); |
Sissors | 11:a7a0730e20db | 84 | break; |
Sissors | 11:a7a0730e20db | 85 | } |
Sissors | 11:a7a0730e20db | 86 | |
Sissors | 11:a7a0730e20db | 87 | //Reset buffercount for next buffer |
Sissors | 11:a7a0730e20db | 88 | write("#"); |
Sissors | 11:a7a0730e20db | 89 | buffercount = 0; |
Sissors | 11:a7a0730e20db | 90 | count += BUFFER_SIZE; |
Sissors | 11:a7a0730e20db | 91 | } |
Sissors | 11:a7a0730e20db | 92 | } else { |
Sissors | 11:a7a0730e20db | 93 | //No new data, increase timeout |
Dot | 12:beaae3757b7d | 94 | timeout++; |
Sissors | 11:a7a0730e20db | 95 | //We have received no new data for a while, assume we are done |
Sissors | 11:a7a0730e20db | 96 | if (timeout > TIMEOUT) { |
Sissors | 11:a7a0730e20db | 97 | //If there is data left in the buffer, program it |
Sissors | 11:a7a0730e20db | 98 | if (buffercount != 0) { |
Sissors | 11:a7a0730e20db | 99 | for (int i = buffercount; i<BUFFER_SIZE; i++) { |
Sissors | 11:a7a0730e20db | 100 | buffer[i] = 0xFF; |
Sissors | 11:a7a0730e20db | 101 | } |
Sissors | 11:a7a0730e20db | 102 | program_flash(count, buffer, BUFFER_SIZE); |
Sissors | 11:a7a0730e20db | 103 | } |
Sissors | 11:a7a0730e20db | 104 | break; //We should be done programming :D |
Sissors | 11:a7a0730e20db | 105 | } |
Sissors | 11:a7a0730e20db | 106 | } |
Sissors | 11:a7a0730e20db | 107 | } |
Sissors | 11:a7a0730e20db | 108 | write("Done programming!\r\n"); |
Sissors | 11:a7a0730e20db | 109 | NVIC_SystemReset(); |
Sissors | 11:a7a0730e20db | 110 | |
Sissors | 11:a7a0730e20db | 111 | //Shouldn't arrive here |
Sissors | 11:a7a0730e20db | 112 | while(1); |
Sissors | 11:a7a0730e20db | 113 | } |
Sissors | 11:a7a0730e20db | 114 | |
Dot | 12:beaae3757b7d | 115 | __attribute__((section(".ARM.__at_0x7C80"))) static void setupserial(void) { |
Sissors | 11:a7a0730e20db | 116 | //Setup USBTX/USBRX pins (PTB16/PTB17) |
Sissors | 11:a7a0730e20db | 117 | SIM->SCGC5 |= 1 << SIM_SCGC5_PORTB_SHIFT; |
Sissors | 11:a7a0730e20db | 118 | PORTB->PCR[16] = (PORTB->PCR[16] & 0x700) | (3 << 8); |
Sissors | 11:a7a0730e20db | 119 | PORTB->PCR[17] = (PORTB->PCR[17] & 0x700) | (3 << 8); |
Sissors | 11:a7a0730e20db | 120 | |
Sissors | 11:a7a0730e20db | 121 | //Setup UART (ugly, copied resulting values from mbed serial setup) |
Sissors | 11:a7a0730e20db | 122 | SIM->SCGC4 |= SIM_SCGC4_UART0_MASK; |
Sissors | 11:a7a0730e20db | 123 | |
Sissors | 11:a7a0730e20db | 124 | UART0->BDH = 3; |
Sissors | 11:a7a0730e20db | 125 | UART0->BDL = 13; |
Sissors | 11:a7a0730e20db | 126 | UART0->C4 = 8; |
Sissors | 11:a7a0730e20db | 127 | UART0->C2 = 12; //Enables UART |
Sissors | 11:a7a0730e20db | 128 | |
Sissors | 11:a7a0730e20db | 129 | } |
Sissors | 11:a7a0730e20db | 130 | |
Dot | 12:beaae3757b7d | 131 | __attribute__((section(".ARM.__at_0x7CA0"))) static void write(char *value) |
Sissors | 11:a7a0730e20db | 132 | { |
Sissors | 11:a7a0730e20db | 133 | int i = 0; |
Sissors | 11:a7a0730e20db | 134 | //Loop through string and send everything |
Sissors | 11:a7a0730e20db | 135 | while(*(value+i) != '\0') { |
Sissors | 11:a7a0730e20db | 136 | while(!(UART0->S1 & UART_S1_TDRE_MASK)); |
Sissors | 11:a7a0730e20db | 137 | UART0->D = *(value+i); |
Sissors | 11:a7a0730e20db | 138 | i++; |
Sissors | 11:a7a0730e20db | 139 | } |
Sissors | 11:a7a0730e20db | 140 | } |