#include #include #include #include #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_raise(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