Damien | bd8e110 | 2013-11-06 23:04:33 +0000 | [diff] [blame] | 1 | #include <stdint.h> |
| 2 | #include <stdio.h> |
| 3 | |
| 4 | #include "stm_misc.h" |
| 5 | #include "stm32f4xx_rcc.h" |
| 6 | #include "stm32f4xx_tim.h" |
| 7 | |
| 8 | #include "nlr.h" |
| 9 | #include "misc.h" |
Damien | d99b052 | 2013-12-21 18:17:45 +0000 | [diff] [blame] | 10 | #include "mpconfig.h" |
Damien | bd8e110 | 2013-11-06 23:04:33 +0000 | [diff] [blame] | 11 | #include "parse.h" |
Damien | d99b052 | 2013-12-21 18:17:45 +0000 | [diff] [blame] | 12 | #include "obj.h" |
Damien | bd8e110 | 2013-11-06 23:04:33 +0000 | [diff] [blame] | 13 | #include "runtime.h" |
| 14 | |
| 15 | #include "timer.h" |
| 16 | |
| 17 | // TIM6 is used as an internal interrup to schedule something at a specific rate |
Damien | d99b052 | 2013-12-21 18:17:45 +0000 | [diff] [blame] | 18 | mp_obj_t timer_py_callback; |
Damien | bd8e110 | 2013-11-06 23:04:33 +0000 | [diff] [blame] | 19 | |
Damien | d99b052 | 2013-12-21 18:17:45 +0000 | [diff] [blame] | 20 | mp_obj_t timer_py_set_callback(mp_obj_t f) { |
Damien | bd8e110 | 2013-11-06 23:04:33 +0000 | [diff] [blame] | 21 | timer_py_callback = f; |
Damien | d99b052 | 2013-12-21 18:17:45 +0000 | [diff] [blame] | 22 | return mp_const_none; |
Damien | bd8e110 | 2013-11-06 23:04:33 +0000 | [diff] [blame] | 23 | } |
| 24 | |
Damien | d99b052 | 2013-12-21 18:17:45 +0000 | [diff] [blame] | 25 | mp_obj_t timer_py_set_period(mp_obj_t period) { |
| 26 | TIM6->ARR = mp_obj_get_int(period) & 0xffff; |
| 27 | return mp_const_none; |
Damien | 6d42ab6 | 2013-11-09 11:29:49 +0000 | [diff] [blame] | 28 | } |
| 29 | |
Damien | d99b052 | 2013-12-21 18:17:45 +0000 | [diff] [blame] | 30 | mp_obj_t timer_py_set_prescaler(mp_obj_t prescaler) { |
| 31 | TIM6->PSC = mp_obj_get_int(prescaler) & 0xffff; |
| 32 | return mp_const_none; |
Damien | bd8e110 | 2013-11-06 23:04:33 +0000 | [diff] [blame] | 33 | } |
| 34 | |
Damien | d99b052 | 2013-12-21 18:17:45 +0000 | [diff] [blame] | 35 | mp_obj_t timer_py_get_value(void) { |
| 36 | return mp_obj_new_int(TIM6->CNT & 0xfffff); |
Damien | bd8e110 | 2013-11-06 23:04:33 +0000 | [diff] [blame] | 37 | } |
| 38 | |
| 39 | void timer_init(void) { |
Damien | d99b052 | 2013-12-21 18:17:45 +0000 | [diff] [blame] | 40 | timer_py_callback = mp_const_none; |
Damien | bd8e110 | 2013-11-06 23:04:33 +0000 | [diff] [blame] | 41 | |
| 42 | // TIM6 clock enable |
| 43 | RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); |
| 44 | |
Damien | 6d42ab6 | 2013-11-09 11:29:49 +0000 | [diff] [blame] | 45 | // Compute the prescaler value so TIM6 runs at 20kHz |
| 46 | uint16_t PrescalerValue = (uint16_t) ((SystemCoreClock / 2) / 20000) - 1; |
Damien | bd8e110 | 2013-11-06 23:04:33 +0000 | [diff] [blame] | 47 | |
| 48 | // Time base configuration |
| 49 | TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; |
Damien | 6d42ab6 | 2013-11-09 11:29:49 +0000 | [diff] [blame] | 50 | TIM_TimeBaseStructure.TIM_Period = 20000; // timer cycles at 1Hz |
Damien | bd8e110 | 2013-11-06 23:04:33 +0000 | [diff] [blame] | 51 | TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue; |
| 52 | TIM_TimeBaseStructure.TIM_ClockDivision = 0; // unused for TIM6 |
| 53 | TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // unused for TIM6 |
| 54 | TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure); |
| 55 | |
| 56 | // enable perhipheral preload register |
| 57 | TIM_ARRPreloadConfig(TIM6, ENABLE); |
| 58 | |
| 59 | // enable interrupt when counter overflows |
| 60 | TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE); |
| 61 | |
| 62 | // set up interrupt |
| 63 | NVIC_InitTypeDef NVIC_InitStructure; |
| 64 | NVIC_InitStructure.NVIC_IRQChannel = TIM6_DAC_IRQn; |
| 65 | NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0f; // lowest priority |
| 66 | NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0f; // lowest priority |
| 67 | NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; |
| 68 | NVIC_Init(&NVIC_InitStructure); |
| 69 | |
| 70 | // TIM6 enable counter |
| 71 | TIM_Cmd(TIM6, ENABLE); |
| 72 | |
| 73 | // Python interface |
Damien George | aae7847 | 2014-01-03 00:10:22 +0000 | [diff] [blame] | 74 | mp_obj_t m = mp_obj_new_module(qstr_from_str_static("timer")); |
Damien George | f62d33a | 2014-01-13 19:50:05 +0000 | [diff] [blame] | 75 | rt_store_attr(m, qstr_from_str_static("callback"), rt_make_function_n(1, timer_py_set_callback)); |
| 76 | rt_store_attr(m, qstr_from_str_static("period"), rt_make_function_n(1, timer_py_set_period)); |
| 77 | rt_store_attr(m, qstr_from_str_static("prescaler"), rt_make_function_n(1, timer_py_set_prescaler)); |
| 78 | rt_store_attr(m, qstr_from_str_static("value"), rt_make_function_n(0, timer_py_get_value)); |
Damien | bd8e110 | 2013-11-06 23:04:33 +0000 | [diff] [blame] | 79 | rt_store_name(qstr_from_str_static("timer"), m); |
| 80 | } |
| 81 | |
| 82 | void timer_interrupt(void) { |
Damien | d99b052 | 2013-12-21 18:17:45 +0000 | [diff] [blame] | 83 | if (timer_py_callback != mp_const_none) { |
Damien | bd8e110 | 2013-11-06 23:04:33 +0000 | [diff] [blame] | 84 | nlr_buf_t nlr; |
| 85 | if (nlr_push(&nlr) == 0) { |
Damien | 6d42ab6 | 2013-11-09 11:29:49 +0000 | [diff] [blame] | 86 | // XXX what to do if the GC is in the middle of running?? |
Damien | bd8e110 | 2013-11-06 23:04:33 +0000 | [diff] [blame] | 87 | rt_call_function_0(timer_py_callback); |
| 88 | nlr_pop(); |
| 89 | } else { |
| 90 | // uncaught exception |
| 91 | printf("exception in timer interrupt\n"); |
Paul Sokolovsky | 76d982e | 2014-01-13 19:19:16 +0200 | [diff] [blame^] | 92 | mp_obj_print((mp_obj_t)nlr.ret_val, PRINT_REPR); |
Damien | bd8e110 | 2013-11-06 23:04:33 +0000 | [diff] [blame] | 93 | printf("\n"); |
| 94 | } |
| 95 | } |
| 96 | } |