timer.c 15.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#include <stm32f4xx_hal.h>
#include "usbd_cdc_msc_hid.h"
#include "usbd_cdc_interface.h"

#include "nlr.h"
#include "misc.h"
#include "mpconfig.h"
#include "qstr.h"
13
#include "gc.h"
14
15
16
17
18
19
20
21
22
#include "obj.h"
#include "runtime.h"
#include "timer.h"
#include "servo.h"

// The timers can be used by multiple drivers, and need a common point for
// the interrupts to be dispatched, so they are all collected here.
//
// TIM3:
23
//  - flash storage controller, to flush the cache
24
25
26
27
28
//  - USB CDC interface, interval, to check for new data
//  - LED 4, PWM to set the LED intensity
//
// TIM5:
//  - servo controller, PWM
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
//
// TIM6:
//  - ADC, DAC for read_timed and write_timed
//
// Python usage model:
//
//      tim = pyb.Timer(4, freq=100)    # freq in Hz
//      tim = pyb.Timer(4, prescaler=1, period=100)
//      tim.counter()                   # get counter (can also set)
//      tim.prescaler(2)                # set prescaler (can also get)
//      tim.period(200)                 # set period (can also get)
//      tim.callback(lambda t: ...)     # set callback for update interrupt (t=tim instance)
//      tim.callback(None)              # clear callback

typedef struct _pyb_timer_obj_t {
    mp_obj_base_t base;
    machine_uint_t tim_id;
    mp_obj_t callback;
    TIM_HandleTypeDef tim;
    IRQn_Type irqn;
} pyb_timer_obj_t;
50
51
52

TIM_HandleTypeDef TIM3_Handle;
TIM_HandleTypeDef TIM5_Handle;
53
TIM_HandleTypeDef TIM6_Handle;
54

55
56
57
// Used to divide down TIM3 and periodically call the flash storage IRQ
static uint32_t tim3_counter = 0;

58
59
// Used to do callbacks to Python code on interrupt
STATIC pyb_timer_obj_t *pyb_timer_obj_all[14];
60
#define PYB_TIMER_OBJ_ALL_NUM ARRAY_SIZE(pyb_timer_obj_all)
61
62
63
64
65
66
67
68

void timer_init0(void) {
    tim3_counter = 0;
    for (uint i = 0; i < PYB_TIMER_OBJ_ALL_NUM; i++) {
        pyb_timer_obj_all[i] = NULL;
    }
}

69
70
71
72
73
74
// TIM3 is set-up for the USB CDC interface
void timer_tim3_init(void) {
    // set up the timer for USBD CDC
    __TIM3_CLK_ENABLE();

    TIM3_Handle.Instance = TIM3;
75
76
    TIM3_Handle.Init.Period = (USBD_CDC_POLLING_INTERVAL*1000) - 1; // TIM3 fires every USBD_CDC_POLLING_INTERVAL ms
    TIM3_Handle.Init.Prescaler = 84-1; // for System clock at 168MHz, TIM3 runs at 1MHz
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
    TIM3_Handle.Init.ClockDivision = 0;
    TIM3_Handle.Init.CounterMode = TIM_COUNTERMODE_UP;
    HAL_TIM_Base_Init(&TIM3_Handle);

    HAL_NVIC_SetPriority(TIM3_IRQn, 6, 0);
    HAL_NVIC_EnableIRQ(TIM3_IRQn);

    if (HAL_TIM_Base_Start(&TIM3_Handle) != HAL_OK) {
        /* Starting Error */
    }
}

/* unused
void timer_tim3_deinit(void) {
    // reset TIM3 timer
    __TIM3_FORCE_RESET();
    __TIM3_RELEASE_RESET();
}
*/

// TIM5 is set-up for the servo controller
98
// This function inits but does not start the timer
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
void timer_tim5_init(void) {
    // TIM5 clock enable
    __TIM5_CLK_ENABLE();

    // set up and enable interrupt
    HAL_NVIC_SetPriority(TIM5_IRQn, 6, 0);
    HAL_NVIC_EnableIRQ(TIM5_IRQn);

    // PWM clock configuration
    TIM5_Handle.Instance = TIM5;
    TIM5_Handle.Init.Period = 2000; // timer cycles at 50Hz
    TIM5_Handle.Init.Prescaler = ((SystemCoreClock / 2) / 100000) - 1; // timer runs at 100kHz
    TIM5_Handle.Init.ClockDivision = 0;
    TIM5_Handle.Init.CounterMode = TIM_COUNTERMODE_UP;
    HAL_TIM_PWM_Init(&TIM5_Handle);
}

