pwm.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. /*
  2. * Copyright (C) 2016 Stefan Brüns <stefan.bruens@rwth-aachen.de>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. /* Set the following three defines to your needs */
  19. #ifndef SDK_PWM_PERIOD_COMPAT_MODE
  20. #define SDK_PWM_PERIOD_COMPAT_MODE 0
  21. #endif
  22. #ifndef PWM_MAX_CHANNELS
  23. #define PWM_MAX_CHANNELS 8
  24. #endif
  25. #define PWM_DEBUG 0
  26. #define PWM_USE_NMI 0
  27. /* no user servicable parts beyond this point */
  28. #define PWM_MAX_TICKS 0x7fffff
  29. #if SDK_PWM_PERIOD_COMPAT_MODE
  30. #define PWM_PERIOD_TO_TICKS(x) (x * 0.2)
  31. #define PWM_DUTY_TO_TICKS(x) (x * 5)
  32. #define PWM_MAX_DUTY (PWM_MAX_TICKS * 0.2)
  33. #define PWM_MAX_PERIOD (PWM_MAX_TICKS * 5)
  34. #else
  35. #define PWM_PERIOD_TO_TICKS(x) (x)
  36. #define PWM_DUTY_TO_TICKS(x) (x)
  37. #define PWM_MAX_DUTY PWM_MAX_TICKS
  38. #define PWM_MAX_PERIOD PWM_MAX_TICKS
  39. #endif
  40. #include <c_types.h>
  41. #include <pwm.h>
  42. #include <eagle_soc.h>
  43. #include <ets_sys.h>
  44. // from SDK hw_timer.c
  45. #define TIMER1_DIVIDE_BY_16 0x0004
  46. #define TIMER1_ENABLE_TIMER 0x0080
  47. struct pwm_phase {
  48. uint32_t ticks; ///< delay until next phase, in 200ns units
  49. uint16_t on_mask; ///< GPIO mask to switch on
  50. uint16_t off_mask; ///< GPIO mask to switch off
  51. };
  52. /* Three sets of PWM phases, the active one, the one used
  53. * starting with the next cycle, and the one updated
  54. * by pwm_start. After the update pwm_next_set
  55. * is set to the last updated set. pwm_current_set is set to
  56. * pwm_next_set from the interrupt routine during the first
  57. * pwm phase
  58. */
  59. typedef struct pwm_phase (pwm_phase_array)[PWM_MAX_CHANNELS + 2];
  60. static pwm_phase_array pwm_phases[3];
  61. static struct {
  62. struct pwm_phase* next_set;
  63. struct pwm_phase* current_set;
  64. uint8_t current_phase;
  65. } pwm_state;
  66. static uint32_t pwm_period;
  67. static uint32_t pwm_period_ticks;
  68. static uint32_t pwm_duty[PWM_MAX_CHANNELS];
  69. static uint16_t gpio_mask[PWM_MAX_CHANNELS];
  70. static uint8_t pwm_channels;
  71. // 3-tuples of MUX_REGISTER, MUX_VALUE and GPIO number
  72. typedef uint32_t (pin_info_type)[3];
  73. struct gpio_regs {
  74. uint32_t out; /* 0x60000300 */
  75. uint32_t out_w1ts; /* 0x60000304 */
  76. uint32_t out_w1tc; /* 0x60000308 */
  77. uint32_t enable; /* 0x6000030C */
  78. uint32_t enable_w1ts; /* 0x60000310 */
  79. uint32_t enable_w1tc; /* 0x60000314 */
  80. uint32_t in; /* 0x60000318 */
  81. uint32_t status; /* 0x6000031C */
  82. uint32_t status_w1ts; /* 0x60000320 */
  83. uint32_t status_w1tc; /* 0x60000324 */
  84. };
  85. static struct gpio_regs* gpio = (struct gpio_regs*)(0x60000300);
  86. struct timer_regs {
  87. uint32_t frc1_load; /* 0x60000600 */
  88. uint32_t frc1_count; /* 0x60000604 */
  89. uint32_t frc1_ctrl; /* 0x60000608 */
  90. uint32_t frc1_int; /* 0x6000060C */
  91. uint8_t pad[16];
  92. uint32_t frc2_load; /* 0x60000620 */
  93. uint32_t frc2_count; /* 0x60000624 */
  94. uint32_t frc2_ctrl; /* 0x60000628 */
  95. uint32_t frc2_int; /* 0x6000062C */
  96. uint32_t frc2_alarm; /* 0x60000630 */
  97. };
  98. static struct timer_regs* timer = (struct timer_regs*)(0x60000600);
  99. static void ICACHE_RAM_ATTR
  100. pwm_intr_handler(void)
  101. {
  102. if ((pwm_state.current_set[pwm_state.current_phase].off_mask == 0) &&
  103. (pwm_state.current_set[pwm_state.current_phase].on_mask == 0)) {
  104. pwm_state.current_set = pwm_state.next_set;
  105. pwm_state.current_phase = 0;
  106. }
  107. do {
  108. // force write to GPIO registers on each loop
  109. asm volatile ("" : : : "memory");
  110. gpio->out_w1ts = (uint32_t)(pwm_state.current_set[pwm_state.current_phase].on_mask);
  111. gpio->out_w1tc = (uint32_t)(pwm_state.current_set[pwm_state.current_phase].off_mask);
  112. uint32_t ticks = pwm_state.current_set[pwm_state.current_phase].ticks;
  113. pwm_state.current_phase++;
  114. if (ticks) {
  115. if (ticks >= 16) {
  116. // constant interrupt overhead
  117. ticks -= 9;
  118. timer->frc1_int &= ~FRC1_INT_CLR_MASK;
  119. WRITE_PERI_REG(&timer->frc1_load, ticks);
  120. return;
  121. }
  122. ticks *= 4;
  123. do {
  124. ticks -= 1;
  125. // stop compiler from optimizing delay loop to noop
  126. asm volatile ("" : : : "memory");
  127. } while (ticks > 0);
  128. }
  129. } while (1);
  130. }
  131. /**
  132. * period: initial period (base unit 1us OR 200ns)
  133. * duty: array of initial duty values, may be NULL, may be freed after pwm_init
  134. * pwm_channel_num: number of channels to use
  135. * pin_info_list: array of pin_info
  136. */
  137. void ICACHE_FLASH_ATTR
  138. pwm_init(uint32_t period, uint32_t *duty, uint32_t pwm_channel_num,
  139. uint32_t (*pin_info_list)[3])
  140. {
  141. int i, j, n;
  142. pwm_channels = pwm_channel_num;
  143. if (pwm_channels > PWM_MAX_CHANNELS)
  144. pwm_channels = PWM_MAX_CHANNELS;
  145. for (i = 0; i < 3; i++) {
  146. for (j = 0; j < (PWM_MAX_CHANNELS + 2); j++) {
  147. pwm_phases[i][j].ticks = 0;
  148. pwm_phases[i][j].on_mask = 0;
  149. pwm_phases[i][j].off_mask = 0;
  150. }
  151. }
  152. pwm_state.current_set = pwm_state.next_set = 0;
  153. pwm_state.current_phase = 0;
  154. uint32_t all = 0;
  155. // PIN info: MUX-Register, Mux-Setting, PIN-Nr
  156. for (n = 0; n < pwm_channels; n++) {
  157. pin_info_type* pin_info = &pin_info_list[n];
  158. PIN_FUNC_SELECT((*pin_info)[0], (*pin_info)[1]);
  159. gpio_mask[n] = 1 << (*pin_info)[2];
  160. all |= 1 << (*pin_info)[2];
  161. if (duty)
  162. pwm_set_duty(duty[n], n);
  163. }
  164. GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, all);
  165. GPIO_REG_WRITE(GPIO_ENABLE_W1TS_ADDRESS, all);
  166. pwm_set_period(period);
  167. #if PWM_USE_NMI
  168. ETS_FRC_TIMER1_NMI_INTR_ATTACH(pwm_intr_handler);
  169. #else
  170. ETS_FRC_TIMER1_INTR_ATTACH(pwm_intr_handler, NULL);
  171. #endif
  172. TM1_EDGE_INT_ENABLE();
  173. timer->frc1_int &= ~FRC1_INT_CLR_MASK;
  174. timer->frc1_ctrl = 0;
  175. pwm_start();
  176. }
  177. __attribute__ ((noinline))
  178. static uint8_t ICACHE_FLASH_ATTR
  179. _pwm_phases_prep(struct pwm_phase* pwm)
  180. {
  181. uint8_t n, phases;
  182. uint16_t off_mask = 0;
  183. for (n = 0; n < pwm_channels + 2; n++) {
  184. pwm[n].ticks = 0;
  185. pwm[n].on_mask = 0;
  186. pwm[n].off_mask = 0;
  187. }
  188. phases = 1;
  189. for (n = 0; n < pwm_channels; n++) {
  190. uint32_t ticks = PWM_DUTY_TO_TICKS(pwm_duty[n]);
  191. if (ticks == 0) {
  192. pwm[0].off_mask |= gpio_mask[n];
  193. } else if (ticks >= pwm_period_ticks) {
  194. pwm[0].on_mask |= gpio_mask[n];
  195. } else {
  196. if (ticks < (pwm_period_ticks/2)) {
  197. pwm[phases].ticks = ticks;
  198. pwm[0].on_mask |= gpio_mask[n];
  199. pwm[phases].off_mask = gpio_mask[n];
  200. } else {
  201. pwm[phases].ticks = pwm_period_ticks - ticks;
  202. pwm[phases].on_mask = gpio_mask[n];
  203. pwm[0].off_mask |= gpio_mask[n];
  204. }
  205. phases++;
  206. }
  207. }
  208. pwm[phases].ticks = pwm_period_ticks;
  209. // bubble sort, lowest to hightest duty
  210. n = 2;
  211. while (n < phases) {
  212. if (pwm[n].ticks < pwm[n - 1].ticks) {
  213. struct pwm_phase t = pwm[n];
  214. pwm[n] = pwm[n - 1];
  215. pwm[n - 1] = t;
  216. if (n > 2)
  217. n--;
  218. } else {
  219. n++;
  220. }
  221. }
  222. #if PWM_DEBUG
  223. int t = 0;
  224. for (t = 0; t <= phases; t++) {
  225. ets_printf("%d @%d: %04x %04x\n", t, pwm[t].ticks, pwm[t].on_mask, pwm[t].off_mask);
  226. }
  227. #endif
  228. // shift left to align right edge;
  229. uint8_t l = 0, r = 1;
  230. while (r <= phases) {
  231. uint32_t diff = pwm[r].ticks - pwm[l].ticks;
  232. if (diff && (diff <= 16)) {
  233. uint16_t mask = pwm[r].on_mask | pwm[r].off_mask;
  234. pwm[l].off_mask ^= pwm[r].off_mask;
  235. pwm[l].on_mask ^= pwm[r].on_mask;
  236. pwm[0].off_mask ^= pwm[r].on_mask;
  237. pwm[0].on_mask ^= pwm[r].off_mask;
  238. pwm[r].ticks = pwm_period_ticks - diff;
  239. pwm[r].on_mask ^= mask;
  240. pwm[r].off_mask ^= mask;
  241. } else {
  242. l = r;
  243. }
  244. r++;
  245. }
  246. #if PWM_DEBUG
  247. for (t = 0; t <= phases; t++) {
  248. ets_printf("%d @%d: %04x %04x\n", t, pwm[t].ticks, pwm[t].on_mask, pwm[t].off_mask);
  249. }
  250. #endif
  251. // sort again
  252. n = 2;
  253. while (n <= phases) {
  254. if (pwm[n].ticks < pwm[n - 1].ticks) {
  255. struct pwm_phase t = pwm[n];
  256. pwm[n] = pwm[n - 1];
  257. pwm[n - 1] = t;
  258. if (n > 2)
  259. n--;
  260. } else {
  261. n++;
  262. }
  263. }
  264. // merge same duty
  265. l = 0, r = 1;
  266. while (r <= phases) {
  267. if (pwm[r].ticks == pwm[l].ticks) {
  268. pwm[l].off_mask |= pwm[r].off_mask;
  269. pwm[l].on_mask |= pwm[r].on_mask;
  270. pwm[r].on_mask = 0;
  271. pwm[r].off_mask = 0;
  272. } else {
  273. l++;
  274. if (l != r) {
  275. struct pwm_phase t = pwm[l];
  276. pwm[l] = pwm[r];
  277. pwm[r] = t;
  278. }
  279. }
  280. r++;
  281. }
  282. phases = l;
  283. #if PWM_DEBUG
  284. for (t = 0; t <= phases; t++) {
  285. ets_printf("%d @%d: %04x %04x\n", t, pwm[t].ticks, pwm[t].on_mask, pwm[t].off_mask);
  286. }
  287. #endif
  288. // transform absolute end time to phase durations
  289. for (n = 0; n < phases; n++) {
  290. pwm[n].ticks =
  291. pwm[n + 1].ticks - pwm[n].ticks;
  292. // subtract common overhead
  293. pwm[n].ticks--;
  294. }
  295. pwm[phases].ticks = 0;
  296. // do a cyclic shift if last phase is short
  297. if (pwm[phases - 1].ticks < 16) {
  298. for (n = 0; n < phases - 1; n++) {
  299. struct pwm_phase t = pwm[n];
  300. pwm[n] = pwm[n + 1];
  301. pwm[n + 1] = t;
  302. }
  303. }
  304. #if PWM_DEBUG
  305. for (t = 0; t <= phases; t++) {
  306. ets_printf("%d +%d: %04x %04x\n", t, pwm[t].ticks, pwm[t].on_mask, pwm[t].off_mask);
  307. }
  308. ets_printf("\n");
  309. #endif
  310. return phases;
  311. }
  312. void ICACHE_FLASH_ATTR
  313. pwm_start(void)
  314. {
  315. pwm_phase_array* pwm = &pwm_phases[0];
  316. if ((*pwm == pwm_state.next_set) ||
  317. (*pwm == pwm_state.current_set))
  318. pwm++;
  319. if ((*pwm == pwm_state.next_set) ||
  320. (*pwm == pwm_state.current_set))
  321. pwm++;
  322. uint8_t phases = _pwm_phases_prep(*pwm);
  323. // all with 0% / 100% duty - stop timer
  324. if (phases == 1) {
  325. if (pwm_state.next_set) {
  326. #if PWM_DEBUG
  327. ets_printf("PWM stop\n");
  328. #endif
  329. timer->frc1_ctrl = 0;
  330. ETS_FRC1_INTR_DISABLE();
  331. }
  332. pwm_state.next_set = NULL;
  333. GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, (*pwm)[0].on_mask);
  334. GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, (*pwm)[0].off_mask);
  335. return;
  336. }
  337. // start if not running
  338. if (!pwm_state.next_set) {
  339. #if PWM_DEBUG
  340. ets_printf("PWM start\n");
  341. #endif
  342. pwm_state.current_set = pwm_state.next_set = *pwm;
  343. pwm_state.current_phase = phases - 1;
  344. ETS_FRC1_INTR_ENABLE();
  345. RTC_REG_WRITE(FRC1_LOAD_ADDRESS, 0);
  346. timer->frc1_ctrl = TIMER1_DIVIDE_BY_16 | TIMER1_ENABLE_TIMER;
  347. return;
  348. }
  349. pwm_state.next_set = *pwm;
  350. }
  351. void ICACHE_FLASH_ATTR
  352. pwm_set_duty(uint32_t duty, uint8_t channel)
  353. {
  354. if (channel > PWM_MAX_CHANNELS)
  355. return;
  356. if (duty > PWM_MAX_DUTY)
  357. duty = PWM_MAX_DUTY;
  358. pwm_duty[channel] = duty;
  359. }
  360. uint32_t ICACHE_FLASH_ATTR
  361. pwm_get_duty(uint8_t channel)
  362. {
  363. if (channel > PWM_MAX_CHANNELS)
  364. return 0;
  365. return pwm_duty[channel];
  366. }
  367. void ICACHE_FLASH_ATTR
  368. pwm_set_period(uint32_t period)
  369. {
  370. pwm_period = period;
  371. if (pwm_period > PWM_MAX_PERIOD)
  372. pwm_period = PWM_MAX_PERIOD;
  373. pwm_period_ticks = PWM_PERIOD_TO_TICKS(period);
  374. }
  375. uint32_t ICACHE_FLASH_ATTR
  376. pwm_get_period(void)
  377. {
  378. return pwm_period;
  379. }
  380. uint32_t ICACHE_FLASH_ATTR
  381. get_pwm_version(void)
  382. {
  383. return 1;
  384. }
  385. void ICACHE_FLASH_ATTR
  386. set_pwm_debug_en(uint8_t print_en)
  387. {
  388. (void) print_en;
  389. }