.

Dependencies:   mbed EthernetInterface mbed-rtos

Fork of Bootloader_K64F by Erik -

Files at this revision

API Documentation at this revision

Comitter:
Sissors
Date:
Sun Apr 24 12:46:37 2016 +0000
Parent:
9:56ed3a56ecc3
Commit message:
I just committed already

Changed in this revision

FreescaleIAP/FreescaleIAP.cpp Show annotated file Show diff for this revision Revisions of this file
FreescaleIAP/FreescaleIAP.h Show annotated file Show diff for this revision Revisions of this file
FreescaleIAP/bootloader.cpp Show annotated file Show diff for this revision Revisions of this file
--- /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++;
+        }
+    }