| /* Teensyduino Core Library | /* Teensyduino Core Library | ||||
| * http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
| * Copyright (c) 2013 PJRC.COM, LLC. | |||||
| * Copyright (c) 2016 PJRC.COM, LLC. | |||||
| * | * | ||||
| * Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
| * a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
| #if defined(__MK20DX128__) || defined(__MK20DX256__) | #if defined(__MK20DX128__) || defined(__MK20DX256__) | ||||
| #define EEPROM_MAX 2048 | #define EEPROM_MAX 2048 | ||||
| #define EEPARTITION 0x03 // all 32K dataflash for EEPROM, none for Data | #define EEPARTITION 0x03 // all 32K dataflash for EEPROM, none for Data | ||||
| #define EEESPLIT 0x30 // must be 0x30 on these chips | |||||
| #elif defined(__MK64FX512__) | #elif defined(__MK64FX512__) | ||||
| #define EEPROM_MAX 4096 | #define EEPROM_MAX 4096 | ||||
| #define EEPARTITION 0x04 // 64K dataflash for EEPROM, 64K for Data | |||||
| #define EEPARTITION 0x05 // all 128K dataflash for EEPROM | |||||
| #define EEESPLIT 0x10 // best endurance: 0x00 = first 12%, 0x10 = first 25%, 0x30 = all equal | |||||
| #elif defined(__MK66FX1M0__) | #elif defined(__MK66FX1M0__) | ||||
| #define EEPROM_MAX 4096 | #define EEPROM_MAX 4096 | ||||
| #define EEPARTITION 0x05 // 128K dataflash for EEPROM, 128K for Data | #define EEPARTITION 0x05 // 128K dataflash for EEPROM, 128K for Data | ||||
| #define EEESPLIT 0x10 // best endurance: 0x00 = first 12%, 0x10 = first 25%, 0x30 = all equal | |||||
| #elif defined(__MKL26Z64__) | #elif defined(__MKL26Z64__) | ||||
| #define EEPROM_MAX 255 | #define EEPROM_MAX 255 | ||||
| #endif | #endif | ||||
| #if E2END < 32 | #if E2END < 32 | ||||
| #define EEPROM_SIZE 32 | #define EEPROM_SIZE 32 | ||||
| #define EEESIZE 0x39 | |||||
| #define EEESIZE 0x09 | |||||
| #elif E2END < 64 | #elif E2END < 64 | ||||
| #define EEPROM_SIZE 64 | #define EEPROM_SIZE 64 | ||||
| #define EEESIZE 0x38 | |||||
| #define EEESIZE 0x08 | |||||
| #elif E2END < 128 | #elif E2END < 128 | ||||
| #define EEPROM_SIZE 128 | #define EEPROM_SIZE 128 | ||||
| #define EEESIZE 0x37 | |||||
| #define EEESIZE 0x07 | |||||
| #elif E2END < 256 | #elif E2END < 256 | ||||
| #define EEPROM_SIZE 256 | #define EEPROM_SIZE 256 | ||||
| #define EEESIZE 0x36 | |||||
| #define EEESIZE 0x06 | |||||
| #elif E2END < 512 | #elif E2END < 512 | ||||
| #define EEPROM_SIZE 512 | #define EEPROM_SIZE 512 | ||||
| #define EEESIZE 0x35 | |||||
| #define EEESIZE 0x05 | |||||
| #elif E2END < 1024 | #elif E2END < 1024 | ||||
| #define EEPROM_SIZE 1024 | #define EEPROM_SIZE 1024 | ||||
| #define EEESIZE 0x34 | |||||
| #define EEESIZE 0x04 | |||||
| #elif E2END < 2048 | #elif E2END < 2048 | ||||
| #define EEPROM_SIZE 2048 | #define EEPROM_SIZE 2048 | ||||
| #define EEESIZE 0x33 | |||||
| #define EEESIZE 0x03 | |||||
| #elif E2END < 4096 | #elif E2END < 4096 | ||||
| #define EEPROM_SIZE 4096 | #define EEPROM_SIZE 4096 | ||||
| #define EEESIZE 0x32 | |||||
| #define EEESIZE 0x02 | |||||
| #endif | #endif | ||||
| // Writing unaligned 16 or 32 bit data is handled automatically when | // Writing unaligned 16 or 32 bit data is handled automatically when | ||||
| uint8_t status; | uint8_t status; | ||||
| if (FTFL_FCNFG & FTFL_FCNFG_RAMRDY) { | if (FTFL_FCNFG & FTFL_FCNFG_RAMRDY) { | ||||
| uint8_t stat = FTFL_FSTAT & 0x70; | |||||
| if (stat) FTFL_FSTAT = stat; | |||||
| // FlexRAM is configured as traditional RAM | // FlexRAM is configured as traditional RAM | ||||
| // We need to reconfigure for EEPROM usage | // We need to reconfigure for EEPROM usage | ||||
| FTFL_FCCOB0 = 0x80; // PGMPART = Program Partition Command | FTFL_FCCOB0 = 0x80; // PGMPART = Program Partition Command | ||||
| FTFL_FCCOB4 = EEESIZE; // EEPROM Size | |||||
| FTFL_FCCOB3 = 0; | |||||
| FTFL_FCCOB4 = EEESPLIT | EEESIZE; | |||||
| FTFL_FCCOB5 = EEPARTITION; | FTFL_FCCOB5 = EEPARTITION; | ||||
| __disable_irq(); | __disable_irq(); | ||||
| // do_flash_cmd() must execute from RAM. Luckily the C syntax is simple... | // do_flash_cmd() must execute from RAM. Luckily the C syntax is simple... | ||||
| } | } | ||||
| // wait for eeprom to become ready (is this really necessary?) | // wait for eeprom to become ready (is this really necessary?) | ||||
| while (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) { | while (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) { | ||||
| if (++count > 20000) break; | |||||
| if (++count > 200000) break; | |||||
| } | } | ||||
| } | } | ||||
| #define FlexRAM ((uint8_t *)0x14000000) | |||||
| #define FlexRAM ((volatile uint8_t *)0x14000000) | |||||
| uint8_t eeprom_read_byte(const uint8_t *addr) | uint8_t eeprom_read_byte(const uint8_t *addr) | ||||
| { | { | ||||
| if (offset >= EEPROM_SIZE) return; | if (offset >= EEPROM_SIZE) return; | ||||
| if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); | if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); | ||||
| if (FlexRAM[offset] != value) { | if (FlexRAM[offset] != value) { | ||||
| uint8_t stat = FTFL_FSTAT & 0x70; | |||||
| if (stat) FTFL_FSTAT = stat; | |||||
| FlexRAM[offset] = value; | FlexRAM[offset] = value; | ||||
| flexram_wait(); | flexram_wait(); | ||||
| } | } | ||||
| if ((offset & 1) == 0) { | if ((offset & 1) == 0) { | ||||
| #endif | #endif | ||||
| if (*(uint16_t *)(&FlexRAM[offset]) != value) { | if (*(uint16_t *)(&FlexRAM[offset]) != value) { | ||||
| uint8_t stat = FTFL_FSTAT & 0x70; | |||||
| if (stat) FTFL_FSTAT = stat; | |||||
| *(uint16_t *)(&FlexRAM[offset]) = value; | *(uint16_t *)(&FlexRAM[offset]) = value; | ||||
| flexram_wait(); | flexram_wait(); | ||||
| } | } | ||||
| #ifdef HANDLE_UNALIGNED_WRITES | #ifdef HANDLE_UNALIGNED_WRITES | ||||
| } else { | } else { | ||||
| if (FlexRAM[offset] != value) { | if (FlexRAM[offset] != value) { | ||||
| uint8_t stat = FTFL_FSTAT & 0x70; | |||||
| if (stat) FTFL_FSTAT = stat; | |||||
| FlexRAM[offset] = value; | FlexRAM[offset] = value; | ||||
| flexram_wait(); | flexram_wait(); | ||||
| } | } | ||||
| if (FlexRAM[offset + 1] != (value >> 8)) { | if (FlexRAM[offset + 1] != (value >> 8)) { | ||||
| uint8_t stat = FTFL_FSTAT & 0x70; | |||||
| if (stat) FTFL_FSTAT = stat; | |||||
| FlexRAM[offset + 1] = value >> 8; | FlexRAM[offset + 1] = value >> 8; | ||||
| flexram_wait(); | flexram_wait(); | ||||
| } | } | ||||
| case 0: | case 0: | ||||
| #endif | #endif | ||||
| if (*(uint32_t *)(&FlexRAM[offset]) != value) { | if (*(uint32_t *)(&FlexRAM[offset]) != value) { | ||||
| uint8_t stat = FTFL_FSTAT & 0x70; | |||||
| if (stat) FTFL_FSTAT = stat; | |||||
| *(uint32_t *)(&FlexRAM[offset]) = value; | *(uint32_t *)(&FlexRAM[offset]) = value; | ||||
| flexram_wait(); | flexram_wait(); | ||||
| } | } | ||||
| #ifdef HANDLE_UNALIGNED_WRITES | #ifdef HANDLE_UNALIGNED_WRITES | ||||
| case 2: | case 2: | ||||
| if (*(uint16_t *)(&FlexRAM[offset]) != value) { | if (*(uint16_t *)(&FlexRAM[offset]) != value) { | ||||
| uint8_t stat = FTFL_FSTAT & 0x70; | |||||
| if (stat) FTFL_FSTAT = stat; | |||||
| *(uint16_t *)(&FlexRAM[offset]) = value; | *(uint16_t *)(&FlexRAM[offset]) = value; | ||||
| flexram_wait(); | flexram_wait(); | ||||
| } | } | ||||
| if (*(uint16_t *)(&FlexRAM[offset + 2]) != (value >> 16)) { | if (*(uint16_t *)(&FlexRAM[offset + 2]) != (value >> 16)) { | ||||
| uint8_t stat = FTFL_FSTAT & 0x70; | |||||
| if (stat) FTFL_FSTAT = stat; | |||||
| *(uint16_t *)(&FlexRAM[offset + 2]) = value >> 16; | *(uint16_t *)(&FlexRAM[offset + 2]) = value >> 16; | ||||
| flexram_wait(); | flexram_wait(); | ||||
| } | } | ||||
| return; | return; | ||||
| default: | default: | ||||
| if (FlexRAM[offset] != value) { | if (FlexRAM[offset] != value) { | ||||
| uint8_t stat = FTFL_FSTAT & 0x70; | |||||
| if (stat) FTFL_FSTAT = stat; | |||||
| FlexRAM[offset] = value; | FlexRAM[offset] = value; | ||||
| flexram_wait(); | flexram_wait(); | ||||
| } | } | ||||
| if (*(uint16_t *)(&FlexRAM[offset + 1]) != (value >> 8)) { | if (*(uint16_t *)(&FlexRAM[offset + 1]) != (value >> 8)) { | ||||
| uint8_t stat = FTFL_FSTAT & 0x70; | |||||
| if (stat) FTFL_FSTAT = stat; | |||||
| *(uint16_t *)(&FlexRAM[offset + 1]) = value >> 8; | *(uint16_t *)(&FlexRAM[offset + 1]) = value >> 8; | ||||
| flexram_wait(); | flexram_wait(); | ||||
| } | } | ||||
| if (FlexRAM[offset + 3] != (value >> 24)) { | if (FlexRAM[offset + 3] != (value >> 24)) { | ||||
| uint8_t stat = FTFL_FSTAT & 0x70; | |||||
| if (stat) FTFL_FSTAT = stat; | |||||
| FlexRAM[offset + 3] = value >> 24; | FlexRAM[offset + 3] = value >> 24; | ||||
| flexram_wait(); | flexram_wait(); | ||||
| } | } | ||||
| val32 |= (*src++ << 16); | val32 |= (*src++ << 16); | ||||
| val32 |= (*src++ << 24); | val32 |= (*src++ << 24); | ||||
| if (*(uint32_t *)(&FlexRAM[offset]) != val32) { | if (*(uint32_t *)(&FlexRAM[offset]) != val32) { | ||||
| uint8_t stat = FTFL_FSTAT & 0x70; | |||||
| if (stat) FTFL_FSTAT = stat; | |||||
| *(uint32_t *)(&FlexRAM[offset]) = val32; | *(uint32_t *)(&FlexRAM[offset]) = val32; | ||||
| flexram_wait(); | flexram_wait(); | ||||
| } | } | ||||
| val16 = *src++; | val16 = *src++; | ||||
| val16 |= (*src++ << 8); | val16 |= (*src++ << 8); | ||||
| if (*(uint16_t *)(&FlexRAM[offset]) != val16) { | if (*(uint16_t *)(&FlexRAM[offset]) != val16) { | ||||
| uint8_t stat = FTFL_FSTAT & 0x70; | |||||
| if (stat) FTFL_FSTAT = stat; | |||||
| *(uint16_t *)(&FlexRAM[offset]) = val16; | *(uint16_t *)(&FlexRAM[offset]) = val16; | ||||
| flexram_wait(); | flexram_wait(); | ||||
| } | } | ||||
| // write 8 bits | // write 8 bits | ||||
| uint8_t val8 = *src++; | uint8_t val8 = *src++; | ||||
| if (FlexRAM[offset] != val8) { | if (FlexRAM[offset] != val8) { | ||||
| uint8_t stat = FTFL_FSTAT & 0x70; | |||||
| if (stat) FTFL_FSTAT = stat; | |||||
| FlexRAM[offset] = val8; | FlexRAM[offset] = val8; | ||||
| flexram_wait(); | flexram_wait(); | ||||
| } | } |