diff --git a/stmhal/Makefile b/stmhal/Makefile index 0f3fe46cfabf8ead4700d26e1243a97c5a5a766b..fff966934abab2a8f468aa0a2c2ad718fc123b9f 100644 --- a/stmhal/Makefile +++ b/stmhal/Makefile @@ -61,6 +61,7 @@ SRC_C = \ usbd_msc_storage.c \ pendsv.c \ systick.c \ + timer.c \ led.c \ pin.c \ pin_map.c \ @@ -98,7 +99,6 @@ SRC_C = \ adc.c \ i2c.c \ -# timer.c \ # pybwlan.c \ SRC_S = \ diff --git a/stmhal/led.c b/stmhal/led.c index b7afdd40c5cf625771e2de54b8edfc50d50a98da..3108ee7792a47204e3d73e1edcf3749d67aa144b 100644 --- a/stmhal/led.c +++ b/stmhal/led.c @@ -1,7 +1,5 @@ #include <stdio.h> #include <stm32f4xx_hal.h> -#include "usbd_cdc_msc_hid.h" -#include "usbd_cdc_interface.h" #include "nlr.h" #include "misc.h" @@ -9,6 +7,7 @@ #include "qstr.h" #include "obj.h" #include "runtime.h" +#include "timer.h" #include "led.h" #include "pin.h" #include "build/pins.h" @@ -54,6 +53,8 @@ void led_init(void) { // LED4 (blue) is on PB4 which is TIM3_CH1 // we use PWM on this channel to fade the LED + // LED3 (yellow) is on PA15 which has TIM2_CH1, so we could PWM that as well + // GPIO configuration GPIO_InitStructure.Pin = MICROPY_HW_LED4.pin_mask; GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; diff --git a/stmhal/main.c b/stmhal/main.c index d6d9b9ed7eebe26a3b729d67448b4f589862a676..afef84e290f9ff2f8609894c3abf3a3d158020d2 100644 --- a/stmhal/main.c +++ b/stmhal/main.c @@ -22,6 +22,7 @@ #include "readline.h" #include "pyexec.h" #include "usart.h" +#include "timer.h" #include "led.h" #include "exti.h" #include "usrsw.h" @@ -38,7 +39,6 @@ #include "dac.h" #include "pin.h" #if 0 -#include "timer.h" #include "pybwlan.h" #endif @@ -177,6 +177,7 @@ int main(void) { // basic sub-system init pendsv_init(); + timer_tim3_init(); led_init(); switch_init0(); @@ -409,6 +410,11 @@ soft_reset: rng_init(); #endif +#if MICROPY_HW_ENABLE_TIMER + // timer + //timer_init(); +#endif + // I2C i2c_init(); @@ -422,13 +428,6 @@ soft_reset: servo_init(); #endif -#if 0 -#if MICROPY_HW_ENABLE_TIMER - // timer - timer_init(); -#endif -#endif - #if MICROPY_HW_ENABLE_DAC // DAC dac_init(); diff --git a/stmhal/servo.c b/stmhal/servo.c index 15ba35165cb40fad2db29c2ee533a06062bfc35c..9c757c56596a6688645d4d14db12836ab4ec7dc1 100644 --- a/stmhal/servo.c +++ b/stmhal/servo.c @@ -8,12 +8,13 @@ #include "qstr.h" #include "obj.h" #include "runtime.h" +#include "timer.h" #include "servo.h" // this servo driver uses hardware PWM to drive servos on PA0, PA1, PA2, PA3 = X1, X2, X3, X4 // TIM2 and TIM5 have CH1, CH2, CH3, CH4 on PA0-PA3 respectively // they are both 32-bit counters with 16-bit prescaler -// we use TIM2 +// we use TIM5 #define PYB_SERVO_NUM (4) @@ -30,23 +31,8 @@ STATIC const mp_obj_type_t servo_obj_type; STATIC pyb_servo_obj_t pyb_servo_obj[PYB_SERVO_NUM]; -TIM_HandleTypeDef TIM2_Handle; - void servo_init(void) { - // TIM2 clock enable - __TIM2_CLK_ENABLE(); - - // set up and enable interrupt - HAL_NVIC_SetPriority(TIM2_IRQn, 6, 0); - HAL_NVIC_EnableIRQ(TIM2_IRQn); - - // PWM clock configuration - TIM2_Handle.Instance = TIM2; - TIM2_Handle.Init.Period = 2000; // timer cycles at 50Hz - TIM2_Handle.Init.Prescaler = ((SystemCoreClock / 2) / 100000) - 1; // timer runs at 100kHz - TIM2_Handle.Init.ClockDivision = 0; - TIM2_Handle.Init.CounterMode = TIM_COUNTERMODE_UP; - HAL_TIM_PWM_Init(&TIM2_Handle); + timer_tim5_init(); // reset servo objects for (int i = 0; i < PYB_SERVO_NUM; i++) { @@ -74,17 +60,17 @@ void servo_timer_irq_callback(void) { need_it = true; } switch (s->servo_id) { - case 1: TIM2->CCR1 = s->pulse_cur; break; - case 2: TIM2->CCR2 = s->pulse_cur; break; - case 3: TIM2->CCR3 = s->pulse_cur; break; - case 4: TIM2->CCR4 = s->pulse_cur; break; + case 1: TIM5->CCR1 = s->pulse_cur; break; + case 2: TIM5->CCR2 = s->pulse_cur; break; + case 3: TIM5->CCR3 = s->pulse_cur; break; + case 4: TIM5->CCR4 = s->pulse_cur; break; } } } if (need_it) { - __HAL_TIM_ENABLE_IT(&TIM2_Handle, TIM_IT_UPDATE); + __HAL_TIM_ENABLE_IT(&TIM5_Handle, TIM_IT_UPDATE); } else { - __HAL_TIM_DISABLE_IT(&TIM2_Handle, TIM_IT_UPDATE); + __HAL_TIM_DISABLE_IT(&TIM5_Handle, TIM_IT_UPDATE); } } @@ -105,7 +91,7 @@ STATIC void servo_init_channel(pyb_servo_obj_t *s) { GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; GPIO_InitStructure.Speed = GPIO_SPEED_FAST; GPIO_InitStructure.Pull = GPIO_NOPULL; - GPIO_InitStructure.Alternate = GPIO_AF1_TIM2; + GPIO_InitStructure.Alternate = GPIO_AF2_TIM5; HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); // PWM mode configuration @@ -114,10 +100,10 @@ STATIC void servo_init_channel(pyb_servo_obj_t *s) { oc_init.Pulse = s->pulse_cur; // units of 10us oc_init.OCPolarity = TIM_OCPOLARITY_HIGH; oc_init.OCFastMode = TIM_OCFAST_DISABLE; - HAL_TIM_PWM_ConfigChannel(&TIM2_Handle, &oc_init, channel); + HAL_TIM_PWM_ConfigChannel(&TIM5_Handle, &oc_init, channel); // start PWM - HAL_TIM_PWM_Start(&TIM2_Handle, channel); + HAL_TIM_PWM_Start(&TIM5_Handle, channel); } /******************************************************************************/ @@ -129,10 +115,10 @@ STATIC mp_obj_t pyb_servo_set(mp_obj_t port, mp_obj_t value) { if (v < 50) { v = 50; } if (v > 250) { v = 250; } switch (p) { - case 1: TIM2->CCR1 = v; break; - case 2: TIM2->CCR2 = v; break; - case 3: TIM2->CCR3 = v; break; - case 4: TIM2->CCR4 = v; break; + case 1: TIM5->CCR1 = v; break; + case 2: TIM5->CCR2 = v; break; + case 3: TIM5->CCR3 = v; break; + case 4: TIM5->CCR4 = v; break; } return mp_const_none; } @@ -142,8 +128,8 @@ MP_DEFINE_CONST_FUN_OBJ_2(pyb_servo_set_obj, pyb_servo_set); STATIC mp_obj_t pyb_pwm_set(mp_obj_t period, mp_obj_t pulse) { int pe = mp_obj_get_int(period); int pu = mp_obj_get_int(pulse); - TIM2->ARR = pe; - TIM2->CCR3 = pu; + TIM5->ARR = pe; + TIM5->CCR3 = pu; return mp_const_none; } diff --git a/stmhal/servo.h b/stmhal/servo.h index d5fb6a8505df7ff0cd813cb48d907b1ea6ea25aa..865b0fc9f550eedf3d82836f962be674bd7d4ce0 100644 --- a/stmhal/servo.h +++ b/stmhal/servo.h @@ -1,5 +1,3 @@ -extern TIM_HandleTypeDef TIM2_Handle; - void servo_init(void); void servo_timer_irq_callback(void); diff --git a/stmhal/stm32f4xx_hal_msp.c b/stmhal/stm32f4xx_hal_msp.c index 1cf78336f85cfdaf8067fc6f673226512ea30ef9..7004912e145593ddfc53c8b48dd6ce3c2bf26225 100644 --- a/stmhal/stm32f4xx_hal_msp.c +++ b/stmhal/stm32f4xx_hal_msp.c @@ -38,8 +38,6 @@ /* Includes ------------------------------------------------------------------*/ #include "stm32f4xx_hal.h" -#include "usbd_cdc_msc_hid.h" -#include "usbd_cdc_interface.h" #include "misc.h" #include "mpconfig.h" @@ -47,30 +45,12 @@ #include "obj.h" #include "servo.h" -TIM_HandleTypeDef TIM3_Handle; - /** * @brief Initializes the Global MSP. * @param None * @retval None */ void HAL_MspInit(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 */ - } } /** @@ -79,9 +59,6 @@ void HAL_MspInit(void) { * @retval None */ void HAL_MspDeInit(void) { - // reset TIM3 timer - __TIM3_FORCE_RESET(); - __TIM3_RELEASE_RESET(); } /** @@ -146,14 +123,6 @@ void HAL_RTC_MspDeInit(RTC_HandleTypeDef *hrtc) __HAL_RCC_RTC_DISABLE(); } -void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { - if (htim == &TIM3_Handle) { - USBD_CDC_HAL_TIM_PeriodElapsedCallback(); - } else if (htim == &TIM2_Handle) { - servo_timer_irq_callback(); - } -} - /** * @} */ diff --git a/stmhal/stm32f4xx_it.c b/stmhal/stm32f4xx_it.c index e74b1c6c75a0a0e18146d6420f41781db1941b72..aee689d7e2001e6c6cbd2f9952906a50fc8cb9aa 100644 --- a/stmhal/stm32f4xx_it.c +++ b/stmhal/stm32f4xx_it.c @@ -42,15 +42,13 @@ #include "stm32f4xx_it.h" #include "stm32f4xx_hal.h" -#include "usbd_cdc_msc_hid.h" -#include "usbd_cdc_interface.h" #include "misc.h" #include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "exti.h" -#include "servo.h" +#include "timer.h" /** @addtogroup STM32F4xx_HAL_Examples * @{ @@ -351,12 +349,12 @@ void RTC_WKUP_IRQHandler(void) { Handle_EXTI_Irq(EXTI_RTC_WAKEUP); } -void TIM2_IRQHandler(void) { - HAL_TIM_IRQHandler(&TIM2_Handle); -} - void TIM3_IRQHandler(void) { HAL_TIM_IRQHandler(&TIM3_Handle); } +void TIM5_IRQHandler(void) { + HAL_TIM_IRQHandler(&TIM5_Handle); +} + /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/stmhal/timer.c b/stmhal/timer.c new file mode 100644 index 0000000000000000000000000000000000000000..cfdb93587fe345c221b63e75f8fd23f0e92fdd08 --- /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 diff --git a/stmhal/timer.h b/stmhal/timer.h new file mode 100644 index 0000000000000000000000000000000000000000..317b39b3f714e8518b82d2c1b88fbe662e60f48b --- /dev/null +++ b/stmhal/timer.h @@ -0,0 +1,10 @@ +// Periodically, the state of the buffer "UserTxBuffer" is checked. +// The period depends on USBD_CDC_POLLING_INTERVAL +// The value is in ms. The max is 65 and the min is 1. +#define USBD_CDC_POLLING_INTERVAL (10) + +extern TIM_HandleTypeDef TIM3_Handle; +extern TIM_HandleTypeDef TIM5_Handle; + +void timer_tim3_init(void); +void timer_tim5_init(void); diff --git a/stmhal/usbd_cdc_interface.h b/stmhal/usbd_cdc_interface.h index 5ed5ecef46bc73d42032faf392567d1eb7ace539..88ea7e5afc0a4a15a9c4e22244d03566d74b951a 100644 --- a/stmhal/usbd_cdc_interface.h +++ b/stmhal/usbd_cdc_interface.h @@ -33,10 +33,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -/* Periodically, the state of the buffer "UserTxBuffer" is checked. - The period depends on USBD_CDC_POLLING_INTERVAL */ -#define USBD_CDC_POLLING_INTERVAL 10 /* in ms. The max is 65 and the min is 1 */ - extern TIM_HandleTypeDef TIM3_Handle; extern const USBD_CDC_ItfTypeDef USBD_CDC_fops;