找回密码
 立即注册

QQ登录

只需一步,快速开始

打印 上一主题 下一主题
开启左侧

[NUC] NUC240的PWM capture 最小输入频率

[复制链接]
跳转到指定楼层
楼主
assman 发表于 2022-5-18 09:26:50 | 显示全部楼层 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 assman 于 2022-5-20 08:56 编辑

各位大大安安,我在学习NUC240 BSP中Smpl_Basic01_PWM_Capture范例,输入的PWM频率范围在0~100Hz区间,量测周期结果不是输入的PWM频率,是否该设定PWM_ConfigCaptureChannel中的参数才能正确量测?
  1. /**
  2. * @brief Configure PWM capture and get the nearest unit time.
  3. * @param[in] pwm The pointer of the specified PWM module
  4. * @param[in] u32ChannelNum PWM channel number. Valid values are between 0~3
  5. * @param[in] u32UnitTimeNsec The unit time of counter
  6. * @param[in] u32CaptureEdge The condition to latch the counter. This parameter is not used
  7. * @return The nearest unit time in nano second.
  8. * @details This function is used to configure PWM capture and get the nearest unit time.
  9. */
  10. uint32_t PWM_ConfigCaptureChannel(PWM_T *pwm,
  11.                                   uint32_t u32ChannelNum,
  12.                                   uint32_t u32UnitTimeNsec,
  13.                                   uint32_t u32CaptureEdge)
  14. {
  15.     uint32_t u32Src;
  16.     uint32_t u32PWMClockSrc;
  17.     uint32_t u32PWMClkTbl[8] = {__HXT, __LXT, NULL, __HIRC, NULL, NULL, NULL, __LIRC};
  18.     uint32_t u32NearestUnitTimeNsec;
  19.     uint8_t  u8Divider = 1;
  20.     /* this table is mapping divider value to register configuration */
  21.     uint32_t u32PWMDividerToRegTbl[17] = {NULL, 4, 0, NULL, 1, NULL, NULL, NULL, 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 3};
  22.     uint16_t u16Prescale = 2;
  23.     uint16_t u16CNR = 0xFFFF;

  24.     if(pwm == PWMA)
  25.     {
  26.         if(u32ChannelNum < 2)/* channel 0 and channel 1 */
  27.             u32Src = ((CLK->CLKSEL2 & (CLK_CLKSEL2_PWM01_S_EXT_Msk)) >> (CLK_CLKSEL2_PWM01_S_EXT_Pos - 2)) | (CLK->CLKSEL1 & (CLK_CLKSEL1_PWM01_S_Msk)) >> (CLK_CLKSEL1_PWM01_S_Pos);
  28.         else /* channel 2 and channel 3 */
  29.             u32Src = ((CLK->CLKSEL2 & (CLK_CLKSEL2_PWM23_S_EXT_Msk)) >> (CLK_CLKSEL2_PWM23_S_EXT_Pos - 2)) | (CLK->CLKSEL1 & (CLK_CLKSEL1_PWM23_S_Msk)) >> (CLK_CLKSEL1_PWM23_S_Pos);
  30.     }
  31.     else /*pwm == PWMB*/
  32.     {
  33.         if(u32ChannelNum < 2)/* channel 0 and channel 1 */
  34.             u32Src = ((CLK->CLKSEL2 & (CLK_CLKSEL2_PWM45_S_EXT_Msk)) >> (CLK_CLKSEL2_PWM45_S_EXT_Pos - 2)) | (CLK->CLKSEL2 & (CLK_CLKSEL2_PWM45_S_Msk)) >> (CLK_CLKSEL2_PWM45_S_Pos);
  35.         else /* channel 2 and channel 3 */
  36.             u32Src = ((CLK->CLKSEL2 & (CLK_CLKSEL2_PWM67_S_EXT_Msk)) >> (CLK_CLKSEL2_PWM67_S_EXT_Pos - 2)) | (CLK->CLKSEL2 & (CLK_CLKSEL2_PWM67_S_Msk)) >> (CLK_CLKSEL2_PWM67_S_Pos);
  37.     }

  38.     if(u32Src == 2)
  39.     {
  40.         SystemCoreClockUpdate();
  41.         u32PWMClockSrc = SystemCoreClock;
  42.     }
  43.     else
  44.     {
  45.         u32PWMClockSrc = u32PWMClkTbl[u32Src];
  46.     }

  47.     u32PWMClockSrc /= 1000;
  48.     for(; u16Prescale <= 0x100; u16Prescale++)
  49.     {
  50.         u32NearestUnitTimeNsec = (1000000 * u16Prescale * u8Divider) / u32PWMClockSrc;
  51.         if(u32NearestUnitTimeNsec < u32UnitTimeNsec)
  52.         {
  53.             if((u16Prescale == 0x100) && (u8Divider == 16))  //limit to the maximum unit time(nano second)
  54.                 break;
  55.             if(u16Prescale == 0x100)
  56.             {
  57.                 u16Prescale = 2;
  58.                 u8Divider <<= 1; // clk divider could only be 1, 2, 4, 8, 16
  59.                 continue;
  60.             }
  61.             if(!((1000000  * ((u16Prescale * u8Divider) + 1)) > (u32NearestUnitTimeNsec * u32PWMClockSrc)))
  62.                 break;
  63.             continue;
  64.         }
  65.         break;
  66.     }

  67.     // Store return value here 'cos we're gonna change u8Divider & u16Prescale & u16CNR to the real value to fill into register
  68.     u16Prescale -= 1;

  69.     // convert to real register value
  70.     u8Divider = u32PWMDividerToRegTbl[u8Divider];

  71.     // every two channels share a prescaler
  72.     (pwm)->PPR = ((pwm)->PPR & ~(PWM_PPR_CP01_Msk << ((u32ChannelNum >> 1) * 8))) | (u16Prescale << ((u32ChannelNum >> 1) * 8));
  73.     (pwm)->CSR = ((pwm)->CSR & ~(PWM_CSR_CSR0_Msk << (4 * u32ChannelNum))) | (u8Divider << (4 * u32ChannelNum));
  74.     // set PWM to edge aligned type
  75.     (pwm)->PCR &= ~(PWM_PCR_PWM01TYPE_Msk << (u32ChannelNum >> 1));
  76.     (pwm)->PCR |= PWM_PCR_CH0MOD_Msk << (8 * u32ChannelNum);
  77.     *((__IO uint32_t *)((((uint32_t) & ((pwm)->CNR0)) + (u32ChannelNum) * 12))) = u16CNR;

  78.     return (u32NearestUnitTimeNsec);
  79. }
