Skip to content

Commit ed8db2e

Browse files
author
danicampora
committed
cc3200: Finally fix the Timer class API.
Properly calculate the period and the prescaler, this now allows to set the PWM frequency down to 5Hz. Make Timer IDs go from 0 to 3. Add the trigger definitions for the channel IRQ.
1 parent 53fec1e commit ed8db2e

2 files changed

Lines changed: 61 additions & 34 deletions

File tree

cc3200/mods/pybtimer.c

Lines changed: 58 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
///
6161
/// Example usage to toggle an LED at a fixed frequency:
6262
///
63-
/// tim = pyb.Timer(4) # create a timer object using timer 4
63+
/// tim = pyb.Timer(3) # create a timer object using timer 3
6464
/// tim.init(mode=Timer.PERIODIC) # initialize it in periodic mode
6565
/// tim_ch = tim.channel(Timer.A, freq=2) # configure channel A at a frequency of 2Hz
6666
/// tim_ch.callback(handler=lambda t:led.toggle()) # toggle a LED on every cycle of the timer
@@ -87,6 +87,10 @@
8787
#define PYBTIMER_POLARITY_POS (0x01)
8888
#define PYBTIMER_POLARITY_NEG (0x02)
8989

90+
#define PYBTIMER_TIMEOUT_TRIGGER (0x01)
91+
#define PYBTIMER_MATCH_TRIGGER (0x02)
92+
#define PYBTIMER_EVENT_TRIGGER (0x04)
93+
9094
#define PYBTIMER_SRC_FREQ_HZ HAL_FCPU_HZ
9195

9296
/******************************************************************************
@@ -127,6 +131,7 @@ STATIC const mp_obj_type_t pyb_timer_channel_type;
127131
******************************************************************************/
128132
STATIC mp_obj_t pyb_timer_channel_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
129133
STATIC void timer_disable (pyb_timer_obj_t *tim);
134+
STATIC void timer_channel_init (pyb_timer_channel_obj_t *ch);
130135
STATIC void TIMER0AIntHandler(void);
131136
STATIC void TIMER0BIntHandler(void);
132137
STATIC void TIMER1AIntHandler(void);
@@ -177,22 +182,33 @@ STATIC void pyb_timer_channel_remove (pyb_timer_channel_obj_t *ch) {
177182
pyb_timer_channel_obj_t *channel;
178183
if ((channel = pyb_timer_channel_find(ch->timer->timer, ch->channel))) {
179184
mp_obj_list_remove(&MP_STATE_PORT(pyb_timer_channel_obj_list), channel);
185+
// unregister it with the sleep module
186+
pyb_sleep_remove((const mp_obj_t)channel);
180187
}
181188
}
182189

183190
STATIC void pyb_timer_channel_add (pyb_timer_channel_obj_t *ch) {
184191
// remove it in case it already exists
185192
pyb_timer_channel_remove(ch);
186193
mp_obj_list_append(&MP_STATE_PORT(pyb_timer_channel_obj_list), ch);
194+
// register it with the sleep module
195+
pyb_sleep_add((const mp_obj_t)ch, (WakeUpCB_t)timer_channel_init);
187196
}
188197

