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.

399 lines
12KB

  1. /* Teensyduino Core Library
  2. * http://www.pjrc.com/teensy/
  3. * Copyright (c) 2019 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. #ifndef _avr_emulation_h_
  31. #define _avr_emulation_h_
  32. #include "imxrt.h"
  33. #include "core_pins.h"
  34. #include "pins_arduino.h"
  35. #ifdef __cplusplus
  36. // SPI Control Register ­ SPCR
  37. #define SPIE 7 // SPI Interrupt Enable - not supported
  38. #define SPE 6 // SPI Enable
  39. #define DORD 5 // DORD: Data Order
  40. #define MSTR 4 // MSTR: Master/Slave Select
  41. #define CPOL 3 // CPOL: Clock Polarity
  42. #define CPHA 2 // CPHA: Clock Phase
  43. #define SPR1 1 // Clock: 3 = 125 kHz, 2 = 250 kHz, 1 = 1 MHz, 0->4 MHz
  44. #define SPR0 0
  45. // SPI Status Register ­ SPSR
  46. #define SPIF 7 // SPIF: SPI Interrupt Flag
  47. #define WCOL 6 // WCOL: Write COLlision Flag - not implemented
  48. #define SPI2X 0 // SPI2X: Double SPI Speed Bit
  49. // SPI Data Register ­ SPDR
  50. class SPCRemulation;
  51. class SPSRemulation;
  52. class SPDRemulation;
  53. class SPCRemulation
  54. {
  55. public:
  56. inline SPCRemulation & operator = (int val) __attribute__((always_inline)) {
  57. /*
  58. uint32_t ctar, mcr, sim6;
  59. //serial_print("SPCR=");
  60. //serial_phex(val);
  61. //serial_print("\n");
  62. sim6 = SIM_SCGC6;
  63. if (!(sim6 & SIM_SCGC6_SPI0)) {
  64. //serial_print("init1\n");
  65. SIM_SCGC6 = sim6 | SIM_SCGC6_SPI0;
  66. SPI0_CTAR0 = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(1) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
  67. }
  68. if (!(val & (1<<SPE))) {
  69. SPI0_MCR |= SPI_MCR_MDIS; // TODO: use bitband for atomic access
  70. }
  71. ctar = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(1);
  72. if (val & (1<<DORD)) ctar |= SPI_CTAR_LSBFE;
  73. if (val & (1<<CPOL)) ctar |= SPI_CTAR_CPOL;
  74. if (val & (1<<CPHA)) {
  75. ctar |= SPI_CTAR_CPHA;
  76. if ((val & 3) == 0) {
  77. ctar |= SPI_CTAR_BR(1) | SPI_CTAR_ASC(1);
  78. } else if ((val & 3) == 1) {
  79. ctar |= SPI_CTAR_BR(4) | SPI_CTAR_ASC(4);
  80. } else if ((val & 3) == 2) {
  81. ctar |= SPI_CTAR_BR(6) | SPI_CTAR_ASC(6);
  82. } else {
  83. ctar |= SPI_CTAR_BR(7) | SPI_CTAR_ASC(7);
  84. }
  85. } else {
  86. if ((val & 3) == 0) {
  87. ctar |= SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
  88. } else if ((val & 3) == 1) {
  89. ctar |= SPI_CTAR_BR(4) | SPI_CTAR_CSSCK(4);
  90. } else if ((val & 3) == 2) {
  91. ctar |= SPI_CTAR_BR(6) | SPI_CTAR_CSSCK(6);
  92. } else {
  93. ctar |= SPI_CTAR_BR(7) | SPI_CTAR_CSSCK(7);
  94. }
  95. }
  96. ctar |= (SPI0_CTAR0 & SPI_CTAR_DBR);
  97. update_ctar(ctar);
  98. mcr = SPI_MCR_DCONF(0) | SPI_MCR_PCSIS(0x1F);
  99. if (val & (1<<MSTR)) mcr |= SPI_MCR_MSTR;
  100. if (val & (1<<SPE)) {
  101. mcr &= ~(SPI_MCR_MDIS | SPI_MCR_HALT);
  102. SPI0_MCR = mcr;
  103. enable_pins();
  104. } else {
  105. mcr |= (SPI_MCR_MDIS | SPI_MCR_HALT);
  106. SPI0_MCR = mcr;
  107. disable_pins();
  108. }
  109. //serial_print("MCR:");
  110. //serial_phex32(SPI0_MCR);
  111. //serial_print(", CTAR0:");
  112. //serial_phex32(SPI0_CTAR0);
  113. //serial_print("\n");
  114. */
  115. return *this;
  116. }
  117. inline SPCRemulation & operator |= (int val) __attribute__((always_inline)) {
  118. /*
  119. uint32_t sim6;
  120. //serial_print("SPCR |= ");
  121. //serial_phex(val);
  122. //serial_print("\n");
  123. sim6 = SIM_SCGC6;
  124. if (!(sim6 & SIM_SCGC6_SPI0)) {
  125. //serial_print("init2\n");
  126. SIM_SCGC6 = sim6 | SIM_SCGC6_SPI0;
  127. SPI0_CTAR0 = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(1) | SPI_CTAR_BR(1);
  128. }
  129. if (val & ((1<<DORD)|(1<<CPOL)|(1<<CPHA)|3)) {
  130. uint32_t ctar = SPI0_CTAR0;
  131. if (val & (1<<DORD)) ctar |= SPI_CTAR_LSBFE; // TODO: use bitband
  132. if (val & (1<<CPOL)) ctar |= SPI_CTAR_CPOL;
  133. if (val & (1<<CPHA) && !(ctar & SPI_CTAR_CPHA)) {
  134. ctar |= SPI_CTAR_CPHA;
  135. ctar &= 0xFFFF00FF;
  136. ctar |= SPI_CTAR_ASC(ctar & 15);
  137. }
  138. if ((val & 3) != 0) {
  139. uint32_t br = ctar & 15;
  140. uint32_t priorval;
  141. if (br <= 1) priorval = 0;
  142. else if (br <= 4) priorval = 1;
  143. else if (br <= 6) priorval = 2;
  144. else priorval = 3;
  145. uint32_t newval = priorval | (val & 3);
  146. if (newval != priorval) {
  147. if (newval == 0) br = 1;
  148. else if (newval == 0) br = 4;
  149. else if (newval == 0) br = 6;
  150. else br = 7;
  151. ctar &= 0xFFFF00F0; // clear BR, ASC, CSSCK
  152. if ((ctar & SPI_CTAR_CPHA)) {
  153. ctar |= SPI_CTAR_BR(br) | SPI_CTAR_ASC(br);
  154. } else {
  155. ctar |= SPI_CTAR_BR(br) | SPI_CTAR_CSSCK(br);
  156. }
  157. }
  158. }
  159. update_ctar(ctar);
  160. }
  161. if (val & (1<<MSTR)) SPI0_MCR |= SPI_MCR_MSTR;
  162. if (val & (1<<SPE)) {
  163. SPI0_MCR &= ~(SPI_MCR_MDIS | SPI_MCR_HALT);
  164. enable_pins();
  165. }
  166. //serial_print("MCR:");
  167. //serial_phex32(SPI0_MCR);
  168. //serial_print(", CTAR0:");
  169. //serial_phex32(SPI0_CTAR0);
  170. //serial_print("\n");
  171. */
  172. return *this;
  173. }
  174. inline SPCRemulation & operator &= (int val) __attribute__((always_inline)) {
  175. /*
  176. //serial_print("SPCR &= ");
  177. //serial_phex(val);
  178. //serial_print("\n");
  179. SIM_SCGC6 |= SIM_SCGC6_SPI0;
  180. if (!(val & (1<<SPE))) {
  181. SPI0_MCR |= (SPI_MCR_MDIS | SPI_MCR_HALT);
  182. disable_pins();
  183. }
  184. if ((val & ((1<<DORD)|(1<<CPOL)|(1<<CPHA)|3)) != ((1<<DORD)|(1<<CPOL)|(1<<CPHA)|3)) {
  185. uint32_t ctar = SPI0_CTAR0;
  186. if (!(val & (1<<DORD))) ctar &= ~SPI_CTAR_LSBFE; // TODO: use bitband
  187. if (!(val & (1<<CPOL))) ctar &= ~SPI_CTAR_CPOL;
  188. if (!(val & (1<<CPHA)) && (ctar & SPI_CTAR_CPHA)) {
  189. ctar &= ~SPI_CTAR_CPHA;
  190. ctar &= 0xFFFF00FF;
  191. ctar |= SPI_CTAR_CSSCK(ctar & 15);
  192. }
  193. if ((val & 3) != 3) {
  194. uint32_t br = ctar & 15;
  195. uint32_t priorval;
  196. if (br <= 1) priorval = 0;
  197. else if (br <= 4) priorval = 1;
  198. else if (br <= 6) priorval = 2;
  199. else priorval = 3;
  200. uint32_t newval = priorval & (val & 3);
  201. if (newval != priorval) {
  202. if (newval == 0) br = 1;
  203. else if (newval == 0) br = 4;
  204. else if (newval == 0) br = 6;
  205. else br = 7;
  206. ctar &= 0xFFFF00F0; // clear BR, ASC, CSSCK
  207. if ((ctar & SPI_CTAR_CPHA)) {
  208. ctar |= SPI_CTAR_BR(br) | SPI_CTAR_ASC(br);
  209. } else {
  210. ctar |= SPI_CTAR_BR(br) | SPI_CTAR_CSSCK(br);
  211. }
  212. }
  213. }
  214. update_ctar(ctar);
  215. }
  216. if (!(val & (1<<MSTR))) SPI0_MCR &= ~SPI_MCR_MSTR;
  217. */
  218. return *this;
  219. }
  220. inline int operator & (int val) const __attribute__((always_inline)) {
  221. int ret = 0;
  222. /*
  223. //serial_print("SPCR & ");
  224. //serial_phex(val);
  225. //serial_print("\n");
  226. SIM_SCGC6 |= SIM_SCGC6_SPI0;
  227. if ((val & (1<<DORD)) && (SPI0_CTAR0 & SPI_CTAR_LSBFE)) ret |= (1<<DORD);
  228. if ((val & (1<<CPOL)) && (SPI0_CTAR0 & SPI_CTAR_CPOL)) ret |= (1<<CPOL);
  229. if ((val & (1<<CPHA)) && (SPI0_CTAR0 & SPI_CTAR_CPHA)) ret |= (1<<CPHA);
  230. if ((val & 3) != 0) {
  231. uint32_t dbr = SPI0_CTAR0 & 15;
  232. uint32_t spr10;
  233. if (dbr <= 1) {
  234. spr10 = 0;
  235. } else if (dbr <= 4) {
  236. spr10 |= (1<<SPR0);
  237. } else if (dbr <= 6) {
  238. spr10 |= (1<<SPR1);
  239. } else {
  240. spr10 |= (1<<SPR1)|(1<<SPR0);
  241. }
  242. ret |= spr10 & (val & 3);
  243. }
  244. if (val & (1<<SPE) && (!(SPI0_MCR & SPI_MCR_MDIS))) ret |= (1<<SPE);
  245. if (val & (1<<MSTR) && (SPI0_MCR & SPI_MCR_MSTR)) ret |= (1<<MSTR);
  246. //serial_print("ret = ");
  247. //serial_phex(ret);
  248. //serial_print("\n");
  249. */
  250. return ret;
  251. }
  252. operator int () const __attribute__((always_inline)) {
  253. int ret = 0;
  254. /*
  255. if ((SIM_SCGC6 & SIM_SCGC6_SPI0)) {
  256. int ctar = SPI0_CTAR0;
  257. if (ctar & SPI_CTAR_LSBFE) ret |= (1<<DORD);
  258. if (ctar & SPI_CTAR_CPOL) ret |= (1<<CPOL);
  259. if (ctar & SPI_CTAR_CPHA) ret |= (1<<CPHA);
  260. ctar &= 15;
  261. if (ctar <= 1) {
  262. } else if (ctar <= 4) {
  263. ret |= (1<<SPR0);
  264. } else if (ctar <= 6) {
  265. ret |= (1<<SPR1);
  266. } else {
  267. ret |= (1<<SPR1)|(1<<SPR0);
  268. }
  269. int mcr = SPI0_MCR;
  270. if (!(mcr & SPI_MCR_MDIS)) ret |= (1<<SPE);
  271. if (mcr & SPI_MCR_MSTR) ret |= (1<<MSTR);
  272. }
  273. */
  274. return ret;
  275. }
  276. inline void setMOSI(uint8_t pin) __attribute__((always_inline)) {
  277. }
  278. inline void setMOSI_soft(uint8_t pin) __attribute__((always_inline)) {
  279. }
  280. inline void setMISO(uint8_t pin) __attribute__((always_inline)) {
  281. }
  282. inline void setSCK(uint8_t pin) __attribute__((always_inline)) {
  283. }
  284. friend class SPSRemulation;
  285. friend class SPIFIFOclass;
  286. private:
  287. static uint8_t pinout;
  288. public:
  289. inline void enable_pins(void) __attribute__((always_inline)) {
  290. //serial_print("enable_pins\n");
  291. }
  292. inline void disable_pins(void) __attribute__((always_inline)) {
  293. }
  294. };
  295. extern SPCRemulation SPCR;
  296. class SPSRemulation
  297. {
  298. public:
  299. inline SPSRemulation & operator = (int val) __attribute__((always_inline)) {
  300. //serial_print("SPSR=");
  301. //serial_phex(val);
  302. //serial_print("\n");
  303. /*
  304. uint32_t ctar = SPI0_CTAR0;
  305. if (val & (1<<SPI2X)) {
  306. ctar |= SPI_CTAR_DBR;
  307. } else {
  308. ctar &= ~SPI_CTAR_DBR;
  309. }
  310. SPCRemulation::update_ctar(ctar);
  311. //serial_print("MCR:");
  312. //serial_phex32(SPI0_MCR);
  313. //serial_print(", CTAR0:");
  314. //serial_phex32(SPI0_CTAR0);
  315. //serial_print("\n");
  316. */
  317. return *this;
  318. }
  319. inline SPSRemulation & operator |= (int val) __attribute__((always_inline)) {
  320. /*
  321. //serial_print("SPSR |= ");
  322. //serial_phex(val);
  323. //serial_print("\n");
  324. if (val & (1<<SPI2X)) SPCRemulation::update_ctar(SPI0_CTAR0 |= SPI_CTAR_DBR);
  325. */
  326. return *this;
  327. }
  328. inline SPSRemulation & operator &= (int val) __attribute__((always_inline)) {
  329. /*
  330. //serial_print("SPSR &= ");
  331. //serial_phex(val);
  332. //serial_print("\n");
  333. if (!(val & (1<<SPI2X))) SPCRemulation::update_ctar(SPI0_CTAR0 &= ~SPI_CTAR_DBR);
  334. */
  335. return *this;
  336. }
  337. inline int operator & (int val) const __attribute__((always_inline)) {
  338. int ret = 0;
  339. //serial_print("SPSR & ");
  340. //serial_phex(val);
  341. //serial_print("\n");
  342. // TODO: using SPI_SR_TCF isn't quite right. Control returns to the
  343. // caller after the final edge that captures data, which is 1/2 cycle
  344. // sooner than AVR returns. At 500 kHz and slower SPI, this can make
  345. // a difference when digitalWrite is used to manually control the CS
  346. // pin, and perhaps it could matter at high clocks if faster register
  347. // access is used? But does it really matter? Do any SPI chips in
  348. // practice really perform differently if CS negates early, after the
  349. // final bit is clocked, but before the end of the whole clock cycle?
  350. if ((val & (1<<SPIF)) && ((LPSPI4_RSR & LPSPI_RSR_RXEMPTY) == 0)) ret = (1<<SPIF);
  351. //if ((val & (1<<SPI2X)) && (SPI0_CTAR0 & SPI_CTAR_DBR)) ret |= (1<<SPI2X);
  352. //delayMicroseconds(50000);
  353. return ret;
  354. }
  355. operator int () const __attribute__((always_inline)) {
  356. int ret = 0;
  357. //serial_print("SPSR (int)\n");
  358. if ((LPSPI4_RSR & LPSPI_RSR_RXEMPTY) == 0) ret = (1<<SPIF);
  359. //if (SPI0_CTAR0 & SPI_CTAR_DBR) ret |= (1<<SPI2X);
  360. return ret;
  361. }
  362. };
  363. extern SPSRemulation SPSR;
  364. class SPDRemulation
  365. {
  366. public:
  367. inline SPDRemulation & operator = (int val) __attribute__((always_inline)) {
  368. //serial_print("SPDR = ");
  369. //serial_phex(val);
  370. //serial_print("\n");
  371. LPSPI4_CR = LPSPI_CR_RRF | LPSPI_CR_MEN; // Module enabled anc clear the receive.
  372. LPSPI4_TDR = (val & 255);
  373. return *this;
  374. }
  375. operator int () const __attribute__((always_inline)) {
  376. uint32_t val;
  377. val = LPSPI4_RDR & 255;
  378. return val;
  379. }
  380. };
  381. extern SPDRemulation SPDR;
  382. #endif // __cplusplus
  383. #endif