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.

pwm.c 12KB

4 years ago
4 years ago
5 years ago
5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  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. #ifdef ARDUINO_TEENSY40
  49. {1, M(1, 1), 2, 1}, // FlexPWM1_1_B 34 // SD_B0_03
  50. {1, M(1, 1), 1, 1}, // FlexPWM1_1_A 35 // SD_B0_02
  51. {1, M(1, 0), 2, 1}, // FlexPWM1_0_B 36 // SD_B0_01
  52. {1, M(1, 0), 1, 1}, // FlexPWM1_0_A 37 // SD_B0_00
  53. {1, M(1, 2), 2, 1}, // FlexPWM1_2_B 38 // SD_B0_05
  54. {1, M(1, 2), 1, 1}, // FlexPWM1_2_A 39 // SD_B0_04
  55. #endif
  56. #ifdef ARDUINO_TEENSY41
  57. {0, M(1, 0), 0, 0},
  58. {0, M(1, 0), 0, 0},
  59. {1, M(2, 3), 1, 6}, // FlexPWM2_3_A 36 // B1_00
  60. {1, M(2, 3), 2, 6}, // FlexPWM2_3_B 37 // B1_01
  61. {0, M(1, 0), 0, 0},
  62. {0, M(1, 0), 0, 0},
  63. {0, M(1, 0), 0, 0},
  64. {0, M(1, 0), 0, 0},
  65. {1, M(1, 1), 2, 1}, // FlexPWM1_1_B 42 // SD_B0_03
  66. {1, M(1, 1), 1, 1}, // FlexPWM1_1_A 43 // SD_B0_02
  67. {1, M(1, 0), 2, 1}, // FlexPWM1_0_B 44 // SD_B0_01
  68. {1, M(1, 0), 1, 1}, // FlexPWM1_0_A 45 // SD_B0_00
  69. {1, M(1, 2), 2, 1}, // FlexPWM1_2_B 46 // SD_B0_05
  70. {1, M(1, 2), 1, 1}, // FlexPWM1_2_A 47 // SD_B0_04
  71. {0, M(1, 0), 0, 0}, // duplicate FlexPWM1_0_B
  72. {0, M(1, 0), 0, 0}, // duplicate FlexPWM1_2_A
  73. {0, M(1, 0), 0, 0}, // duplicate FlexPWM1_2_B
  74. {1, M(3, 3), 2, 1}, // FlexPWM3_3_B 51 // EMC_22
  75. {0, M(1, 0), 0, 0}, // duplicate FlexPWM1_1_B
  76. {0, M(1, 0), 0, 0}, // duplicate FlexPWM1_1_A
  77. {1, M(3, 0), 1, 1}, // FlexPWM3_0_A 53 // EMC_29
  78. #endif
  79. #ifdef ARDUINO_TEENSY_MICROMOD
  80. {1, M(1, 1), 2, 1}, // FlexPWM1_1_B 34 // SD_B0_03
  81. {1, M(1, 1), 1, 1}, // FlexPWM1_1_A 35 // SD_B0_02
  82. {1, M(1, 0), 2, 1}, // FlexPWM1_0_B 36 // SD_B0_01
  83. {1, M(1, 0), 1, 1}, // FlexPWM1_0_A 37 // SD_B0_00
  84. {1, M(1, 2), 2, 1}, // FlexPWM1_2_B 38 // SD_B0_05
  85. {1, M(1, 2), 1, 1}, // FlexPWM1_2_A 39 // SD_B0_04
  86. {2, M(2, 1), 0, 1}, // QuadTimer2_1 40 // B0_04
  87. {2, M(2, 2), 0, 1}, // QuadTimer2_2 41 // B0_05
  88. {0, M(1, 0), 0, 0}, // duplicate QuadTimer3_0
  89. {0, M(1, 0), 0, 0}, // duplicate QuadTimer3_1
  90. {0, M(1, 0), 0, 0}, // duplicate QuadTimer3_2
  91. {2, M(4, 0), 0, 1}, // QuadTimer4_0 45 // B0_09
  92. #endif
  93. };
  94. // Known usage of FlexPWM and QuadTimers
  95. // -------------------------------------
  96. // FlexPWM1_0 PWM pin 1, 36(T4.0), 37(T4.0), 44(T4.1), 45(T4.1)
  97. // FlexPWM1_1 PWM pin 0, 34(T4.0), 35(T4.0), 42(T4.1), 43(T4.1)
  98. // FlexPWM1_2 PWM pin 24, 38(T4.0), 39(T4.0), 46(T4.1), 47(T4.1)
  99. // FlexPWM1_3 PWM pin 7, 8, 25
  100. // FlexPWM2_0 PWM pin 4, 33
  101. // FlexPWM2_1 PWM pin 5
  102. // FlexPWM2_2 PWM pin 6, 9
  103. // FlexPWM2_3 PWM pin 36(T4.1), 37(T4.1)
  104. // FlexPWM3_0 PWM pin 53(T4.1)
  105. // FlexPWM3_1 PWM pin 28, 29
  106. // FlexPWM3_2
  107. // FlexPWM3_3 PWM pin 41(T4.1)
  108. // FlexPWM4_0 PWM pin 22
  109. // FlexPWM4_1 PWM pin 23
  110. // FlexPWM4_2 PWM pin 2, 3
  111. // FlexPWM4_3
  112. // QuadTimer1_0 PWM pin 10
  113. // QuadTimer1_1 PWM pin 12
  114. // QuadTimer1_2 PWM pin 11
  115. // QuadTimer1_3
  116. // QuadTimer2_0 PWM pin 13
  117. // QuadTimer2_1
  118. // QuadTimer2_2
  119. // QuadTimer2_3
  120. // QuadTimer3_0 PWM pin 19
  121. // QuadTimer3_1 PWM pin 18
  122. // QuadTimer3_2 PWM pin 14
  123. // QuadTimer3_3 PWM pin 15
  124. // QuadTimer4_0 OctoWS2811
  125. // QuadTimer4_1 OctoWS2811
  126. // QuadTimer4_2 OctoWS2811
  127. // QuadTimer4_3 AudioInputAnalog
  128. #endif // __IMXRT1062__
  129. void flexpwmWrite(IMXRT_FLEXPWM_t *p, unsigned int submodule, uint8_t channel, uint16_t val)
  130. {
  131. uint16_t mask = 1 << submodule;
  132. uint32_t modulo = p->SM[submodule].VAL1;
  133. uint32_t cval = ((uint32_t)val * (modulo + 1)) >> analog_write_res;
  134. if (cval > modulo) cval = modulo; // TODO: is this check correct?
  135. //printf("flexpwmWrite, p=%08lX, sm=%d, ch=%c, cval=%ld\n",
  136. //(uint32_t)p, submodule, channel == 0 ? 'X' : (channel == 1 ? 'A' : 'B'), cval);
  137. p->MCTRL |= FLEXPWM_MCTRL_CLDOK(mask);
  138. switch (channel) {
  139. case 0: // X
  140. p->SM[submodule].VAL0 = modulo - cval;
  141. p->OUTEN |= FLEXPWM_OUTEN_PWMX_EN(mask);
  142. //printf(" write channel X\n");
  143. break;
  144. case 1: // A
  145. p->SM[submodule].VAL3 = cval;
  146. p->OUTEN |= FLEXPWM_OUTEN_PWMA_EN(mask);
  147. //printf(" write channel A\n");
  148. break;
  149. case 2: // B
  150. p->SM[submodule].VAL5 = cval;
  151. p->OUTEN |= FLEXPWM_OUTEN_PWMB_EN(mask);
  152. //printf(" write channel B\n");
  153. }
  154. p->MCTRL |= FLEXPWM_MCTRL_LDOK(mask);
  155. }
  156. void flexpwmFrequency(IMXRT_FLEXPWM_t *p, unsigned int submodule, uint8_t channel, float frequency)
  157. {
  158. uint16_t mask = 1 << submodule;
  159. uint32_t olddiv = p->SM[submodule].VAL1;
  160. uint32_t newdiv = (uint32_t)((float)F_BUS_ACTUAL / frequency + 0.5f);
  161. uint32_t prescale = 0;
  162. //printf(" div=%lu\n", newdiv);
  163. while (newdiv > 65535 && prescale < 7) {
  164. newdiv = newdiv >> 1;
  165. prescale = prescale + 1;
  166. }
  167. if (newdiv > 65535) {
  168. newdiv = 65535;
  169. } else if (newdiv < 2) {
  170. newdiv = 2;
  171. }
  172. //printf(" div=%lu, scale=%lu\n", newdiv, prescale);
  173. p->MCTRL |= FLEXPWM_MCTRL_CLDOK(mask);
  174. p->SM[submodule].CTRL = FLEXPWM_SMCTRL_FULL | FLEXPWM_SMCTRL_PRSC(prescale);
  175. p->SM[submodule].VAL1 = newdiv - 1;
  176. p->SM[submodule].VAL0 = (p->SM[submodule].VAL0 * newdiv) / olddiv;
  177. p->SM[submodule].VAL3 = (p->SM[submodule].VAL3 * newdiv) / olddiv;
  178. p->SM[submodule].VAL5 = (p->SM[submodule].VAL5 * newdiv) / olddiv;
  179. p->MCTRL |= FLEXPWM_MCTRL_LDOK(mask);
  180. }
  181. void quadtimerWrite(IMXRT_TMR_t *p, unsigned int submodule, uint16_t val)
  182. {
  183. uint32_t modulo = 65537 - p->CH[submodule].LOAD + p->CH[submodule].CMPLD1;
  184. uint32_t high = ((uint32_t)val * (modulo - 1)) >> analog_write_res;
  185. if (high >= modulo - 1) high = modulo - 2;
  186. //printf(" modulo=%lu\n", modulo);
  187. //printf(" high=%lu\n", high);
  188. uint32_t low = modulo - high; // low must 2 or higher
  189. //printf(" low=%lu\n", low);
  190. p->CH[submodule].LOAD = 65537 - low;
  191. p->CH[submodule].CMPLD1 = high;
  192. }
  193. void quadtimerFrequency(IMXRT_TMR_t *p, unsigned int submodule, float frequency)
  194. {
  195. uint32_t newdiv = (uint32_t)((float)F_BUS_ACTUAL / frequency + 0.5f);
  196. uint32_t prescale = 0;
  197. //printf(" div=%lu\n", newdiv);
  198. while (newdiv > 65534 && prescale < 7) {
  199. newdiv = newdiv >> 1;
  200. prescale = prescale + 1;
  201. }
  202. if (newdiv > 65534) {
  203. newdiv = 65534;
  204. } else if (newdiv < 2) {
  205. newdiv = 2;
  206. }
  207. //printf(" div=%lu, scale=%lu\n", newdiv, prescale);
  208. uint32_t oldhigh = p->CH[submodule].CMPLD1;
  209. uint32_t oldlow = 65537 - p->CH[submodule].LOAD;
  210. uint32_t high = (oldhigh * newdiv) / (oldhigh + oldlow);
  211. // TODO: low must never be less than 2 - can it happen with this?
  212. uint32_t low = newdiv - high;
  213. //printf(" high=%lu, low=%lu\n", high, low);
  214. p->CH[submodule].LOAD = 65537 - low;
  215. p->CH[submodule].CMPLD1 = high;
  216. p->CH[submodule].CTRL = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8 + prescale) |
  217. TMR_CTRL_LENGTH | TMR_CTRL_OUTMODE(6);
  218. }
  219. void analogWrite(uint8_t pin, int val)
  220. {
  221. const struct pwm_pin_info_struct *info;
  222. if (pin >= CORE_NUM_DIGITAL) return;
  223. //printf("analogWrite, pin %d, val %d\n", pin, val);
  224. info = pwm_pin_info + pin;
  225. if (info->type == 1) {
  226. // FlexPWM pin
  227. IMXRT_FLEXPWM_t *flexpwm;
  228. switch ((info->module >> 4) & 3) {
  229. case 0: flexpwm = &IMXRT_FLEXPWM1; break;
  230. case 1: flexpwm = &IMXRT_FLEXPWM2; break;
  231. case 2: flexpwm = &IMXRT_FLEXPWM3; break;
  232. default: flexpwm = &IMXRT_FLEXPWM4;
  233. }
  234. flexpwmWrite(flexpwm, info->module & 0x03, info->channel, val);
  235. } else if (info->type == 2) {
  236. // QuadTimer pin
  237. IMXRT_TMR_t *qtimer;
  238. switch ((info->module >> 4) & 3) {
  239. case 0: qtimer = &IMXRT_TMR1; break;
  240. case 1: qtimer = &IMXRT_TMR2; break;
  241. case 2: qtimer = &IMXRT_TMR3; break;
  242. default: qtimer = &IMXRT_TMR4;
  243. }
  244. quadtimerWrite(qtimer, info->module & 0x03, val);
  245. } else {
  246. return;
  247. }
  248. *(portConfigRegister(pin)) = info->muxval;
  249. // TODO: pad config register
  250. }
  251. void analogWriteFrequency(uint8_t pin, float frequency)
  252. {
  253. const struct pwm_pin_info_struct *info;
  254. if (pin >= CORE_NUM_DIGITAL) return;
  255. //printf("analogWriteFrequency, pin %d, freq %d\n", pin, (int)frequency);
  256. info = pwm_pin_info + pin;
  257. if (info->type == 1) {
  258. // FlexPWM pin
  259. IMXRT_FLEXPWM_t *flexpwm;
  260. switch ((info->module >> 4) & 3) {
  261. case 0: flexpwm = &IMXRT_FLEXPWM1; break;
  262. case 1: flexpwm = &IMXRT_FLEXPWM2; break;
  263. case 2: flexpwm = &IMXRT_FLEXPWM3; break;
  264. default: flexpwm = &IMXRT_FLEXPWM4;
  265. }
  266. flexpwmFrequency(flexpwm, info->module & 0x03, info->channel, frequency);
  267. } else if (info->type == 2) {
  268. // QuadTimer pin
  269. IMXRT_TMR_t *qtimer;
  270. switch ((info->module >> 4) & 3) {
  271. case 0: qtimer = &IMXRT_TMR1; break;
  272. case 1: qtimer = &IMXRT_TMR2; break;
  273. case 2: qtimer = &IMXRT_TMR3; break;
  274. default: qtimer = &IMXRT_TMR4;
  275. }
  276. quadtimerFrequency(qtimer, info->module & 0x03, frequency);
  277. }
  278. }
  279. void flexpwm_init(IMXRT_FLEXPWM_t *p)
  280. {
  281. int i;
  282. p->FCTRL0 = FLEXPWM_FCTRL0_FLVL(15); // logic high = fault
  283. p->FSTS0 = 0x000F; // clear fault status
  284. p->FFILT0 = 0;
  285. p->MCTRL |= FLEXPWM_MCTRL_CLDOK(15);
  286. for (i=0; i < 4; i++) {
  287. p->SM[i].CTRL2 = FLEXPWM_SMCTRL2_INDEP | FLEXPWM_SMCTRL2_WAITEN
  288. | FLEXPWM_SMCTRL2_DBGEN;
  289. p->SM[i].CTRL = FLEXPWM_SMCTRL_FULL;
  290. p->SM[i].OCTRL = 0;
  291. p->SM[i].DTCNT0 = 0;
  292. p->SM[i].INIT = 0;
  293. p->SM[i].VAL0 = 0;
  294. p->SM[i].VAL1 = 33464;
  295. p->SM[i].VAL2 = 0;
  296. p->SM[i].VAL3 = 0;
  297. p->SM[i].VAL4 = 0;
  298. p->SM[i].VAL5 = 0;
  299. }
  300. p->MCTRL |= FLEXPWM_MCTRL_LDOK(15);
  301. p->MCTRL |= FLEXPWM_MCTRL_RUN(15);
  302. }
  303. void quadtimer_init(IMXRT_TMR_t *p)
  304. {
  305. int i;
  306. for (i=0; i < 4; i++) {
  307. p->CH[i].CTRL = 0; // stop timer
  308. p->CH[i].CNTR = 0;
  309. p->CH[i].SCTRL = TMR_SCTRL_OEN | TMR_SCTRL_OPS | TMR_SCTRL_VAL | TMR_SCTRL_FORCE;
  310. p->CH[i].CSCTRL = TMR_CSCTRL_CL1(1) | TMR_CSCTRL_ALT_LOAD;
  311. // COMP must be less than LOAD - otherwise output is always low
  312. p->CH[i].LOAD = 24000; // low time (65537 - x) -
  313. p->CH[i].COMP1 = 0; // high time (0 = always low, max = LOAD-1)
  314. p->CH[i].CMPLD1 = 0;
  315. p->CH[i].CTRL = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8) |
  316. TMR_CTRL_LENGTH | TMR_CTRL_OUTMODE(6);
  317. }
  318. }
  319. void pwm_init(void)
  320. {
  321. //printf("pwm init\n");
  322. CCM_CCGR4 |= CCM_CCGR4_PWM1(CCM_CCGR_ON) | CCM_CCGR4_PWM2(CCM_CCGR_ON) |
  323. CCM_CCGR4_PWM3(CCM_CCGR_ON) | CCM_CCGR4_PWM4(CCM_CCGR_ON);
  324. CCM_CCGR6 |= CCM_CCGR6_QTIMER1(CCM_CCGR_ON) | CCM_CCGR6_QTIMER2(CCM_CCGR_ON) |
  325. CCM_CCGR6_QTIMER3(CCM_CCGR_ON) | CCM_CCGR6_QTIMER4(CCM_CCGR_ON);
  326. flexpwm_init(&IMXRT_FLEXPWM1);
  327. flexpwm_init(&IMXRT_FLEXPWM2);
  328. flexpwm_init(&IMXRT_FLEXPWM3);
  329. flexpwm_init(&IMXRT_FLEXPWM4);
  330. quadtimer_init(&IMXRT_TMR1);
  331. quadtimer_init(&IMXRT_TMR2);
  332. quadtimer_init(&IMXRT_TMR3);
  333. }
  334. void xbar_connect(unsigned int input, unsigned int output)
  335. {
  336. if (input >= 88) return;
  337. if (output >= 132) return;
  338. #if 1
  339. volatile uint16_t *xbar = &XBARA1_SEL0 + (output / 2);
  340. uint16_t val = *xbar;
  341. if (!(output & 1)) {
  342. val = (val & 0xFF00) | input;
  343. } else {
  344. val = (val & 0x00FF) | (input << 8);
  345. }
  346. *xbar = val;
  347. #else
  348. // does not work, seems 8 bit access is not allowed
  349. volatile uint8_t *xbar = (volatile uint8_t *)XBARA1_SEL0;
  350. xbar[output] = input;
  351. #endif
  352. }
  353. uint32_t analogWriteRes(uint32_t bits)
  354. {
  355. uint32_t prior;
  356. if (bits < 1) {
  357. bits = 1;
  358. } else if (bits > 16) {
  359. bits = 16;
  360. }
  361. prior = analog_write_res;
  362. analog_write_res = bits;
  363. return prior;
  364. }