189198
STATIC void timer_disable (pyb_timer_obj_t *tim) {
190199
// disable all timers and it's interrupts
191200
MAP_TimerDisable(tim->timer, TIMER_A | TIMER_B);
192201
MAP_TimerIntDisable(tim->timer, tim->irq_trigger);
193202
MAP_TimerIntClear(tim->timer, tim->irq_trigger);
203+
pyb_timer_channel_obj_t *ch;
204+
// disable its channels
205+
if ((ch = pyb_timer_channel_find (tim->timer, TIMER_A))) {
206+
pyb_sleep_remove(ch);
207+
}
208+
if ((ch = pyb_timer_channel_find (tim->timer, TIMER_B))) {
209+
pyb_sleep_remove(ch);
210+
}
194211
MAP_PRCMPeripheralClkDisable(tim->peripheral, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
195-
memset(&pyb_timer_obj[tim->id], 0, sizeof(pyb_timer_obj_t));
196212
}
197213

198214
// computes prescaler period and match value so timer triggers at freq-Hz
@@ -205,8 +221,10 @@ STATIC uint32_t compute_prescaler_period_and_match_value(pyb_timer_channel_obj_t
205221
if (period_c == 0) {
206222
goto error;
207223
}
208-
prescaler = period_c >> 16;
224+
225+
prescaler = period_c >> 16; // The prescaler is an extension of the timer counter
209226
*period_out = period_c;
227+
210228
if (prescaler > 0xFF && maxcount == 0xFFFF) {
211229
goto error;
212230
}
@@ -217,9 +235,6 @@ STATIC uint32_t compute_prescaler_period_and_match_value(pyb_timer_channel_obj_t
217235
else {
218236
*match_out = period_c - ((period_c * ch->duty_cycle) / 100);
219237
}
220-
if ((ch->timer->config & 0x0F) == TIMER_CFG_A_PWM && (*match_out > 0xFFFF)) {
221-
goto error;
222-
}
223238
return prescaler;
224239

225240
error:
@@ -250,6 +265,7 @@ STATIC void timer_channel_init (pyb_timer_channel_obj_t *ch) {
250265
MAP_TimerControlLevel(ch->timer->timer, ch->channel, (ch->polarity == PYBTIMER_POLARITY_NEG) ? true : false);
251266
// set the match value (which is simply the duty cycle translated to ticks)
252267
MAP_TimerMatchSet(ch->timer->timer, ch->channel, match);
268+
MAP_TimerPrescaleMatchSet(ch->timer->timer, ch->channel, match >> 16);
253269
}
254270
// configure the event edge type if we are in such mode
255271
else if ((ch->timer->config & 0x0F) == TIMER_CFG_A_CAP_COUNT || (ch->timer->config & 0x0F) == TIMER_CFG_A_CAP_TIME) {
@@ -282,10 +298,10 @@ STATIC void pyb_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_
282298
// timer mode
283299
qstr mode_qst = MP_QSTR_PWM;
284300
switch(mode) {
285-
case TIMER_CFG_A_ONE_SHOT:
301+
case TIMER_CFG_A_ONE_SHOT_UP:
286302
mode_qst = MP_QSTR_ONE_SHOT;
287303
break;
288-
case TIMER_CFG_A_PERIODIC:
304+
case TIMER_CFG_A_PERIODIC_UP:
289305
mode_qst = MP_QSTR_PERIODIC;
290306
break;
291307
case TIMER_CFG_A_CAP_COUNT:
@@ -297,7 +313,7 @@ STATIC void pyb_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_
297313
default:
298314
break;
299315
}
300-
mp_printf(print, "<Timer%u, mode=Timer.%q>", (tim->id + 1), mode_qst);
316+
mp_printf(print, "Timer(%u, mode=Timer.%q)", (tim->id + 1), mode_qst);
301317
}
302318

303319
/// \method init(mode, *, width)
@@ -325,7 +341,7 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *tim, mp_uint_t n_args, co
325341

326342
// check the mode
327343
uint32_t _mode = args[0].u_int;
328-
if (_mode != TIMER_CFG_A_ONE_SHOT && _mode != TIMER_CFG_A_PERIODIC && _mode != TIMER_CFG_A_CAP_COUNT &&
344+
if (_mode != TIMER_CFG_A_ONE_SHOT_UP && _mode != TIMER_CFG_A_PERIODIC_UP && _mode != TIMER_CFG_A_CAP_COUNT &&
329345
_mode != TIMER_CFG_A_CAP_TIME && _mode != TIMER_CFG_A_PWM) {
330346
goto error;
331347
}
@@ -336,7 +352,7 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *tim, mp_uint_t n_args, co
336352
}
337353
bool is16bit = (args[1].u_int == 16);
338354

339-
if (!is16bit && (_mode != TIMER_CFG_A_ONE_SHOT && _mode != TIMER_CFG_A_PERIODIC)) {
355+
if (!is16bit && (_mode != TIMER_CFG_A_ONE_SHOT_UP && _mode != TIMER_CFG_A_PERIODIC_UP)) {
340356
// 32-bit mode is only available when in free running modes
341357
goto error;
342358
}
@@ -361,7 +377,7 @@ STATIC mp_obj_t pyb_timer_make_new(const mp_obj_type_t *type, mp_uint_t n_args,
361377
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
362378

363379
// create a new Timer object
364-
int32_t timer_idx = mp_obj_get_int(args[0]) - 1;
380+
int32_t timer_idx = mp_obj_get_int(args[0]);
365381
if (timer_idx < 0 || timer_idx > (PYBTIMER_NUM_TIMERS - 1)) {
366382
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable));
367383
}
@@ -478,9 +494,6 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp
478494

479495
timer_channel_init(ch);
480496

481-
// register it with the sleep module
482-
pyb_sleep_add ((const mp_obj_t)ch, (WakeUpCB_t)timer_channel_init);
483-
484497
// add the timer to the list
485498
pyb_timer_channel_add(ch);
486499

@@ -500,13 +513,16 @@ STATIC const mp_map_elem_t pyb_timer_locals_dict_table[] = {
500513
// class constants
501514
{ MP_OBJ_NEW_QSTR(MP_QSTR_A), MP_OBJ_NEW_SMALL_INT(TIMER_A) },
502515
{ MP_OBJ_NEW_QSTR(MP_QSTR_B), MP_OBJ_NEW_SMALL_INT(TIMER_B) },
503-
{ MP_OBJ_NEW_QSTR(MP_QSTR_ONE_SHOT), MP_OBJ_NEW_SMALL_INT(TIMER_CFG_A_ONE_SHOT) },
504-
{ MP_OBJ_NEW_QSTR(MP_QSTR_PERIODIC), MP_OBJ_NEW_SMALL_INT(TIMER_CFG_A_PERIODIC) },
516+
{ MP_OBJ_NEW_QSTR(MP_QSTR_ONE_SHOT), MP_OBJ_NEW_SMALL_INT(TIMER_CFG_A_ONE_SHOT_UP) },
517+
{ MP_OBJ_NEW_QSTR(MP_QSTR_PERIODIC), MP_OBJ_NEW_SMALL_INT(TIMER_CFG_A_PERIODIC_UP) },
505518
{ MP_OBJ_NEW_QSTR(MP_QSTR_EDGE_COUNT), MP_OBJ_NEW_SMALL_INT(TIMER_CFG_A_CAP_COUNT) },
506519
{ MP_OBJ_NEW_QSTR(MP_QSTR_EDGE_TIME), MP_OBJ_NEW_SMALL_INT(TIMER_CFG_A_CAP_TIME) },
507520
{ MP_OBJ_NEW_QSTR(MP_QSTR_PWM), MP_OBJ_NEW_SMALL_INT(TIMER_CFG_A_PWM) },
508521
{ MP_OBJ_NEW_QSTR(MP_QSTR_POSITIVE), MP_OBJ_NEW_SMALL_INT(PYBTIMER_POLARITY_POS) },
509522
{ MP_OBJ_NEW_QSTR(MP_QSTR_NEGATIVE), MP_OBJ_NEW_SMALL_INT(PYBTIMER_POLARITY_NEG) },
523+
{ MP_OBJ_NEW_QSTR(MP_QSTR_TIMEOUT), MP_OBJ_NEW_SMALL_INT(PYBTIMER_TIMEOUT_TRIGGER) },
524+
{ MP_OBJ_NEW_QSTR(MP_QSTR_MATCH), MP_OBJ_NEW_SMALL_INT(PYBTIMER_MATCH_TRIGGER) },
525+
{ MP_OBJ_NEW_QSTR(MP_QSTR_EVENT), MP_OBJ_NEW_SMALL_INT(PYBTIMER_EVENT_TRIGGER) },
510526
};
511527
STATIC MP_DEFINE_CONST_DICT(pyb_timer_locals_dict, pyb_timer_locals_dict_table);
512528

@@ -528,7 +544,6 @@ STATIC const mp_irq_methods_t pyb_timer_channel_irq_methods = {
528544
STATIC void TIMERGenericIntHandler(uint32_t timer, uint16_t channel) {
529545
pyb_timer_channel_obj_t *self;
530546
uint32_t status;
531-
532547
if ((self = pyb_timer_channel_find(timer, channel))) {
533548
status = MAP_TimerIntStatus(self->timer->timer, true) & self->channel;
534549
MAP_TimerIntClear(self->timer->timer, status);
@@ -574,13 +589,11 @@ STATIC void pyb_timer_channel_print(const mp_print_t *print, mp_obj_t self_in, m
574589
// timer channel
575590
if (ch->channel == TIMER_A) {
576591
ch_id = "A";
577-
}
578-
else if (ch->channel == TIMER_B) {
592+
} else if (ch->channel == TIMER_B) {
579593
ch_id = "B";
580594
}
581595

582-
mp_printf(print, "<%q %s, timer=%u, %q=%u", MP_QSTR_TimerChannel,
583-
ch_id, (ch->timer->id + 1), MP_QSTR_freq, ch->frequency);
596+
mp_printf(print, "timer.channel(Timer.%s, %q=%u", ch_id, MP_QSTR_freq, ch->frequency);
584597

585598
uint32_t mode = ch->timer->config & 0xFF;
586599
if (mode == TIMER_CFG_A_CAP_COUNT || mode == TIMER_CFG_A_CAP_TIME || mode == TIMER_CFG_A_PWM) {
@@ -600,7 +613,7 @@ STATIC void pyb_timer_channel_print(const mp_print_t *print, mp_obj_t self_in, m
600613
mp_printf(print, ", %q=%u", MP_QSTR_duty_cycle, ch->duty_cycle);
601614
}
602615
}
603-
mp_printf(print, ">");
616+
mp_printf(print, ")");
604617
}
605618

606619
/// \method freq([value])
@@ -658,11 +671,9 @@ STATIC mp_obj_t pyb_timer_channel_time(mp_uint_t n_args, const mp_obj_t *args) {
658671
// get
659672
value = (ch->channel == TIMER_B) ? HWREG(ch->timer->timer + TIMER_O_TBV) : HWREG(ch->timer->timer + TIMER_O_TAV);
660673
// return the current timer value in microseconds
661-
// substract value to period since we are always operating in count-down mode
662-
uint32_t time_t = (1000 * (period_c - value)) / period_c;
674+
uint32_t time_t = (1000 * value) / period_c;
663675
return mp_obj_new_int((time_t * 1000) / ch->frequency);
664-
}
665-
else {
676+
} else {
666677
// set
667678
value = (mp_obj_get_int(args[1]) * ((ch->frequency * period_c) / 1000)) / 1000;
668679
if ((value > 0xFFFF) && (ch->timer->config & TIMER_CFG_SPLIT_PAIR)) {
@@ -693,8 +704,7 @@ STATIC mp_obj_t pyb_timer_channel_event_time(mp_obj_t self_in) {
693704
uint32_t match;
694705
(void)compute_prescaler_period_and_match_value(ch, &period_c, &match);
695706
uint32_t value = MAP_TimerValueGet(ch->timer->timer, ch->channel == (TIMER_A | TIMER_B) ? TIMER_A : ch->channel);
696-
// substract value to period since we are always operating in count-down mode
697-
uint32_t time_t = (1000 * (period_c - value)) / period_c;
707+
uint32_t time_t = (1000 * value) / period_c;
698708
return mp_obj_new_int((time_t * 1000) / ch->frequency);
699709
}
700710
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_channel_event_time_obj, pyb_timer_channel_event_time);
@@ -706,8 +716,7 @@ STATIC mp_obj_t pyb_timer_channel_duty_cycle(mp_uint_t n_args, const mp_obj_t *a
706716
if (n_args == 1) {
707717
// get
708718
return mp_obj_new_int(ch->duty_cycle);
709-
}
710-
else {
719+
} else {
711720
// duty cycle must be converted from percentage to ticks
712721
// calculate the period, the prescaler and the match value
713722
uint32_t period_c;
@@ -720,13 +729,13 @@ STATIC mp_obj_t pyb_timer_channel_duty_cycle(mp_uint_t n_args, const mp_obj_t *a
720729
MAP_TimerControlLevel(ch->timer->timer, ch->channel, (ch->polarity == PYBTIMER_POLARITY_NEG) ? true : false);
721730
}
722731
MAP_TimerMatchSet(ch->timer->timer, ch->channel, match);
732+
MAP_TimerPrescaleMatchSet(ch->timer->timer, ch->channel, match >> 16);
723733
return mp_const_none;
724734
}
725735
}
726736
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_duty_cycle_obj, 1, 3, pyb_timer_channel_duty_cycle);
727737

728738
/// \method irq(trigger, priority, handler, wake)
729-
/// FIXME triggers!!
730739
STATIC mp_obj_t pyb_timer_channel_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
731740
mp_arg_val_t args[mp_irq_INIT_NUM_ARGS];
732741
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args);
@@ -741,25 +750,40 @@ STATIC mp_obj_t pyb_timer_channel_irq (mp_uint_t n_args, const mp_obj_t *pos_arg
741750
goto invalid_args;
742751
}
743752

753+
// get the trigger
754+
uint trigger = mp_obj_get_int(args[0].u_obj);
755+
744756
// disable the callback first
745757
pyb_timer_channel_irq_disable(ch);
746758

747759
uint8_t shift = (ch->channel == TIMER_B) ? 8 : 0;
748760
uint32_t _config = (ch->channel == TIMER_B) ? ((ch->timer->config & TIMER_B) >> 8) : (ch->timer->config & TIMER_A);
749761
switch (_config) {
750-
case TIMER_CFG_A_ONE_SHOT:
751-
case TIMER_CFG_A_PERIODIC:
762+
case TIMER_CFG_A_ONE_SHOT_UP:
763+
case TIMER_CFG_A_PERIODIC_UP:
752764
ch->timer->irq_trigger |= TIMER_TIMA_TIMEOUT << shift;
765+
if (trigger != PYBTIMER_TIMEOUT_TRIGGER) {
766+
goto invalid_args;
767+
}
753768
break;
754769
case TIMER_CFG_A_CAP_COUNT:
755770
ch->timer->irq_trigger |= TIMER_CAPA_MATCH << shift;
771+
if (trigger != PYBTIMER_MATCH_TRIGGER) {
772+
goto invalid_args;
773+
}
756774
break;
757775
case TIMER_CFG_A_CAP_TIME:
758776
ch->timer->irq_trigger |= TIMER_CAPA_EVENT << shift;
777+
if (trigger != PYBTIMER_EVENT_TRIGGER) {
778+
goto invalid_args;
779+
}
759780
break;
760781
case TIMER_CFG_A_PWM:
761782
// special case for the PWM match interrupt
762783
ch->timer->irq_trigger |= ((ch->channel & TIMER_A) == TIMER_A) ? TIMER_TIMA_MATCH : TIMER_TIMB_MATCH;
784+
if (trigger != PYBTIMER_MATCH_TRIGGER) {
785+
goto invalid_args;
786+
}
763787
break;
764788
default:
765789
break;

cc3200/qstrdefsport.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,9 @@ Q(EDGE_TIME)
377377
Q(PWM)
378378
Q(POSITIVE)
379379
Q(NEGATIVE)
380+
Q(TIMEOUT)
381+
Q(MATCH)
382+
Q(EVENT)
380383

381384
// for uhashlib module
382385
//Q(uhashlib)

0 commit comments

Comments
 (0)