diff options
author | Damien George <damien.p.george@gmail.com> | 2014-04-02 15:09:36 +0100 |
---|---|---|
committer | Damien George <damien.p.george@gmail.com> | 2014-04-02 15:09:36 +0100 |
commit | a12be917a4644305e7813b3f4b11880aba3632ca (patch) | |
tree | d1c5cacae61e38673d034bbdc55b0a534c9fc62a /stmhal/timer.c | |
parent | 69dee59ce44685d34662870fff439d7249cace36 (diff) | |
download | micropython-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.c | 189 |
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 |