导航

    全志在线开发者论坛

    • 注册
    • 登录
    • 搜索
    • 版块
    • 话题
    • 在线文档
    • 社区主页

    大佬们,谁知道这个PWM的控制器怎么直接改变占空比啊?

    MR Series
    1
    1
    824
    正在加载更多帖子
    • 从旧到新
    • 从新到旧
    • 最多赞同
    回复
    • 在新帖中回复
    登录后回复
    此主题已被删除。只有拥有主题管理权限的用户可以查看。
    • L
      leomini5 LV 6 最后由 编辑

      我想用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;
      
      }
      
      1 条回复 最后回复 回复 引用 分享 0
      • 1 / 1
      • First post
        Last post

      Copyright © 2024 深圳全志在线有限公司 粤ICP备2021084185号 粤公网安备44030502007680号

      行为准则 | 用户协议 | 隐私权政策