大佬们,谁知道这个PWM的控制器怎么直接改变占空比啊?
-
我想用PWM+DMA去控制ws2812的灯
先讲为什么,这个芯片貌似只有一个LEDC的输出总线,也就是只有一条ws2812的灯串,但是我需要3条,那么PWM输出脚就很多,所以想拿来用一下顺便学一下那个DMA怎么用
感觉加个定时器应该不难
PWM控制用的是下面这个库
hal_pwm.c
我看了一圈有个hal_pwm_control
这个是可以去控制PWM的,也测试成功了
但是想要控制WS2812,这种灯需要直接把PWM的占空比当作01010101这种数据去输出我的想法是弄个定时器,周期就是800K的时钟周期(按ws2812需要的设置),每一个callback去设置一次占空比,直接用DMA从内存往占空比的那个寄存器写数据,这么搞应该可以吧
无奈这个库里面貌似没有直接改占空比的操作的函数,然后我就想从那个hal_pwm_control,里面扒出来,无奈的是没怎么看明白是怎么操作那个PWM寄存器的
所以想请教一下各位大佬怎么直接改寄存器,配置PWM占空比啊?我用的是Meils,谢谢啦
/* Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved. * Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in * the the People's Republic of China and other countries. * All Allwinner Technology Co.,Ltd. trademarks are used with permission. * DISCLAIMER * THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT. * IF YOU NEED TO INTEGRATE THIRD PARTY’S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.) * IN ALLWINNERS’SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN * ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES. * ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS * COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE. * YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY’S TECHNOLOGY. * THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT * PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND, * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING * THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE * OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * =========================================================================================== * * Filename: hal_pwm.c * * Description: pwm driver core hal,be used by drv_pwm.c * * Version: Melis3.0 * Create: 2019-12-23 * Revision: none * Compiler: GCC:version 9.2.1 20170904 (release),ARM/embedded-7-branch revision 255204 * * Author: liuyus@allwinnertech.com * Organization: SWC-BPD * Last Modified: 2019-12-31 17:55 * * =========================================================================================== */ #include <hal_log.h> #include <stdio.h> #include <stdint.h> #include <hal_clk.h> #include <hal_reset.h> #include <sunxi_hal_common.h> #include <sunxi_hal_pwm.h> #ifdef CONFIG_DRIVER_SYSCONFIG #include <hal_cfg.h> #include <script.h> #endif #ifdef CONFIG_STANDBY #include <standby/standby.h> #endif #ifdef CONFIG_COMPONENTS_PM #include <pm_devops.h> #endif hal_pwm_t sunxi_pwm; static int pwm_init = 0; #define SET_REG_VAL(reg_val, shift, width, set_val) ((reg_val & ~((-1UL) >> (32 - width) << shift)) | (set_val << shift)) #define pwm_do_div(n,base) ({ \ u32 __base = (base); \ u32 __rem; \ __rem = ((u64)(n)) % __base; \ (n) = ((u64)(n)) / __base; \ if (__rem > __base / 2) \ ++(n); \ __rem; \ }) /************** config *************************/ /* * pwm_set_clk_src(): pwm clock source selection * * @channel_in: pwm channel number * pwm01 pwm23 pwm45 pwm67 pwm89 * * @clk_src: The clock you want to set * 0:OSC24M 1:APB1 */ void hal_pwm_clk_src_set(uint32_t channel_in, hal_pwm_clk_src clk_src) { unsigned long reg_addr = PWM_BASE + PWM_PCCR_BASE; uint32_t reg_val; uint32_t channel = channel_in / 2; reg_addr += 4 * channel; /*set clock source OSC24M or apb1*/ reg_val = hal_readl(reg_addr); reg_val = SET_REG_VAL(reg_val, PWM_CLK_SRC_SHIFT, PWM_CLK_SRC_WIDTH, clk_src); hal_writel(reg_val, reg_addr); } /* * pwm_clk_div_m(): pwm clock divide * * @div_m: 1 2 4 8 16 32 64 128 256 */ void hal_pwm_clk_div_m(uint32_t channel_in, uint32_t div_m) { unsigned long reg_addr = PWM_BASE + PWM_PCCR_BASE; uint32_t reg_val; uint32_t channel = channel_in / 2; reg_addr += 4 * channel; /*set clock div_m*/ reg_val = hal_readl(reg_addr); reg_val = SET_REG_VAL(reg_val, PWM_DIV_M_SHIFT, PWM_DIV_M_WIDTH, div_m); hal_writel(reg_val, reg_addr); } void hal_pwm_prescal_set(uint32_t channel_in, uint32_t prescal) { unsigned long reg_addr = PWM_BASE + PWM_PCR; uint32_t reg_val; uint32_t channel = channel_in; reg_addr += 0x20 * channel; /*set prescal*/ reg_val = hal_readl(reg_addr); reg_val = SET_REG_VAL(reg_val, PWM_PRESCAL_SHIFT, PWM_PRESCAL_WIDTH, prescal); hal_writel(reg_val, reg_addr); } /* active cycles */ void hal_pwm_set_active_cycles(uint32_t channel_in, uint32_t active_cycles) //64 { unsigned long reg_addr = PWM_BASE + PWM_PPR ; uint32_t reg_val; uint32_t channel = channel_in; reg_addr += 0x20 * channel; /*set active*/ reg_val = hal_readl(reg_addr); reg_val = SET_REG_VAL(reg_val, PWM_ACTIVE_CYCLES_SHIFT, PWM_ACTIVE_CYCLES_WIDTH, active_cycles); hal_writel(reg_val, reg_addr); } /* entire cycles */ void hal_pwm_set_period_cycles(uint32_t channel_in, uint32_t period_cycles) { unsigned long reg_addr = PWM_BASE + PWM_PPR ; uint32_t reg_val; uint32_t channel = channel_in; reg_addr += 0x20 * channel; /*set clock BYPASS*/ reg_val = hal_readl(reg_addr); reg_val = SET_REG_VAL(reg_val, PWM_PERIOD_SHIFT, PWM_PERIOD_WIDTH, period_cycles); hal_writel(reg_val, reg_addr); } static uint32_t get_pccr_reg_offset(uint32_t channel) { uint32_t val; switch (channel) { case 0: case 1: return PWM_PCCR01; break; case 2: case 3: return PWM_PCCR23; break; case 4: case 5: return PWM_PCCR45; break; case 6: case 7: return PWM_PCCR67; break; #ifndef CONFIG_ARCH_SUN20IW2 case 8: case 9: return PWM_PCCR8; break; #endif default : PWM_ERR("channel is error \n"); return PWM_PCCR01; break; } } /************ enable **************/ void hal_pwm_enable_clk_gating(uint32_t channel_in) { unsigned long reg_addr = PWM_BASE + PWM_PCGR; uint32_t reg_val; uint32_t channel = channel_in / 2; /*enable clk_gating*/ reg_addr += 4 * channel; reg_val = hal_readl(reg_addr); reg_val = SET_REG_VAL(reg_val, PWM_CLK_GATING_SHIFT, PWM_CLK_GATING_WIDTH, 1); hal_writel(reg_val, reg_addr); } void hal_pwm_enable_controller(uint32_t channel_in) { unsigned long reg_addr = PWM_BASE + PWM_PER; uint32_t reg_val; reg_val = readl(reg_addr); reg_val |= 1 << channel_in; writel(reg_val, reg_addr); } /************ disable **************/ void hal_pwm_disable_controller(uint32_t channel_in) { unsigned long reg_val; unsigned long reg_addr = PWM_BASE + PWM_PER; reg_val = readl(reg_addr); reg_val |= 1 << channel_in; writel(reg_val, reg_addr); } /*************** polarity *****************/ void hal_pwm_porality(uint32_t channel_in, hal_pwm_polarity polarity) { uint32_t reg_val; unsigned long reg_addr = PWM_BASE + PWM_PCR; uint32_t channel = channel_in; reg_addr += 0x20 * channel; /*set polarity*/ reg_val = hal_readl(reg_addr); reg_val = SET_REG_VAL(reg_val, PWM_ACT_STA_SHIFT, PWM_ACT_STA_WIDTH, polarity); hal_writel(reg_val, reg_addr); } static int hal_pwm_pinctrl_init(hal_pwm_t sunxi_pwm, int channel) { #ifdef CONFIG_DRIVER_SYSCONFIG user_gpio_set_t gpio_cfg = {0}; char pwm_name[16]; int count, ret; sprintf(pwm_name, "pwm%d", channel); count = Hal_Cfg_GetGPIOSecKeyCount(pwm_name); if (!count) { PWM_ERR("[pwm%d] not support in sys_config\n", channel); return -1; } Hal_Cfg_GetGPIOSecData(pwm_name, &gpio_cfg, count); sunxi_pwm.pin[channel] = (gpio_cfg.port - 1) * 32 + gpio_cfg.port_num; sunxi_pwm.enable_muxsel[channel] = gpio_cfg.mul_sel; ret = hal_gpio_pinmux_set_function(sunxi_pwm.pin[channel], sunxi_pwm.enable_muxsel[channel]); if (ret) { PWM_ERR("[pwm%d] PIN%u set function failed! return %d\n", channel, sunxi_pwm.pin[channel], ret); return -1; } ret = hal_gpio_set_driving_level(sunxi_pwm.pin[channel], gpio_cfg.drv_level); if (ret) { PWM_ERR("[pwm%d] PIN%u set driving level failed! return %d\n", channel, gpio_cfg.drv_level, ret); return -1; } if (gpio_cfg.pull) { return hal_gpio_set_pull(sunxi_pwm.pin[channel], gpio_cfg.pull); } sunxi_pwm.pin_state[channel] = true; return 0; #else PWM_ERR("[pwm%d] not support in sys_config\n", channel); return -1; #endif } static int hal_pwm_pinctrl_exit(hal_pwm_t sunxi_pwm, uint32_t channel) { if (sunxi_pwm.pin[channel]) //sys_config { return hal_gpio_pinmux_set_function(sunxi_pwm.pin[channel], 0); //gpio_in } else { return hal_gpio_pinmux_set_function(pwm_gpio[channel].pwm_pin, 0); } } #ifdef CONFIG_STANDBY int hal_pwm_resume(void *dev) { if (hal_reset_control_assert(sunxi_pwm.pwm_reset)) { return -1; } if (hal_reset_control_deassert(sunxi_pwm.pwm_reset)) { return -1; } if (hal_clock_enable(sunxi_pwm.pwm_bus_clk)) { return -1; } PWM_INFO("hal pwm resume"); return 0; } int hal_pwm_suspend(void *dev) { if (hal_reset_control_assert(sunxi_pwm.pwm_reset)) { return -1; } if (hal_clock_disable(sunxi_pwm.pwm_bus_clk)) { return -1; } PWM_INFO("hal pwm suspend"); return 0; } #endif #ifdef CONFIG_COMPONENTS_PM static inline void sunxi_pwm_save_regs(hal_pwm_t *pwm) { int i; for (i = 0; i < ARRAY_SIZE(hal_pwm_regs_offset); i++) pwm->regs_backup[i] = readl(PWM_BASE + hal_pwm_regs_offset[i]); } static inline void sunxi_pwm_restore_regs(hal_pwm_t *pwm) { int i; for (i = 0; i < ARRAY_SIZE(hal_pwm_regs_offset); i++) writel(pwm->regs_backup[i], PWM_BASE + hal_pwm_regs_offset[i]); } static int sunxi_pwm_resume(struct pm_device *dev, suspend_mode_t mode) { hal_pwm_t *pwm = &sunxi_pwm; int i, err; hal_reset_control_reset(sunxi_pwm.pwm_reset); hal_clock_enable(sunxi_pwm.pwm_bus_clk); for (i = 0; i < PWM_NUM; i++) { if (sunxi_pwm.pin_state[i]) { PWM_INFO("the pwm%d is resume\n", i); sunxi_pwm.pin_state[i] = false; err = hal_pwm_pinctrl_init(sunxi_pwm, i); if (err) { err = hal_gpio_pinmux_set_function(pwm_gpio[i].pwm_pin, pwm_gpio[i].pwm_function); if (err) { PWM_ERR("pinmux set failed\n"); return -1; } sunxi_pwm.pin_state[i] = true; } } } sunxi_pwm_restore_regs(pwm); PWM_INFO("hal pwm resume\n"); return 0; } static int sunxi_pwm_suspend(struct pm_device *dev, suspend_mode_t mode) { hal_pwm_t *pwm = &sunxi_pwm; int i; sunxi_pwm_save_regs(pwm); for (i = 0; i < PWM_NUM; i++) hal_pwm_pinctrl_exit(sunxi_pwm, i); hal_clock_disable(sunxi_pwm.pwm_bus_clk); hal_reset_control_assert(sunxi_pwm.pwm_reset); PWM_INFO("hal pwm suspend\n"); return 0; } struct pm_devops pm_pwm_ops = { .suspend = sunxi_pwm_suspend, .resume = sunxi_pwm_resume, }; struct pm_device pm_pwm = { .name = "sunxi_pwm", .ops = &pm_pwm_ops, }; #endif pwm_status_t hal_pwm_init(void) { int i; PWM_INFO("pwm init start"); if (pwm_init) { pwm_init++; return 0; } sunxi_pwm.pwm_clk_type = SUNXI_PWM_CLK_TYPE; sunxi_pwm.pwm_bus_clk_id = SUNXI_PWM_CLK_ID; sunxi_pwm.pwm_reset_type = SUNXI_PWM_RESET_TYPE; sunxi_pwm.pwm_reset_id = SUNXI_PWM_RESET_ID; for (i = 0; i < PWM_NUM; i++) sunxi_pwm.pin_state[i] = false; if (!sunxi_pwm.pwm_reset) sunxi_pwm.pwm_reset = hal_reset_control_get(sunxi_pwm.pwm_reset_type, sunxi_pwm.pwm_reset_id); hal_reset_control_reset(sunxi_pwm.pwm_reset); if (!sunxi_pwm.pwm_bus_clk) sunxi_pwm.pwm_bus_clk = hal_clock_get(sunxi_pwm.pwm_clk_type, sunxi_pwm.pwm_bus_clk_id); if (hal_clock_enable(sunxi_pwm.pwm_bus_clk)) { return -1; } #ifdef CONFIG_STANDBY register_pm_dev_notify(hal_pwm_suspend, hal_pwm_resume, NULL); #endif #ifdef CONFIG_COMPONENTS_PM pm_devops_register(&pm_pwm); #endif PWM_INFO("pwm init end "); pwm_init++; return 0; } pwm_status_t hal_pwm_deinit(void) { int i; if (pwm_init) { pwm_init--; if (!pwm_init) { #ifdef CONFIG_COMPONENTS_PM pm_devops_unregister(&pm_pwm); #endif for (i = 0; i < PWM_NUM; i++) { hal_pwm_pinctrl_exit(sunxi_pwm, i); sunxi_pwm.pin_state[i] = false; } hal_reset_control_assert(sunxi_pwm.pwm_reset); hal_reset_control_put(sunxi_pwm.pwm_reset); hal_clock_disable(sunxi_pwm.pwm_bus_clk); hal_clock_put(sunxi_pwm.pwm_bus_clk); } } PWM_INFO("pwm deinit end"); return 0; } pwm_status_t hal_pwm_control(int channel, struct pwm_config *config_pwm) { PWM_INFO("pwm control start"); unsigned int temp; unsigned long long c = 0; unsigned long entire_cycles = 256, active_cycles = 192; unsigned int reg_offset, reg_shift, reg_width; unsigned int reg_bypass_shift; unsigned int reg_clk_src_shift, reg_clk_src_width; unsigned int reg_div_m_shift, reg_div_m_width, value; int32_t clk_osc24m; char pwm_name[16]; int err; PWM_INFO("period_ns = %ld", config_pwm->period_ns); PWM_INFO("duty_ns = %ld", config_pwm->duty_ns); PWM_INFO("polarity = %d", config_pwm->polarity); PWM_INFO("channel = %d", channel); if ((config_pwm->period_ns < config_pwm->duty_ns) || (!config_pwm->period_ns)) { PWM_ERR("paremeter error : period_ns can't greater than duty_ns and period_ns can't be 0"); return -1; } /* pwm set port */ err = hal_pwm_pinctrl_init(sunxi_pwm, channel); if (err) { err = hal_gpio_pinmux_set_function(pwm_gpio[channel].pwm_pin, pwm_gpio[channel].pwm_function); if (err) { PWM_ERR("pinmux set failed\n"); return -1; } sunxi_pwm.pin_state[channel] = true; } /* pwm enable controller */ hal_pwm_enable_controller(channel); /* pwm set polarity */ hal_pwm_porality(channel, config_pwm->polarity); /* pwm config function */ uint32_t pre_scal_id = 0, div_m = 0, prescale = 0; uint32_t pre_scal[][2] = { /* reg_val clk_pre_div */ {0, 1}, {1, 2}, {2, 4}, {3, 8}, {4, 16}, {5, 32}, {6, 64}, {7, 128}, {8, 256}, }; reg_clk_src_shift = PWM_CLK_SRC_SHIFT; reg_clk_src_width = PWM_CLK_SRC_WIDTH; reg_offset = get_pccr_reg_offset(channel); sprintf(pwm_name, "pwm%d", channel); #ifdef CONFIG_DRIVER_SYSCONFIG err = Hal_Cfg_GetKeyValue(pwm_name, "clk_osc24m", &clk_osc24m, 1); if (err) { clk_osc24m = 0; //PWM_ERR("[pwm%d] clk_osc24m not support in sys_config\n", channel); //leo关掉,这个没啥用 } #else clk_osc24m = 0; #endif if (clk_osc24m) { /* if need freq 24M, then direct output 24M clock,set clk_bypass. */ reg_bypass_shift = channel; reg_offset = get_pccr_reg_offset(channel); temp = hal_readl(PWM_BASE + PWM_PCGR); temp = SET_BITS(reg_bypass_shift, 1, temp, 1); /* clk_gating set */ temp = SET_BITS(reg_bypass_shift + 16, 1, temp, 1); /* clk_bypass set */ hal_writel(temp, PWM_BASE + PWM_PCGR); /* clk_src_reg */ temp = hal_readl(PWM_BASE + reg_offset); temp = SET_BITS(reg_clk_src_shift, reg_clk_src_width, temp, 0); /* select clock source */ hal_writel(temp, PWM_BASE + reg_offset); return 0; } if (config_pwm->period_ns > 0 && config_pwm->period_ns <= 10) { #if defined(CONFIG_ARCH_SUN20IW2) /* if freq lt 96M, then direct output 96M clock,set by pass. */ c = 96000000; #else /* if freq lt 100M, then direct output 100M clock,set by pass. */ c = 100000000; #endif /* CONFIG_ARCH_SUN20IW2 */ reg_bypass_shift = channel; reg_offset = get_pccr_reg_offset(channel); temp = hal_readl(PWM_BASE + PWM_PCGR); temp = SET_BITS(reg_bypass_shift, 1, temp, 1); /* clk_gating set */ temp = SET_BITS(reg_bypass_shift + 16, 1, temp, 1); /* clk_bypass set */ hal_writel(temp, PWM_BASE + PWM_PCGR); /* clk_src_reg */ temp = hal_readl(PWM_BASE + reg_offset); temp = SET_BITS(reg_clk_src_shift, reg_clk_src_width, temp, 1); /* select clock source */ hal_writel(temp, PWM_BASE + reg_offset); return 0; } else if (config_pwm->period_ns > 10 && config_pwm->period_ns <= 334) { #if defined(CONFIG_ARCH_SUN20IW2) /* if freq between 3M~100M, then select 96M as clock */ c = 96000000; #else /* if freq between 3M~100M, then select 100M as clock */ c = 100000000; #endif /* CONFIG_ARCH_SUN20IW2 */ /* clk_src_reg : use APB1 clock */ temp = hal_readl(PWM_BASE + reg_offset); temp = SET_BITS(reg_clk_src_shift, reg_clk_src_width, temp, 1); hal_writel(temp, PWM_BASE + reg_offset); } else if (config_pwm->period_ns > 334) { #if defined(CONFIG_ARCH_SUN20IW2) /* if freq < 3M, then select 40M clock */ c = 40000000; #else /* if freq < 3M, then select 24M clock */ c = 24000000; #endif /* CONFIG_ARCH_SUN20IW2 */ /* clk_src_reg : use OSC24M clock */ temp = hal_readl(PWM_BASE + reg_offset); temp = SET_BITS(reg_clk_src_shift, reg_clk_src_width, temp, 0); hal_writel(temp, PWM_BASE + reg_offset); } c = c * config_pwm->period_ns; pwm_do_div(c, 1000000000); entire_cycles = (unsigned long)c; for (pre_scal_id = 0; pre_scal_id < 9; pre_scal_id++) { if (entire_cycles <= 65536) { break; } for (prescale = 0; prescale < PRESCALE_MAX + 1; prescale++) { entire_cycles = ((unsigned long)c / pre_scal[pre_scal_id][1]) / (prescale + 1); if (entire_cycles <= 65536) { div_m = pre_scal[pre_scal_id][0]; break; } } } c = (unsigned long long)entire_cycles * config_pwm->duty_ns; pwm_do_div(c, config_pwm->period_ns); active_cycles = c; if (entire_cycles == 0) { entire_cycles++; } /* config clk div_m */ reg_div_m_shift = PWM_DIV_M_SHIFT; reg_div_m_width = PWM_DIV_M_WIDTH; temp = hal_readl(PWM_BASE + reg_offset); temp = SET_BITS(reg_div_m_shift, reg_div_m_width, temp, div_m); hal_writel(temp, PWM_BASE + reg_offset); /* config gating */ #ifdef CONFIG_ARCH_SUN8IW18P1 reg_shift = PWM_CLK_GATING_SHIFT; value = hal_readl(PWM_BASE + reg_offset); value = SET_BITS(reg_shift, 1, value, 1); /* set gating */ hal_writel(value, PWM_BASE + reg_offset); #else reg_shift = channel; value = hal_readl(PWM_BASE + PWM_PCGR); value = SET_BITS(reg_shift, 1, value, 1); /* set gating */ hal_writel(value, PWM_BASE + PWM_PCGR); #endif /* config prescal */ reg_offset = PWM_PCR + 0x20 * channel; reg_shift = PWM_PRESCAL_SHIFT; reg_width = PWM_PRESCAL_WIDTH; temp = hal_readl(PWM_BASE + reg_offset); temp = SET_BITS(reg_shift, reg_width, temp, prescale); hal_writel(temp, PWM_BASE + reg_offset); /* config active cycles */ reg_offset = PWM_PPR + 0x20 * channel; reg_shift = PWM_ACT_CYCLES_SHIFT; reg_width = PWM_ACT_CYCLES_WIDTH; temp = hal_readl(PWM_BASE + reg_offset); temp = SET_BITS(reg_shift, reg_width, temp, active_cycles); hal_writel(temp, PWM_BASE + reg_offset); /* config period cycles */ reg_offset = PWM_PPR + 0x20 * channel; reg_shift = PWM_PERIOD_CYCLES_SHIFT; reg_width = PWM_PERIOD_CYCLES_WIDTH; temp = hal_readl(PWM_BASE + reg_offset); temp = SET_BITS(reg_shift, reg_width, temp, (entire_cycles - 1)); hal_writel(temp, PWM_BASE + reg_offset); PWM_INFO("pwm control end "); return 0; } //leo add //直接改变占空比 void set_pwm_duty(uint32_t duty_ns) { // c = (unsigned long long)entire_cycles * config_pwm->duty_ns; // pwm_do_div(c, config_pwm->period_ns); // active_cycles = c; }
Copyright © 2024 深圳全志在线有限公司 粤ICP备2021084185号 粤公网安备44030502007680号