123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631 |
- /*
- * 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 <board.h>
- #ifdef RT_USING_PWM
- #include <drivers/rt_drv_pwm.h>
- #define DBG_TAG "drv.pwm"
- #define DBG_LVL DBG_INFO
- #include <rtdbg.h>
- #define MAX_PERIOD 65535
- #define MIN_PERIOD 3
- #define MIN_PULSE 2
- /* Init timer gpio and enable clock */
- extern void apm32_msp_timer_init(void *Instance);
- enum
- {
- #ifdef BSP_USING_PWM1
- PWM1_INDEX,
- #endif
- #ifdef BSP_USING_PWM2
- PWM2_INDEX,
- #endif
- #ifdef BSP_USING_PWM3
- PWM3_INDEX,
- #endif
- #ifdef BSP_USING_PWM4
- PWM4_INDEX,
- #endif
- #ifdef BSP_USING_PWM5
- PWM5_INDEX,
- #endif
- #ifdef BSP_USING_PWM8
- PWM8_INDEX,
- #endif
- #ifdef BSP_USING_PWM9
- PWM9_INDEX,
- #endif
- #ifdef BSP_USING_PWM10
- PWM10_INDEX,
- #endif
- #ifdef BSP_USING_PWM11
- PWM11_INDEX,
- #endif
- #ifdef BSP_USING_PWM12
- PWM12_INDEX,
- #endif
- #ifdef BSP_USING_PWM13
- PWM13_INDEX,
- #endif
- #ifdef BSP_USING_PWM14
- PWM14_INDEX,
- #endif
- #ifdef BSP_USING_PWM15
- PWM15_INDEX,
- #endif
- #ifdef BSP_USING_PWM16
- PWM16_INDEX,
- #endif
- #ifdef BSP_USING_PWM17
- PWM17_INDEX,
- #endif
- };
- struct apm32_pwm
- {
- char *name;
- TMR_T *tmr;
- rt_uint8_t channel;
- struct rt_device_pwm pwm_device;
- };
- static struct apm32_pwm pwm_config[] =
- {
- #ifdef BSP_USING_PWM1
- {
- "pwm1",
- TMR1,
- 0,
- },
- #endif
- #ifdef BSP_USING_PWM2
- {
- "pwm2",
- TMR2,
- 0,
- },
- #endif
- #ifdef BSP_USING_PWM3
- {
- "pwm3",
- TMR3,
- 0,
- },
- #endif
- #ifdef BSP_USING_PWM4
- {
- "pwm4",
- TMR4,
- 0,
- },
- #endif
- #ifdef BSP_USING_PWM5
- {
- "pwm5",
- TMR5,
- 0,
- },
- #endif
- #ifdef BSP_USING_PWM8
- {
- "pwm8",
- TMR8,
- 0,
- },
- #endif
- #ifdef BSP_USING_PWM9
- {
- "pwm9",
- TMR9,
- 0,
- },
- #endif
- #ifdef BSP_USING_PWM10
- {
- "pwm10",
- TMR10,
- 0,
- },
- #endif
- #ifdef BSP_USING_PWM11
- {
- "pwm11",
- TMR11,
- 0,
- },
- #endif
- #ifdef BSP_USING_PWM12
- {
- "pwm12",
- TMR12,
- 0,
- },
- #endif
- #ifdef BSP_USING_PWM13
- {
- "pwm13",
- TMR13,
- 0,
- },
- #endif
- #ifdef BSP_USING_PWM14
- {
- "pwm14",
- TMR14,
- 0,
- },
- #endif
- #ifdef BSP_USING_PWM15
- {
- "pwm15",
- TMR15,
- 0,
- },
- #endif
- #ifdef BSP_USING_PWM16
- {
- "pwm16",
- TMR16,
- 0,
- },
- #endif
- #ifdef BSP_USING_PWM17
- {
- "pwm17",
- TMR17,
- 0,
- },
- #endif
- };
- static void pwm_channel_init(void)
- {
- #ifdef BSP_USING_PWM1_CH1
- pwm_config[PWM1_INDEX].channel |= 1 << 0;
- #endif
- #ifdef BSP_USING_PWM1_CH2
- pwm_config[PWM1_INDEX].channel |= 1 << 1;
- #endif
- #ifdef BSP_USING_PWM1_CH3
- pwm_config[PWM1_INDEX].channel |= 1 << 2;
- #endif
- #ifdef BSP_USING_PWM1_CH4
- pwm_config[PWM1_INDEX].channel |= 1 << 3;
- #endif
- #ifdef BSP_USING_PWM2_CH1
- pwm_config[PWM2_INDEX].channel |= 1 << 0;
- #endif
- #ifdef BSP_USING_PWM2_CH2
- pwm_config[PWM2_INDEX].channel |= 1 << 1;
- #endif
- #ifdef BSP_USING_PWM2_CH3
- pwm_config[PWM2_INDEX].channel |= 1 << 2;
- #endif
- #ifdef BSP_USING_PWM2_CH4
- pwm_config[PWM2_INDEX].channel |= 1 << 3;
- #endif
- #ifdef BSP_USING_PWM3_CH1
- pwm_config[PWM3_INDEX].channel |= 1 << 0;
- #endif
- #ifdef BSP_USING_PWM3_CH2
- pwm_config[PWM3_INDEX].channel |= 1 << 1;
- #endif
- #ifdef BSP_USING_PWM3_CH3
- pwm_config[PWM3_INDEX].channel |= 1 << 2;
- #endif
- #ifdef BSP_USING_PWM3_CH4
- pwm_config[PWM3_INDEX].channel |= 1 << 3;
- #endif
- #ifdef BSP_USING_PWM4_CH1
- pwm_config[PWM4_INDEX].channel |= 1 << 0;
- #endif
- #ifdef BSP_USING_PWM4_CH2
- pwm_config[PWM4_INDEX].channel |= 1 << 1;
- #endif
- #ifdef BSP_USING_PWM4_CH3
- pwm_config[PWM4_INDEX].channel |= 1 << 2;
- #endif
- #ifdef BSP_USING_PWM4_CH4
- pwm_config[PWM4_INDEX].channel |= 1 << 3;
- #endif
- #ifdef BSP_USING_PWM5_CH1
- pwm_config[PWM5_INDEX].channel |= 1 << 0;
- #endif
- #ifdef BSP_USING_PWM5_CH2
- pwm_config[PWM5_INDEX].channel |= 1 << 1;
- #endif
- #ifdef BSP_USING_PWM5_CH3
- pwm_config[PWM5_INDEX].channel |= 1 << 2;
- #endif
- #ifdef BSP_USING_PWM5_CH4
- pwm_config[PWM5_INDEX].channel |= 1 << 3;
- #endif
- #ifdef BSP_USING_PWM8_CH1
- pwm_config[PWM8_INDEX].channel |= 1 << 0;
- #endif
- #ifdef BSP_USING_PWM8_CH2
- pwm_config[PWM8_INDEX].channel |= 1 << 1;
- #endif
- #ifdef BSP_USING_PWM8_CH3
- pwm_config[PWM8_INDEX].channel |= 1 << 2;
- #endif
- #ifdef BSP_USING_PWM8_CH4
- pwm_config[PWM8_INDEX].channel |= 1 << 3;
- #endif
- #ifdef BSP_USING_PWM9_CH1
- pwm_config[PWM9_INDEX].channel |= 1 << 0;
- #endif
- #ifdef BSP_USING_PWM9_CH2
- pwm_config[PWM9_INDEX].channel |= 1 << 1;
- #endif
- #ifdef BSP_USING_PWM10_CH1
- pwm_config[PWM10_INDEX].channel |= 1 << 0;
- #endif
- #ifdef BSP_USING_PWM11_CH1
- pwm_config[PWM11_INDEX].channel |= 1 << 0;
- #endif
- #ifdef BSP_USING_PWM12_CH1
- pwm_config[PWM12_INDEX].channel |= 1 << 0;
- #endif
- #ifdef BSP_USING_PWM12_CH2
- pwm_config[PWM12_INDEX].channel |= 1 << 1;
- #endif
- #ifdef BSP_USING_PWM13_CH1
- pwm_config[PWM13_INDEX].channel |= 1 << 0;
- #endif
- #ifdef BSP_USING_PWM14_CH1
- pwm_config[PWM14_INDEX].channel |= 1 << 0;
- #endif
- #ifdef BSP_USING_PWM15_CH1
- pwm_config[PWM15_INDEX].channel |= 1 << 0;
- #endif
- #ifdef BSP_USING_PWM15_CH2
- pwm_config[PWM15_INDEX].channel |= 1 << 1;
- #endif
- #ifdef BSP_USING_PWM16_CH1
- pwm_config[PWM16_INDEX].channel |= 1 << 0;
- #endif
- #ifdef BSP_USING_PWM17_CH1
- pwm_config[PWM17_INDEX].channel |= 1 << 0;
- #endif
- }
- static rt_err_t apm32_pwm_hw_init(struct apm32_pwm *device)
- {
- rt_err_t result = RT_EOK;
- TMR_T *tmr = RT_NULL;
- RT_ASSERT(device != RT_NULL);
- tmr = (TMR_T *)device->tmr;
- /* Init timer gpio and enable clock */
- apm32_msp_timer_init(tmr);
- #if defined(SOC_SERIES_APM32F0)
- TMR_TimeBase_T base_config;
- TMR_OCConfig_T oc_config;
- /* configure the tmrer to pwm mode */
- base_config.div = 0;
- base_config.counterMode = TMR_COUNTER_MODE_UP;
- base_config.period = 0;
- base_config.clockDivision = TMR_CKD_DIV1;
- TMR_ConfigTimeBase(tmr, &base_config);
- TMR_SelectOutputTrigger(tmr, TMR_TRGOSOURCE_RESET);
- TMR_DisableMasterSlaveMode(tmr);
- oc_config.OC_Mode = TMR_OC_MODE_PWM1;
- oc_config.Pulse = 0;
- oc_config.OC_Polarity = TMR_OC_POLARITY_HIGH;
- oc_config.OC_NIdlestate = TMR_OCNIDLESTATE_RESET;
- oc_config.OC_Idlestate = TMR_OCIDLESTATE_RESET;
- oc_config.OC_OutputState = TMR_OUTPUT_STATE_ENABLE;
- /* config pwm channel */
- if (device->channel & 0x01)
- {
- TMR_OC1Config(tmr, &oc_config);
- }
- if (device->channel & 0x02)
- {
- TMR_OC2Config(tmr, &oc_config);
- }
- if (device->channel & 0x04)
- {
- TMR_OC3Config(tmr, &oc_config);
- }
- if (device->channel & 0x08)
- {
- TMR_OC4Config(tmr, &oc_config);
- }
- /* enable update request source */
- TMR_ConfigUPdateRequest(tmr, TMR_UPDATE_SOURCE_REGULAR);
- #else
- TMR_BaseConfig_T base_config;
- TMR_OCConfig_T oc_config;
- /* configure the tmrer to pwm mode */
- base_config.division = 0;
- base_config.countMode = TMR_COUNTER_MODE_UP;
- base_config.period = 0;
- base_config.clockDivision = TMR_CLOCK_DIV_1;
- TMR_ConfigTimeBase(tmr, &base_config);
- TMR_SelectOutputTrigger(tmr, TMR_TRGO_SOURCE_RESET);
- TMR_DisableMasterSlaveMode(tmr);
- oc_config.mode = TMR_OC_MODE_PWM1;
- oc_config.pulse = 0;
- oc_config.polarity = TMR_OC_POLARITY_HIGH;
- oc_config.nIdleState = TMR_OC_NIDLE_STATE_RESET;
- oc_config.idleState = TMR_OC_IDLE_STATE_RESET;
- oc_config.outputState = TMR_OC_STATE_ENABLE;
- /* config pwm channel */
- if (device->channel & 0x01)
- {
- TMR_ConfigOC1(tmr, &oc_config);
- }
- if (device->channel & 0x02)
- {
- TMR_ConfigOC2(tmr, &oc_config);
- }
- if (device->channel & 0x04)
- {
- TMR_ConfigOC3(tmr, &oc_config);
- }
- if (device->channel & 0x08)
- {
- TMR_ConfigOC4(tmr, &oc_config);
- }
- /* enable update request source */
- TMR_ConfigUpdateRequest(tmr, TMR_UPDATE_SOURCE_REGULAR);
- #endif
- return result;
- }
- static rt_uint32_t timer_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 rt_err_t drv_pwm_enable(TMR_T *tmr, struct rt_pwm_configuration *configuration, rt_bool_t enable)
- {
- rt_uint32_t channel = (configuration->channel - 1) << 2;
- if (enable)
- {
- if (configuration->complementary)
- {
- TMR_EnableCCxNChannel(tmr, (TMR_CHANNEL_T)(0x01 << (channel & 0x1FU)));
- }
- else
- {
- TMR_EnableCCxChannel(tmr, (TMR_CHANNEL_T)(0x01 << (channel & 0x1FU)));
- }
- #if defined(SOC_SERIES_APM32F0)
- if (tmr == TMR1 || tmr == TMR15 || tmr == TMR16 || tmr == TMR17)
- #else
- if (tmr == TMR1 || tmr == TMR8)
- #endif
- {
- TMR_EnablePWMOutputs(tmr);
- }
- TMR_Enable(tmr);
- }
- else
- {
- if (configuration->complementary)
- {
- TMR_DisableCCxNChannel(tmr, (TMR_CHANNEL_T)(0x01 << (channel & 0x1FU)));
- }
- else
- {
- TMR_DisableCCxChannel(tmr, (TMR_CHANNEL_T)(0x01 << (channel & 0x1FU)));
- }
- #if defined(SOC_SERIES_APM32F0)
- if (tmr == TMR1 || tmr == TMR15 || tmr == TMR16 || tmr == TMR17)
- #else
- if (tmr == TMR1 || tmr == TMR8)
- #endif
- {
- TMR_DisablePWMOutputs(tmr);
- }
- TMR_Disable(tmr);
- }
- return RT_EOK;
- }
- static rt_err_t drv_pwm_get(TMR_T *tmr, struct rt_pwm_configuration *configuration)
- {
- /* Converts the channel number to the channel number of library */
- rt_uint32_t channel = (configuration->channel - 1) << 2;
- rt_uint64_t timer_clock;
- rt_uint32_t timer_reload, timer_psc;
- timer_clock = timer_clock_get(tmr);
- #if defined(SOC_SERIES_APM32F0)
- if (tmr->CTRL1_B.CLKDIV == TMR_CKD_DIV2)
- #else
- if (tmr->CTRL1_B.CLKDIV == TMR_CLOCK_DIV_2)
- #endif
- {
- timer_clock = timer_clock / 2;
- }
- #if defined(SOC_SERIES_APM32F0)
- if (tmr->CTRL1_B.CLKDIV == TMR_CKD_DIV4)
- #else
- else if (tmr->CTRL1_B.CLKDIV == TMR_CLOCK_DIV_4)
- #endif
- {
- timer_clock = timer_clock / 4;
- }
- uint32_t temp;
- temp = (uint32_t)tmr;
- temp += (uint32_t)(0x34 + channel);
- /* Convert nanosecond to frequency and duty cycle.*/
- timer_clock /= 1000000UL;
- timer_reload = tmr->AUTORLD;
- timer_psc = tmr->PSC;
- configuration->period = (timer_reload + 1) * (timer_psc + 1) * 1000UL / timer_clock;
- configuration->pulse = ((*(__IO uint32_t *)temp) + 1) * (timer_psc + 1) * 1000UL / timer_clock;
- return RT_EOK;
- }
- static rt_err_t drv_pwm_set(TMR_T *tmr, struct rt_pwm_configuration *configuration)
- {
- rt_uint32_t period, pulse;
- rt_uint64_t timer_clock, psc;
- rt_uint32_t channel = 0x04 * (configuration->channel - 1);
- uint32_t temp = (uint32_t)tmr;
- timer_clock = timer_clock_get(tmr);
- /* Convert nanosecond to frequency and duty cycle. */
- timer_clock /= 1000000UL;
- period = (unsigned long long)configuration->period * timer_clock / 1000ULL ;
- psc = period / MAX_PERIOD + 1;
- period = period / psc;
- tmr->PSC = (uint16_t)(psc - 1);
- if (period < MIN_PERIOD)
- {
- period = MIN_PERIOD;
- }
- tmr->AUTORLD = (uint16_t)(period - 1);
- pulse = (unsigned long long)configuration->pulse * timer_clock / psc / 1000ULL;
- if (pulse < MIN_PULSE)
- {
- pulse = MIN_PULSE;
- }
- else if (pulse > period)
- {
- pulse = period;
- }
- temp += (uint32_t)(0x34 + channel);
- *(__IO uint32_t *)temp = pulse - 1;
- tmr->CNT = 0;
- /* Update frequency value */
- TMR_GenerateEvent(tmr, TMR_EVENT_UPDATE);
- return RT_EOK;
- }
- static rt_err_t drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
- {
- struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
- TMR_T *tmr = (TMR_T *)device->parent.user_data;
- switch (cmd)
- {
- case PWMN_CMD_ENABLE:
- configuration->complementary = RT_TRUE;
- case PWM_CMD_ENABLE:
- return drv_pwm_enable(tmr, configuration, RT_TRUE);
- case PWMN_CMD_DISABLE:
- configuration->complementary = RT_FALSE;
- case PWM_CMD_DISABLE:
- return drv_pwm_enable(tmr, configuration, RT_FALSE);
- case PWM_CMD_SET:
- return drv_pwm_set(tmr, configuration);
- case PWM_CMD_GET:
- return drv_pwm_get(tmr, configuration);
- default:
- return -RT_EINVAL;
- }
- }
- static const struct rt_pwm_ops drv_pwm_ops =
- {
- drv_pwm_control
- };
- static int rt_hw_pwm_init(void)
- {
- rt_uint32_t i = 0;
- rt_err_t result = RT_EOK;
- pwm_channel_init();
- for (i = 0; i < sizeof(pwm_config) / sizeof(pwm_config[0]); i++)
- {
- /* pwm init */
- if (apm32_pwm_hw_init(&pwm_config[i]) != RT_EOK)
- {
- LOG_E("%s init failed", pwm_config[i].name);
- return -RT_ERROR;
- }
- else
- {
- LOG_D("%s init success", pwm_config[i].name);
- /* register pwm device */
- if (rt_device_pwm_register(&pwm_config[i].pwm_device, pwm_config[i].name, &drv_pwm_ops, pwm_config[i].tmr) == RT_EOK)
- {
- LOG_D("%s register success", pwm_config[i].name);
- }
- else
- {
- LOG_E("%s register failed", pwm_config[i].name);
- result = -RT_ERROR;
- }
- }
- }
- return result;
- }
- INIT_DEVICE_EXPORT(rt_hw_pwm_init);
- #endif /* RT_USING_PWM */
|