复制代码

实际输入PWM频率100Hz,量测得到Total Period = 60399,利用下面公式计算频率=12000000/2/60399=99.36Hz
假设输入PWM频率为50Hz,(CNR+1)=120000000/2/50=120000 大于65536,所以必须增大prescaler值,请问该如何调整prescaler值?

擷取.PNG (27.37 KB, 下载次数: 350)

擷取.PNG
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 顶 踩
回复

使用道具 举报

沙发
 楼主| assman 发表于 2022-5-19 09:52:38 | 显示全部楼层
另外还想问CalPeriodTime这函数,一开始是先清除下降沿指示,然后等下降沿信号,再清除下降沿指示,这里为何要连清二次下降沿指示,
不是已经下降完成了,接着肯定要上升沿了,也就是上升信号?

另外在循环里,一开始等下降沿信号,然后清除上升/下降沿指示,这里为何不是只清除下降沿指示即可,而是二者皆清除?

  1. void CalPeriodTime(PWM_T *PWM, uint32_t u32Ch)
  2. {
  3.     uint16_t u32Count[4];
  4.     uint32_t u32i;
  5.     uint16_t u16RisingTime, u16FallingTime, u16HighPeroid, u16LowPeroid, u16TotalPeroid;

  6.     /* Clear Capture Falling Indicator (Time A) */
  7.     PWM_ClearCaptureIntFlag(PWM, u32Ch, PWM_CAPTURE_INT_FALLING_LATCH);

  8.     /* Wait for Capture Falling Indicator  */
  9.     while(PWM_GetCaptureIntFlag(PWM, u32Ch) < 2);

  10.     /* Clear Capture Falling Indicator (Time B)*/
  11.     PWM_ClearCaptureIntFlag(PWM, u32Ch, PWM_CAPTURE_INT_FALLING_LATCH);

  12.     u32i = 0;

  13.     while(u32i < 4)
  14.     {
  15.         /* Wait for Capture Falling Indicator */
  16.         while(PWM_GetCaptureIntFlag(PWM, u32Ch) < 2);

  17.         /* Clear Capture Falling and Rising Indicator */
  18.         PWM_ClearCaptureIntFlag(PWM, u32Ch, PWM_CAPTURE_INT_FALLING_LATCH | PWM_CAPTURE_INT_RISING_LATCH);

  19.         /* Get Capture Falling Latch Counter Data */
  20.         u32Count[u32i++] = PWM_GET_CAPTURE_FALLING_DATA(PWM, u32Ch);

  21.         /* Wait for Capture Rising Indicator */
  22.         while(PWM_GetCaptureIntFlag(PWM, u32Ch) < 2);

  23.         /* Clear Capture Rising Indicator */
  24.         PWM_ClearCaptureIntFlag(PWM, u32Ch, PWM_CAPTURE_INT_RISING_LATCH);

  25.         /* Get Capture Rising Latch Counter Data */
  26.         u32Count[u32i++] = PWM_GET_CAPTURE_RISING_DATA(PWM, u32Ch);
  27.     }

  28.     u16RisingTime = u32Count[1];

  29.     u16FallingTime = u32Count[0];

  30.     u16HighPeroid = u32Count[1] - u32Count[2];

  31.     u16LowPeroid = 0x10000 - u32Count[1];

  32.     u16TotalPeroid = 0x10000 - u32Count[2];

  33.     printf("\nCapture Result: Rising Time = %d, Falling Time = %d \nHigh Period = %d, Low Period = %d, Total Period = %d.\n\n",
  34.            u16RisingTime, u16FallingTime, u16HighPeroid, u16LowPeroid, u16TotalPeroid);
  35. }
复制代码


回复 支持 反对

使用道具 举报

板凳
 楼主| assman 发表于 2022-5-23 15:28:23 | 显示全部楼层

感谢版大讲说,另外想问这四对PWM可以将每一对分别设定输出模式和补获模式使用嘛,比方说PWM0是补获模式,PWM1是输出模式,这样用好像补获模式数值会怪怪的,谢谢!
回复 支持 反对

使用道具 举报

地板
 楼主| assman 发表于 2022-5-23 22:39:32 | 显示全部楼层
admin 发表于 2022-5-23 16:24
可以每一组分开设置是作为PWM输出还是捕获输入

版大抱歉我的意思是同一组中输出模式和补获模式同时使用,这样补获模式数值似乎会怪怪的,谢谢!
回复 支持 反对

使用道具 举报

高级模式
B Color Image Link Quote Code Smilies |上传

本版积分规则

新唐MCU