Teensy 4.1 core updated for C++20
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.

295 lines
8.4KB

  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 "mk20dx128.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. static void flexram_wait(void)
  128. {
  129. while (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) {
  130. // TODO: timeout
  131. }
  132. }
  133. void eeprom_write_byte(uint8_t *addr, uint8_t value)
  134. {
  135. uint32_t offset = (uint32_t)addr;
  136. if (offset >= EEPROM_SIZE) return;
  137. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  138. if (FlexRAM[offset] != value) {
  139. FlexRAM[offset] = value;
  140. flexram_wait();
  141. }
  142. }
  143. void eeprom_write_word(uint16_t *addr, uint16_t value)
  144. {
  145. uint32_t offset = (uint32_t)addr;
  146. if (offset >= EEPROM_SIZE-1) return;
  147. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  148. #ifdef HANDLE_UNALIGNED_WRITES
  149. if ((offset & 1) == 0) {
  150. #endif
  151. if (*(uint16_t *)(&FlexRAM[offset]) != value) {
  152. *(uint16_t *)(&FlexRAM[offset]) = value;
  153. flexram_wait();
  154. }
  155. #ifdef HANDLE_UNALIGNED_WRITES
  156. } else {
  157. if (FlexRAM[offset] != value) {
  158. FlexRAM[offset] = value;
  159. flexram_wait();
  160. }
  161. if (FlexRAM[offset + 1] != (value >> 8)) {
  162. FlexRAM[offset + 1] = value >> 8;
  163. flexram_wait();
  164. }
  165. }
  166. #endif
  167. }
  168. void eeprom_write_dword(uint32_t *addr, uint32_t value)
  169. {
  170. uint32_t offset = (uint32_t)addr;
  171. if (offset >= EEPROM_SIZE-3) return;
  172. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  173. #ifdef HANDLE_UNALIGNED_WRITES
  174. switch (offset & 3) {
  175. case 0:
  176. #endif
  177. if (*(uint32_t *)(&FlexRAM[offset]) != value) {
  178. *(uint32_t *)(&FlexRAM[offset]) = value;
  179. flexram_wait();
  180. }
  181. return;
  182. #ifdef HANDLE_UNALIGNED_WRITES
  183. case 2:
  184. if (*(uint16_t *)(&FlexRAM[offset]) != value) {
  185. *(uint16_t *)(&FlexRAM[offset]) = value;
  186. flexram_wait();
  187. }
  188. if (*(uint16_t *)(&FlexRAM[offset + 2]) != (value >> 16)) {
  189. *(uint16_t *)(&FlexRAM[offset + 2]) = value >> 16;
  190. flexram_wait();
  191. }
  192. return;
  193. default:
  194. if (FlexRAM[offset] != value) {
  195. FlexRAM[offset] = value;
  196. flexram_wait();
  197. }
  198. if (*(uint16_t *)(&FlexRAM[offset + 1]) != (value >> 8)) {
  199. *(uint16_t *)(&FlexRAM[offset + 1]) = value >> 8;
  200. flexram_wait();
  201. }
  202. if (FlexRAM[offset + 3] != (value >> 24)) {
  203. FlexRAM[offset + 3] = value >> 24;
  204. flexram_wait();
  205. }
  206. }
  207. #endif
  208. }
  209. void eeprom_write_block(const void *buf, void *addr, uint32_t len)
  210. {
  211. uint32_t offset = (uint32_t)addr;
  212. const uint8_t *src = (const uint8_t *)buf;
  213. if (offset >= EEPROM_SIZE) return;
  214. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  215. if (len >= EEPROM_SIZE) len = EEPROM_SIZE;
  216. if (offset + len >= EEPROM_SIZE) len = EEPROM_SIZE - offset;
  217. while (len > 0) {
  218. uint32_t lsb = offset & 3;
  219. if (lsb == 0 && len >= 4) {
  220. // write aligned 32 bits
  221. uint32_t val32;
  222. val32 = *src++;
  223. val32 |= (*src++ << 8);
  224. val32 |= (*src++ << 16);
  225. val32 |= (*src++ << 24);
  226. if (*(uint32_t *)(&FlexRAM[offset]) != val32) {
  227. *(uint32_t *)(&FlexRAM[offset]) = val32;
  228. flexram_wait();
  229. }
  230. offset += 4;
  231. len -= 4;
  232. } else if ((lsb == 0 || lsb == 2) && len >= 2) {
  233. // write aligned 16 bits
  234. uint16_t val16;
  235. val16 = *src++;
  236. val16 |= (*src++ << 8);
  237. if (*(uint16_t *)(&FlexRAM[offset]) != val16) {
  238. *(uint16_t *)(&FlexRAM[offset]) = val16;
  239. flexram_wait();
  240. }
  241. offset += 2;
  242. len -= 2;
  243. } else {
  244. // write 8 bits
  245. uint8_t val8 = *src++;
  246. if (FlexRAM[offset] != val8) {
  247. FlexRAM[offset] = val8;
  248. flexram_wait();
  249. }
  250. offset++;
  251. len--;
  252. }
  253. }
  254. }
  255. /*
  256. void do_flash_cmd(volatile uint8_t *fstat)
  257. {
  258. *fstat = 0x80;
  259. while ((*fstat & 0x80) == 0) ; // wait
  260. }
  261. 00000000 <do_flash_cmd>:
  262. 0: f06f 037f mvn.w r3, #127 ; 0x7f
  263. 4: 7003 strb r3, [r0, #0]
  264. 6: 7803 ldrb r3, [r0, #0]
  265. 8: f013 0f80 tst.w r3, #128 ; 0x80
  266. c: d0fb beq.n 6 <do_flash_cmd+0x6>
  267. e: 4770 bx lr
  268. */