/* * Copyright (c) 2006-2023, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2022-03-04 stevetong459 first version * 2022-07-15 Aligagago add apm32F4 serie MCU support * 2022-12-26 luobeihai add apm32F0 serie MCU support */ #include #define DBG_TAG "drv.hwtimer" #define DBG_LVL DBG_INFO #include #ifdef RT_USING_HWTIMER static const struct rt_hwtimer_info apm32_timer_info = { .maxfreq = 1000000, .minfreq = 2000, .maxcnt = 0xFFFF, .cntmode = HWTIMER_CNTMODE_UP, }; /* apm32 config class */ struct apm32_timer { char *name; TMR_T *tmr; IRQn_Type irqn; rt_hwtimer_t device; }; enum { #ifdef BSP_USING_TMR1 TMR1_INDEX, #endif #ifdef BSP_USING_TMR2 TMR2_INDEX, #endif #ifdef BSP_USING_TMR3 TMR3_INDEX, #endif #ifdef BSP_USING_TMR4 TMR4_INDEX, #endif #ifdef BSP_USING_TMR5 TMR5_INDEX, #endif #ifdef BSP_USING_TMR6 TMR6_INDEX, #endif #ifdef BSP_USING_TMR7 TMR7_INDEX, #endif #ifdef BSP_USING_TMR8 TMR8_INDEX, #endif #ifdef BSP_USING_TMR9 TMR9_INDEX, #endif #ifdef BSP_USING_TMR10 TMR10_INDEX, #endif #ifdef BSP_USING_TMR11 TMR11_INDEX, #endif #ifdef BSP_USING_TMR12 TMR12_INDEX, #endif #ifdef BSP_USING_TMR13 TMR13_INDEX, #endif #ifdef BSP_USING_TMR14 TMR14_INDEX, #endif #ifdef BSP_USING_TMR15 TMR15_INDEX, #endif #ifdef BSP_USING_TMR16 TMR16_INDEX, #endif #ifdef BSP_USING_TMR17 TMR17_INDEX, #endif }; static struct apm32_timer tmr_config[] = { #ifdef BSP_USING_TMR1 { "timer1", TMR1, #if defined(SOC_SERIES_APM32F1) TMR1_UP_IRQn, #elif defined(SOC_SERIES_APM32F4) TMR1_UP_TMR10_IRQn, #elif defined(SOC_SERIES_APM32F0) TMR1_BRK_UP_TRG_COM_IRQn #endif }, #endif #ifdef BSP_USING_TMR2 { "timer2", TMR2, TMR2_IRQn, }, #endif #ifdef BSP_USING_TMR3 { "timer3", TMR3, TMR3_IRQn, }, #endif #ifdef BSP_USING_TMR4 { "timer4", TMR4, TMR4_IRQn, }, #endif #ifdef BSP_USING_TMR5 { "timer5", TMR5, TMR5_IRQn, }, #endif #ifdef BSP_USING_TMR6 { "timer6", TMR6, #if defined(SOC_SERIES_APM32F1) || defined(APM32F030) || defined(APM32F070) TMR6_IRQn, #elif defined(SOC_SERIES_APM32F4) TMR6_DAC_IRQn #elif defined(SOC_SERIES_APM32F0) && !defined(APM32F030) && !defined(APM32F070) TMR6_DAC_IRQn #endif }, #endif #ifdef BSP_USING_TMR7 { "timer7", TMR7, TMR7_IRQn, }, #endif #ifdef BSP_USING_TMR8 { "timer8", TMR8, #if defined(SOC_SERIES_APM32F1) TMR8_UP_IRQn, #elif defined(SOC_SERIES_APM32F4) TMR8_UP_TMR13_IRQn, #endif }, #endif #ifdef BSP_USING_TMR9 { "timer9", TMR9, TMR1_BRK_TMR9_IRQn, }, #endif #ifdef BSP_USING_TMR10 { "timer10", TMR10, TMR1_UP_TMR10_IRQn, }, #endif #ifdef BSP_USING_TMR11 { "timer11", TMR11, TMR1_TRG_COM_TMR11_IRQn, }, #endif #ifdef BSP_USING_TMR12 { "timer12", TMR12, TMR8_BRK_TMR12_IRQn, }, #endif #ifdef BSP_USING_TMR13 { "timer13", TMR13, TMR8_UP_TMR13_IRQn, }, #endif #ifdef BSP_USING_TMR14 { "timer14", TMR14, #if defined(SOC_SERIES_APM32F0) TMR14_IRQn, #elif defined(SOC_SERIES_APM32F4) TMR8_TRG_COM_TMR14_IRQn, #endif }, #endif #ifdef BSP_USING_TMR15 { "timer15", TMR15, TMR15_IRQn, }, #endif #ifdef BSP_USING_TMR16 { "timer16", TMR16, TMR16_IRQn, }, #endif #ifdef BSP_USING_TMR17 { "timer17", TMR17, TMR17_IRQn, }, #endif }; static rt_uint32_t apm32_hwtimer_clock_get(TMR_T *tmr) { #if defined(SOC_SERIES_APM32F0) uint32_t pclk1; pclk1 = RCM_ReadPCLKFreq(); return (rt_uint32_t)(pclk1 * ((RCM->CFG1_B.APB1PSC != 0) ? 2 : 1)); #else uint32_t pclk1, pclk2; RCM_ReadPCLKFreq(&pclk1, &pclk2); if (tmr == TMR1 || tmr == TMR8 || tmr == TMR9 || tmr == TMR10 || tmr == TMR11) { return (rt_uint32_t)(pclk2 * ((RCM->CFG_B.APB2PSC != 0) ? 2 : 1)); } else { return (rt_uint32_t)(pclk1 * ((RCM->CFG_B.APB1PSC != 0) ? 2 : 1)); } #endif } static void apm32_hwtimer_enable_clock(void) { #ifdef BSP_USING_TMR1 RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_TMR1); #endif #ifdef BSP_USING_TMR2 RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_TMR2); #endif #ifdef BSP_USING_TMR3 RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_TMR3); #endif #ifdef BSP_USING_TMR4 RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_TMR4); #endif #ifdef BSP_USING_TMR5 RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_TMR5); #endif #ifdef BSP_USING_TMR6 RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_TMR6); #endif #ifdef BSP_USING_TMR7 RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_TMR7); #endif #ifdef BSP_USING_TMR8 RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_TMR8); #endif #ifdef BSP_USING_TMR9 RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_TMR9); #endif #ifdef BSP_USING_TMR10 RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_TMR10); #endif #ifdef BSP_USING_TMR11 RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_TMR11); #endif #ifdef BSP_USING_TMR12 RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_TMR12); #endif #ifdef BSP_USING_TMR13 RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_TMR13); #endif #ifdef BSP_USING_TMR14 RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_TMR14); #endif #ifdef BSP_USING_TMR15 RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_TMR15); #endif #ifdef BSP_USING_TMR16 RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_TMR16); #endif #ifdef BSP_USING_TMR17 RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_TMR17); #endif } static void apm32_hwtimer_init(struct rt_hwtimer_device *timer, rt_uint32_t state) { #if defined(SOC_SERIES_APM32F0) TMR_TimeBase_T base_config; #else TMR_BaseConfig_T base_config; #endif uint32_t prescaler = 0; struct apm32_timer *timer_config; RT_ASSERT(timer != RT_NULL); if (state) { timer_config = (struct apm32_timer *)timer->parent.user_data; apm32_hwtimer_enable_clock(); prescaler = (uint32_t)(apm32_hwtimer_clock_get(timer_config->tmr) / 10000) - 1; base_config.period = 10000 - 1; #if defined(SOC_SERIES_APM32F0) base_config.div = prescaler; base_config.clockDivision = TMR_CKD_DIV1; if (timer->info->cntmode == HWTIMER_CNTMODE_UP) { base_config.counterMode = TMR_COUNTER_MODE_UP; } else { base_config.counterMode = TMR_COUNTER_MODE_DOWN; } #else base_config.division = prescaler; base_config.clockDivision = TMR_CLOCK_DIV_1; if (timer->info->cntmode == HWTIMER_CNTMODE_UP) { base_config.countMode = TMR_COUNTER_MODE_UP; } else { base_config.countMode = TMR_COUNTER_MODE_DOWN; } #endif base_config.repetitionCounter = 0; TMR_ConfigTimeBase(timer_config->tmr, &base_config); #if defined(SOC_SERIES_APM32F0) /* set the TIMx priority */ NVIC_EnableIRQRequest(timer_config->irqn, 3); /* enable update request source */ TMR_ConfigUPdateRequest(timer_config->tmr, TMR_UPDATE_SOURCE_REGULAR); #else /* set the TIMx priority */ NVIC_EnableIRQRequest(timer_config->irqn, 3, 0); /* enable update request source */ TMR_ConfigUpdateRequest(timer_config->tmr, TMR_UPDATE_SOURCE_REGULAR); #endif /* clear update flag */ TMR_ClearStatusFlag(timer_config->tmr, TMR_FLAG_UPDATE); LOG_D("%s init success", timer_config->name); } } static rt_err_t apm32_hwtimer_start(rt_hwtimer_t *timer, rt_uint32_t t, rt_hwtimer_mode_t opmode) { rt_err_t result = RT_EOK; struct apm32_timer *timer_config = RT_NULL; RT_ASSERT(timer != RT_NULL); timer_config = (struct apm32_timer *)timer->parent.user_data; /* set timer_config counter */ timer_config->tmr->CNT = 0; /* set timer_config autoReload */ timer_config->tmr->AUTORLD = t - 1; if (opmode == HWTIMER_MODE_ONESHOT) { /* set timer to single mode */ timer_config->tmr->CTRL1_B.SPMEN = 1; } else { timer_config->tmr->CTRL1_B.SPMEN = 0; } TMR_EnableInterrupt(timer_config->tmr, TMR_INT_UPDATE); #if defined(SOC_SERIES_APM32F0) if (timer_config->tmr == TMR1 || timer_config->tmr == TMR2 || timer_config->tmr == TMR3 || \ timer_config->tmr == TMR15) #else if (timer_config->tmr == TMR1 || timer_config->tmr == TMR2 || timer_config->tmr == TMR3 || \ timer_config->tmr == TMR4 || timer_config->tmr == TMR5 || timer_config->tmr == TMR8 || \ timer_config->tmr == TMR9 || timer_config->tmr == TMR12) #endif { if (timer_config->tmr->SMCTRL_B.SMFSEL != 0x06) { TMR_Enable(timer_config->tmr); result = RT_EOK; } } else { TMR_Enable(timer_config->tmr); result = RT_EOK; } return result; } static void apm32_hwtimer_stop(rt_hwtimer_t *timer) { struct apm32_timer *timer_config = RT_NULL; RT_ASSERT(timer != RT_NULL); timer_config = (struct apm32_timer *)timer->parent.user_data; TMR_DisableInterrupt(timer_config->tmr, TMR_INT_UPDATE); TMR_Enable(timer_config->tmr); timer_config->tmr->CNT = 0; } static rt_err_t apm32_hwtimer_ctrl(rt_hwtimer_t *timer, rt_uint32_t cmd, void *arg) { struct apm32_timer *timer_config = RT_NULL; rt_err_t result = RT_EOK; rt_uint32_t freq; rt_uint16_t val; RT_ASSERT(timer != RT_NULL); RT_ASSERT(arg != RT_NULL); timer_config = (struct apm32_timer *)timer->parent.user_data; switch (cmd) { case HWTIMER_CTRL_FREQ_SET: /* set timer frequence */ freq = *((rt_uint32_t *)arg); val = apm32_hwtimer_clock_get(timer_config->tmr) / freq; /* Configures the timer prescaler */ timer_config->tmr->PSC_B.PSC = val - 1; timer_config->tmr->CEG_B.UEG = 1; break; default: LOG_E("invalid cmd: 0x%x\n", cmd); result = -RT_ENOSYS; break; } return result; } static rt_uint32_t apm32_hwtimer_counter_get(rt_hwtimer_t *timer) { struct apm32_timer *timer_config = RT_NULL; RT_ASSERT(timer != RT_NULL); timer_config = (struct apm32_timer *)timer->parent.user_data; return timer_config->tmr->CNT; } static const struct rt_hwtimer_ops apm32_hwtimer_ops = { .init = apm32_hwtimer_init, .start = apm32_hwtimer_start, .stop = apm32_hwtimer_stop, .count_get = apm32_hwtimer_counter_get, .control = apm32_hwtimer_ctrl, }; #if defined(SOC_SERIES_APM32F0) #ifdef BSP_USING_TMR1 void TMR1_BRK_UP_TRG_COM_IRQHandler(void) { rt_interrupt_enter(); rt_device_hwtimer_isr(&tmr_config[TMR1_INDEX].device); TMR_ClearIntFlag(TMR1, TMR_INT_UPDATE); rt_interrupt_leave(); } #endif #elif defined(SOC_SERIES_APM32F1) #ifdef BSP_USING_TMR1 void TMR1_UP_IRQHandler(void) { rt_interrupt_enter(); rt_device_hwtimer_isr(&tmr_config[TMR1_INDEX].device); TMR_ClearIntFlag(TMR1, TMR_INT_UPDATE); rt_interrupt_leave(); } #endif #elif defined(SOC_SERIES_APM32F4) #if (defined(BSP_USING_TMR1) || defined(BSP_USING_TMR10)) void TMR1_UP_TMR10_IRQHandler(void) { rt_interrupt_enter(); if (TMR_ReadIntFlag(TMR1, TMR_INT_UPDATE)) { rt_device_hwtimer_isr(&tmr_config[TMR1_INDEX].device); TMR_ClearIntFlag(TMR1, TMR_INT_UPDATE); } if (TMR_ReadIntFlag(TMR10, TMR_INT_UPDATE)) { rt_device_hwtimer_isr(&tmr_config[TMR10_INDEX].device); TMR_ClearIntFlag(TMR10, TMR_INT_UPDATE); } rt_interrupt_leave(); } #endif #endif #ifdef BSP_USING_TMR2 void TMR2_IRQHandler(void) { rt_interrupt_enter(); rt_device_hwtimer_isr(&tmr_config[TMR2_INDEX].device); TMR_ClearIntFlag(TMR2, TMR_INT_UPDATE); rt_interrupt_leave(); } #endif #ifdef BSP_USING_TMR3 void TMR3_IRQHandler(void) { rt_interrupt_enter(); rt_device_hwtimer_isr(&tmr_config[TMR3_INDEX].device); TMR_ClearIntFlag(TMR3, TMR_INT_UPDATE); rt_interrupt_leave(); } #endif #ifdef BSP_USING_TMR4 void TMR4_IRQHandler(void) { rt_interrupt_enter(); rt_device_hwtimer_isr(&tmr_config[TMR4_INDEX].device); TMR_ClearIntFlag(TMR4, TMR_INT_UPDATE); rt_interrupt_leave(); } #endif #ifdef BSP_USING_TMR5 void TMR5_IRQHandler(void) { rt_interrupt_enter(); rt_device_hwtimer_isr(&tmr_config[TMR5_INDEX].device); TMR_ClearIntFlag(TMR5, TMR_INT_UPDATE); rt_interrupt_leave(); } #endif #ifdef BSP_USING_TMR6 #if defined(SOC_SERIES_APM32F1) || defined(APM32F030) || defined(APM32F070) void TMR6_IRQHandler(void) #elif defined(SOC_SERIES_APM32F4) void TMR6_DAC_IRQHandler(void) #elif defined(SOC_SERIES_APM32F0) && !defined(APM32F030) && !defined(APM32F070) void TMR6_DAC_IRQHandler(void) #endif { rt_interrupt_enter(); rt_device_hwtimer_isr(&tmr_config[TMR6_INDEX].device); TMR_ClearIntFlag(TMR6, TMR_INT_UPDATE); rt_interrupt_leave(); } #endif #ifdef BSP_USING_TMR7 void TMR7_IRQHandler(void) { rt_interrupt_enter(); rt_device_hwtimer_isr(&tmr_config[TMR7_INDEX].device); TMR_ClearIntFlag(TMR7, TMR_INT_UPDATE); rt_interrupt_leave(); } #endif #if defined(SOC_SERIES_APM32F1) #ifdef BSP_USING_TMR8 void TMR8_UP_IRQHandler(void) { rt_interrupt_enter(); rt_device_hwtimer_isr(&tmr_config[TMR8_INDEX].device); TMR_ClearIntFlag(TMR8, TMR_INT_UPDATE); rt_interrupt_leave(); } #endif #elif defined(SOC_SERIES_APM32F4) #if (defined(BSP_USING_TMR8) || defined(BSP_USING_TMR13)) void TMR8_UP_TMR13_IRQHandler(void) { rt_interrupt_enter(); if (TMR_ReadIntFlag(TMR8, TMR_INT_UPDATE)) { rt_device_hwtimer_isr(&tmr_config[TMR8_INDEX].device); TMR_ClearIntFlag(TMR8, TMR_INT_UPDATE); } if (TMR_ReadIntFlag(TMR13, TMR_INT_UPDATE)) { rt_device_hwtimer_isr(&tmr_config[TMR13_INDEX].device); TMR_ClearIntFlag(TMR13, TMR_INT_UPDATE); } rt_interrupt_leave(); } #endif #endif #ifdef BSP_USING_TMR9 void TMR1_BRK_TMR9_IRQHandler(void) { rt_interrupt_enter(); rt_device_hwtimer_isr(&tmr_config[TMR9_INDEX].device); TMR_ClearIntFlag(TMR9, TMR_INT_UPDATE); rt_interrupt_leave(); } #endif #ifdef BSP_USING_TMR11 void TMR1_TRG_COM_TMR11_IRQHandler(void) { rt_interrupt_enter(); rt_device_hwtimer_isr(&tmr_config[TMR11_INDEX].device); TMR_ClearIntFlag(TMR11, TMR_INT_UPDATE); rt_interrupt_leave(); } #endif #ifdef BSP_USING_TMR12 void TMR8_BRK_TMR12_IRQHandler(void) { rt_interrupt_enter(); rt_device_hwtimer_isr(&tmr_config[TMR12_INDEX].device); TMR_ClearIntFlag(TMR12, TMR_INT_UPDATE); rt_interrupt_leave(); } #endif #ifdef BSP_USING_TMR14 #if defined(SOC_SERIES_APM32F0) void TMR14_IRQHandler(void) #elif defined(SOC_SERIES_APM32F4) void TMR8_TRG_COM_TMR14_IRQHandler(void) #endif { rt_interrupt_enter(); rt_device_hwtimer_isr(&tmr_config[TMR14_INDEX].device); TMR_ClearIntFlag(TMR14, TMR_INT_UPDATE); rt_interrupt_leave(); } #endif #ifdef BSP_USING_TMR15 void TMR15_IRQHandler(void) { rt_interrupt_enter(); rt_device_hwtimer_isr(&tmr_config[TMR15_INDEX].device); TMR_ClearIntFlag(TMR15, TMR_INT_UPDATE); rt_interrupt_leave(); } #endif #ifdef BSP_USING_TMR16 void TMR16_IRQHandler(void) { rt_interrupt_enter(); rt_device_hwtimer_isr(&tmr_config[TMR16_INDEX].device); TMR_ClearIntFlag(TMR16, TMR_INT_UPDATE); rt_interrupt_leave(); } #endif #ifdef BSP_USING_TMR17 void TMR17_IRQHandler(void) { rt_interrupt_enter(); rt_device_hwtimer_isr(&tmr_config[TMR17_INDEX].device); TMR_ClearIntFlag(TMR17, TMR_INT_UPDATE); rt_interrupt_leave(); } #endif static int rt_hw_hwtimer_init(void) { int i = 0; int result = RT_EOK; for (i = 0; i < sizeof(tmr_config) / sizeof(tmr_config[0]); i++) { tmr_config[i].device.info = &apm32_timer_info; tmr_config[i].device.ops = &apm32_hwtimer_ops; if (rt_device_hwtimer_register(&tmr_config[i].device, tmr_config[i].name, &tmr_config[i]) == RT_EOK) { LOG_D("%s register success", tmr_config[i].name); } else { LOG_E("%s register failed", tmr_config[i].name); result = -RT_ERROR; } } return result; } INIT_BOARD_EXPORT(rt_hw_hwtimer_init); #endif /* RT_USING_HWTIMER */