summaryrefslogtreecommitdiffstatshomepage
path: root/stmhal/timer.c
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2014-04-02 15:09:36 +0100
committerDamien George <damien.p.george@gmail.com>2014-04-02 15:09:36 +0100
commita12be917a4644305e7813b3f4b11880aba3632ca (patch)
treed1c5cacae61e38673d034bbdc55b0a534c9fc62a /stmhal/timer.c
parent69dee59ce44685d34662870fff439d7249cace36 (diff)
downloadmicropython-a12be917a4644305e7813b3f4b11880aba3632ca.tar.gz
micropython-a12be917a4644305e7813b3f4b11880aba3632ca.zip
stmhal: Add timer module; move servo PWM from TIM2 to TIM5.
As per issue #257, servo is better on TIM5 because TIM2 is connected to more GPIO.
Diffstat (limited to 'stmhal/timer.c')
-rw-r--r--stmhal/timer.c189
1 files changed, 189 insertions, 0 deletions
diff --git a/stmhal/timer.c b/stmhal/timer.c
new file mode 100644
index 0000000000..cfdb93587f
--- /dev/null
+++ b/stmhal/timer.c
@@ -0,0 +1,189 @@
+#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"
+#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:
+// - USB CDC interface, interval, to check for new data
+// - LED 4, PWM to set the LED intensity
+//
+// TIM5:
+// - servo controller, PWM
+
+TIM_HandleTypeDef TIM3_Handle;
+TIM_HandleTypeDef TIM5_Handle;
+
+// 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;
+ TIM3_Handle.Init.Period = (USBD_CDC_POLLING_INTERVAL*1000) - 1;
+ TIM3_Handle.Init.Prescaler = 84-1;
+ 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
+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);
+}
+
+// Interrupt dispatch
+void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
+ if (htim == &TIM3_Handle) {
+ USBD_CDC_HAL_TIM_PeriodElapsedCallback();
+ } else if (htim == &TIM5_Handle) {
+ servo_timer_irq_callback();
+ }
+}
+
+// below is old code from stm/ which has not yet been fully ported to stmhal/
+#if 0
+typedef struct _pyb_hal_tim_t {
+ mp_obj_base_t base;
+ TIM_HandleTypeDef htim;
+} pyb_hal_tim_t;
+
+pyb_hal_tim_t pyb_hal_tim_6;
+
+ pyb_hal_tim_6 = {
+ .base = {&pyb_type_hal_tim};
+ .htim = {TIM6
+
+// TIM6 is used as an internal interrup to schedule something at a specific rate
+mp_obj_t timer_py_callback;
+
+mp_obj_t timer_py_set_callback(mp_obj_t f) {
+ timer_py_callback = f;
+ return mp_const_none;
+}
+
+mp_obj_t timer_py_set_period(mp_obj_t period) {
+ TIM6->ARR = mp_obj_get_int(period) & 0xffff;
+ return mp_const_none;
+}
+
+mp_obj_t timer_py_set_prescaler(mp_obj_t prescaler) {
+ TIM6->PSC = mp_obj_get_int(prescaler) & 0xffff;
+ return mp_const_none;
+}
+
+mp_obj_t timer_py_get_value(void) {
+ return mp_obj_new_int(TIM6->CNT & 0xfffff);
+}
+
+void timer_init(void) {
+ timer_py_callback = mp_const_none;
+
+ // TIM6 clock enable
+ __TIM6_CLK_ENABLE();
+
+ // Compute the prescaler value so TIM6 runs at 20kHz
+ uint16_t PrescalerValue = (uint16_t) ((SystemCoreClock / 2) / 20000) - 1;
+
+ // Time base configuration
+ tim_handle.Instance = TIM6;
+ tim_handle.Init.Prescaler = PrescalerValue;
+ tim_handle.Init.CounterMode = TIM_COUNTERMODE_UP; // unused for TIM6
+ tim_handle.Init.Period = 20000; // timer cycles at 1Hz
+ tim_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // unused for TIM6
+ tim_handle.Init.RepetitionCounter = 0; // unused for TIM6
+ HAL_TIM_Base_Init(&tim_handle);
+
+ // enable perhipheral preload register
+ //TIM_ARRPreloadConfig(TIM6, ENABLE); ??
+
+ // set up interrupt
+ HAL_NVIC_SetPriority(TIM6_DAC_IRQn, 0xf, 0xf); // lowest priority
+ HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn);
+
+ // start timer, so that it interrupts on overflow
+ HAL_TIM_Base_Start_IT(&tim_handle);
+
+ // Python interface
+ mp_obj_t m = mp_obj_new_module(QSTR_FROM_STR_STATIC("timer"));
+ rt_store_attr(m, QSTR_FROM_STR_STATIC("callback"), rt_make_function_n(1, timer_py_set_callback));
+ rt_store_attr(m, QSTR_FROM_STR_STATIC("period"), rt_make_function_n(1, timer_py_set_period));
+ rt_store_attr(m, QSTR_FROM_STR_STATIC("prescaler"), rt_make_function_n(1, timer_py_set_prescaler));
+ rt_store_attr(m, QSTR_FROM_STR_STATIC("value"), rt_make_function_n(0, timer_py_get_value));
+ rt_store_name(QSTR_FROM_STR_STATIC("timer"), m);
+}
+
+void timer_interrupt(void) {
+ if (timer_py_callback != mp_const_none) {
+ nlr_buf_t nlr;
+ if (nlr_push(&nlr) == 0) {
+ // XXX what to do if the GC is in the middle of running??
+ rt_call_function_0(timer_py_callback);
+ nlr_pop();
+ } else {
+ // uncaught exception
+ printf("exception in timer interrupt\n");
+ mp_obj_print((mp_obj_t)nlr.ret_val, PRINT_REPR);
+ printf("\n");
+ }
+ }
+}
+
+mp_obj_t pyb_Timer(mp_obj_t timx_in) {
+ TIM_TypeDef *TIMx = (TIM_TypeDef*)mp_obj_get_int(timx_in);
+ if (!IS_TIM_INSTANCE(TIMx)) {
+ nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "argument 1 is not a TIM instance"));
+ }
+ pyb_hal_tim_t *tim = m_new_obj(pyb_hal_tim_t);
+ tim->htim.Instance = TIMx;
+ tim->htim.Instance.Init.Prescaler = x;
+ tim->htim.Instance.Init.CounterMode = y;
+ tim->htim.Instance.Init.Period = y;
+ tim->htim.Instance.Init.ClockDivision = y;
+ tim->htim.Instance.Init.RepetitionCounter = y;
+ HAL_TIM_Base_Init(&tim->htim);
+ return tim;
+}
+#endif