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.

449 lines
11 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 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 1
  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 <eagle_soc.h>
  42. #include <ets_sys.h>
  43. #include "libs/pwm.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. for (n = 0; n < pwm_channels + 2; n++) {
  183. pwm[n].ticks = 0;
  184. pwm[n].on_mask = 0;
  185. pwm[n].off_mask = 0;
  186. }
  187. phases = 1;
  188. for (n = 0; n < pwm_channels; n++) {
  189. uint32_t ticks = PWM_DUTY_TO_TICKS(pwm_duty[n]);
  190. if (ticks == 0) {
  191. pwm[0].off_mask |= gpio_mask[n];
  192. } else if (ticks >= pwm_period_ticks) {
  193. pwm[0].on_mask |= gpio_mask[n];
  194. } else {
  195. if (ticks < (pwm_period_ticks/2)) {
  196. pwm[phases].ticks = ticks;
  197. pwm[0].on_mask |= gpio_mask[n];
  198. pwm[phases].off_mask = gpio_mask[n];
  199. } else {
  200. pwm[phases].ticks = pwm_period_ticks - ticks;
  201. pwm[phases].on_mask = gpio_mask[n];
  202. pwm[0].off_mask |= gpio_mask[n];
  203. }
  204. phases++;
  205. }
  206. }
  207. pwm[phases].ticks = pwm_period_ticks;
  208. // bubble sort, lowest to hightest duty
  209. n = 2;
  210. while (n < phases) {
  211. if (pwm[n].ticks < pwm[n - 1].ticks) {
  212. struct pwm_phase t = pwm[n];
  213. pwm[n] = pwm[n - 1];
  214. pwm[n - 1] = t;
  215. if (n > 2)
  216. n--;
  217. } else {
  218. n++;
  219. }
  220. }
  221. #if PWM_DEBUG
  222. int t = 0;
  223. for (t = 0; t <= phases; t++) {
  224. ets_printf("%d @%d: %04x %04x\n", t, pwm[t].ticks, pwm[t].on_mask, pwm[t].off_mask);
  225. }
  226. #endif
  227. // shift left to align right edge;
  228. uint8_t l = 0, r = 1;
  229. while (r <= phases) {
  230. uint32_t diff = pwm[r].ticks - pwm[l].ticks;
  231. if (diff && (diff <= 16)) {
  232. uint16_t mask = pwm[r].on_mask | pwm[r].off_mask;
  233. pwm[l].off_mask ^= pwm[r].off_mask;
  234. pwm[l].on_mask ^= pwm[r].on_mask;
  235. pwm[0].off_mask ^= pwm[r].on_mask;
  236. pwm[0].on_mask ^= pwm[r].off_mask;
  237. pwm[r].ticks = pwm_period_ticks - diff;
  238. pwm[r].on_mask ^= mask;
  239. pwm[r].off_mask ^= mask;
  240. } else {
  241. l = r;
  242. }
  243. r++;
  244. }
  245. #if PWM_DEBUG
  246. for (t = 0; t <= phases; t++) {
  247. ets_printf("%d @%d: %04x %04x\n", t, pwm[t].ticks, pwm[t].on_mask, pwm[t].off_mask);
  248. }
  249. #endif
  250. // sort again
  251. n = 2;
  252. while (n <= phases) {
  253. if (pwm[n].ticks < pwm[n - 1].ticks) {
  254. struct pwm_phase t = pwm[n];
  255. pwm[n] = pwm[n - 1];
  256. pwm[n - 1] = t;
  257. if (n > 2)
  258. n--;
  259. } else {
  260. n++;
  261. }
  262. }
  263. // merge same duty
  264. l = 0, r = 1;
  265. while (r <= phases) {
  266. if (pwm[r].ticks == pwm[l].ticks) {
  267. pwm[l].off_mask |= pwm[r].off_mask;
  268. pwm[l].on_mask |= pwm[r].on_mask;
  269. pwm[r].on_mask = 0;
  270. pwm[r].off_mask = 0;
  271. } else {
  272. l++;
  273. if (l != r) {
  274. struct pwm_phase t = pwm[l];
  275. pwm[l] = pwm[r];
  276. pwm[r] = t;
  277. }
  278. }
  279. r++;
  280. }
  281. phases = l;
  282. #if PWM_DEBUG
  283. for (t = 0; t <= phases; t++) {
  284. ets_printf("%d @%d: %04x %04x\n", t, pwm[t].ticks, pwm[t].on_mask, pwm[t].off_mask);
  285. }
  286. #endif
  287. // transform absolute end time to phase durations
  288. for (n = 0; n < phases; n++) {
  289. pwm[n].ticks =
  290. pwm[n + 1].ticks - pwm[n].ticks;
  291. // subtract common overhead
  292. pwm[n].ticks--;
  293. }
  294. pwm[phases].ticks = 0;
  295. // do a cyclic shift if last phase is short
  296. if (pwm[phases - 1].ticks < 16) {
  297. for (n = 0; n < phases - 1; n++) {
  298. struct pwm_phase t = pwm[n];
  299. pwm[n] = pwm[n + 1];
  300. pwm[n + 1] = t;
  301. }
  302. }
  303. #if PWM_DEBUG
  304. for (t = 0; t <= phases; t++) {
  305. ets_printf("%d +%d: %04x %04x\n", t, pwm[t].ticks, pwm[t].on_mask, pwm[t].off_mask);
  306. }
  307. ets_printf("\n");
  308. #endif
  309. return phases;
  310. }
  311. void ICACHE_FLASH_ATTR
  312. pwm_start(void)
  313. {
  314. pwm_phase_array* pwm = &pwm_phases[0];
  315. if ((*pwm == pwm_state.next_set) ||
  316. (*pwm == pwm_state.current_set))
  317. pwm++;
  318. if ((*pwm == pwm_state.next_set) ||
  319. (*pwm == pwm_state.current_set))
  320. pwm++;
  321. uint8_t phases = _pwm_phases_prep(*pwm);
  322. // all with 0% / 100% duty - stop timer
  323. if (phases == 1) {
  324. if (pwm_state.next_set) {
  325. #if PWM_DEBUG
  326. ets_printf("PWM stop\n");
  327. #endif
  328. timer->frc1_ctrl = 0;
  329. ETS_FRC1_INTR_DISABLE();
  330. }
  331. pwm_state.next_set = NULL;
  332. GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, (*pwm)[0].on_mask);
  333. GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, (*pwm)[0].off_mask);
  334. return;
  335. }
  336. // start if not running
  337. if (!pwm_state.next_set) {
  338. #if PWM_DEBUG
  339. ets_printf("PWM start\n");
  340. #endif
  341. pwm_state.current_set = pwm_state.next_set = *pwm;
  342. pwm_state.current_phase = phases - 1;
  343. ETS_FRC1_INTR_ENABLE();
  344. RTC_REG_WRITE(FRC1_LOAD_ADDRESS, 0);
  345. timer->frc1_ctrl = TIMER1_DIVIDE_BY_16 | TIMER1_ENABLE_TIMER;
  346. return;
  347. }
  348. pwm_state.next_set = *pwm;
  349. }
  350. void ICACHE_FLASH_ATTR
  351. pwm_set_duty(uint32_t duty, uint8_t channel)
  352. {
  353. if (channel >= PWM_MAX_CHANNELS)
  354. return;
  355. if (duty > PWM_MAX_DUTY)
  356. duty = PWM_MAX_DUTY;
  357. pwm_duty[channel] = duty;
  358. }
  359. uint32_t ICACHE_FLASH_ATTR
  360. pwm_get_duty(uint8_t channel)
  361. {
  362. if (channel >= PWM_MAX_CHANNELS)
  363. return 0;
  364. return pwm_duty[channel];
  365. }
  366. void ICACHE_FLASH_ATTR
  367. pwm_set_period(uint32_t period)
  368. {
  369. pwm_period = period;
  370. if (pwm_period > PWM_MAX_PERIOD)
  371. pwm_period = PWM_MAX_PERIOD;
  372. pwm_period_ticks = PWM_PERIOD_TO_TICKS(period);
  373. }
  374. uint32_t ICACHE_FLASH_ATTR
  375. pwm_get_period(void)
  376. {
  377. return pwm_period;
  378. }
  379. uint32_t ICACHE_FLASH_ATTR
  380. get_pwm_version(void)
  381. {
  382. return 1;
  383. }
  384. void ICACHE_FLASH_ATTR
  385. set_pwm_debug_en(uint8_t print_en)
  386. {
  387. (void) print_en;
  388. }