blob: 1e77f0fea366a3d95b94c6eacde8bbafb81934f4 [file] [log] [blame]
Damien Georgea12be912014-04-02 15:09:36 +01001#include <stdint.h>
2#include <stdio.h>
3#include <string.h>
4
5#include <stm32f4xx_hal.h>
6#include "usbd_cdc_msc_hid.h"
7#include "usbd_cdc_interface.h"
8
9#include "nlr.h"
10#include "misc.h"
11#include "mpconfig.h"
12#include "qstr.h"
13#include "obj.h"
14#include "runtime.h"
15#include "timer.h"
16#include "servo.h"
17
18// The timers can be used by multiple drivers, and need a common point for
19// the interrupts to be dispatched, so they are all collected here.
20//
21// TIM3:
22// - USB CDC interface, interval, to check for new data
23// - LED 4, PWM to set the LED intensity
24//
25// TIM5:
26// - servo controller, PWM
27
28TIM_HandleTypeDef TIM3_Handle;
29TIM_HandleTypeDef TIM5_Handle;
30
31// TIM3 is set-up for the USB CDC interface
32void timer_tim3_init(void) {
33 // set up the timer for USBD CDC
34 __TIM3_CLK_ENABLE();
35
36 TIM3_Handle.Instance = TIM3;
37 TIM3_Handle.Init.Period = (USBD_CDC_POLLING_INTERVAL*1000) - 1;
38 TIM3_Handle.Init.Prescaler = 84-1;
39 TIM3_Handle.Init.ClockDivision = 0;
40 TIM3_Handle.Init.CounterMode = TIM_COUNTERMODE_UP;
41 HAL_TIM_Base_Init(&TIM3_Handle);
42
43 HAL_NVIC_SetPriority(TIM3_IRQn, 6, 0);
44 HAL_NVIC_EnableIRQ(TIM3_IRQn);
45
46 if (HAL_TIM_Base_Start(&TIM3_Handle) != HAL_OK) {
47 /* Starting Error */
48 }
49}
50
51/* unused
52void timer_tim3_deinit(void) {
53 // reset TIM3 timer
54 __TIM3_FORCE_RESET();
55 __TIM3_RELEASE_RESET();
56}
57*/
58
59// TIM5 is set-up for the servo controller
60void timer_tim5_init(void) {
61 // TIM5 clock enable
62 __TIM5_CLK_ENABLE();
63
64 // set up and enable interrupt
65 HAL_NVIC_SetPriority(TIM5_IRQn, 6, 0);
66 HAL_NVIC_EnableIRQ(TIM5_IRQn);
67
68 // PWM clock configuration
69 TIM5_Handle.Instance = TIM5;
70 TIM5_Handle.Init.Period = 2000; // timer cycles at 50Hz
71 TIM5_Handle.Init.Prescaler = ((SystemCoreClock / 2) / 100000) - 1; // timer runs at 100kHz
72 TIM5_Handle.Init.ClockDivision = 0;
73 TIM5_Handle.Init.CounterMode = TIM_COUNTERMODE_UP;
74 HAL_TIM_PWM_Init(&TIM5_Handle);
75}
76
77// Interrupt dispatch
78void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
79 if (htim == &TIM3_Handle) {
80 USBD_CDC_HAL_TIM_PeriodElapsedCallback();
81 } else if (htim == &TIM5_Handle) {
82 servo_timer_irq_callback();
83 }
84}
85
86// below is old code from stm/ which has not yet been fully ported to stmhal/
87#if 0
88typedef struct _pyb_hal_tim_t {
89 mp_obj_base_t base;
90 TIM_HandleTypeDef htim;
91} pyb_hal_tim_t;
92
93pyb_hal_tim_t pyb_hal_tim_6;
94
95 pyb_hal_tim_6 = {
96 .base = {&pyb_type_hal_tim};
97 .htim = {TIM6
98
99// TIM6 is used as an internal interrup to schedule something at a specific rate
100mp_obj_t timer_py_callback;
101
102mp_obj_t timer_py_set_callback(mp_obj_t f) {
103 timer_py_callback = f;
104 return mp_const_none;
105}
106
107mp_obj_t timer_py_set_period(mp_obj_t period) {
108 TIM6->ARR = mp_obj_get_int(period) & 0xffff;
109 return mp_const_none;
110}
111
112mp_obj_t timer_py_set_prescaler(mp_obj_t prescaler) {
113 TIM6->PSC = mp_obj_get_int(prescaler) & 0xffff;
114 return mp_const_none;
115}
116
117mp_obj_t timer_py_get_value(void) {
118 return mp_obj_new_int(TIM6->CNT & 0xfffff);
119}
120
121void timer_init(void) {
122 timer_py_callback = mp_const_none;
123
124 // TIM6 clock enable
125 __TIM6_CLK_ENABLE();
126
127 // Compute the prescaler value so TIM6 runs at 20kHz
128 uint16_t PrescalerValue = (uint16_t) ((SystemCoreClock / 2) / 20000) - 1;
129
130 // Time base configuration
131 tim_handle.Instance = TIM6;
132 tim_handle.Init.Prescaler = PrescalerValue;
133 tim_handle.Init.CounterMode = TIM_COUNTERMODE_UP; // unused for TIM6
134 tim_handle.Init.Period = 20000; // timer cycles at 1Hz
135 tim_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // unused for TIM6
136 tim_handle.Init.RepetitionCounter = 0; // unused for TIM6
137 HAL_TIM_Base_Init(&tim_handle);
138
139 // enable perhipheral preload register
140 //TIM_ARRPreloadConfig(TIM6, ENABLE); ??
141
142 // set up interrupt
143 HAL_NVIC_SetPriority(TIM6_DAC_IRQn, 0xf, 0xf); // lowest priority
144 HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn);
145
146 // start timer, so that it interrupts on overflow
147 HAL_TIM_Base_Start_IT(&tim_handle);
148
149 // Python interface
150 mp_obj_t m = mp_obj_new_module(QSTR_FROM_STR_STATIC("timer"));
151 rt_store_attr(m, QSTR_FROM_STR_STATIC("callback"), rt_make_function_n(1, timer_py_set_callback));
152 rt_store_attr(m, QSTR_FROM_STR_STATIC("period"), rt_make_function_n(1, timer_py_set_period));
153 rt_store_attr(m, QSTR_FROM_STR_STATIC("prescaler"), rt_make_function_n(1, timer_py_set_prescaler));
154 rt_store_attr(m, QSTR_FROM_STR_STATIC("value"), rt_make_function_n(0, timer_py_get_value));
155 rt_store_name(QSTR_FROM_STR_STATIC("timer"), m);
156}
157
158void timer_interrupt(void) {
159 if (timer_py_callback != mp_const_none) {
160 nlr_buf_t nlr;
161 if (nlr_push(&nlr) == 0) {
162 // XXX what to do if the GC is in the middle of running??
163 rt_call_function_0(timer_py_callback);
164 nlr_pop();
165 } else {
166 // uncaught exception
167 printf("exception in timer interrupt\n");
168 mp_obj_print((mp_obj_t)nlr.ret_val, PRINT_REPR);
169 printf("\n");
170 }
171 }
172}
173
174mp_obj_t pyb_Timer(mp_obj_t timx_in) {
175 TIM_TypeDef *TIMx = (TIM_TypeDef*)mp_obj_get_int(timx_in);
176 if (!IS_TIM_INSTANCE(TIMx)) {
Damien Georgeea13f402014-04-05 18:32:08 +0100177 nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "argument 1 is not a TIM instance"));
Damien Georgea12be912014-04-02 15:09:36 +0100178 }
179 pyb_hal_tim_t *tim = m_new_obj(pyb_hal_tim_t);
180 tim->htim.Instance = TIMx;
181 tim->htim.Instance.Init.Prescaler = x;
182 tim->htim.Instance.Init.CounterMode = y;
183 tim->htim.Instance.Init.Period = y;
184 tim->htim.Instance.Init.ClockDivision = y;
185 tim->htim.Instance.Init.RepetitionCounter = y;
186 HAL_TIM_Base_Init(&tim->htim);
187 return tim;
188}
189#endif