Fork of the espurna firmware for `mhsw` switches
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.

481 lines
12 KiB

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