timer.c 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991
  1. /*
  2. * This file is part of the MicroPython project, http://micropython.org/
  3. *
  4. * The MIT License (MIT)
  5. *
  6. * Copyright (c) 2013, 2014 Damien P. George
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy
  9. * of this software and associated documentation files (the "Software"), to deal
  10. * in the Software without restriction, including without limitation the rights
  11. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. * copies of the Software, and to permit persons to whom the Software is
  13. * furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included in
  16. * all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. * THE SOFTWARE.
  25. */
  26. #include <stdio.h>
  27. #include <stdint.h>
  28. #include <string.h>
  29. #include <stddef.h>
  30. #include "py/runtime.h"
  31. #include "py/gc.h"
  32. #include "py/mphal.h"
  33. #include "pin.h"
  34. #include "reg.h"
  35. #include "timer.h"
  36. typedef enum {
  37. CHANNEL_MODE_PWM_NORMAL,
  38. CHANNEL_MODE_PWM_INVERTED,
  39. CHANNEL_MODE_OC_TIMING,
  40. CHANNEL_MODE_OC_ACTIVE,
  41. CHANNEL_MODE_OC_INACTIVE,
  42. CHANNEL_MODE_OC_TOGGLE,
  43. // CHANNEL_MODE_OC_FORCED_ACTIVE,
  44. // CHANNEL_MODE_OC_FORCED_INACTIVE,
  45. CHANNEL_MODE_IC,
  46. } pyb_channel_mode;
  47. STATIC const struct {
  48. qstr name;
  49. uint32_t oc_mode;
  50. } channel_mode_info[] = {
  51. { MP_QSTR_PWM, FTM_OCMODE_PWM1 },
  52. { MP_QSTR_PWM_INVERTED, FTM_OCMODE_PWM2 },
  53. { MP_QSTR_OC_TIMING, FTM_OCMODE_TIMING },
  54. { MP_QSTR_OC_ACTIVE, FTM_OCMODE_ACTIVE },
  55. { MP_QSTR_OC_INACTIVE, FTM_OCMODE_INACTIVE },
  56. { MP_QSTR_OC_TOGGLE, FTM_OCMODE_TOGGLE },
  57. // { MP_QSTR_OC_FORCED_ACTIVE, FTM_OCMODE_FORCED_ACTIVE },
  58. // { MP_QSTR_OC_FORCED_INACTIVE, FTM_OCMODE_FORCED_INACTIVE },
  59. { MP_QSTR_IC, 0 },
  60. };
  61. struct _pyb_timer_obj_t;
  62. typedef struct _pyb_timer_channel_obj_t {
  63. mp_obj_base_t base;
  64. struct _pyb_timer_obj_t *timer;
  65. uint8_t channel;
  66. uint8_t mode;
  67. mp_obj_t callback;
  68. struct _pyb_timer_channel_obj_t *next;
  69. } pyb_timer_channel_obj_t;
  70. typedef struct _pyb_timer_obj_t {
  71. mp_obj_base_t base;
  72. uint8_t tim_id;
  73. uint8_t irqn;
  74. mp_obj_t callback;
  75. FTM_HandleTypeDef ftm;
  76. pyb_timer_channel_obj_t *channel;
  77. } pyb_timer_obj_t;
  78. // Used to do callbacks to Python code on interrupt
  79. STATIC pyb_timer_obj_t *pyb_timer_obj_all[3];
  80. #define PYB_TIMER_OBJ_ALL_NUM MP_ARRAY_SIZE(pyb_timer_obj_all)
  81. STATIC mp_obj_t pyb_timer_deinit(mp_obj_t self_in);
  82. STATIC mp_obj_t pyb_timer_callback(mp_obj_t self_in, mp_obj_t callback);
  83. STATIC mp_obj_t pyb_timer_channel_callback(mp_obj_t self_in, mp_obj_t callback);
  84. void timer_init0(void) {
  85. for (uint i = 0; i < PYB_TIMER_OBJ_ALL_NUM; i++) {
  86. pyb_timer_obj_all[i] = NULL;
  87. }
  88. }
  89. // unregister all interrupt sources
  90. void timer_deinit(void) {
  91. for (uint i = 0; i < PYB_TIMER_OBJ_ALL_NUM; i++) {
  92. pyb_timer_obj_t *tim = pyb_timer_obj_all[i];
  93. if (tim != NULL) {
  94. pyb_timer_deinit(tim);
  95. }
  96. }
  97. }
  98. mp_uint_t get_prescaler_shift(mp_int_t prescaler) {
  99. mp_uint_t prescaler_shift;
  100. for (prescaler_shift = 0; prescaler_shift < 8; prescaler_shift++) {
  101. if (prescaler == (1 << prescaler_shift)) {
  102. return prescaler_shift;
  103. }
  104. }
  105. nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "prescaler must be a power of 2 between 1 and 128, not %d", prescaler));
  106. }
  107. /******************************************************************************/
  108. /* MicroPython bindings */
  109. STATIC const mp_obj_type_t pyb_timer_channel_type;
  110. // Helper function for determining the period used for calculating percent
  111. STATIC uint32_t compute_period(pyb_timer_obj_t *self) {
  112. // In center mode, compare == period corresponds to 100%
  113. // In edge mode, compare == (period + 1) corresponds to 100%
  114. FTM_TypeDef *FTMx = self->ftm.Instance;
  115. uint32_t period = (FTMx->MOD & 0xffff);
  116. if ((FTMx->SC & FTM_SC_CPWMS) == 0) {
  117. // Edge mode
  118. period++;
  119. }
  120. return period;
  121. }
  122. // Helper function to compute PWM value from timer period and percent value.
  123. // 'val' can be an int or a float between 0 and 100 (out of range values are
  124. // clamped).
  125. STATIC uint32_t compute_pwm_value_from_percent(uint32_t period, mp_obj_t percent_in) {
  126. uint32_t cmp;
  127. if (0) {
  128. #if MICROPY_PY_BUILTINS_FLOAT
  129. } else if (MP_OBJ_IS_TYPE(percent_in, &mp_type_float)) {
  130. float percent = mp_obj_get_float(percent_in);
  131. if (percent <= 0.0) {
  132. cmp = 0;
  133. } else if (percent >= 100.0) {
  134. cmp = period;
  135. } else {
  136. cmp = percent / 100.0 * ((float)period);
  137. }
  138. #endif
  139. } else {
  140. mp_int_t percent = mp_obj_get_int(percent_in);
  141. if (percent <= 0) {
  142. cmp = 0;
  143. } else if (percent >= 100) {
  144. cmp = period;
  145. } else {
  146. cmp = ((uint32_t)percent * period) / 100;
  147. }
  148. }
  149. return cmp;
  150. }
  151. // Helper function to compute percentage from timer perion and PWM value.
  152. STATIC mp_obj_t compute_percent_from_pwm_value(uint32_t period, uint32_t cmp) {
  153. #if MICROPY_PY_BUILTINS_FLOAT
  154. float percent = (float)cmp * 100.0 / (float)period;
  155. if (cmp >= period) {
  156. percent = 100.0;
  157. } else {
  158. percent = (float)cmp * 100.0 / (float)period;
  159. }
  160. return mp_obj_new_float(percent);
  161. #else
  162. mp_int_t percent;
  163. if (cmp >= period) {
  164. percent = 100;
  165. } else {
  166. percent = cmp * 100 / period;
  167. }
  168. return mp_obj_new_int(percent);
  169. #endif
  170. }
  171. STATIC void pyb_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
  172. pyb_timer_obj_t *self = self_in;
  173. if (self->ftm.State == HAL_FTM_STATE_RESET) {
  174. mp_printf(print, "Timer(%u)", self->tim_id);
  175. } else {
  176. mp_printf(print, "Timer(%u, prescaler=%u, period=%u, mode=%s)",
  177. self->tim_id,
  178. 1 << (self->ftm.Instance->SC & 7),
  179. self->ftm.Instance->MOD & 0xffff,
  180. self->ftm.Init.CounterMode == FTM_COUNTERMODE_UP ? "UP" : "CENTER");
  181. }
  182. }
  183. /// \method init(*, freq, prescaler, period)
  184. /// Initialise the timer. Initialisation must be either by frequency (in Hz)
  185. /// or by prescaler and period:
  186. ///
  187. /// tim.init(freq=100) # set the timer to trigger at 100Hz
  188. /// tim.init(prescaler=83, period=999) # set the prescaler and period directly
  189. ///
  190. /// Keyword arguments:
  191. ///
  192. /// - `freq` - specifies the periodic frequency of the timer. You migh also
  193. /// view this as the frequency with which the timer goes through
  194. /// one complete cycle.
  195. ///
  196. /// - `prescaler` 1, 2, 4, 8 16 32, 64 or 128 - specifies the value to be loaded into the
  197. /// timer's prescaler. The timer clock source is divided by
  198. /// (`prescaler`) to arrive at the timer clock.
  199. ///
  200. /// - `period` [0-0xffff] - Specifies the value to be loaded into the timer's
  201. /// Modulo Register (MOD). This determines the period of the timer (i.e.
  202. /// when the counter cycles). The timer counter will roll-over after
  203. /// `period` timer clock cycles. In center mode, a compare register > 0x7fff
  204. /// doesn't seem to work properly, so keep this in mind.
  205. ///
  206. /// - `mode` can be one of:
  207. /// - `Timer.UP` - configures the timer to count from 0 to MOD (default)
  208. /// - `Timer.CENTER` - confgures the timer to count from 0 to MOD and
  209. /// then back down to 0.
  210. ///
  211. /// - `callback` - as per Timer.callback()
  212. ///
  213. /// You must either specify freq or both of period and prescaler.
  214. STATIC const mp_arg_t pyb_timer_init_args[] = {
  215. { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} },
  216. { MP_QSTR_prescaler, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} },
  217. { MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} },
  218. { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = FTM_COUNTERMODE_UP} },
  219. { MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
  220. };
  221. #define PYB_TIMER_INIT_NUM_ARGS MP_ARRAY_SIZE(pyb_timer_init_args)
  222. STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
  223. // parse args
  224. mp_arg_val_t vals[PYB_TIMER_INIT_NUM_ARGS];
  225. mp_arg_parse_all(n_args, args, kw_args, PYB_TIMER_INIT_NUM_ARGS, pyb_timer_init_args, vals);
  226. FTM_HandleTypeDef *ftm = &self->ftm;
  227. // set the TIM configuration values
  228. FTM_Base_InitTypeDef *init = &ftm->Init;
  229. if (vals[0].u_int != 0xffffffff) {
  230. // set prescaler and period from frequency
  231. if (vals[0].u_int == 0) {
  232. mp_raise_ValueError("can't have 0 frequency");
  233. }
  234. uint32_t period = MAX(1, F_BUS / vals[0].u_int);
  235. uint32_t prescaler_shift = 0;
  236. while (period > 0xffff && prescaler_shift < 7) {
  237. period >>= 1;
  238. prescaler_shift++;
  239. }
  240. if (period > 0xffff) {
  241. period = 0xffff;
  242. }
  243. init->PrescalerShift = prescaler_shift;
  244. init->Period = period;
  245. } else if (vals[1].u_int != 0xffffffff && vals[2].u_int != 0xffffffff) {
  246. // set prescaler and period directly
  247. init->PrescalerShift = get_prescaler_shift(vals[1].u_int);
  248. init->Period = vals[2].u_int;
  249. if (!IS_FTM_PERIOD(init->Period)) {
  250. nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "period must be between 0 and 65535, not %d", init->Period));
  251. }
  252. } else {
  253. mp_raise_TypeError("must specify either freq, or prescaler and period");
  254. }
  255. init->CounterMode = vals[3].u_int;
  256. if (!IS_FTM_COUNTERMODE(init->CounterMode)) {
  257. nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "invalid counter mode: %d", init->CounterMode));
  258. }
  259. // Currently core/mk20dx128.c sets SIM_SCGC6_FTM0, SIM_SCGC6_FTM1, SIM_SCGC3_FTM2
  260. // so we don't need to do it here.
  261. NVIC_SET_PRIORITY(self->irqn, 0xe); // next-to lowest priority
  262. HAL_FTM_Base_Init(ftm);
  263. if (vals[4].u_obj == mp_const_none) {
  264. HAL_FTM_Base_Start(ftm);
  265. } else {
  266. pyb_timer_callback(self, vals[4].u_obj);
  267. }
  268. return mp_const_none;
  269. }
  270. /// \classmethod \constructor(id, ...)
  271. /// Construct a new timer object of the given id. If additional
  272. /// arguments are given, then the timer is initialised by `init(...)`.
  273. /// `id` can be 1 to 14, excluding 3.
  274. STATIC mp_obj_t pyb_timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
  275. // check arguments
  276. mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
  277. // create new Timer object
  278. pyb_timer_obj_t *tim = m_new_obj(pyb_timer_obj_t);
  279. memset(tim, 0, sizeof(*tim));
  280. tim->base.type = &pyb_timer_type;
  281. tim->callback = mp_const_none;
  282. tim->channel = NULL;
  283. // get FTM number
  284. tim->tim_id = mp_obj_get_int(args[0]);
  285. switch (tim->tim_id) {
  286. case 0: tim->ftm.Instance = FTM0; tim->irqn = IRQ_FTM0; break;
  287. case 1: tim->ftm.Instance = FTM1; tim->irqn = IRQ_FTM1; break;
  288. case 2: tim->ftm.Instance = FTM2; tim->irqn = IRQ_FTM2; break;
  289. default: nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Timer %d does not exist", tim->tim_id));
  290. }
  291. if (n_args > 1 || n_kw > 0) {
  292. // start the peripheral
  293. mp_map_t kw_args;
  294. mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
  295. pyb_timer_init_helper(tim, n_args - 1, args + 1, &kw_args);
  296. }
  297. // set the global variable for interrupt callbacks
  298. if (tim->tim_id < PYB_TIMER_OBJ_ALL_NUM) {
  299. pyb_timer_obj_all[tim->tim_id] = tim;
  300. }
  301. return (mp_obj_t)tim;
  302. }
  303. STATIC mp_obj_t pyb_timer_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
  304. return pyb_timer_init_helper(args[0], n_args - 1, args + 1, kw_args);
  305. }
  306. STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_init_obj, 1, pyb_timer_init);
  307. /// \method deinit()
  308. /// Deinitialises the timer.
  309. ///
  310. /// Disables the callback (and the associated irq).
  311. /// Disables any channel callbacks (and the associated irq).
  312. /// Stops the timer, and disables the timer peripheral.
  313. STATIC mp_obj_t pyb_timer_deinit(mp_obj_t self_in) {
  314. pyb_timer_obj_t *self = self_in;
  315. // Disable the base interrupt
  316. pyb_timer_callback(self_in, mp_const_none);
  317. pyb_timer_channel_obj_t *chan = self->channel;
  318. self->channel = NULL;
  319. // Disable the channel interrupts
  320. while (chan != NULL) {
  321. pyb_timer_channel_callback(chan, mp_const_none);
  322. pyb_timer_channel_obj_t *prev_chan = chan;
  323. chan = chan->next;
  324. prev_chan->next = NULL;
  325. }
  326. HAL_FTM_Base_DeInit(&self->ftm);
  327. return mp_const_none;
  328. }
  329. STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_deinit_obj, pyb_timer_deinit);
  330. /// \method channel(channel, mode, ...)
  331. ///
  332. /// If only a channel number is passed, then a previously initialized channel
  333. /// object is returned (or `None` if there is no previous channel).
  334. ///
  335. /// Othwerwise, a TimerChannel object is initialized and returned.
  336. ///
  337. /// Each channel can be configured to perform pwm, output compare, or
  338. /// input capture. All channels share the same underlying timer, which means
  339. /// that they share the same timer clock.
  340. ///
  341. /// Keyword arguments:
  342. ///
  343. /// - `mode` can be one of:
  344. /// - `Timer.PWM` - configure the timer in PWM mode (active high).
  345. /// - `Timer.PWM_INVERTED` - configure the timer in PWM mode (active low).
  346. /// - `Timer.OC_TIMING` - indicates that no pin is driven.
  347. /// - `Timer.OC_ACTIVE` - the pin will be made active when a compare
  348. /// match occurs (active is determined by polarity)
  349. /// - `Timer.OC_INACTIVE` - the pin will be made inactive when a compare
  350. /// match occurs.
  351. /// - `Timer.OC_TOGGLE` - the pin will be toggled when an compare match occurs.
  352. /// - `Timer.IC` - configure the timer in Input Capture mode.
  353. ///
  354. /// - `callback` - as per TimerChannel.callback()
  355. ///
  356. /// - `pin` None (the default) or a Pin object. If specified (and not None)
  357. /// this will cause the alternate function of the the indicated pin
  358. /// to be configured for this timer channel. An error will be raised if
  359. /// the pin doesn't support any alternate functions for this timer channel.
  360. ///
  361. /// Keyword arguments for Timer.PWM modes:
  362. ///
  363. /// - `pulse_width` - determines the initial pulse width value to use.
  364. /// - `pulse_width_percent` - determines the initial pulse width percentage to use.
  365. ///
  366. /// Keyword arguments for Timer.OC modes:
  367. ///
  368. /// - `compare` - determines the initial value of the compare register.
  369. ///
  370. /// - `polarity` can be one of:
  371. /// - `Timer.HIGH` - output is active high
  372. /// - `Timer.LOW` - output is acive low
  373. ///
  374. /// Optional keyword arguments for Timer.IC modes:
  375. ///
  376. /// - `polarity` can be one of:
  377. /// - `Timer.RISING` - captures on rising edge.
  378. /// - `Timer.FALLING` - captures on falling edge.
  379. /// - `Timer.BOTH` - captures on both edges.
  380. ///
  381. /// PWM Example:
  382. ///
  383. /// timer = pyb.Timer(0, prescaler=128, period=37500, counter_mode=pyb.Timer.COUNTER_MODE_CENTER)
  384. /// ch0 = t0.channel(0, pyb.Timer.PWM, pin=pyb.Pin.board.D22, pulse_width=(t0.period() + 1) // 4)
  385. /// ch1 = t0.channel(1, pyb.Timer.PWM, pin=pyb.Pin.board.D23, pulse_width=(t0.period() + 1) // 2)
  386. STATIC const mp_arg_t pyb_timer_channel_args[] = {
  387. { MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
  388. { MP_QSTR_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
  389. { MP_QSTR_pulse_width, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
  390. { MP_QSTR_pulse_width_percent, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
  391. { MP_QSTR_compare, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
  392. { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} },
  393. };
  394. #define PYB_TIMER_CHANNEL_NUM_ARGS MP_ARRAY_SIZE(pyb_timer_channel_args)
  395. STATIC mp_obj_t pyb_timer_channel(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
  396. pyb_timer_obj_t *self = args[0];
  397. mp_int_t channel = mp_obj_get_int(args[1]);
  398. if (channel < 0 || channel > 7) {
  399. nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid channel (%d)", channel));
  400. }
  401. pyb_timer_channel_obj_t *chan = self->channel;
  402. pyb_timer_channel_obj_t *prev_chan = NULL;
  403. while (chan != NULL) {
  404. if (chan->channel == channel) {
  405. break;
  406. }
  407. prev_chan = chan;
  408. chan = chan->next;
  409. }
  410. // If only the channel number is given return the previously allocated
  411. // channel (or None if no previous channel).
  412. if (n_args == 2) {
  413. if (chan) {
  414. return chan;
  415. }
  416. return mp_const_none;
  417. }
  418. // If there was already a channel, then remove it from the list. Note that
  419. // the order we do things here is important so as to appear atomic to
  420. // the IRQ handler.
  421. if (chan) {
  422. // Turn off any IRQ associated with the channel.
  423. pyb_timer_channel_callback(chan, mp_const_none);
  424. // Unlink the channel from the list.
  425. if (prev_chan) {
  426. prev_chan->next = chan->next;
  427. }
  428. self->channel = chan->next;
  429. chan->next = NULL;
  430. }
  431. // Allocate and initialize a new channel
  432. mp_arg_val_t vals[PYB_TIMER_CHANNEL_NUM_ARGS];
  433. mp_arg_parse_all(n_args - 3, args + 3, kw_args, PYB_TIMER_CHANNEL_NUM_ARGS, pyb_timer_channel_args, vals);
  434. chan = m_new_obj(pyb_timer_channel_obj_t);
  435. memset(chan, 0, sizeof(*chan));
  436. chan->base.type = &pyb_timer_channel_type;
  437. chan->timer = self;
  438. chan->channel = channel;
  439. chan->mode = mp_obj_get_int(args[2]);
  440. chan->callback = vals[0].u_obj;
  441. mp_obj_t pin_obj = vals[1].u_obj;
  442. if (pin_obj != mp_const_none) {
  443. if (!MP_OBJ_IS_TYPE(pin_obj, &pin_type)) {
  444. mp_raise_ValueError("pin argument needs to be be a Pin type");
  445. }
  446. const pin_obj_t *pin = pin_obj;
  447. const pin_af_obj_t *af = pin_find_af(pin, AF_FN_FTM, self->tim_id);
  448. if (af == NULL) {
  449. nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin %s doesn't have an af for TIM%d", qstr_str(pin->name), self->tim_id));
  450. }
  451. // pin.init(mode=AF_PP, af=idx)
  452. const mp_obj_t args[6] = {
  453. (mp_obj_t)&pin_init_obj,
  454. pin_obj,
  455. MP_OBJ_NEW_QSTR(MP_QSTR_mode), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_AF_PP),
  456. MP_OBJ_NEW_QSTR(MP_QSTR_af), MP_OBJ_NEW_SMALL_INT(af->idx)
  457. };
  458. mp_call_method_n_kw(0, 2, args);
  459. }
  460. // Link the channel to the timer before we turn the channel on.
  461. // Note that this needs to appear atomic to the IRQ handler (the write
  462. // to self->channel is atomic, so we're good, but I thought I'd mention
  463. // in case this was ever changed in the future).
  464. chan->next = self->channel;
  465. self->channel = chan;
  466. switch (chan->mode) {
  467. case CHANNEL_MODE_PWM_NORMAL:
  468. case CHANNEL_MODE_PWM_INVERTED: {
  469. FTM_OC_InitTypeDef oc_config;
  470. oc_config.OCMode = channel_mode_info[chan->mode].oc_mode;
  471. if (vals[3].u_obj != mp_const_none) {
  472. // pulse width ratio given
  473. uint32_t period = compute_period(self);
  474. oc_config.Pulse = compute_pwm_value_from_percent(period, vals[3].u_obj);
  475. } else {
  476. // use absolute pulse width value (defaults to 0 if nothing given)
  477. oc_config.Pulse = vals[2].u_int;
  478. }
  479. oc_config.OCPolarity = FTM_OCPOLARITY_HIGH;
  480. HAL_FTM_PWM_ConfigChannel(&self->ftm, &oc_config, channel);
  481. if (chan->callback == mp_const_none) {
  482. HAL_FTM_PWM_Start(&self->ftm, channel);
  483. } else {
  484. HAL_FTM_PWM_Start_IT(&self->ftm, channel);
  485. }
  486. break;
  487. }
  488. case CHANNEL_MODE_OC_TIMING:
  489. case CHANNEL_MODE_OC_ACTIVE:
  490. case CHANNEL_MODE_OC_INACTIVE:
  491. case CHANNEL_MODE_OC_TOGGLE: {
  492. FTM_OC_InitTypeDef oc_config;
  493. oc_config.OCMode = channel_mode_info[chan->mode].oc_mode;
  494. oc_config.Pulse = vals[4].u_int;
  495. oc_config.OCPolarity = vals[5].u_int;
  496. if (oc_config.OCPolarity == 0xffffffff) {
  497. oc_config.OCPolarity = FTM_OCPOLARITY_HIGH;
  498. }
  499. if (!IS_FTM_OC_POLARITY(oc_config.OCPolarity)) {
  500. nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid polarity (%d)", oc_config.OCPolarity));
  501. }
  502. HAL_FTM_OC_ConfigChannel(&self->ftm, &oc_config, channel);
  503. if (chan->callback == mp_const_none) {
  504. HAL_FTM_OC_Start(&self->ftm, channel);
  505. } else {
  506. HAL_FTM_OC_Start_IT(&self->ftm, channel);
  507. }
  508. break;
  509. }
  510. case CHANNEL_MODE_IC: {
  511. FTM_IC_InitTypeDef ic_config;
  512. ic_config.ICPolarity = vals[5].u_int;
  513. if (ic_config.ICPolarity == 0xffffffff) {
  514. ic_config.ICPolarity = FTM_ICPOLARITY_RISING;
  515. }
  516. if (!IS_FTM_IC_POLARITY(ic_config.ICPolarity)) {
  517. nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid polarity (%d)", ic_config.ICPolarity));
  518. }
  519. HAL_FTM_IC_ConfigChannel(&self->ftm, &ic_config, chan->channel);
  520. if (chan->callback == mp_const_none) {
  521. HAL_FTM_IC_Start(&self->ftm, channel);
  522. } else {
  523. HAL_FTM_IC_Start_IT(&self->ftm, channel);
  524. }
  525. break;
  526. }
  527. default:
  528. nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid mode (%d)", chan->mode));
  529. }
  530. return chan;
  531. }
  532. STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_channel_obj, 2, pyb_timer_channel);
  533. /// \method counter([value])
  534. /// Get or set the timer counter.
  535. STATIC mp_obj_t pyb_timer_counter(size_t n_args, const mp_obj_t *args) {
  536. pyb_timer_obj_t *self = args[0];
  537. if (n_args == 1) {
  538. // get
  539. return mp_obj_new_int(self->ftm.Instance->CNT);
  540. }
  541. // set - In order to write to CNT we need to set CNTIN
  542. self->ftm.Instance->CNTIN = mp_obj_get_int(args[1]);
  543. self->ftm.Instance->CNT = 0; // write any value to load CNTIN into CNT
  544. return mp_const_none;
  545. }
  546. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_counter_obj, 1, 2, pyb_timer_counter);
  547. /// \method prescaler([value])
  548. /// Get or set the prescaler for the timer.
  549. STATIC mp_obj_t pyb_timer_prescaler(size_t n_args, const mp_obj_t *args) {
  550. pyb_timer_obj_t *self = args[0];
  551. if (n_args == 1) {
  552. // get
  553. return mp_obj_new_int(1 << (self->ftm.Instance->SC & 7));
  554. }
  555. // set
  556. mp_uint_t prescaler_shift = get_prescaler_shift(mp_obj_get_int(args[1]));
  557. mp_uint_t sc = self->ftm.Instance->SC;
  558. sc &= ~7;
  559. sc |= FTM_SC_PS(prescaler_shift);
  560. self->ftm.Instance->SC = sc;
  561. return mp_const_none;
  562. }
  563. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_prescaler_obj, 1, 2, pyb_timer_prescaler);
  564. /// \method period([value])
  565. /// Get or set the period of the timer.
  566. STATIC mp_obj_t pyb_timer_period(size_t n_args, const mp_obj_t *args) {
  567. pyb_timer_obj_t *self = args[0];
  568. if (n_args == 1) {
  569. // get
  570. return mp_obj_new_int(self->ftm.Instance->MOD & 0xffff);
  571. }
  572. // set
  573. mp_int_t period = mp_obj_get_int(args[1]) & 0xffff;
  574. self->ftm.Instance->CNT = 0;
  575. self->ftm.Instance->MOD = period;
  576. return mp_const_none;
  577. }
  578. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_period_obj, 1, 2, pyb_timer_period);
  579. /// \method callback(fun)
  580. /// Set the function to be called when the timer triggers.
  581. /// `fun` is passed 1 argument, the timer object.
  582. /// If `fun` is `None` then the callback will be disabled.
  583. STATIC mp_obj_t pyb_timer_callback(mp_obj_t self_in, mp_obj_t callback) {
  584. pyb_timer_obj_t *self = self_in;
  585. if (callback == mp_const_none) {
  586. // stop interrupt (but not timer)
  587. __HAL_FTM_DISABLE_TOF_IT(&self->ftm);
  588. self->callback = mp_const_none;
  589. } else if (mp_obj_is_callable(callback)) {
  590. self->callback = callback;
  591. HAL_NVIC_EnableIRQ(self->irqn);
  592. // start timer, so that it interrupts on overflow
  593. HAL_FTM_Base_Start_IT(&self->ftm);
  594. } else {
  595. mp_raise_ValueError("callback must be None or a callable object");
  596. }
  597. return mp_const_none;
  598. }
  599. STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_timer_callback_obj, pyb_timer_callback);
  600. #if MICROPY_TIMER_REG
  601. reg_t timer_reg[] = {
  602. REG_ENTRY(FTM_TypeDef, SC),
  603. REG_ENTRY(FTM_TypeDef, CNT),
  604. REG_ENTRY(FTM_TypeDef, MOD),
  605. REG_ENTRY(FTM_TypeDef, CNTIN),
  606. REG_ENTRY(FTM_TypeDef, STATUS),
  607. REG_ENTRY(FTM_TypeDef, MODE),
  608. REG_ENTRY(FTM_TypeDef, SYNC),
  609. REG_ENTRY(FTM_TypeDef, OUTINIT),
  610. REG_ENTRY(FTM_TypeDef, OUTMASK),
  611. REG_ENTRY(FTM_TypeDef, COMBINE),
  612. REG_ENTRY(FTM_TypeDef, DEADTIME),
  613. REG_ENTRY(FTM_TypeDef, EXTTRIG),
  614. REG_ENTRY(FTM_TypeDef, POL),
  615. REG_ENTRY(FTM_TypeDef, FMS),
  616. REG_ENTRY(FTM_TypeDef, FILTER),
  617. REG_ENTRY(FTM_TypeDef, FLTCTRL),
  618. REG_ENTRY(FTM_TypeDef, QDCTRL),
  619. REG_ENTRY(FTM_TypeDef, CONF),
  620. REG_ENTRY(FTM_TypeDef, FLTPOL),
  621. REG_ENTRY(FTM_TypeDef, SYNCONF),
  622. REG_ENTRY(FTM_TypeDef, INVCTRL),
  623. REG_ENTRY(FTM_TypeDef, SWOCTRL),
  624. REG_ENTRY(FTM_TypeDef, PWMLOAD),
  625. };
  626. mp_obj_t pyb_timer_reg(uint n_args, const mp_obj_t *args) {
  627. pyb_timer_obj_t *self = args[0];
  628. return reg_cmd(self->ftm.Instance, timer_reg, MP_ARRAY_SIZE(timer_reg), n_args - 1, args + 1);
  629. }
  630. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_reg_obj, 1, 3, pyb_timer_reg);
  631. #endif // MICROPY_TIMER_REG
  632. STATIC const mp_rom_map_elem_t pyb_timer_locals_dict_table[] = {
  633. // instance methods
  634. { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_timer_init_obj) },
  635. { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_timer_deinit_obj) },
  636. { MP_ROM_QSTR(MP_QSTR_channel), MP_ROM_PTR(&pyb_timer_channel_obj) },
  637. { MP_ROM_QSTR(MP_QSTR_counter), MP_ROM_PTR(&pyb_timer_counter_obj) },
  638. { MP_ROM_QSTR(MP_QSTR_prescaler), MP_ROM_PTR(&pyb_timer_prescaler_obj) },
  639. { MP_ROM_QSTR(MP_QSTR_period), MP_ROM_PTR(&pyb_timer_period_obj) },
  640. { MP_ROM_QSTR(MP_QSTR_callback), MP_ROM_PTR(&pyb_timer_callback_obj) },
  641. #if MICROPY_TIMER_REG
  642. { MP_ROM_QSTR(MP_QSTR_reg), MP_ROM_PTR(&pyb_timer_reg_obj) },
  643. #endif
  644. { MP_ROM_QSTR(MP_QSTR_UP), MP_ROM_INT(FTM_COUNTERMODE_UP) },
  645. { MP_ROM_QSTR(MP_QSTR_CENTER), MP_ROM_INT(FTM_COUNTERMODE_CENTER) },
  646. { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_INT(CHANNEL_MODE_PWM_NORMAL) },
  647. { MP_ROM_QSTR(MP_QSTR_PWM_INVERTED), MP_ROM_INT(CHANNEL_MODE_PWM_INVERTED) },
  648. { MP_ROM_QSTR(MP_QSTR_OC_TIMING), MP_ROM_INT(CHANNEL_MODE_OC_TIMING) },
  649. { MP_ROM_QSTR(MP_QSTR_OC_ACTIVE), MP_ROM_INT(CHANNEL_MODE_OC_ACTIVE) },
  650. { MP_ROM_QSTR(MP_QSTR_OC_INACTIVE), MP_ROM_INT(CHANNEL_MODE_OC_INACTIVE) },
  651. { MP_ROM_QSTR(MP_QSTR_OC_TOGGLE), MP_ROM_INT(CHANNEL_MODE_OC_TOGGLE) },
  652. { MP_ROM_QSTR(MP_QSTR_IC), MP_ROM_INT(CHANNEL_MODE_IC) },
  653. { MP_ROM_QSTR(MP_QSTR_HIGH), MP_ROM_INT(FTM_OCPOLARITY_HIGH) },
  654. { MP_ROM_QSTR(MP_QSTR_LOW), MP_ROM_INT(FTM_OCPOLARITY_LOW) },
  655. { MP_ROM_QSTR(MP_QSTR_RISING), MP_ROM_INT(FTM_ICPOLARITY_RISING) },
  656. { MP_ROM_QSTR(MP_QSTR_FALLING), MP_ROM_INT(FTM_ICPOLARITY_FALLING) },
  657. { MP_ROM_QSTR(MP_QSTR_BOTH), MP_ROM_INT(FTM_ICPOLARITY_BOTH) },
  658. };
  659. STATIC MP_DEFINE_CONST_DICT(pyb_timer_locals_dict, pyb_timer_locals_dict_table);
  660. const mp_obj_type_t pyb_timer_type = {
  661. { &mp_type_type },
  662. .name = MP_QSTR_Timer,
  663. .print = pyb_timer_print,
  664. .make_new = pyb_timer_make_new,
  665. .locals_dict = (mp_obj_t)&pyb_timer_locals_dict,
  666. };
  667. /// \moduleref pyb
  668. /// \class TimerChannel - setup a channel for a timer.
  669. ///
  670. /// Timer channels are used to generate/capture a signal using a timer.
  671. ///
  672. /// TimerChannel objects are created using the Timer.channel() method.
  673. STATIC void pyb_timer_channel_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
  674. pyb_timer_channel_obj_t *self = self_in;
  675. mp_printf(print, "TimerChannel(timer=%u, channel=%u, mode=%s)",
  676. self->timer->tim_id,
  677. self->channel,
  678. qstr_str(channel_mode_info[self->mode].name));
  679. }
  680. /// \method capture([value])
  681. /// Get or set the capture value associated with a channel.
  682. /// capture, compare, and pulse_width are all aliases for the same function.
  683. /// capture is the logical name to use when the channel is in input capture mode.
  684. /// \method compare([value])
  685. /// Get or set the compare value associated with a channel.
  686. /// capture, compare, and pulse_width are all aliases for the same function.
  687. /// compare is the logical name to use when the channel is in output compare mode.
  688. /// \method pulse_width([value])
  689. /// Get or set the pulse width value associated with a channel.
  690. /// capture, compare, and pulse_width are all aliases for the same function.
  691. /// pulse_width is the logical name to use when the channel is in PWM mode.
  692. ///
  693. /// In edge aligned mode, a pulse_width of `period + 1` corresponds to a duty cycle of 100%
  694. /// In center aligned mode, a pulse width of `period` corresponds to a duty cycle of 100%
  695. STATIC mp_obj_t pyb_timer_channel_capture_compare(size_t n_args, const mp_obj_t *args) {
  696. pyb_timer_channel_obj_t *self = args[0];
  697. FTM_TypeDef *FTMx = self->timer->ftm.Instance;
  698. if (n_args == 1) {
  699. // get
  700. return mp_obj_new_int(FTMx->channel[self->channel].CV & 0xffff);
  701. }
  702. mp_int_t pw = mp_obj_get_int(args[1]);
  703. // set
  704. FTMx->channel[self->channel].CV = pw & 0xffff;
  705. return mp_const_none;
  706. }
  707. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_capture_compare_obj, 1, 2, pyb_timer_channel_capture_compare);
  708. /// \method pulse_width_percent([value])
  709. /// Get or set the pulse width percentage associated with a channel. The value
  710. /// is a number between 0 and 100 and sets the percentage of the timer period
  711. /// for which the pulse is active. The value can be an integer or
  712. /// floating-point number for more accuracy. For example, a value of 25 gives
  713. /// a duty cycle of 25%.
  714. STATIC mp_obj_t pyb_timer_channel_pulse_width_percent(size_t n_args, const mp_obj_t *args) {
  715. pyb_timer_channel_obj_t *self = args[0];
  716. FTM_TypeDef *FTMx = self->timer->ftm.Instance;
  717. uint32_t period = compute_period(self->timer);
  718. if (n_args == 1) {
  719. // get
  720. uint32_t cmp = FTMx->channel[self->channel].CV & 0xffff;
  721. return compute_percent_from_pwm_value(period, cmp);
  722. } else {
  723. // set
  724. uint32_t cmp = compute_pwm_value_from_percent(period, args[1]);
  725. FTMx->channel[self->channel].CV = cmp & 0xffff;
  726. return mp_const_none;
  727. }
  728. }
  729. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_pulse_width_percent_obj, 1, 2, pyb_timer_channel_pulse_width_percent);
  730. /// \method callback(fun)
  731. /// Set the function to be called when the timer channel triggers.
  732. /// `fun` is passed 1 argument, the timer object.
  733. /// If `fun` is `None` then the callback will be disabled.
  734. STATIC mp_obj_t pyb_timer_channel_callback(mp_obj_t self_in, mp_obj_t callback) {
  735. pyb_timer_channel_obj_t *self = self_in;
  736. if (callback == mp_const_none) {
  737. // stop interrupt (but not timer)
  738. __HAL_FTM_DISABLE_CH_IT(&self->timer->ftm, self->channel);
  739. self->callback = mp_const_none;
  740. } else if (mp_obj_is_callable(callback)) {
  741. self->callback = callback;
  742. HAL_NVIC_EnableIRQ(self->timer->irqn);
  743. // start timer, so that it interrupts on overflow
  744. switch (self->mode) {
  745. case CHANNEL_MODE_PWM_NORMAL:
  746. case CHANNEL_MODE_PWM_INVERTED:
  747. HAL_FTM_PWM_Start_IT(&self->timer->ftm, self->channel);
  748. break;
  749. case CHANNEL_MODE_OC_TIMING:
  750. case CHANNEL_MODE_OC_ACTIVE:
  751. case CHANNEL_MODE_OC_INACTIVE:
  752. case CHANNEL_MODE_OC_TOGGLE:
  753. HAL_FTM_OC_Start_IT(&self->timer->ftm, self->channel);
  754. break;
  755. case CHANNEL_MODE_IC:
  756. HAL_FTM_IC_Start_IT(&self->timer->ftm, self->channel);
  757. break;
  758. }
  759. } else {
  760. mp_raise_ValueError("callback must be None or a callable object");
  761. }
  762. return mp_const_none;
  763. }
  764. STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_timer_channel_callback_obj, pyb_timer_channel_callback);
  765. #if MICROPY_TIMER_REG
  766. reg_t timer_channel_reg[] = {
  767. REG_ENTRY(FTM_ChannelTypeDef, CSC),
  768. REG_ENTRY(FTM_ChannelTypeDef, CV),
  769. };
  770. mp_obj_t pyb_timer_channel_reg(uint n_args, const mp_obj_t *args) {
  771. pyb_timer_channel_obj_t *self = args[0];
  772. return reg_cmd(&self->timer->ftm.Instance->channel[self->channel],
  773. timer_channel_reg, MP_ARRAY_SIZE(timer_channel_reg),
  774. n_args - 1, args + 1);
  775. }
  776. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_reg_obj, 1, 3, pyb_timer_channel_reg);
  777. #endif
  778. STATIC const mp_rom_map_elem_t pyb_timer_channel_locals_dict_table[] = {
  779. // instance methods
  780. { MP_ROM_QSTR(MP_QSTR_callback), MP_ROM_PTR(&pyb_timer_channel_callback_obj) },
  781. { MP_ROM_QSTR(MP_QSTR_pulse_width), MP_ROM_PTR(&pyb_timer_channel_capture_compare_obj) },
  782. { MP_ROM_QSTR(MP_QSTR_pulse_width_percent), MP_ROM_PTR(&pyb_timer_channel_pulse_width_percent_obj) },
  783. { MP_ROM_QSTR(MP_QSTR_capture), MP_ROM_PTR(&pyb_timer_channel_capture_compare_obj) },
  784. { MP_ROM_QSTR(MP_QSTR_compare), MP_ROM_PTR(&pyb_timer_channel_capture_compare_obj) },
  785. #if MICROPY_TIMER_REG
  786. { MP_ROM_QSTR(MP_QSTR_reg), MP_ROM_PTR(&pyb_timer_channel_reg_obj) },
  787. #endif
  788. };
  789. STATIC MP_DEFINE_CONST_DICT(pyb_timer_channel_locals_dict, pyb_timer_channel_locals_dict_table);
  790. STATIC const mp_obj_type_t pyb_timer_channel_type = {
  791. { &mp_type_type },
  792. .name = MP_QSTR_TimerChannel,
  793. .print = pyb_timer_channel_print,
  794. .locals_dict = (mp_obj_t)&pyb_timer_channel_locals_dict,
  795. };
  796. STATIC bool ftm_handle_irq_callback(pyb_timer_obj_t *self, mp_uint_t channel, mp_obj_t callback) {
  797. // execute callback if it's set
  798. if (callback == mp_const_none) {
  799. return false;
  800. }
  801. bool handled = false;
  802. // When executing code within a handler we must lock the GC to prevent
  803. // any memory allocations. We must also catch any exceptions.
  804. gc_lock();
  805. nlr_buf_t nlr;
  806. if (nlr_push(&nlr) == 0) {
  807. mp_call_function_1(callback, self);
  808. nlr_pop();
  809. handled = true;
  810. } else {
  811. // Uncaught exception; disable the callback so it doesn't run again.
  812. self->callback = mp_const_none;
  813. if (channel == 0xffffffff) {
  814. printf("Uncaught exception in Timer(" UINT_FMT
  815. ") interrupt handler\n", self->tim_id);
  816. } else {
  817. printf("Uncaught exception in Timer(" UINT_FMT ") channel "
  818. UINT_FMT " interrupt handler\n", self->tim_id, channel);
  819. }
  820. mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
  821. }
  822. gc_unlock();
  823. return handled;
  824. }
  825. STATIC void ftm_irq_handler(uint tim_id) {
  826. if (tim_id >= PYB_TIMER_OBJ_ALL_NUM) {
  827. return;
  828. }
  829. // get the timer object
  830. pyb_timer_obj_t *self = pyb_timer_obj_all[tim_id];
  831. if (self == NULL) {
  832. // timer object has not been set, so we can't do anything
  833. printf("No timer object for id=%d\n", tim_id);
  834. return;
  835. }
  836. FTM_HandleTypeDef *hftm = &self->ftm;
  837. bool handled = false;
  838. // Check for timer (versus timer channel) interrupt.
  839. if (__HAL_FTM_GET_TOF_IT(hftm) && __HAL_FTM_GET_TOF_FLAG(hftm)) {
  840. __HAL_FTM_CLEAR_TOF_FLAG(hftm);
  841. if (ftm_handle_irq_callback(self, 0xffffffff, self->callback)) {
  842. handled = true;
  843. } else {
  844. __HAL_FTM_DISABLE_TOF_IT(&self->ftm);
  845. printf("No callback for Timer %d TOF (now disabled)\n", tim_id);
  846. }
  847. }
  848. uint32_t processed = 0;
  849. // Check to see if a timer channel interrupt is pending
  850. pyb_timer_channel_obj_t *chan = self->channel;
  851. while (chan != NULL) {
  852. processed |= (1 << chan->channel);
  853. if (__HAL_FTM_GET_CH_IT(&self->ftm, chan->channel) && __HAL_FTM_GET_CH_FLAG(&self->ftm, chan->channel)) {
  854. __HAL_FTM_CLEAR_CH_FLAG(&self->ftm, chan->channel);
  855. if (ftm_handle_irq_callback(self, chan->channel, chan->callback)) {
  856. handled = true;
  857. } else {
  858. __HAL_FTM_DISABLE_CH_IT(&self->ftm, chan->channel);
  859. printf("No callback for Timer %d channel %u (now disabled)\n",
  860. self->tim_id, chan->channel);
  861. }
  862. }
  863. chan = chan->next;
  864. }
  865. if (!handled) {
  866. // An interrupt occurred for a channel we didn't process. Find it and
  867. // turn it off.
  868. for (mp_uint_t channel = 0; channel < 8; channel++) {
  869. if ((processed & (1 << channel)) == 0) {
  870. if (__HAL_FTM_GET_CH_FLAG(&self->ftm, channel) != 0) {
  871. __HAL_FTM_CLEAR_CH_FLAG(&self->ftm, channel);
  872. __HAL_FTM_DISABLE_CH_IT(&self->ftm, channel);
  873. printf("Unhandled interrupt Timer %d channel %u (now disabled)\n",
  874. tim_id, channel);
  875. }
  876. }
  877. }
  878. }
  879. }
  880. void ftm0_isr(void) {
  881. ftm_irq_handler(0);
  882. }
  883. void ftm1_isr(void) {
  884. ftm_irq_handler(1);
  885. }
  886. void ftm2_isr(void) {
  887. ftm_irq_handler(2);
  888. }