.
Dependencies: mbed EthernetInterface mbed-rtos
Fork of Bootloader_K64F by
Revision 10:fb5121bcc468, committed 2016-04-24
- Comitter:
- Sissors
- Date:
- Sun Apr 24 12:46:37 2016 +0000
- Parent:
- 9:56ed3a56ecc3
- Commit message:
- I just committed already
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FreescaleIAP/FreescaleIAP.cpp Sun Apr 24 12:46:37 2016 +0000 @@ -0,0 +1,241 @@ +#include "FreescaleIAP.h" + +//#define IAPDEBUG + +#ifdef TARGET_K64F +//For K64F +# include "MK64F12.h" +# define USE_ProgramPhrase 1 +# define FTFA FTFE +# define FTFA_FSTAT_FPVIOL_MASK FTFE_FSTAT_FPVIOL_MASK +# define FTFA_FSTAT_ACCERR_MASK FTFE_FSTAT_ACCERR_MASK +# define FTFA_FSTAT_RDCOLERR_MASK FTFE_FSTAT_RDCOLERR_MASK +# define FTFA_FSTAT_CCIF_MASK FTFE_FSTAT_CCIF_MASK +# define FTFA_FSTAT_MGSTAT0_MASK FTFE_FSTAT_MGSTAT0_MASK +#else +//Different names used on at least the K20: +# ifndef FTFA_FSTAT_FPVIOL_MASK +# define FTFA FTFL +# define FTFA_FSTAT_FPVIOL_MASK FTFL_FSTAT_FPVIOL_MASK +# define FTFA_FSTAT_ACCERR_MASK FTFL_FSTAT_ACCERR_MASK +# define FTFA_FSTAT_RDCOLERR_MASK FTFL_FSTAT_RDCOLERR_MASK +# define FTFA_FSTAT_CCIF_MASK FTFL_FSTAT_CCIF_MASK +# define FTFA_FSTAT_MGSTAT0_MASK FTFL_FSTAT_MGSTAT0_MASK +# endif +#endif + + +enum FCMD { + Read1s = 0x01, + ProgramCheck = 0x02, + ReadResource = 0x03, + ProgramLongword = 0x06, + ProgramPhrase = 0x07, + EraseSector = 0x09, + Read1sBlock = 0x40, + ReadOnce = 0x41, + ProgramOnce = 0x43, + EraseAll = 0x44, + VerifyBackdoor = 0x45 + }; + +inline void run_command(void); +bool check_boundary(int address, unsigned int length); +bool check_align(int address); +IAPCode verify_erased(int address, unsigned int length); +IAPCode check_error(void); +IAPCode program_word(int address, char *data); + +__attribute__((section(".ARM.__at_0x79420"))) IAPCode erase_sector(int address) { + #ifdef IAPDEBUG + printf("IAP: Erasing at %x\r\n", address); + #endif + if (check_align(address)) + return AlignError; + + //Setup command + FTFA->FCCOB0 = EraseSector; + FTFA->FCCOB1 = (address >> 16) & 0xFF; + FTFA->FCCOB2 = (address >> 8) & 0xFF; + FTFA->FCCOB3 = address & 0xFF; + + run_command(); + + return check_error(); +} + +__attribute__((section(".ARM.__at_0x79420"))) 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 + if (check_align(address)) + return AlignError; + + IAPCode eraseCheck = verify_erased(address, length); + if (eraseCheck != Success) + return eraseCheck; + + IAPCode progResult; +#ifdef USE_ProgramPhrase + for (int i = 0; i < length; i+=8) { + progResult = program_word(address + i, data + i); + if (progResult != Success) + return progResult; + } +#else + for (int i = 0; i < length; i+=4) { + progResult = program_word(address + i, data + i); + if (progResult != Success) + return progResult; + } +#endif + return Success; +} + +__attribute__((section(".ARM.__at_0x79420"))) 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) { + #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]); + #else + printf("IAP: Programming word at %x, %d - %d - %d - %d\r\n", address, data[0], data[1], data[2], data[3]); + #endif + + #endif + if (check_align(address)) + return AlignError; +#ifdef USE_ProgramPhrase + FTFA->FCCOB0 = ProgramPhrase; + FTFA->FCCOB1 = (address >> 16) & 0xFF; + FTFA->FCCOB2 = (address >> 8) & 0xFF; + FTFA->FCCOB3 = address & 0xFF; + FTFA->FCCOB4 = data[3]; + FTFA->FCCOB5 = data[2]; + FTFA->FCCOB6 = data[1]; + FTFA->FCCOB7 = data[0]; + FTFA->FCCOB8 = data[7]; + FTFA->FCCOB9 = data[6]; + FTFA->FCCOBA = data[5]; + FTFA->FCCOBB = data[4]; +#else + //Setup command + FTFA->FCCOB0 = ProgramLongword; + FTFA->FCCOB1 = (address >> 16) & 0xFF; + FTFA->FCCOB2 = (address >> 8) & 0xFF; + FTFA->FCCOB3 = address & 0xFF; + FTFA->FCCOB4 = data[3]; + FTFA->FCCOB5 = data[2]; + FTFA->FCCOB6 = data[1]; + FTFA->FCCOB7 = data[0]; +#endif + run_command(); + + return check_error(); +} + +/* Clear possible flags which are set, run command, wait until done */ +__attribute__((section(".ARM.__at_0x79420"))) 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; + FTFA->FSTAT = FTFA_FSTAT_CCIF_MASK; + while (!(FTFA->FSTAT & FTFA_FSTAT_CCIF_MASK)); + __enable_irq(); +} + + + +/* Check if no flash boundary is violated + Returns true on violation */ +__attribute__((section(".ARM.__at_0x79420"))) bool check_boundary(int address, unsigned int length) { + int temp = (address+length - 1) / SECTOR_SIZE; + address /= SECTOR_SIZE; + bool retval = (address != temp); + #ifdef IAPDEBUG + if (retval) + printf("IAP: Boundary violation\r\n"); + #endif + return retval; +} + +/* Check if address is correctly aligned + Returns true on violation */ +__attribute__((section(".ARM.__at_0x79420"))) bool check_align(int address) { + bool retval = address & 0x03; + #ifdef IAPDEBUG + if (retval) + printf("IAP: Alignment violation\r\n"); + #endif + return retval; +} + +/* 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) { + #ifdef IAPDEBUG + printf("IAP: Verify erased at %x with length %d\r\n", address, length); + #endif + + if (check_align(address)) + return AlignError; + + //Setup command + FTFA->FCCOB0 = Read1s; + FTFA->FCCOB1 = (address >> 16) & 0xFF; + FTFA->FCCOB2 = (address >> 8) & 0xFF; + FTFA->FCCOB3 = address & 0xFF; + FTFA->FCCOB4 = (length >> 10) & 0xFF; + FTFA->FCCOB5 = (length >> 2) & 0xFF; + FTFA->FCCOB6 = 0; + + run_command(); + + IAPCode retval = check_error(); + if (retval == RuntimeError) { + #ifdef IAPDEBUG + printf("IAP: Flash was not erased\r\n"); + #endif + return EraseError; + } + return retval; + +} + +/* Check if an error occured + Returns error code or Success*/ +__attribute__((section(".ARM.__at_0x79420"))) IAPCode check_error(void) { + if (FTFA->FSTAT & FTFA_FSTAT_FPVIOL_MASK) { + #ifdef IAPDEBUG + printf("IAP: Protection violation\r\n"); + #endif + return ProtectionError; + } + if (FTFA->FSTAT & FTFA_FSTAT_ACCERR_MASK) { + #ifdef IAPDEBUG + printf("IAP: Flash access error\r\n"); + #endif + return AccessError; + } + if (FTFA->FSTAT & FTFA_FSTAT_RDCOLERR_MASK) { + #ifdef IAPDEBUG + printf("IAP: Collision error\r\n"); + #endif + return CollisionError; + } + if (FTFA->FSTAT & FTFA_FSTAT_MGSTAT0_MASK) { + #ifdef IAPDEBUG + printf("IAP: Runtime error\r\n"); + #endif + return RuntimeError; + } + #ifdef IAPDEBUG + printf("IAP: No error reported\r\n"); + #endif + return Success; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FreescaleIAP/FreescaleIAP.h Sun Apr 24 12:46:37 2016 +0000 @@ -0,0 +1,59 @@ +#ifndef FREESCALEIAP_H +#define FREESCALEIAP_H + +#include "mbed.h" + +#if defined(TARGET_KLXX) | defined(TARGET_K20D50M) +#define SECTOR_SIZE 1024 +#elif (TARGET_K22F) +#define SECTOR_SIZE 2048 +#elif defined(TARGET_K64F) +#define SECTOR_SIZE 4096 +#else +#warning FreescaleIAP unknown target, using default 1024B +#define SECTOR_SIZE 1024 +#endif + +enum IAPCode { + BoundaryError = -99, //Commands may not span several sectors + AlignError, //Data must be aligned on longword (two LSBs zero) + ProtectionError, //Flash sector is protected + AccessError, //Something went wrong + CollisionError, //During writing something tried to flash which was written to + LengthError, //The length must be multiples of 4 + RuntimeError, + EraseError, //The flash was not erased before writing to it + Success = 0 + }; + +/** Erase a flash sector + * + * The size erased depends on the used device + * + * @param address address in the sector which needs to be erased + * @param return Success if no errors were encountered, otherwise one of the error states + */ +IAPCode erase_sector(int address); + +/** Program flash + * + * Before programming the used area needs to be erased. The erase state is checked + * before programming, and will return an error if not erased. + * + * @param address starting address where the data needs to be programmed (must be longword alligned: two LSBs must be zero) + * @param data pointer to array with the data to program + * @param length number of bytes to program (must be a multiple of 4. must be a multiple of 8 when K64F) + * @param return Success if no errors were encountered, otherwise one of the error states + */ +IAPCode program_flash(int address, char *data, unsigned int length); + +/** + * Returns size of flash memory + * + * This is the first address which is not flash + * + * @param return length of flash memory in bytes + */ +uint32_t flash_size(void); + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FreescaleIAP/bootloader.cpp Sun Apr 24 12:46:37 2016 +0000 @@ -0,0 +1,80 @@ +#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++; + } + }