Freescale Kinetis MK20DX-series FLASH erasing.

I needed a small program to initialize two MK20DX256 CPUs that were acting up. Below is part of the code to erase the flash. The mk20dx128.h file is from Paul Stoffregen’s Teensy 3.x GIT repository. You also want his linker scripts (.ld). The code was tested on MK20DX128 and 256 CPUs. Use at your own risk!

/* 
    MK20DX128/256 flash init/write program.
    
    Niels A. Moseley, 2015.
    
    1) Disable the watchdog
    2) If needed, erase the FLASH protection sector & stop. (requires reboot to reinit FLASH)
    3) Fully erase the FLASH.
    
    Note: this program MUST be loaded into RAM. Use at your own risk!

    This code is released into the public domain.
*/

#include <mk20dx128.h>
#include <stdint.h>

// NOTE: the entire program should execute from RAM
// address 0x1FFF8000

#define size_t unsigned int;

inline void flash_word(uint32_t address, uint32_t word);
inline void flash_erase();
inline void flash_erase_zerosector();

void unused_isr() __attribute__((interrupt("IRQ")));
void hardfault_isr() __attribute__((interrupt("IRQ")));
void boot_error() __attribute__((interrupt("IRQ")));
void systick_isr() __attribute__((interrupt("IRQ")));

__attribute__ ((section(".ramcode")))
void unused_isr()
{
    asm("bkpt #0");
    while(1) {};
}

__attribute__ ((section(".ramcode")))
void hardfault_isr()
{
    asm("bkpt #0");
    while(1) {};
}

__attribute__ ((section(".ramcode")))
void boot_error()
{
    asm("bkpt #0");
    while(1) {};
}
__attribute__ ((section(".ramcode")))
void systick_isr()
{
    
}

// NOTE: all of the peripheral interrupt handlers were deleted.
// we don't need them!
__attribute__ ((section(".vectorsram"), used))
void (* const gVectors[])(void) =
{
    (uint32_t*)0x20008000,	    // 0 ARM: Initial Stack Pointer
    boot_error,	// 1 ARM: Initial Program Counter
    unused_isr,	// 2 ARM: Non-maskable Interrupt (NMI)
    hardfault_isr,	// 3 ARM: Hard Fault
    unused_isr,	// 4 ARM: MemManage Fault
    unused_isr,	// 5 ARM: Bus Fault
    unused_isr,	// 6 ARM: Usage Fault
    unused_isr,	// 7 --
    unused_isr,	// 8 --
    unused_isr,	// 9 --
    unused_isr,	// 10 --
    unused_isr,	// 11 ARM: Supervisor call (SVCall)
    unused_isr,	// 12 ARM: Debug Monitor
    unused_isr,	// 13 --
    unused_isr,	// 14 ARM: Pendable req serv(PendableSrvReq)
    systick_isr,	// 15 ARM: System tick timer (SysTick)
    
    unused_isr,	// 16 DMA channel 0 transfer complete
    unused_isr,	// 17 DMA channel 1 transfer complete
    unused_isr,	// 18 DMA channel 2 transfer complete
    unused_isr,	// 19 DMA channel 3 transfer complete
    unused_isr,	// 20 DMA channel 4 transfer complete
    unused_isr,	// 21 DMA channel 5 transfer complete
    unused_isr,	// 22 DMA channel 6 transfer complete
    unused_isr,	// 23 DMA channel 7 transfer complete
    unused_isr,	// 24 DMA channel 8 transfer complete
    unused_isr,	// 25 DMA channel 9 transfer complete
    unused_isr,	// 26 DMA channel 10 transfer complete
    unused_isr,	// 27 DMA channel 10 transfer complete
    unused_isr,	// 28 DMA channel 10 transfer complete
    unused_isr,	// 29 DMA channel 10 transfer complete
    unused_isr,	// 30 DMA channel 10 transfer complete
    unused_isr,	// 31 DMA channel 10 transfer complete
    unused_isr,	// 32 DMA error interrupt channel
    unused_isr,	// 33 --
    unused_isr,	// 34 Flash Memory Command complete
    unused_isr,	// 35 Flash Read collision
    unused_isr,	// 36 Low-voltage detect/warning
    unused_isr,	// 37 Low Leakage Wakeup
    unused_isr,	// 38 Both EWM and WDOG interrupt
    unused_isr,	// 39 --
    unused_isr,	// 40 I2C0
    unused_isr,	// 41 I2C1
    unused_isr,	// 42 SPI0
    unused_isr,	// 43 SPI1
    unused_isr,	// 44 --
    unused_isr,	// 45 CAN OR'ed Message buffer (0-15)
    unused_isr,	// 46 CAN Bus Off
    unused_isr,	// 47 CAN Error
    unused_isr,	// 48 CAN Transmit Warning
    unused_isr,	// 49 CAN Receive Warning
    unused_isr,	// 50 CAN Wake Up
    unused_isr,	// 51 I2S0 Transmit
    unused_isr,	// 52 I2S0 Receive
    unused_isr,	// 53 --
    unused_isr,	// 54 --
    unused_isr,	// 55 --
    unused_isr,	// 56 --
    unused_isr,	// 57 --
    unused_isr,	// 58 --
    unused_isr,	// 59 --
    unused_isr,	// 60 UART0 CEA709.1-B (LON) status
    unused_isr,	// 61 UART0 status
    unused_isr,	// 62 UART0 error
    unused_isr,	// 63 UART1 status
    unused_isr,	// 64 UART1 error
    unused_isr,	// 65 UART2 status
    unused_isr,	// 66 UART2 error
    unused_isr,	// 67 --
    unused_isr,	// 68 --
    unused_isr,	// 69 --
    unused_isr,	// 70 --
    unused_isr,	// 71 --
    unused_isr,	// 72 --
    unused_isr,	// 73 ADC0
    unused_isr,	// 74 ADC1
    unused_isr,	// 75 CMP0
    unused_isr,	// 76 CMP1
    unused_isr,	// 77 CMP2
    unused_isr,	// 78 FTM0
    unused_isr,	// 79 FTM1
    unused_isr,	// 80 FTM2
    unused_isr,	// 81 CMT
    unused_isr,	// 82 RTC Alarm interrupt
    unused_isr,	// 83 RTC Seconds interrupt
    unused_isr,	// 84 PIT Channel 0
    unused_isr,	// 85 PIT Channel 1
    unused_isr,	// 86 PIT Channel 2
    unused_isr,	// 87 PIT Channel 3
    unused_isr,	// 88 PDB Programmable Delay Block
    unused_isr,	// 89 USB OTG
    unused_isr,	// 90 USB Charger Detect
    unused_isr,	// 91 --
    unused_isr,	// 92 --
    unused_isr,	// 93 --
    unused_isr,	// 94 --
    unused_isr,	// 95 --
    unused_isr,	// 96 --
    unused_isr,	// 97 DAC0
    unused_isr,	// 98 --
    unused_isr,	// 99 TSI0
    unused_isr,	// 100 MCG
    unused_isr,	// 101 Low Power Timer
    unused_isr,	// 102 --
    unused_isr,	// 103 Pin detect (Port A)
    unused_isr,	// 104 Pin detect (Port B)
    unused_isr,	// 105 Pin detect (Port C)
    unused_isr,	// 106 Pin detect (Port D)
    unused_isr,	// 107 Pin detect (Port E)
    unused_isr,	// 108 --
    unused_isr,	// 109 --
    unused_isr,	// 110 Software interrupt    
};

