Teensy 4.1 core updated for C++20
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

367 lines
12KB

  1. #include "imxrt.h"
  2. #include "core_pins.h"
  3. #include "debug/printf.h"
  4. struct pwm_pin_info_struct {
  5. uint8_t type; // 0=no pwm, 1=flexpwm, 2=quad
  6. uint8_t module; // 0-3, 0-3
  7. uint8_t channel; // 0=X, 1=A, 2=B
  8. uint8_t muxval; //
  9. };
  10. uint8_t analog_write_res = 8;
  11. #define M(a, b) ((((a) - 1) << 4) | (b))
  12. #if defined(__IMXRT1062__)
  13. const struct pwm_pin_info_struct pwm_pin_info[] = {
  14. {1, M(1, 1), 0, 4}, // FlexPWM1_1_X 0 // AD_B0_03
  15. {1, M(1, 0), 0, 4}, // FlexPWM1_0_X 1 // AD_B0_02
  16. {1, M(4, 2), 1, 1}, // FlexPWM4_2_A 2 // EMC_04
  17. {1, M(4, 2), 2, 1}, // FlexPWM4_2_B 3 // EMC_05
  18. {1, M(2, 0), 1, 1}, // FlexPWM2_0_A 4 // EMC_06
  19. {1, M(2, 1), 1, 1}, // FlexPWM2_1_A 5 // EMC_08
  20. {1, M(2, 2), 1, 2}, // FlexPWM2_2_A 6 // B0_10
  21. {1, M(1, 3), 2, 6}, // FlexPWM1_3_B 7 // B1_01
  22. {1, M(1, 3), 1, 6}, // FlexPWM1_3_A 8 // B1_00
  23. {1, M(2, 2), 2, 2}, // FlexPWM2_2_B 9 // B0_11
  24. {2, M(1, 0), 0, 1}, // QuadTimer1_0 10 // B0_00
  25. {2, M(1, 2), 0, 1}, // QuadTimer1_2 11 // B0_02
  26. {2, M(1, 1), 0, 1}, // QuadTimer1_1 12 // B0_01
  27. {2, M(2, 0), 0, 1}, // QuadTimer2_0 13 // B0_03
  28. {2, M(3, 2), 0, 1}, // QuadTimer3_2 14 // AD_B1_02
  29. {2, M(3, 3), 0, 1}, // QuadTimer3_3 15 // AD_B1_03
  30. {0, M(1, 0), 0, 0},
  31. {0, M(1, 0), 0, 0},
  32. {2, M(3, 1), 0, 1}, // QuadTimer3_1 18 // AD_B1_01
  33. {2, M(3, 0), 0, 1}, // QuadTimer3_0 19 // AD_B1_00
  34. {0, M(1, 0), 0, 0},
  35. {0, M(1, 0), 0, 0},
  36. {1, M(4, 0), 1, 1}, // FlexPWM4_0_A 22 // AD_B1_08
  37. {1, M(4, 1), 1, 1}, // FlexPWM4_1_A 23 // AD_B1_09
  38. {1, M(1, 2), 0, 4}, // FlexPWM1_2_X 24 // AD_B0_12
  39. {1, M(1, 3), 0, 4}, // FlexPWM1_3_X 25 // AD_B0_13
  40. {0, M(1, 0), 0, 0},
  41. {0, M(1, 0), 0, 0},
  42. {1, M(3, 1), 2, 1}, // FlexPWM3_1_B 28 // EMC_32
  43. {1, M(3, 1), 1, 1}, // FlexPWM3_1_A 29 // EMC_31
  44. {0, M(1, 0), 0, 0},
  45. {0, M(1, 0), 0, 0},
  46. {0, M(1, 0), 0, 0},
  47. {1, M(2, 0), 2, 1}, // FlexPWM2_0_B 33 // EMC_07
  48. {1, M(1, 1), 2, 1}, // FlexPWM1_1_B 34 // SD_B0_03
  49. {1, M(1, 1), 1, 1}, // FlexPWM1_1_A 35 // SD_B0_02
  50. {1, M(1, 0), 2, 1}, // FlexPWM1_0_B 36 // SD_B0_01
  51. {1, M(1, 0), 1, 1}, // FlexPWM1_0_A 37 // SD_B0_00
  52. {1, M(1, 2), 2, 1}, // FlexPWM1_2_B 38 // SD_B0_05
  53. {1, M(1, 2), 1, 1}, // FlexPWM1_2_A 39 // SD_B0_04
  54. };
  55. #elif defined(__IMXRT1052__)
  56. const struct pwm_pin_info_struct pwm_pin_info[] = {
  57. {1, M(1, 1), 0, 4}, // FlexPWM1_1_X 0 // AD_B0_03
  58. {1, M(1, 0), 0, 4}, // FlexPWM1_0_X 1 // AD_B0_02
  59. {1, M(4, 2), 1, 1}, // FlexPWM4_2_A 2 // EMC_04
  60. {1, M(4, 2), 2, 1}, // FlexPWM4_2_B 3 // EMC_05
  61. {1, M(2, 0), 1, 1}, // FlexPWM2_0_A 4 // EMC_06
  62. {1, M(2, 0), 2, 1}, // FlexPWM2_0_B 5 // EMC_07
  63. {1, M(1, 3), 2, 6}, // FlexPWM1_3_B 6 // B1_01
  64. {1, M(1, 3), 1, 6}, // FlexPWM1_3_A 7 // B1_00
  65. {1, M(2, 2), 1, 2}, // FlexPWM2_2_A 8 // B0_10
  66. {1, M(2, 2), 2, 2}, // FlexPWM2_2_B 9 // B0_11
  67. {2, M(1, 0), 0, 1}, // QuadTimer1_0 10 // B0_00
  68. {2, M(1, 2), 0, 1}, // QuadTimer1_2 11 // B0_02
  69. {2, M(1, 1), 0, 1}, // QuadTimer1_1 12 // B0_01
  70. {2, M(2, 0), 0, 1}, // QuadTimer2_0 13 // B0_03
  71. {2, M(3, 2), 0, 1}, // QuadTimer3_2 14 // AD_B1_02
  72. {2, M(3, 3), 0, 1}, // QuadTimer3_3 15 // AD_B1_03
  73. {0, M(1, 0), 0, 0},
  74. {0, M(1, 0), 0, 0},
  75. {2, M(3, 1), 0, 1}, // QuadTimer3_1 18 // AD_B1_01
  76. {2, M(3, 0), 0, 1}, // QuadTimer3_0 19 // AD_B1_00
  77. {0, M(1, 0), 0, 0},
  78. {0, M(1, 0), 0, 0},
  79. {1, M(4, 0), 1, 1}, // FlexPWM4_0_A 22 // AD_B1_08
  80. {1, M(4, 1), 1, 1}, // FlexPWM4_1_A 23 // AD_B1_09
  81. {1, M(1, 2), 0, 4}, // FlexPWM1_2_X 24 // AD_B0_12
  82. {1, M(1, 3), 0, 4}, // FlexPWM1_3_X 25 // AD_B0_13
  83. {0, M(1, 0), 0, 0},
  84. {0, M(1, 0), 0, 0},
  85. {1, M(3, 1), 2, 1}, // FlexPWM3_1_B 28 // EMC_32
  86. {1, M(3, 1), 1, 1}, // FlexPWM3_1_A 29 // EMC_31
  87. {1, M(1, 0), 2, 1}, // FlexPWM1_0_B 30 // EMC_24
  88. {1, M(1, 0), 1, 1}, // FlexPWM1_0_A 31 // EMC_23
  89. {0, M(1, 0), 0, 0},
  90. {1, M(2, 1), 1, 1}, // FlexPWM2_1_A 33 // EMC_08
  91. {1, M(2, 0), 2, 1}, // FlexPWM2_0_B 33 // EMC_07
  92. {1, M(1, 1), 2, 1}, // FlexPWM1_1_B 34 // SD_B0_03
  93. {1, M(1, 1), 1, 1}, // FlexPWM1_1_A 35 // SD_B0_02
  94. {1, M(1, 0), 2, 1}, // FlexPWM1_0_B 36 // SD_B0_01
  95. {1, M(1, 0), 1, 1}, // FlexPWM1_0_A 37 // SD_B0_00
  96. {1, M(1, 2), 2, 1}, // FlexPWM1_2_B 38 // SD_B0_05
  97. {1, M(1, 2), 1, 1}, // FlexPWM1_2_A 39 // SD_B0_04
  98. };
  99. #endif // __IMXRT1052__
  100. void flexpwmWrite(IMXRT_FLEXPWM_t *p, unsigned int submodule, uint8_t channel, uint16_t val)
  101. {
  102. uint16_t mask = 1 << submodule;
  103. uint32_t modulo = p->SM[submodule].VAL1;
  104. uint32_t cval = ((uint32_t)val * (modulo + 1)) >> analog_write_res;
  105. if (cval > modulo) cval = modulo; // TODO: is this check correct?
  106. //printf("flexpwmWrite, p=%08lX, sm=%d, ch=%c, cval=%ld\n",
  107. //(uint32_t)p, submodule, channel == 0 ? 'X' : (channel == 1 ? 'A' : 'B'), cval);
  108. p->MCTRL |= FLEXPWM_MCTRL_CLDOK(mask);
  109. switch (channel) {
  110. case 0: // X
  111. p->SM[submodule].VAL0 = modulo - cval;
  112. p->OUTEN |= FLEXPWM_OUTEN_PWMX_EN(mask);
  113. //printf(" write channel X\n");
  114. break;
  115. case 1: // A
  116. p->SM[submodule].VAL3 = cval;
  117. p->OUTEN |= FLEXPWM_OUTEN_PWMA_EN(mask);
  118. //printf(" write channel A\n");
  119. break;
  120. case 2: // B
  121. p->SM[submodule].VAL5 = cval;
  122. p->OUTEN |= FLEXPWM_OUTEN_PWMB_EN(mask);
  123. //printf(" write channel B\n");
  124. }
  125. p->MCTRL |= FLEXPWM_MCTRL_LDOK(mask);
  126. }
  127. void flexpwmFrequency(IMXRT_FLEXPWM_t *p, unsigned int submodule, uint8_t channel, float frequency)
  128. {
  129. uint16_t mask = 1 << submodule;
  130. uint32_t olddiv = p->SM[submodule].VAL1;
  131. uint32_t newdiv = (uint32_t)((float)F_BUS_ACTUAL / frequency + 0.5);
  132. uint32_t prescale = 0;
  133. //printf(" div=%lu\n", newdiv);
  134. while (newdiv > 65535 && prescale < 7) {
  135. newdiv = newdiv >> 1;
  136. prescale = prescale + 1;
  137. }
  138. if (newdiv > 65535) {
  139. newdiv = 65535;
  140. } else if (newdiv < 2) {
  141. newdiv = 2;
  142. }
  143. //printf(" div=%lu, scale=%lu\n", newdiv, prescale);
  144. p->MCTRL |= FLEXPWM_MCTRL_CLDOK(mask);
  145. p->SM[submodule].CTRL = FLEXPWM_SMCTRL_FULL | FLEXPWM_SMCTRL_PRSC(prescale);
  146. p->SM[submodule].VAL1 = newdiv - 1;
  147. p->SM[submodule].VAL0 = (p->SM[submodule].VAL0 * newdiv) / olddiv;
  148. p->SM[submodule].VAL3 = (p->SM[submodule].VAL3 * newdiv) / olddiv;
  149. p->SM[submodule].VAL5 = (p->SM[submodule].VAL5 * newdiv) / olddiv;
  150. p->MCTRL |= FLEXPWM_MCTRL_LDOK(mask);
  151. }
  152. void quadtimerWrite(IMXRT_TMR_t *p, unsigned int submodule, uint16_t val)
  153. {
  154. uint32_t modulo = 65537 - p->CH[submodule].LOAD + p->CH[submodule].CMPLD1;
  155. uint32_t high = ((uint32_t)val * (modulo - 1)) >> analog_write_res;
  156. if (high >= modulo) high = modulo - 1; // TODO: is this check correct?
  157. //printf(" modulo=%lu\n", modulo);
  158. //printf(" high=%lu\n", high);
  159. uint32_t low = modulo - high; // TODO: low must never be 0 or 1 - can it be??
  160. //printf(" low=%lu\n", low);
  161. p->CH[submodule].LOAD = 65537 - low;
  162. p->CH[submodule].CMPLD1 = high;
  163. }
  164. void quadtimerFrequency(IMXRT_TMR_t *p, unsigned int submodule, float frequency)
  165. {
  166. uint32_t newdiv = (uint32_t)((float)F_BUS_ACTUAL / frequency + 0.5);
  167. uint32_t prescale = 0;
  168. //printf(" div=%lu\n", newdiv);
  169. while (newdiv > 65534 && prescale < 7) {
  170. newdiv = newdiv >> 1;
  171. prescale = prescale + 1;
  172. }
  173. if (newdiv > 65534) {
  174. newdiv = 65534;
  175. } else if (newdiv < 2) {
  176. newdiv = 2;
  177. }
  178. //printf(" div=%lu, scale=%lu\n", newdiv, prescale);
  179. uint32_t oldhigh = p->CH[submodule].CMPLD1;
  180. uint32_t oldlow = 65537 - p->CH[submodule].LOAD;
  181. uint32_t high = (oldhigh * newdiv) / (oldhigh + oldlow);
  182. // TODO: low must never be less than 2 - can it happen with this?
  183. uint32_t low = newdiv - high;
  184. //printf(" high=%lu, low=%lu\n", high, low);
  185. p->CH[submodule].LOAD = 65537 - low;
  186. p->CH[submodule].CMPLD1 = high;
  187. p->CH[submodule].CTRL = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8 + prescale) |
  188. TMR_CTRL_LENGTH | TMR_CTRL_OUTMODE(6);
  189. }
  190. void analogWrite(uint8_t pin, int val)
  191. {
  192. const struct pwm_pin_info_struct *info;
  193. if (pin >= CORE_NUM_DIGITAL) return;
  194. //printf("analogWrite, pin %d, val %d\n", pin, val);
  195. info = pwm_pin_info + pin;
  196. if (info->type == 1) {
  197. // FlexPWM pin
  198. IMXRT_FLEXPWM_t *flexpwm;
  199. switch ((info->module >> 4) & 3) {
  200. case 0: flexpwm = &IMXRT_FLEXPWM1; break;
  201. case 1: flexpwm = &IMXRT_FLEXPWM2; break;
  202. case 2: flexpwm = &IMXRT_FLEXPWM3; break;
  203. default: flexpwm = &IMXRT_FLEXPWM4;
  204. }
  205. flexpwmWrite(flexpwm, info->module & 0x03, info->channel, val);
  206. } else if (info->type == 2) {
  207. // QuadTimer pin
  208. IMXRT_TMR_t *qtimer;
  209. switch ((info->module >> 4) & 3) {
  210. case 0: qtimer = &IMXRT_TMR1; break;
  211. case 1: qtimer = &IMXRT_TMR2; break;
  212. case 2: qtimer = &IMXRT_TMR3; break;
  213. default: qtimer = &IMXRT_TMR4;
  214. }
  215. quadtimerWrite(qtimer, info->module & 0x03, val);
  216. } else {
  217. return;
  218. }
  219. *(portConfigRegister(pin)) = info->muxval;
  220. // TODO: pad config register
  221. }
  222. void analogWriteFrequency(uint8_t pin, float frequency)
  223. {
  224. const struct pwm_pin_info_struct *info;
  225. if (pin >= CORE_NUM_DIGITAL) return;
  226. //printf("analogWriteFrequency, pin %d, freq %d\n", pin, (int)frequency);
  227. info = pwm_pin_info + pin;
  228. if (info->type == 1) {
  229. // FlexPWM pin
  230. IMXRT_FLEXPWM_t *flexpwm;
  231. switch ((info->module >> 4) & 3) {
  232. case 0: flexpwm = &IMXRT_FLEXPWM1; break;
  233. case 1: flexpwm = &IMXRT_FLEXPWM2; break;
  234. case 2: flexpwm = &IMXRT_FLEXPWM3; break;
  235. default: flexpwm = &IMXRT_FLEXPWM4;
  236. }
  237. flexpwmFrequency(flexpwm, info->module & 0x03, info->channel, frequency);
  238. } else if (info->type == 2) {
  239. // QuadTimer pin
  240. IMXRT_TMR_t *qtimer;
  241. switch ((info->module >> 4) & 3) {
  242. case 0: qtimer = &IMXRT_TMR1; break;
  243. case 1: qtimer = &IMXRT_TMR2; break;
  244. case 2: qtimer = &IMXRT_TMR3; break;
  245. default: qtimer = &IMXRT_TMR4;
  246. }
  247. quadtimerFrequency(qtimer, info->module & 0x03, frequency);
  248. }
  249. }
  250. void flexpwm_init(IMXRT_FLEXPWM_t *p)
  251. {
  252. int i;
  253. p->FCTRL0 = FLEXPWM_FCTRL0_FLVL(15); // logic high = fault
  254. p->FSTS0 = 0x000F; // clear fault status
  255. p->FFILT0 = 0;
  256. p->MCTRL |= FLEXPWM_MCTRL_CLDOK(15);
  257. for (i=0; i < 4; i++) {
  258. p->SM[i].CTRL2 = FLEXPWM_SMCTRL2_INDEP | FLEXPWM_SMCTRL2_WAITEN
  259. | FLEXPWM_SMCTRL2_DBGEN;
  260. p->SM[i].CTRL = FLEXPWM_SMCTRL_FULL;
  261. p->SM[i].OCTRL = 0;
  262. p->SM[i].DTCNT0 = 0;
  263. p->SM[i].INIT = 0;
  264. p->SM[i].VAL0 = 0;
  265. p->SM[i].VAL1 = 33464;
  266. p->SM[i].VAL2 = 0;
  267. p->SM[i].VAL3 = 0;
  268. p->SM[i].VAL4 = 0;
  269. p->SM[i].VAL5 = 0;
  270. }
  271. p->MCTRL |= FLEXPWM_MCTRL_LDOK(15);
  272. p->MCTRL |= FLEXPWM_MCTRL_RUN(15);
  273. }
  274. void quadtimer_init(IMXRT_TMR_t *p)
  275. {
  276. int i;
  277. for (i=0; i < 4; i++) {
  278. p->CH[i].CTRL = 0; // stop timer
  279. p->CH[i].CNTR = 0;
  280. p->CH[i].SCTRL = TMR_SCTRL_OEN | TMR_SCTRL_OPS | TMR_SCTRL_VAL | TMR_SCTRL_FORCE;
  281. p->CH[i].CSCTRL = TMR_CSCTRL_CL1(1) | TMR_CSCTRL_ALT_LOAD;
  282. // COMP must be less than LOAD - otherwise output is always low
  283. p->CH[i].LOAD = 24000; // low time (65537 - x) -
  284. p->CH[i].COMP1 = 0; // high time (0 = always low, max = LOAD-1)
  285. p->CH[i].CMPLD1 = 0;
  286. p->CH[i].CTRL = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8) |
  287. TMR_CTRL_LENGTH | TMR_CTRL_OUTMODE(6);
  288. }
  289. }
  290. void pwm_init(void)
  291. {
  292. //printf("pwm init\n");
  293. CCM_CCGR4 |= CCM_CCGR4_PWM1(CCM_CCGR_ON) | CCM_CCGR4_PWM2(CCM_CCGR_ON) |
  294. CCM_CCGR4_PWM3(CCM_CCGR_ON) | CCM_CCGR4_PWM4(CCM_CCGR_ON);
  295. CCM_CCGR6 |= CCM_CCGR6_QTIMER1(CCM_CCGR_ON) | CCM_CCGR6_QTIMER2(CCM_CCGR_ON) |
  296. CCM_CCGR6_QTIMER3(CCM_CCGR_ON) | CCM_CCGR6_QTIMER4(CCM_CCGR_ON);
  297. flexpwm_init(&IMXRT_FLEXPWM1);
  298. flexpwm_init(&IMXRT_FLEXPWM2);
  299. flexpwm_init(&IMXRT_FLEXPWM3);
  300. flexpwm_init(&IMXRT_FLEXPWM4);
  301. quadtimer_init(&IMXRT_TMR1);
  302. quadtimer_init(&IMXRT_TMR2);
  303. quadtimer_init(&IMXRT_TMR3);
  304. }
  305. void xbar_connect(unsigned int input, unsigned int output)
  306. {
  307. if (input >= 88) return;
  308. if (output >= 132) return;
  309. #if 1
  310. volatile uint16_t *xbar = &XBARA1_SEL0 + (output / 2);
  311. uint16_t val = *xbar;
  312. if (!(output & 1)) {
  313. val = (val & 0xFF00) | input;
  314. } else {
  315. val = (val & 0x00FF) | (input << 8);
  316. }
  317. *xbar = val;
  318. #else
  319. // does not work, seems 8 bit access is not allowed
  320. volatile uint8_t *xbar = (volatile uint8_t *)XBARA1_SEL0;
  321. xbar[output] = input;
  322. #endif
  323. }
  324. uint32_t analogWriteRes(uint32_t bits)
  325. {
  326. uint32_t prior;
  327. if (bits < 1) {
  328. bits = 1;
  329. } else if (bits > 16) {
  330. bits = 16;
  331. }
  332. prior = analog_write_res;
  333. analog_write_res = bits;
  334. return prior;
  335. }