/* * Copyright (C) 2018 Shanghai Eastsoft Microelectronics Co., Ltd. * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2019-03-11 wangyq the first version */ #include #include #include #include #include #include #include static void pwm_set_freq(timer_handle_t *timer_initstruct, uint32_t ns) { uint64_t _arr = (uint64_t)cmu_get_pclk1_clock() * ns / 1000000000 / (timer_initstruct->init.prescaler + 1); WRITE_REG(timer_initstruct->perh->AR, (uint32_t)_arr); timer_initstruct->init.period = (uint32_t)_arr; } static void pwm_set_duty(timer_handle_t *timer_initstruct, timer_channel_t ch, uint32_t ns) { uint64_t tmp = (uint64_t)cmu_get_pclk1_clock() * ns / 1000000000 / (timer_initstruct->init.prescaler + 1); if (ch == TIMER_CHANNEL_1) WRITE_REG(timer_initstruct->perh->CCVAL1, (uint32_t)tmp); else if (ch == TIMER_CHANNEL_2) WRITE_REG(timer_initstruct->perh->CCVAL2, (uint32_t)tmp); else if (ch == TIMER_CHANNEL_3) WRITE_REG(timer_initstruct->perh->CCVAL3, (uint32_t)tmp); else if (ch == TIMER_CHANNEL_4) WRITE_REG(timer_initstruct->perh->CCVAL4, (uint32_t)tmp); } static rt_err_t es32f0_pwm_control(struct rt_device_pwm *device, int cmd, void *arg) { rt_err_t ret = RT_EOK; uint32_t _ccep; timer_channel_t pwm_channel; timer_oc_init_t tim_ocinit; timer_handle_t *timer_initstruct = (timer_handle_t *)device->parent.user_data; struct rt_pwm_configuration *cfg = (struct rt_pwm_configuration *)arg; RT_ASSERT(timer_initstruct != RT_NULL); tim_ocinit.oc_mode = TIMER_OC_MODE_PWM1; tim_ocinit.oc_polarity = TIMER_OC_POLARITY_HIGH; tim_ocinit.oc_fast_en = DISABLE; tim_ocinit.ocn_polarity = TIMER_OCN_POLARITY_HIGH; tim_ocinit.ocn_idle = TIMER_OCN_IDLE_RESET; tim_ocinit.oc_idle = TIMER_OC_IDLE_RESET; /* select pwm output channel */ if (1 == cfg->channel) { pwm_channel = TIMER_CHANNEL_1; } else if (2 == cfg->channel) { pwm_channel = TIMER_CHANNEL_2; } else if (3 == cfg->channel) { if (timer_initstruct->perh == GP16C2T0 || timer_initstruct->perh == GP16C2T1) return RT_EINVAL; pwm_channel = TIMER_CHANNEL_3; } else if (4 == cfg->channel) { if (timer_initstruct->perh == GP16C2T0 || timer_initstruct->perh == GP16C2T1) return RT_EINVAL; pwm_channel = TIMER_CHANNEL_4; } else { return RT_EINVAL; } switch (cmd) { case PWM_CMD_ENABLE: timer_pwm_start(timer_initstruct, pwm_channel); break; case PWM_CMD_DISABLE: timer_pwm_stop(timer_initstruct, pwm_channel); break; case PWM_CMD_SET: _ccep = timer_initstruct->perh->CCEP; /* count registers max 0xFFFF, auto adjust prescaler */ do { pwm_set_freq(timer_initstruct, cfg->period); timer_initstruct->init.prescaler ++; } while (timer_initstruct->init.period > 0xFFFF); /* update prescaler */ WRITE_REG(timer_initstruct->perh->PRES, --timer_initstruct->init.prescaler); timer_oc_config_channel(timer_initstruct, &tim_ocinit, pwm_channel); pwm_set_duty(timer_initstruct, pwm_channel, cfg->pulse); timer_initstruct->perh->CCEP = _ccep; break; case PWM_CMD_GET: cfg->pulse = timer_read_capture_value(timer_initstruct, pwm_channel) * 100 / READ_REG(timer_initstruct->perh->AR); break; default: break; } return ret; } const static struct rt_pwm_ops es32f0_pwm_ops = { es32f0_pwm_control }; int rt_hw_pwm_init(void) { rt_err_t ret = RT_EOK; gpio_init_t gpio_initstructure; gpio_initstructure.mode = GPIO_MODE_OUTPUT; gpio_initstructure.odos = GPIO_PUSH_PULL; gpio_initstructure.pupd = GPIO_PUSH_UP; gpio_initstructure.odrv = GPIO_OUT_DRIVE_NORMAL; gpio_initstructure.flt = GPIO_FILTER_DISABLE; gpio_initstructure.type = GPIO_TYPE_TTL; #ifdef BSP_USING_PWM0 /* 4 channels */ static struct rt_device_pwm pwm_dev0; static timer_handle_t timer_initstruct0; timer_initstruct0.perh = AD16C4T0; timer_pwm_init(&timer_initstruct0); /* gpio initialization */ gpio_initstructure.func = GPIO_FUNC_2; gpio_init(GPIOA, GPIO_PIN_8, &gpio_initstructure); gpio_init(GPIOA, GPIO_PIN_9, &gpio_initstructure); gpio_init(GPIOA, GPIO_PIN_10, &gpio_initstructure); gpio_init(GPIOA, GPIO_PIN_11, &gpio_initstructure); ret = rt_device_pwm_register(&pwm_dev0, "pwm0", &es32f0_pwm_ops, &timer_initstruct0); #endif #ifdef BSP_USING_PWM1 /* 4 channels */ static struct rt_device_pwm pwm_dev1; static timer_handle_t timer_initstruct1; timer_initstruct1.perh = GP16C4T0; timer_pwm_init(&timer_initstruct1); /* gpio initialization */ gpio_initstructure.func = GPIO_FUNC_2; gpio_init(GPIOB, GPIO_PIN_6, &gpio_initstructure); gpio_init(GPIOB, GPIO_PIN_7, &gpio_initstructure); gpio_init(GPIOB, GPIO_PIN_8, &gpio_initstructure); gpio_init(GPIOB, GPIO_PIN_9, &gpio_initstructure); ret = rt_device_pwm_register(&pwm_dev1, "pwm1", &es32f0_pwm_ops, &timer_initstruct1); #endif #ifdef BSP_USING_PWM2 /* 2 channels */ static struct rt_device_pwm pwm_dev2; static timer_handle_t timer_initstruct2; timer_initstruct2.perh = GP16C2T0; timer_pwm_init(&timer_initstruct2); /* gpio initialization */ gpio_initstructure.func = GPIO_FUNC_2; gpio_init(GPIOA, GPIO_PIN_0, &gpio_initstructure); gpio_init(GPIOA, GPIO_PIN_1, &gpio_initstructure); ret = rt_device_pwm_register(&pwm_dev2, "pwm2", &es32f0_pwm_ops, &timer_initstruct2); #endif #ifdef BSP_USING_PWM3 /* 2 channels */ static struct rt_device_pwm pwm_dev3; static timer_handle_t timer_initstruct3; timer_initstruct3.perh = GP16C2T1; timer_pwm_init(&timer_initstruct3); /* gpio initialization */ gpio_initstructure.func = GPIO_FUNC_3; gpio_init(GPIOC, GPIO_PIN_6, &gpio_initstructure); gpio_init(GPIOC, GPIO_PIN_7, &gpio_initstructure); ret = rt_device_pwm_register(&pwm_dev3, "pwm3", &es32f0_pwm_ops, &timer_initstruct3); #endif return ret; } INIT_DEVICE_EXPORT(rt_hw_pwm_init);