116
117
118
119
120
121
122
123
124
// Init TIM6 with a counter-overflow at the given frequency (given in Hz)
// TIM6 is used by the DAC and ADC for auto sampling at a given frequency
// This function inits but does not start the timer
void timer_tim6_init(uint freq) {
    // TIM6 clock enable
    __TIM6_CLK_ENABLE();

    // Timer runs at SystemCoreClock / 2
    // Compute the prescaler value so TIM6 triggers at freq-Hz
125
    uint32_t period = MAX(1, (SystemCoreClock / 2) / freq);
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
    uint32_t prescaler = 1;
    while (period > 0xffff) {
        period >>= 1;
        prescaler <<= 1;
    }

    // Time base clock configuration
    TIM6_Handle.Instance = TIM6;
    TIM6_Handle.Init.Period = period - 1;
    TIM6_Handle.Init.Prescaler = prescaler - 1;
    TIM6_Handle.Init.ClockDivision = 0; // unused for TIM6
    TIM6_Handle.Init.CounterMode = TIM_COUNTERMODE_UP; // unused for TIM6
    HAL_TIM_Base_Init(&TIM6_Handle);
}

141
142
143
144
// Interrupt dispatch
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
    if (htim == &TIM3_Handle) {
        USBD_CDC_HAL_TIM_PeriodElapsedCallback();
145
146
147
148
149
150
151

        // Periodically raise a flash IRQ for the flash storage controller
        if (tim3_counter++ >= 500 / USBD_CDC_POLLING_INTERVAL) {
            tim3_counter = 0;
            NVIC->STIR = FLASH_IRQn;
        }

152
153
154
155
156
    } else if (htim == &TIM5_Handle) {
        servo_timer_irq_callback();
    }
}

157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/******************************************************************************/
/* Micro Python bindings                                                      */

STATIC void pyb_timer_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
    pyb_timer_obj_t *self = self_in;

    if (self->tim.State == HAL_TIM_STATE_RESET) {
        print(env, "Timer(%u)", self->tim_id);
    } else {
        print(env, "Timer(%u, prescaler=%u, period=%u, mode=%u, div=%u)",
            self->tim_id,
            self->tim.Init.Prescaler,
            self->tim.Init.Period,
            self->tim.Init.CounterMode,
            self->tim.Init.ClockDivision
        );
    }
}
175

176
177
178
179
180
181
STATIC const mp_arg_t pyb_timer_init_args[] = {
    { MP_QSTR_freq,      MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} },
    { MP_QSTR_prescaler, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} },
    { MP_QSTR_period,    MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} },
    { MP_QSTR_mode,      MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = TIM_COUNTERMODE_UP} },
    { MP_QSTR_div,       MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = TIM_CLOCKDIVISION_DIV1} },
182
};
183
#define PYB_TIMER_INIT_NUM_ARGS ARRAY_SIZE(pyb_timer_init_args)
184

185
186
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) {
    // parse args
187
188
    mp_arg_val_t vals[PYB_TIMER_INIT_NUM_ARGS];
    mp_arg_parse_all(n_args, args, kw_args, PYB_TIMER_INIT_NUM_ARGS, pyb_timer_init_args, vals);
189

190
191
    // set the TIM configuration values
    TIM_Base_InitTypeDef *init = &self->tim.Init;
192

193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
    if (vals[0].u_int != 0xffffffff) {
        // set prescaler and period from frequency

        if (vals[0].u_int == 0) {
            nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "can't have 0 frequency"));
        }

        // work out TIM's clock source
        uint tim_clock;
        if (self->tim_id == 1 || (8 <= self->tim_id && self->tim_id <= 11)) {
            // TIM{1,8,9,10,11} are on APB2
            tim_clock = HAL_RCC_GetPCLK2Freq();
        } else {
            // TIM{2,3,4,5,6,7,12,13,14} are on APB1
            tim_clock = HAL_RCC_GetPCLK1Freq();
        }

        // compute the prescaler value so TIM triggers at freq-Hz
        // dpgeorge: I don't understand why we need to multiply tim_clock by 2
        uint32_t period = MAX(1, 2 * tim_clock / vals[0].u_int);
        uint32_t prescaler = 1;
        while (period > 0xffff) {
            period >>= 1;
            prescaler <<= 1;
        }
        init->Prescaler = prescaler - 1;
        init->Period = period - 1;
    } else if (vals[1].u_int != 0xffffffff && vals[2].u_int != 0xffffffff) {
        // set prescaler and period directly
        init->Prescaler = vals[1].u_int;
        init->Period = vals[2].u_int;
    } else {
        nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "must specify either freq, or prescaler and period"));
    }

    init->CounterMode = vals[3].u_int;
    init->ClockDivision = vals[4].u_int;
    init->RepetitionCounter = 0;

    // init the TIM peripheral
    switch (self->tim_id) {
        case 1: __TIM1_CLK_ENABLE(); break;
        case 2: __TIM2_CLK_ENABLE(); break;
        case 3: __TIM3_CLK_ENABLE(); break;
        case 4: __TIM4_CLK_ENABLE(); break;
        case 5: __TIM5_CLK_ENABLE(); break;
        case 6: __TIM6_CLK_ENABLE(); break;
        case 7: __TIM7_CLK_ENABLE(); break;
        case 8: __TIM8_CLK_ENABLE(); break;
        case 9: __TIM9_CLK_ENABLE(); break;
        case 10: __TIM10_CLK_ENABLE(); break;
        case 11: __TIM11_CLK_ENABLE(); break;
        case 12: __TIM12_CLK_ENABLE(); break;
        case 13: __TIM13_CLK_ENABLE(); break;
        case 14: __TIM14_CLK_ENABLE(); break;
    }
    HAL_TIM_Base_Init(&self->tim);
    HAL_TIM_Base_Start(&self->tim);

    // set the priority (if not a special timer)
    if (self->tim_id != 3 && self->tim_id != 5) {
        HAL_NVIC_SetPriority(self->irqn, 0xe, 0xe); // next-to lowest priority
    }
