You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

300 lines
8.5KB

  1. /* Teensyduino Core Library
  2. * http://www.pjrc.com/teensy/
  3. * Copyright (c) 2013 PJRC.COM, LLC.
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining
  6. * a copy of this software and associated documentation files (the
  7. * "Software"), to deal in the Software without restriction, including
  8. * without limitation the rights to use, copy, modify, merge, publish,
  9. * distribute, sublicense, and/or sell copies of the Software, and to
  10. * permit persons to whom the Software is furnished to do so, subject to
  11. * the following conditions:
  12. *
  13. * 1. The above copyright notice and this permission notice shall be
  14. * included in all copies or substantial portions of the Software.
  15. *
  16. * 2. If the Software is incorporated into a build system that allows
  17. * selection among a list of target devices, then similar target
  18. * devices manufactured by PJRC.COM must be included in the list of
  19. * target devices and selectable in the same manner.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  22. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  24. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  25. * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  26. * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  27. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  28. * SOFTWARE.
  29. */
  30. #include "kinetis.h"
  31. #include <stdint.h>
  32. //#include "HardwareSerial.h"
  33. // The EEPROM is really RAM with a hardware-based backup system to
  34. // flash memory. Selecting a smaller size EEPROM allows more wear
  35. // leveling, for higher write endurance. If you edit this file,
  36. // set this to the smallest size your application can use. Also,
  37. // due to Freescale's implementation, writing 16 or 32 bit words
  38. // (aligned to 2 or 4 byte boundaries) has twice the endurance
  39. // compared to writing 8 bit bytes.
  40. //
  41. #define EEPROM_SIZE 2048
  42. // Writing unaligned 16 or 32 bit data is handled automatically when
  43. // this is defined, but at a cost of extra code size. Without this,
  44. // any unaligned write will cause a hard fault exception! If you're
  45. // absolutely sure all 16 and 32 bit writes will be aligned, you can
  46. // remove the extra unnecessary code.
  47. //
  48. #define HANDLE_UNALIGNED_WRITES
  49. // Minimum EEPROM Endurance
  50. // ------------------------
  51. #if (EEPROM_SIZE == 2048) // 35000 writes/byte or 70000 writes/word
  52. #define EEESIZE 0x33
  53. #elif (EEPROM_SIZE == 1024) // 75000 writes/byte or 150000 writes/word
  54. #define EEESIZE 0x34
  55. #elif (EEPROM_SIZE == 512) // 155000 writes/byte or 310000 writes/word
  56. #define EEESIZE 0x35
  57. #elif (EEPROM_SIZE == 256) // 315000 writes/byte or 630000 writes/word
  58. #define EEESIZE 0x36
  59. #elif (EEPROM_SIZE == 128) // 635000 writes/byte or 1270000 writes/word
  60. #define EEESIZE 0x37
  61. #elif (EEPROM_SIZE == 64) // 1275000 writes/byte or 2550000 writes/word
  62. #define EEESIZE 0x38
  63. #elif (EEPROM_SIZE == 32) // 2555000 writes/byte or 5110000 writes/word
  64. #define EEESIZE 0x39
  65. #endif
  66. void eeprom_initialize(void)
  67. {
  68. uint32_t count=0;
  69. uint16_t do_flash_cmd[] = {
  70. 0xf06f, 0x037f, 0x7003, 0x7803,
  71. 0xf013, 0x0f80, 0xd0fb, 0x4770};
  72. uint8_t status;
  73. if (FTFL_FCNFG & FTFL_FCNFG_RAMRDY) {
  74. // FlexRAM is configured as traditional RAM
  75. // We need to reconfigure for EEPROM usage
  76. FTFL_FCCOB0 = 0x80; // PGMPART = Program Partition Command
  77. FTFL_FCCOB4 = EEESIZE; // EEPROM Size
  78. FTFL_FCCOB5 = 0x03; // 0K for Dataflash, 32K for EEPROM backup
  79. __disable_irq();
  80. // do_flash_cmd() must execute from RAM. Luckily the C syntax is simple...
  81. (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&FTFL_FSTAT);
  82. __enable_irq();
  83. status = FTFL_FSTAT;
  84. if (status & 0x70) {
  85. FTFL_FSTAT = (status & 0x70);
  86. return; // error
  87. }
  88. }
  89. // wait for eeprom to become ready (is this really necessary?)
  90. while (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) {
  91. if (++count > 20000) break;
  92. }
  93. }
  94. #define FlexRAM ((uint8_t *)0x14000000)
  95. uint8_t eeprom_read_byte(const uint8_t *addr)
  96. {
  97. uint32_t offset = (uint32_t)addr;
  98. if (offset >= EEPROM_SIZE) return 0;
  99. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  100. return FlexRAM[offset];
  101. }
  102. uint16_t eeprom_read_word(const uint16_t *addr)
  103. {
  104. uint32_t offset = (uint32_t)addr;
  105. if (offset >= EEPROM_SIZE-1) return 0;
  106. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  107. return *(uint16_t *)(&FlexRAM[offset]);
  108. }
  109. uint32_t eeprom_read_dword(const uint32_t *addr)
  110. {
  111. uint32_t offset = (uint32_t)addr;
  112. if (offset >= EEPROM_SIZE-3) return 0;
  113. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  114. return *(uint32_t *)(&FlexRAM[offset]);
  115. }
  116. void eeprom_read_block(void *buf, const void *addr, uint32_t len)
  117. {
  118. uint32_t offset = (uint32_t)addr;
  119. uint8_t *dest = (uint8_t *)buf;
  120. uint32_t end = offset + len;
  121. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  122. if (end > EEPROM_SIZE) end = EEPROM_SIZE;
  123. while (offset < end) {
  124. *dest++ = FlexRAM[offset++];
  125. }
  126. }
  127. int eeprom_is_ready(void)
  128. {
  129. return (FTFL_FCNFG & FTFL_FCNFG_EEERDY) ? 1 : 0;
  130. }
  131. static void flexram_wait(void)
  132. {
  133. while (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) {
  134. // TODO: timeout
  135. }
  136. }
  137. void eeprom_write_byte(uint8_t *addr, uint8_t value)
  138. {
  139. uint32_t offset = (uint32_t)addr;
  140. if (offset >= EEPROM_SIZE) return;
  141. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  142. if (FlexRAM[offset] != value) {
  143. FlexRAM[offset] = value;
  144. flexram_wait();
  145. }
  146. }
  147. void eeprom_write_word(uint16_t *addr, uint16_t value)
  148. {
  149. uint32_t offset = (uint32_t)addr;
  150. if (offset >= EEPROM_SIZE-1) return;
  151. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  152. #ifdef HANDLE_UNALIGNED_WRITES
  153. if ((offset & 1) == 0) {
  154. #endif
  155. if (*(uint16_t *)(&FlexRAM[offset]) != value) {
  156. *(uint16_t *)(&FlexRAM[offset]) = value;
  157. flexram_wait();
  158. }
  159. #ifdef HANDLE_UNALIGNED_WRITES
  160. } else {
  161. if (FlexRAM[offset] != value) {
  162. FlexRAM[offset] = value;
  163. flexram_wait();
  164. }
  165. if (FlexRAM[offset + 1] != (value >> 8)) {
  166. FlexRAM[offset + 1] = value >> 8;
  167. flexram_wait();
  168. }
  169. }
  170. #endif
  171. }
  172. void eeprom_write_dword(uint32_t *addr, uint32_t value)
  173. {
  174. uint32_t offset = (uint32_t)addr;
  175. if (offset >= EEPROM_SIZE-3) return;
  176. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  177. #ifdef HANDLE_UNALIGNED_WRITES
  178. switch (offset & 3) {
  179. case 0:
  180. #endif
  181. if (*(uint32_t *)(&FlexRAM[offset]) != value) {
  182. *(uint32_t *)(&FlexRAM[offset]) = value;
  183. flexram_wait();
  184. }
  185. return;
  186. #ifdef HANDLE_UNALIGNED_WRITES
  187. case 2:
  188. if (*(uint16_t *)(&FlexRAM[offset]) != value) {
  189. *(uint16_t *)(&FlexRAM[offset]) = value;
  190. flexram_wait();
  191. }
  192. if (*(uint16_t *)(&FlexRAM[offset + 2]) != (value >> 16)) {
  193. *(uint16_t *)(&FlexRAM[offset + 2]) = value >> 16;
  194. flexram_wait();
  195. }
  196. return;
  197. default:
  198. if (FlexRAM[offset] != value) {
  199. FlexRAM[offset] = value;
  200. flexram_wait();
  201. }
  202. if (*(uint16_t *)(&FlexRAM[offset + 1]) != (value >> 8)) {
  203. *(uint16_t *)(&FlexRAM[offset + 1]) = value >> 8;
  204. flexram_wait();
  205. }
  206. if (FlexRAM[offset + 3] != (value >> 24)) {
  207. FlexRAM[offset + 3] = value >> 24;
  208. flexram_wait();
  209. }
  210. }
  211. #endif
  212. }
  213. void eeprom_write_block(const void *buf, void *addr, uint32_t len)
  214. {
  215. uint32_t offset = (uint32_t)addr;
  216. const uint8_t *src = (const uint8_t *)buf;
  217. if (offset >= EEPROM_SIZE) return;
  218. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  219. if (len >= EEPROM_SIZE) len = EEPROM_SIZE;
  220. if (offset + len >= EEPROM_SIZE) len = EEPROM_SIZE - offset;
  221. while (len > 0) {
  222. uint32_t lsb = offset & 3;
  223. if (lsb == 0 && len >= 4) {
  224. // write aligned 32 bits
  225. uint32_t val32;
  226. val32 = *src++;
  227. val32 |= (*src++ << 8);
  228. val32 |= (*src++ << 16);
  229. val32 |= (*src++ << 24);
  230. if (*(uint32_t *)(&FlexRAM[offset]) != val32) {
  231. *(uint32_t *)(&FlexRAM[offset]) = val32;
  232. flexram_wait();
  233. }
  234. offset += 4;
  235. len -= 4;
  236. } else if ((lsb == 0 || lsb == 2) && len >= 2) {
  237. // write aligned 16 bits
  238. uint16_t val16;
  239. val16 = *src++;
  240. val16 |= (*src++ << 8);
  241. if (*(uint16_t *)(&FlexRAM[offset]) != val16) {
  242. *(uint16_t *)(&FlexRAM[offset]) = val16;
  243. flexram_wait();
  244. }
  245. offset += 2;
  246. len -= 2;
  247. } else {
  248. // write 8 bits
  249. uint8_t val8 = *src++;
  250. if (FlexRAM[offset] != val8) {
  251. FlexRAM[offset] = val8;
  252. flexram_wait();
  253. }
  254. offset++;
  255. len--;
  256. }
  257. }
  258. }
  259. /*
  260. void do_flash_cmd(volatile uint8_t *fstat)
  261. {
  262. *fstat = 0x80;
  263. while ((*fstat & 0x80) == 0) ; // wait
  264. }
  265. 00000000 <do_flash_cmd>:
  266. 0: f06f 037f mvn.w r3, #127 ; 0x7f
  267. 4: 7003 strb r3, [r0, #0]
  268. 6: 7803 ldrb r3, [r0, #0]
  269. 8: f013 0f80 tst.w r3, #128 ; 0x80
  270. c: d0fb beq.n 6 <do_flash_cmd+0x6>
  271. e: 4770 bx lr
  272. */