Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

504 lines
13KB

  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. #if defined(KINETISK)
  34. // The EEPROM is really RAM with a hardware-based backup system to
  35. // flash memory. Selecting a smaller size EEPROM allows more wear
  36. // leveling, for higher write endurance. If you edit this file,
  37. // set this to the smallest size your application can use. Also,
  38. // due to Freescale's implementation, writing 16 or 32 bit words
  39. // (aligned to 2 or 4 byte boundaries) has twice the endurance
  40. // compared to writing 8 bit bytes.
  41. //
  42. #if defined(__MK20DX128__) || defined(__MK20DX256__)
  43. #define EEPROM_SIZE 2048
  44. #define PARTITION 0x03 // all 32K dataflash for EEPROM, none for Data
  45. #elif defined(__MK64FX512__)
  46. #define EEPROM_SIZE 4096
  47. #define PARTITION 0x04 // 64K dataflash for EEPROM, 64K for Data
  48. #elif defined(__MK66FX1M0__)
  49. #define EEPROM_SIZE 4096
  50. #define PARTITION 0x05 // 128K dataflash for EEPROM, 128K for Data
  51. #endif
  52. // Writing unaligned 16 or 32 bit data is handled automatically when
  53. // this is defined, but at a cost of extra code size. Without this,
  54. // any unaligned write will cause a hard fault exception! If you're
  55. // absolutely sure all 16 and 32 bit writes will be aligned, you can
  56. // remove the extra unnecessary code.
  57. //
  58. #define HANDLE_UNALIGNED_WRITES
  59. // Minimum EEPROM Endurance
  60. // ------------------------
  61. #if (EEPROM_SIZE == 4096) //
  62. #define EEESIZE 0x32
  63. #elif (EEPROM_SIZE == 2048) // 35000 writes/byte or 70000 writes/word (with 32K)
  64. #define EEESIZE 0x33
  65. #elif (EEPROM_SIZE == 1024) // 75000 writes/byte or 150000 writes/word
  66. #define EEESIZE 0x34
  67. #elif (EEPROM_SIZE == 512) // 155000 writes/byte or 310000 writes/word
  68. #define EEESIZE 0x35
  69. #elif (EEPROM_SIZE == 256) // 315000 writes/byte or 630000 writes/word
  70. #define EEESIZE 0x36
  71. #elif (EEPROM_SIZE == 128) // 635000 writes/byte or 1270000 writes/word
  72. #define EEESIZE 0x37
  73. #elif (EEPROM_SIZE == 64) // 1275000 writes/byte or 2550000 writes/word
  74. #define EEESIZE 0x38
  75. #elif (EEPROM_SIZE == 32) // 2555000 writes/byte or 5110000 writes/word
  76. #define EEESIZE 0x39
  77. #endif
  78. void eeprom_initialize(void)
  79. {
  80. uint32_t count=0;
  81. uint16_t do_flash_cmd[] = {
  82. 0xf06f, 0x037f, 0x7003, 0x7803,
  83. 0xf013, 0x0f80, 0xd0fb, 0x4770};
  84. uint8_t status;
  85. if (FTFL_FCNFG & FTFL_FCNFG_RAMRDY) {
  86. // FlexRAM is configured as traditional RAM
  87. // We need to reconfigure for EEPROM usage
  88. FTFL_FCCOB0 = 0x80; // PGMPART = Program Partition Command
  89. FTFL_FCCOB4 = EEESIZE; // EEPROM Size
  90. FTFL_FCCOB5 = PARTITION;
  91. __disable_irq();
  92. // do_flash_cmd() must execute from RAM. Luckily the C syntax is simple...
  93. (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&FTFL_FSTAT);
  94. __enable_irq();
  95. status = FTFL_FSTAT;
  96. if (status & 0x70) {
  97. FTFL_FSTAT = (status & 0x70);
  98. return; // error
  99. }
  100. }
  101. // wait for eeprom to become ready (is this really necessary?)
  102. while (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) {
  103. if (++count > 20000) break;
  104. }
  105. }
  106. #define FlexRAM ((uint8_t *)0x14000000)
  107. uint8_t eeprom_read_byte(const uint8_t *addr)
  108. {
  109. uint32_t offset = (uint32_t)addr;
  110. if (offset >= EEPROM_SIZE) return 0;
  111. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  112. return FlexRAM[offset];
  113. }
  114. uint16_t eeprom_read_word(const uint16_t *addr)
  115. {
  116. uint32_t offset = (uint32_t)addr;
  117. if (offset >= EEPROM_SIZE-1) return 0;
  118. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  119. return *(uint16_t *)(&FlexRAM[offset]);
  120. }
  121. uint32_t eeprom_read_dword(const uint32_t *addr)
  122. {
  123. uint32_t offset = (uint32_t)addr;
  124. if (offset >= EEPROM_SIZE-3) return 0;
  125. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  126. return *(uint32_t *)(&FlexRAM[offset]);
  127. }
  128. void eeprom_read_block(void *buf, const void *addr, uint32_t len)
  129. {
  130. uint32_t offset = (uint32_t)addr;
  131. uint8_t *dest = (uint8_t *)buf;
  132. uint32_t end = offset + len;
  133. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  134. if (end > EEPROM_SIZE) end = EEPROM_SIZE;
  135. while (offset < end) {
  136. *dest++ = FlexRAM[offset++];
  137. }
  138. }
  139. int eeprom_is_ready(void)
  140. {
  141. return (FTFL_FCNFG & FTFL_FCNFG_EEERDY) ? 1 : 0;
  142. }
  143. static void flexram_wait(void)
  144. {
  145. while (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) {
  146. // TODO: timeout
  147. }
  148. }
  149. void eeprom_write_byte(uint8_t *addr, uint8_t value)
  150. {
  151. uint32_t offset = (uint32_t)addr;
  152. if (offset >= EEPROM_SIZE) return;
  153. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  154. if (FlexRAM[offset] != value) {
  155. FlexRAM[offset] = value;
  156. flexram_wait();
  157. }
  158. }
  159. void eeprom_write_word(uint16_t *addr, uint16_t value)
  160. {
  161. uint32_t offset = (uint32_t)addr;
  162. if (offset >= EEPROM_SIZE-1) return;
  163. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  164. #ifdef HANDLE_UNALIGNED_WRITES
  165. if ((offset & 1) == 0) {
  166. #endif
  167. if (*(uint16_t *)(&FlexRAM[offset]) != value) {
  168. *(uint16_t *)(&FlexRAM[offset]) = value;
  169. flexram_wait();
  170. }
  171. #ifdef HANDLE_UNALIGNED_WRITES
  172. } else {
  173. if (FlexRAM[offset] != value) {
  174. FlexRAM[offset] = value;
  175. flexram_wait();
  176. }
  177. if (FlexRAM[offset + 1] != (value >> 8)) {
  178. FlexRAM[offset + 1] = value >> 8;
  179. flexram_wait();
  180. }
  181. }
  182. #endif
  183. }
  184. void eeprom_write_dword(uint32_t *addr, uint32_t value)
  185. {
  186. uint32_t offset = (uint32_t)addr;
  187. if (offset >= EEPROM_SIZE-3) return;
  188. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  189. #ifdef HANDLE_UNALIGNED_WRITES
  190. switch (offset & 3) {
  191. case 0:
  192. #endif
  193. if (*(uint32_t *)(&FlexRAM[offset]) != value) {
  194. *(uint32_t *)(&FlexRAM[offset]) = value;
  195. flexram_wait();
  196. }
  197. return;
  198. #ifdef HANDLE_UNALIGNED_WRITES
  199. case 2:
  200. if (*(uint16_t *)(&FlexRAM[offset]) != value) {
  201. *(uint16_t *)(&FlexRAM[offset]) = value;
  202. flexram_wait();
  203. }
  204. if (*(uint16_t *)(&FlexRAM[offset + 2]) != (value >> 16)) {
  205. *(uint16_t *)(&FlexRAM[offset + 2]) = value >> 16;
  206. flexram_wait();
  207. }
  208. return;
  209. default:
  210. if (FlexRAM[offset] != value) {
  211. FlexRAM[offset] = value;
  212. flexram_wait();
  213. }
  214. if (*(uint16_t *)(&FlexRAM[offset + 1]) != (value >> 8)) {
  215. *(uint16_t *)(&FlexRAM[offset + 1]) = value >> 8;
  216. flexram_wait();
  217. }
  218. if (FlexRAM[offset + 3] != (value >> 24)) {
  219. FlexRAM[offset + 3] = value >> 24;
  220. flexram_wait();
  221. }
  222. }
  223. #endif
  224. }
  225. void eeprom_write_block(const void *buf, void *addr, uint32_t len)
  226. {
  227. uint32_t offset = (uint32_t)addr;
  228. const uint8_t *src = (const uint8_t *)buf;
  229. if (offset >= EEPROM_SIZE) return;
  230. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  231. if (len >= EEPROM_SIZE) len = EEPROM_SIZE;
  232. if (offset + len >= EEPROM_SIZE) len = EEPROM_SIZE - offset;
  233. while (len > 0) {
  234. uint32_t lsb = offset & 3;
  235. if (lsb == 0 && len >= 4) {
  236. // write aligned 32 bits
  237. uint32_t val32;
  238. val32 = *src++;
  239. val32 |= (*src++ << 8);
  240. val32 |= (*src++ << 16);
  241. val32 |= (*src++ << 24);
  242. if (*(uint32_t *)(&FlexRAM[offset]) != val32) {
  243. *(uint32_t *)(&FlexRAM[offset]) = val32;
  244. flexram_wait();
  245. }
  246. offset += 4;
  247. len -= 4;
  248. } else if ((lsb == 0 || lsb == 2) && len >= 2) {
  249. // write aligned 16 bits
  250. uint16_t val16;
  251. val16 = *src++;
  252. val16 |= (*src++ << 8);
  253. if (*(uint16_t *)(&FlexRAM[offset]) != val16) {
  254. *(uint16_t *)(&FlexRAM[offset]) = val16;
  255. flexram_wait();
  256. }
  257. offset += 2;
  258. len -= 2;
  259. } else {
  260. // write 8 bits
  261. uint8_t val8 = *src++;
  262. if (FlexRAM[offset] != val8) {
  263. FlexRAM[offset] = val8;
  264. flexram_wait();
  265. }
  266. offset++;
  267. len--;
  268. }
  269. }
  270. }
  271. /*
  272. void do_flash_cmd(volatile uint8_t *fstat)
  273. {
  274. *fstat = 0x80;
  275. while ((*fstat & 0x80) == 0) ; // wait
  276. }
  277. 00000000 <do_flash_cmd>:
  278. 0: f06f 037f mvn.w r3, #127 ; 0x7f
  279. 4: 7003 strb r3, [r0, #0]
  280. 6: 7803 ldrb r3, [r0, #0]
  281. 8: f013 0f80 tst.w r3, #128 ; 0x80
  282. c: d0fb beq.n 6 <do_flash_cmd+0x6>
  283. e: 4770 bx lr
  284. */
  285. #elif defined(KINETISL)
  286. #define EEPROM_SIZE 128
  287. #define FLASH_BEGIN (uint16_t *)63488
  288. #define FLASH_END (uint16_t *)65536
  289. static uint16_t flashend = 0;
  290. void eeprom_initialize(void)
  291. {
  292. const uint16_t *p = FLASH_BEGIN;
  293. do {
  294. if (*p++ == 0xFFFF) {
  295. flashend = (uint32_t)(p - 2);
  296. return;
  297. }
  298. } while (p < FLASH_END);
  299. flashend = (uint32_t)(FLASH_END - 1);
  300. }
  301. uint8_t eeprom_read_byte(const uint8_t *addr)
  302. {
  303. uint32_t offset = (uint32_t)addr;
  304. const uint16_t *p = FLASH_BEGIN;
  305. const uint16_t *end = (const uint16_t *)((uint32_t)flashend);
  306. uint16_t val;
  307. uint8_t data=0xFF;
  308. if (!end) {
  309. eeprom_initialize();
  310. end = (const uint16_t *)((uint32_t)flashend);
  311. }
  312. if (offset < EEPROM_SIZE) {
  313. while (p <= end) {
  314. val = *p++;
  315. if ((val & 255) == offset) data = val >> 8;
  316. }
  317. }
  318. return data;
  319. }
  320. static void flash_write(const uint16_t *code, uint32_t addr, uint32_t data)
  321. {
  322. // with great power comes great responsibility....
  323. uint32_t stat;
  324. *(uint32_t *)&FTFL_FCCOB3 = 0x06000000 | (addr & 0x00FFFFFC);
  325. *(uint32_t *)&FTFL_FCCOB7 = data;
  326. __disable_irq();
  327. (*((void (*)(volatile uint8_t *))((uint32_t)code | 1)))(&FTFL_FSTAT);
  328. __enable_irq();
  329. stat = FTFL_FSTAT & 0x70;
  330. if (stat) {
  331. FTFL_FSTAT = stat;
  332. }
  333. MCM_PLACR |= MCM_PLACR_CFCC;
  334. }
  335. void eeprom_write_byte(uint8_t *addr, uint8_t data)
  336. {
  337. uint32_t offset = (uint32_t)addr;
  338. const uint16_t *p, *end = (const uint16_t *)((uint32_t)flashend);
  339. uint32_t i, val, flashaddr;
  340. uint16_t do_flash_cmd[] = {
  341. 0x2380, 0x7003, 0x7803, 0xb25b, 0x2b00, 0xdafb, 0x4770};
  342. uint8_t buf[EEPROM_SIZE];
  343. if (offset >= EEPROM_SIZE) return;
  344. if (!end) {
  345. eeprom_initialize();
  346. end = (const uint16_t *)((uint32_t)flashend);
  347. }
  348. if (++end < FLASH_END) {
  349. val = (data << 8) | offset;
  350. flashaddr = (uint32_t)end;
  351. flashend = flashaddr;
  352. if ((flashaddr & 2) == 0) {
  353. val |= 0xFFFF0000;
  354. } else {
  355. val <<= 16;
  356. val |= 0x0000FFFF;
  357. }
  358. flash_write(do_flash_cmd, flashaddr, val);
  359. } else {
  360. for (i=0; i < EEPROM_SIZE; i++) {
  361. buf[i] = 0xFF;
  362. }
  363. for (p = FLASH_BEGIN; p < FLASH_END; p++) {
  364. val = *p;
  365. if ((val & 255) < EEPROM_SIZE) {
  366. buf[val & 255] = val >> 8;
  367. }
  368. }
  369. buf[offset] = data;
  370. for (flashaddr=(uint32_t)FLASH_BEGIN; flashaddr < (uint32_t)FLASH_END; flashaddr += 1024) {
  371. *(uint32_t *)&FTFL_FCCOB3 = 0x09000000 | flashaddr;
  372. __disable_irq();
  373. (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&FTFL_FSTAT);
  374. __enable_irq();
  375. val = FTFL_FSTAT & 0x70;
  376. if (val) FTFL_FSTAT = val;
  377. MCM_PLACR |= MCM_PLACR_CFCC;
  378. }
  379. flashaddr=(uint32_t)FLASH_BEGIN;
  380. for (i=0; i < EEPROM_SIZE; i++) {
  381. if (buf[i] == 0xFF) continue;
  382. if ((flashaddr & 2) == 0) {
  383. val = (buf[i] << 8) | i;
  384. } else {
  385. val = val | (buf[i] << 24) | (i << 16);
  386. flash_write(do_flash_cmd, flashaddr, val);
  387. }
  388. flashaddr += 2;
  389. }
  390. flashend = flashaddr;
  391. if ((flashaddr & 2)) {
  392. val |= 0xFFFF0000;
  393. flash_write(do_flash_cmd, flashaddr, val);
  394. }
  395. }
  396. }
  397. /*
  398. void do_flash_cmd(volatile uint8_t *fstat)
  399. {
  400. *fstat = 0x80;
  401. while ((*fstat & 0x80) == 0) ; // wait
  402. }
  403. 00000000 <do_flash_cmd>:
  404. 0: 2380 movs r3, #128 ; 0x80
  405. 2: 7003 strb r3, [r0, #0]
  406. 4: 7803 ldrb r3, [r0, #0]
  407. 6: b25b sxtb r3, r3
  408. 8: 2b00 cmp r3, #0
  409. a: dafb bge.n 4 <do_flash_cmd+0x4>
  410. c: 4770 bx lr
  411. */
  412. uint16_t eeprom_read_word(const uint16_t *addr)
  413. {
  414. const uint8_t *p = (const uint8_t *)addr;
  415. return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8);
  416. }
  417. uint32_t eeprom_read_dword(const uint32_t *addr)
  418. {
  419. const uint8_t *p = (const uint8_t *)addr;
  420. return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8)
  421. | (eeprom_read_byte(p+2) << 16) | (eeprom_read_byte(p+3) << 24);
  422. }
  423. void eeprom_read_block(void *buf, const void *addr, uint32_t len)
  424. {
  425. const uint8_t *p = (const uint8_t *)addr;
  426. uint8_t *dest = (uint8_t *)buf;
  427. while (len--) {
  428. *dest++ = eeprom_read_byte(p++);
  429. }
  430. }
  431. int eeprom_is_ready(void)
  432. {
  433. return 1;
  434. }
  435. void eeprom_write_word(uint16_t *addr, uint16_t value)
  436. {
  437. uint8_t *p = (uint8_t *)addr;
  438. eeprom_write_byte(p++, value);
  439. eeprom_write_byte(p, value >> 8);
  440. }
  441. void eeprom_write_dword(uint32_t *addr, uint32_t value)
  442. {
  443. uint8_t *p = (uint8_t *)addr;
  444. eeprom_write_byte(p++, value);
  445. eeprom_write_byte(p++, value >> 8);
  446. eeprom_write_byte(p++, value >> 16);
  447. eeprom_write_byte(p, value >> 24);
  448. }
  449. void eeprom_write_block(const void *buf, void *addr, uint32_t len)
  450. {
  451. uint8_t *p = (uint8_t *)addr;
  452. const uint8_t *src = (const uint8_t *)buf;
  453. while (len--) {
  454. eeprom_write_byte(p++, *src++);
  455. }
  456. }
  457. #endif // KINETISL