256
257
258
259

    return mp_const_none;
}

260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
STATIC mp_obj_t pyb_timer_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
    // check arguments
    mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);

    // create new Timer object
    pyb_timer_obj_t *tim = m_new_obj(pyb_timer_obj_t);
    tim->base.type = &pyb_timer_type;
    tim->callback = mp_const_none;
    memset(&tim->tim, 0, sizeof(tim->tim));

    // get TIM number
    tim->tim_id = mp_obj_get_int(args[0]);

    switch (tim->tim_id) {
        case 1: tim->tim.Instance = TIM1; tim->irqn = TIM1_UP_TIM10_IRQn; break;
        case 2: tim->tim.Instance = TIM2; tim->irqn = TIM2_IRQn; break;
        case 3: nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Timer 3 is for internal use only")); // TIM3 used for low-level stuff; go via regs if necessary
        case 4: tim->tim.Instance = TIM4; tim->irqn = TIM4_IRQn; break;
        case 5: tim->tim.Instance = TIM5; tim->irqn = TIM5_IRQn; break;
        case 6: tim->tim.Instance = TIM6; tim->irqn = TIM6_DAC_IRQn; break;
        case 7: tim->tim.Instance = TIM7; tim->irqn = TIM7_IRQn; break;
        case 8: tim->tim.Instance = TIM8; tim->irqn = TIM8_UP_TIM13_IRQn; break;
        case 9: tim->tim.Instance = TIM9; tim->irqn = TIM1_BRK_TIM9_IRQn; break;
        case 10: tim->tim.Instance = TIM10; tim->irqn = TIM1_UP_TIM10_IRQn; break;
        case 11: tim->tim.Instance = TIM11; tim->irqn = TIM1_TRG_COM_TIM11_IRQn; break;
        case 12: tim->tim.Instance = TIM12; tim->irqn = TIM8_BRK_TIM12_IRQn; break;
        case 13: tim->tim.Instance = TIM13; tim->irqn = TIM8_UP_TIM13_IRQn; break;
        case 14: tim->tim.Instance = TIM14; tim->irqn = TIM8_TRG_COM_TIM14_IRQn; break;
        default: nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Timer %d does not exist", tim->tim_id));
    }

    if (n_args > 1 || n_kw > 0) {
        // start the peripheral
        mp_map_t kw_args;
        mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
        pyb_timer_init_helper(tim, n_args - 1, args + 1, &kw_args);
    }

    // set the global variable for interrupt callbacks
    if (tim->tim_id - 1 < PYB_TIMER_OBJ_ALL_NUM) {
        pyb_timer_obj_all[tim->tim_id - 1] = tim;
    }

    return (mp_obj_t)tim;
304
305
}

306
307
STATIC mp_obj_t pyb_timer_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
    return pyb_timer_init_helper(args[0], n_args - 1, args + 1, kw_args);
308
}
309
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_init_obj, 1, pyb_timer_init);
310

311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
STATIC mp_obj_t pyb_timer_deinit(mp_obj_t self_in) {
    //pyb_timer_obj_t *self = self_in;
    // TODO implement me
    return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_deinit_obj, pyb_timer_deinit);

