text: #include "mk20dx128.h"
  #include <stdint.h>
  // #include "HardwareSerial.h"
  
  // The EEPROM is really RAM with a hardware-based backup system to
  // flash memory.  Selecting a smaller size EEPROM allows more wear
  // leveling, for higher write endurance.  If you edit this file,
  // set this to the smallest size your application can use.  Also,
  // due to Freescale's implementation, writing 16 or 32 bit words
  // (aligned to 2 or 4 byte boundaries) has twice the endurance
  // compared to writing 8 bit bytes.
  //
  #define EEPROM_SIZE 2048
  
  // Writing unaligned 16 or 32 bit data is handled automatically when
  // this is defined, but at a cost of extra code size.  Without this,
  // any unaligned write will cause a hard fault exception!  If you're
  // absolutely sure all 16 and 32 bit writes will be aligned, you can
  // remove the extra unnecessary code.
  //
  #define HANDLE_UNALIGNED_WRITES
  
  				// Minimum EEPROM Endurance
  				// ------------------------
  #if (EEPROM_SIZE == 2048)	// 35000 writes/byte or 70000 writes/word
    #define EEESIZE 0x33
  #elif (EEPROM_SIZE == 1024)	// 75000 writes/byte or 150000 writes/word
    #define EEESIZE 0x34
  #elif (EEPROM_SIZE == 512)	// 155000 writes/byte or 310000 writes/word
    #define EEESIZE 0x35
  #elif (EEPROM_SIZE == 256)	// 315000 writes/byte or 630000 writes/word
    #define EEESIZE 0x36
  #elif (EEPROM_SIZE == 128)	// 635000 writes/byte or 1270000 writes/word
    #define EEESIZE 0x37
  #elif (EEPROM_SIZE == 64)	// 1275000 writes/byte or 2550000 writes/word
    #define EEESIZE 0x38
  #elif (EEPROM_SIZE == 32)	// 2555000 writes/byte or 5110000 writes/word
    #define EEESIZE 0x39
  #endif
  
  void eeprom_initialize(void)
  {
  	uint32_t count=0;
  	uint16_t do_flash_cmd[] = {
  		0xf06f, 0x037f, 0x7003, 0x7803,
  		0xf013, 0x0f80, 0xd0fb, 0x4770};
  	uint8_t status;
  
  	if (FTFL_FCNFG & FTFL_FCNFG_RAMRDY) {
  		// FlexRAM is configured as traditional RAM
  		// We need to reconfigure for EEPROM usage
  		FTFL_FCCOB0 = 0x80; // PGMPART = Program Partition Command
  		FTFL_FCCOB4 = EEESIZE; // EEPROM Size
  		FTFL_FCCOB5 = 0x03; // 0K for Dataflash, 32K for EEPROM backup
  		__disable_irq();
  		// do_flash_cmd() must execute from RAM.  Luckily the C syntax is simple...
  		(*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&FTFL_FSTAT);
  		__enable_irq();
  		status = FTFL_FSTAT;
  		if (status & 0x70) {
  			FTFL_FSTAT = (status & 0x70);
  			return; // error
  		}
  	}
  	// wait for eeprom to become ready (is this really necessary?)
  	while (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) {
  		if (++count > 20000) break;
  	}
  }
  
  #define FlexRAM ((uint8_t *)0x14000000)
  
  uint8_t eeprom_read_byte(const uint8_t *addr)
  {
  	uint32_t offset = (uint32_t)addr;
  	if (offset >= EEPROM_SIZE) return 0;
  	return FlexRAM[offset];
  }
  
  uint16_t eeprom_read_word(const uint16_t *addr)
  {
  	uint32_t offset = (uint32_t)addr;
  	if (offset >= EEPROM_SIZE-1) return 0;
  	return *(uint16_t *)(&FlexRAM[offset]);
  }
  
  uint32_t eeprom_read_dword(const uint32_t *addr)
  {
  	uint32_t offset = (uint32_t)addr;
  	if (offset >= EEPROM_SIZE-3) return 0;
  	return *(uint32_t *)(&FlexRAM[offset]);
  }
  
  
  static void flexram_wait(void)
  {
  	while (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) {
  		// TODO: timeout
  	}
  }
  
  void eeprom_write_byte(uint8_t *addr, uint8_t value)
  {
  	uint32_t offset = (uint32_t)addr;
  
  	if (offset >= EEPROM_SIZE) return;
  	if (FlexRAM[offset] != value) {
  		FlexRAM[offset] = value;
  		flexram_wait();
  	}
  }
  
  void eeprom_write_word(uint16_t *addr, uint16_t value)
  {
  	uint32_t offset = (uint32_t)addr;
  
  	if (offset >= EEPROM_SIZE-1) return;
  #ifdef HANDLE_UNALIGNED_WRITES
  	if ((offset & 1) == 0) {
  #endif
  		if (*(uint16_t *)(&FlexRAM[offset]) != value) {
  			*(uint16_t *)(&FlexRAM[offset]) = value;
  			flexram_wait();
  		}
  #ifdef HANDLE_UNALIGNED_WRITES
  	} else {
  		if (FlexRAM[offset] != value) {
  			FlexRAM[offset] = value;
  			flexram_wait();
  		}
  		if (FlexRAM[offset + 1] != (value >> 8)) {
  			FlexRAM[offset + 1] = value >> 8;
  			flexram_wait();
  		}
  	}
  #endif
  }
  
  void eeprom_write_dword(uint32_t *addr, uint32_t value)
  {
  	uint32_t offset = (uint32_t)addr;
  
  	if (offset >= EEPROM_SIZE-3) return;
  #ifdef HANDLE_UNALIGNED_WRITES
  	switch (offset & 3) {
  	case 0:
  #endif
  		if (*(uint32_t *)(&FlexRAM[offset]) != value) {
  			*(uint32_t *)(&FlexRAM[offset]) = value;
  			flexram_wait();
  		}
  		return;
  #ifdef HANDLE_UNALIGNED_WRITES
  	case 2:
  		if (*(uint16_t *)(&FlexRAM[offset]) != value) {
  			*(uint16_t *)(&FlexRAM[offset]) = value;
  			flexram_wait();
  		}
  		if (*(uint16_t *)(&FlexRAM[offset + 2]) != (value >> 16)) {
  			*(uint16_t *)(&FlexRAM[offset + 2]) = value >> 16;
  			flexram_wait();
  		}
  		return;
  	default:
  		if (FlexRAM[offset] != value) {
  			FlexRAM[offset] = value;
  			flexram_wait();
  		}
  		if (*(uint16_t *)(&FlexRAM[offset + 1]) != (value >> 8)) {
  			*(uint16_t *)(&FlexRAM[offset + 1]) = value >> 8;
  			flexram_wait();
  		}
  		if (FlexRAM[offset + 3] != (value >> 24)) {
  			FlexRAM[offset + 3] = value >> 24;
  			flexram_wait();
  		}
  	}
  #endif
  }
  
  
  /*
  void do_flash_cmd(volatile uint8_t *fstat)
  {
  	*fstat = 0x80;
  	while ((*fstat & 0x80) == 0) ; // wait
  }
  00000000 <do_flash_cmd>:
     0:	f06f 037f 	mvn.w	r3, #127	; 0x7f
     4:	7003      	strb	r3, [r0, #0]
     6:	7803      	ldrb	r3, [r0, #0]
     8:	f013 0f80 	tst.w	r3, #128	; 0x80
     c:	d0fb      	beq.n	6 <do_flash_cmd+0x6>
     e:	4770      	bx	lr
  */
  
  