这两天在看BSP代码,看到PWM.c的时候有些不懂,求大神指点
PWM_ConfigOutputChannel这个函数里面(整个函数我贴在最后)
if(pwm == PWMA)
u32Src = (CLK->CLKSEL1 & (CLK_CLKSEL1_PWM01_S_Msk << (u32ChannelNum >> 1))) >> (CLK_CLKSEL1_PWM01_S_Pos << (u32ChannelNum >> 1));
else /*pwm == PWMB*/
u32Src = (CLK->CLKSEL2 & (CLK_CLKSEL2_PWM45_S_Msk << (u32ChannelNum >> 1))) >> (CLK_CLKSEL2_PWM45_S_Pos << (u32ChannelNum >> 1));
这里面这两句应该是要读取时钟源配置的信息吧, (u32ChannelNum >> 1)这个是不是有点问题,PWM时钟源的配置占两个位,这里就算channelnum输入3,右移一下变成1,CLK_CLKSEL1_PWM01_S_Msk也只是左移了一位,读出来的值不就错了吗
然后是这里,这句实在是看不懂了
// set PWM to edge aligned type
(pwm)->PCR &= ~(PWM_PCR_PWM01TYPE_Msk << (u32ChannelNum >> 1));
PCR寄存器的第28位之后是保留位,但是
#define PWM_PCR_PWM01TYPE_Pos 30 /*!< PWM PCR: PWM01TYPE Position */#define PWM_PCR_PWM01TYPE_Msk (1ul << PWM_PCR_PWM01TYPE_Pos) /*!< PWM PCR: PWM01TYPE Mask */
这里已经左移30位了,还得再左移n位,这样做操作的位不就是保留位了吗
完整的PWM_ConfigOutputChannel函数
uint32_t PWM_ConfigOutputChannel(PWM_T *pwm,
uint32_t u32ChannelNum,
uint32_t u32Frequency,
uint32_t u32DutyCycle)
{
uint32_t u32Src;
uint32_t u32PWMClockSrc;
uint32_t u32PWMClkTbl[4] = {__HXT, __LIRC, 0, __HIRC};
uint32_t i;
uint8_t u8Divider = 1, u8Prescale = 0xFF;
/* this table is mapping divider value to register configuration */
uint32_t u32PWMDividerToRegTbl[17] = {NULL, 4, 0, NULL, 1, NULL, NULL, NULL, 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 3};
uint16_t u16CNR = 0xFFFF;
if(pwm == PWMA)
u32Src = (CLK->CLKSEL1 & (CLK_CLKSEL1_PWM01_S_Msk << (u32ChannelNum >> 1))) >> (CLK_CLKSEL1_PWM01_S_Pos << (u32ChannelNum >> 1));
else /*pwm == PWMB*/
u32Src = (CLK->CLKSEL2 & (CLK_CLKSEL2_PWM45_S_Msk << (u32ChannelNum >> 1))) >> (CLK_CLKSEL2_PWM45_S_Pos << (u32ChannelNum >> 1));
if(u32Src == 2)
{
SystemCoreClockUpdate();
u32PWMClockSrc = SystemCoreClock;
}
else
{
u32PWMClockSrc = u32PWMClkTbl[u32Src];
}
for(; u8Divider < 17; u8Divider <<= 1) // clk divider could only be 1, 2, 4, 8, 16 ʱÖÓÔ´·ÖƵ
{
i = (u32PWMClockSrc / u32Frequency) / u8Divider;
// If target value is larger than CNR * prescale, need to use a larger divider
if(i > (0x10000 * 0x100)) //×î´ó¼ÆÊýÖµ*×î´óÔ¤·ÖƵֵ Èç¹û¼ÆÊýʱ¼ä³¬¹ýPWMÄ£¿é×î´óʱ¼äÔòÐèÒª¼Ó´óʱÖÓÔ´·ÖƵ
continue;
// CNR = 0xFFFF + 1, get a prescaler that CNR value is below 0xFFFF
u8Prescale = (i + 0xFFFF) / 0x10000;
// u8Prescale must at least be 2, otherwise the output stop
if(u8Prescale < 3)
u8Prescale = 2;
i /= u8Prescale;
if(i <= 0x10000)
{
if(i == 1)
u16CNR = 1;//Too fast, and PWM cannot generate expected frequency...
else
u16CNR = i;
break;
}
}
// Store return value here 'cos we're gonna change u8Divider & u8Prescale & u16CNR to the real value to fill into register
i = u32PWMClockSrc / (u8Prescale * u8Divider * u16CNR);
u8Prescale -= 1;
u16CNR -= 1;
// convert to real register value
u8Divider = u32PWMDividerToRegTbl[u8Divider];
// every two channels share a prescaler
(pwm)->PPR = ((pwm)->PPR & ~(PWM_PPR_CP01_Msk << ((u32ChannelNum >> 1) * 8))) | (u8Prescale << ((u32ChannelNum >> 1) * 8));
(pwm)->CSR = ((pwm)->CSR & ~(PWM_CSR_CSR0_Msk << (4 * u32ChannelNum))) | (u8Divider << (4 * u32ChannelNum));
// set PWM to edge aligned type
(pwm)->PCR &= ~(PWM_PCR_PWM01TYPE_Msk << (u32ChannelNum >> 1));
(pwm)->PCR |= PWM_PCR_CH0MOD_Msk << (8 * u32ChannelNum);
*((__IO uint32_t *)((((uint32_t) & ((pwm)->CMR0)) + u32ChannelNum * 12))) = (u16CNR + 1) * u32DutyCycle / 100 - 1;
*((__IO uint32_t *)((((uint32_t) & ((pwm)->CNR0)) + (u32ChannelNum) * 12))) = u16CNR;
return(i);
}
|