mp_obj_t pyb_timer_counter(uint n_args, const mp_obj_t *args) {
    pyb_timer_obj_t *self = args[0];
    if (n_args == 1) {
        // get
        return mp_obj_new_int(self->tim.Instance->CNT);
    } else {
        // set
        __HAL_TIM_SetCounter(&self->tim, mp_obj_get_int(args[1]));
        return mp_const_none;
    }
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_counter_obj, 1, 2, pyb_timer_counter);

mp_obj_t pyb_timer_prescaler(uint n_args, const mp_obj_t *args) {
    pyb_timer_obj_t *self = args[0];
    if (n_args == 1) {
        // get
        return mp_obj_new_int(self->tim.Instance->PSC & 0xffff);
    } else {
        // set
        self->tim.Init.Prescaler = self->tim.Instance->PSC = mp_obj_get_int(args[1]) & 0xffff;
        return mp_const_none;
    }
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_prescaler_obj, 1, 2, pyb_timer_prescaler);

mp_obj_t pyb_timer_period(uint n_args, const mp_obj_t *args) {
    pyb_timer_obj_t *self = args[0];
    if (n_args == 1) {
        // get
        return mp_obj_new_int(self->tim.Instance->ARR & 0xffff);
    } else {
        // set
        __HAL_TIM_SetAutoreload(&self->tim, mp_obj_get_int(args[1]) & 0xffff);
        return mp_const_none;
    }
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_period_obj, 1, 2, pyb_timer_period);
356

357
358
359
360
361
362
363
364
365
366
367
368
369
STATIC mp_obj_t pyb_timer_callback(mp_obj_t self_in, mp_obj_t callback) {
    pyb_timer_obj_t *self = self_in;
    if (callback == mp_const_none) {
        // stop interrupt (but not timer)
        __HAL_TIM_DISABLE_IT(&self->tim, TIM_IT_UPDATE);
        self->callback = mp_const_none;
    } else if (mp_obj_is_callable(callback)) {
        self->callback = callback;
        HAL_NVIC_EnableIRQ(self->irqn);
        // start timer, so that it interrupts on overflow
        HAL_TIM_Base_Start_IT(&self->tim);
    } else {
        nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "callback must be None or a callable object"));
370
    }
371
    return mp_const_none;
372
}
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_timer_callback_obj, pyb_timer_callback);

STATIC const mp_map_elem_t pyb_timer_locals_dict_table[] = {
    // instance methods
    { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_timer_init_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_timer_deinit_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_counter), (mp_obj_t)&pyb_timer_counter_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_prescaler), (mp_obj_t)&pyb_timer_prescaler_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_period), (mp_obj_t)&pyb_timer_period_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&pyb_timer_callback_obj },
};

STATIC MP_DEFINE_CONST_DICT(pyb_timer_locals_dict, pyb_timer_locals_dict_table);

const mp_obj_type_t pyb_timer_type = {
    { &mp_type_type },
    .name = MP_QSTR_Timer,
    .print = pyb_timer_print,
    .make_new = pyb_timer_make_new,
    .locals_dict = (mp_obj_t)&pyb_timer_locals_dict,
};

void timer_irq_handler(uint tim_id) {
    if (tim_id - 1 < PYB_TIMER_OBJ_ALL_NUM) {
        // get the timer object
        pyb_timer_obj_t *tim = pyb_timer_obj_all[tim_id - 1];

        if (tim == NULL) {
            // timer object has not been set, so we can't do anything
            return;
        }
404

405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
        // see if it was a TIM update event (the only event we currently interrupt on)
        if (__HAL_TIM_GET_FLAG(&tim->tim, TIM_FLAG_UPDATE) != RESET) {
            if (__HAL_TIM_GET_ITSTATUS(&tim->tim, TIM_IT_UPDATE) != RESET) {
                // clear the interrupt
                __HAL_TIM_CLEAR_IT(&tim->tim, TIM_IT_UPDATE);

                // execute callback if it's set
                if (tim->callback != mp_const_none) {
                    // When executing code within a handler we must lock the GC to prevent
                    // any memory allocations.  We must also catch any exceptions.
                    gc_lock();
                    nlr_buf_t nlr;
                    if (nlr_push(&nlr) == 0) {
                        mp_call_function_1(tim->callback, tim);
                        nlr_pop();
                    } else {
                        // Uncaught exception; disable the callback so it doesn't run again.
                        tim->callback = mp_const_none;
                        __HAL_TIM_DISABLE_IT(&tim->tim, TIM_IT_UPDATE);
                        printf("Uncaught exception in Timer(%lu) interrupt handler\n", tim->tim_id);
                        mp_obj_print_exception((mp_obj_t)nlr.ret_val);
                    }
                    gc_unlock();
                }
            }
        }
431
432
    }
}