__attribute__ ((section(".startramcode")))
void start(void)
{
    // disable Watchdog!
	WDOG_UNLOCK = WDOG_UNLOCK_SEQ1;
	WDOG_UNLOCK = WDOG_UNLOCK_SEQ2;
	asm volatile ("nop");
    asm volatile ("nop");    
    
	WDOG_STCTRLH = WDOG_STCTRLH_ALLOWUPDATE;
	SIM_SCGC5 = 0x00043F82;
    SIM_SCGC6 |= SIM_SCGC6_FTFL;

    // custom ISR vector table (table should be in RAM! 🙂 )    
    SCB_VTOR = gVectors;
    
    uint32_t *ptr = 0;
    if (*ptr != 0xFFFFFFFF)
    {
        uint32_t *protbits = (uint32_t*)0x040C;
        if (*protbits != 0xFEFFFFFF)
        {
            // mass erase won't work
            // first erase the flash sector that
            // contains the protection bits.
            flash_erase_zerosector();
        
            // unlock the flash!
            flash_word(0x040C, 0xfeffffff);
            // reboot needed!
        }
        else
        {
            // mass erase the flash!
            flash_erase();
        }
    }
    
    asm("bkpt #0");
    while (1) {};
}

__attribute__ ((section(".ramcode")))
void flash_word(uint32_t address, uint32_t word)
{    
    // wait for flash to be ready!
    while((FTFL_FSTAT & FTFL_FSTAT_CCIF) != FTFL_FSTAT_CCIF) {};
    
    // clear error flags
    FTFL_FSTAT = FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL;

    // program long word!    
    FTFL_FCCOB0 = 0x06;             // PGM
    FTFL_FCCOB1 = address >> 16;
    FTFL_FCCOB2 = address >> 8;
    FTFL_FCCOB3 = address;
    FTFL_FCCOB4 = word >> 24;
    FTFL_FCCOB5 = word >> 16;
    FTFL_FCCOB6 = word >> 8;
    FTFL_FCCOB7 = word;
    
    FTFL_FSTAT  = FTFL_FSTAT_CCIF;  // execute!
    
    while((FTFL_FSTAT & FTFL_FSTAT_CCIF) != FTFL_FSTAT_CCIF) {};    
}

__attribute__ ((section(".ramcode")))
void flash_erase()
{
    // wait for flash to be ready!
    while((FTFL_FSTAT & FTFL_FSTAT_CCIF) != FTFL_FSTAT_CCIF) {}; // wait
    
    // clear error flags
    FTFL_FSTAT = FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL;

    // mass erase!
    FTFL_FCCOB0 = 0x44;             // Erase!
    
    FTFL_FSTAT  = FTFL_FSTAT_CCIF;  // execute!
    
    while((FTFL_FSTAT & FTFL_FSTAT_CCIF) != FTFL_FSTAT_CCIF) {}; // wait
    
    // unlock flash!
    flash_word(0x040C, 0xfeffffff);
}

__attribute__ ((section(".ramcode")))
void flash_erase_zerosector()
{
    // wait for flash to be ready!
    while((FTFL_FSTAT & FTFL_FSTAT_CCIF) != FTFL_FSTAT_CCIF) {}; // wait
    
    // clear error flags
    FTFL_FSTAT = FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL;

    // erase sector
    FTFL_FCCOB0 = 0x09;
    FTFL_FCCOB1 = 0;
    FTFL_FCCOB2 = 0;
    FTFL_FCCOB3 = 0;
    
    FTFL_FSTAT  = FTFL_FSTAT_CCIF;  // execute!
    
    while((FTFL_FSTAT & FTFL_FSTAT_CCIF) != FTFL_FSTAT_CCIF) {}; // wait
}
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s