i.MX6ULL 8 路独立 PWM 控制器(PWM1 ~ PWM8)
- 每路:16bit 递增计数器 + 12bit 预分频器 + 4×16bit FIFO
- 3 个可选时钟源:
ipg_clk66MHz(最常用)ipg_clk_highfreqipg_clk_32k32.768KHz
- 典型用途:LCD 背光、舵机、蜂鸣器、LED 调光

①、此部分是一个选择器,用于选择 PWM 信号的时钟源,一共有三种时钟源:ipg_clk、ipg_clk_highfreq 和 ipg_clk_32k。
②、这是一个 12 位的分频器,可以对①中选择的时钟源进行分频。
③、这是 PWM 的 16 位计数器寄存器,保存着 PWM 的计数值。
④、这是 PWM 的 16 位周期寄存器,此寄存器用来控制 PWM 的频率。
⑤、这是 PWM 的 16 位采样寄存器,此寄存器用来控制 PWM 的占空比。
⑥、此部分是 PWM 的中断信号,PWM 是提供中断功能的,如果使能了相应的中断的话就会产生中断。
核心寄存器
| 寄存器 | 地址偏移 | 作用 |
|---|---|---|
PWMCR |
0x00 | 控制寄存器:模块使能、时钟源、输出极性、软件复位、FIFO 配置 |
PWMSR |
0x04 | 状态寄存器:FIFO 空 / 满、比较完成、溢出标志 |
PWMIR |
0x08 | 中断使能寄存器(FIFO 中断、周期溢出中断) |
PWMSAR |
0x0C | 采样寄存器 → 占空比,写入 FIFO |
PWMPR |
0x10 | 周期寄存器 → PWM 频率 |
PWMCNT |
0x14 | 当前计数值(只读) |
寄存器相关位
PWM1_PWMCR 寄存器
- FWM (bit27:26):FIFO 水位线,用来设置 FIFO 空余位置为多少的时候表示 FIFO 为空。设置为 0 的时候表示 FIFO 空余位置大于等于 1 的时候 FIFO 为空;设置为 1 的时候表示 FIFO 空余位置大于等于 2 的时候 FIFO 为空;设置为 2 的时候表示 FIFO 空余位置大于等于 3 的时候 FIFO 为空;设置为 3 的时候表示 FIFO 空余位置大于等于 4 的时候 FIFO 为空;
- STOPEN (bit25):此位用来设置停止模式下 PWM 是否工作,为 0 的话表示在停止模式下 PWM 继续工作,为 1 的话表示停止模式下关闭 PWM;
- DOZEN (bit24):此位用来设置休眠模式下 PWM 是否工作,为 0 的话表示在休眠模式下 PWM 继续工作,为 1 的话表示休眠模式下关闭 PWM;
- WAITEN (bit23):此位用来设置等待模式下 PWM 是否工作,为 0 的话表示在等待模式下 PWM 继续工作,为 1 的话表示等待模式下关闭 PWM;
- DEGEN (bit22):此位用来设置调试模式下 PWM 是否工作,为 0 的话表示在调试模式下 PWM 继续工作,为 1 的话表示调试模式下关闭 PWM
- BCTR (bit21):字节交换控制位,用来控制 16 位的数据进入 FIFO 的字节顺序。为 0 的时候不进行字节交换,为 1 的时候进行字节交换;
- HCRT (bit20):半字交换控制位,用来决定从 32 位 IP 总线接口传输来的哪个半字数据写入采样寄存器的低 16 位中;
- POUTC (bit19:18):PWM 输出控制控制位,用来设置 PWM 输出模式,为 0 的时候表示 PWM 先输出高电平,当计数器值和采样值相等的话就输出低电平。为 1 的时候相反,当为 2 或者 3 的时候 PWM 信号不输出。我们设置为 0,也就是一开始输出高电平,当计数器值和采样值相等的话就改为低电平,这样采样值越大高电平时间就越长,占空比就越大;
- CLKSRC (bit17:16):PWM 时钟源选择,为 0 的话关闭;为 1 的话选择 ipg_clk 为时钟源;为 2 的话选择 ipg_clk_highfreq 为时钟源;为 3 的话选择 ipg_clk_32k 为时钟源。我们设置为 1,也就是选择 ipg_clk 为 PWM 的时钟源,因此 PWM 时钟源频率为 66MHz;
- PRESCALER (bit15:4):分频值,可设置为 0~4095,对应着 1~4096 分频。我们设置为 65,就是 66 分频,PWM 实际工作频率为 1MHz;
- SWR (bit3):软件复位,向此位写 1 就复位 PWM,此位是自清零的,当复位完成以后此位会自动清零;
- REPEAT (bit2:1):重复采样设置,此位用来设置 FIFO 中的每个数据能用几次。可设置 0~3 分别表示 FIFO 中的每个数据能用 1~4 次。本章我们设置为 3,即 FIFO 中的每个数据用 8 次;
- EN (bit0):PWM 使能位,为 1 的时候使能 PWM,为 0 的时候关闭 PWM。
PWM1_PWMIR 寄存器
- CIE (bit2):比较中断使能位,为 1 的时候使能比较中断,为 0 的时候关闭比较中断;
- RIE (bit1):翻转中断使能位,当计数器值等于采样值并回滚到 0X0000 的时候就会产生此中断,为 1 的时候使能翻转中断,为 0 的时候关闭翻转中断;
- FIE (bit0):FIFO 空中断,为 1 的时候使能,为 0 的时候关闭。我们需要使能这个中断。
PWM1_PWMSR 寄存器
- FWE (bit6):FIFO 写错误事件,为 1 的时候表示发生了 FIFO 写错误;
- CMP (bit5):FIFO 比较事件发标志位,为 1 的时候表示发生 FIFO 比较事件;
- ROV (bit4):翻转事件标志位,为 1 的话表示翻转事件发生;
- FE (bit3):FIFO 到达水位线标志,为 1 的时候表示 FIFO 已到达水位线。我们主要在中断中关注这个标志,并及时清零;
- FIFOAV (bit2:1):此位记录 FIFO 中的有效数据个数,有效值为 0~4,分别表示 FIFO 中有 0~4 个有效数据。
PWM1_PWMPR 寄存器
该寄存器存储PWM的周期时长,计算公式为 PWMO (Hz) = PCLK (Hz) / (PERIOD + 2)
其中 PWMO 是输出频率,PCLK 为输入的时钟频率,我是直接取外设时钟66MHz。计算出的PERIOD就填入该寄存器
示例代码如下:
IOMUXC_SetPinMux(IOMUXC_GPIO1_IO08_PWM1_OUT, 0);
IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO08_PWM1_OUT,0x1079);
PWM1->PWMCR &= ~(1 << 0); //关闭PWM使能开关
PWM1->PWMCR |= (1 << 3); //复位PWM寄存器
while(PWM1->PWMCR & (1 << 3));
PWM1->PWMCR &= ~(2 << 26);
PWM1->PWMCR |= (1 << 26); //设置比较队列剩余2个是产生信号
PWM1->PWMCR &= ~(1 << 25); //设置PWM在停止模式继续工作
PWM1->PWMCR &= ~(1 << 24); //设置PWM在休眠模式继续工作
PWM1->PWMCR &= ~(1 << 23); //设置PWM在等待模式继续工作
PWM1->PWMCR &= ~(1 << 22); //设置PWM在调试模式继续工作
PWM1->PWMCR &= ~(1 << 21); //设置数据进入FIFO的字节序不交换
PWM1->PWMCR &= ~(1 << 20); //设置半字节交换,写入采样寄存器的低16位
PWM1->PWMCR &= ~(3 << 18); //设置PWM模式,起始为高,到达比较直输出低
PWM1->PWMCR &= ~(3 << 16);
PWM1->PWMCR |= (1 << 16); //设置时钟源为外设时钟的66MHz
PWM1->PWMCR &= ~(0XFFF << 4);
PWM1->PWMCR |= (65 << 4); //设置时钟分频因子为65+1,得到1MHz频率
PWM1->PWMCR &= ~(3 << 1);
PWM1->PWMCR |= (3 << 1); //设置FIFO中每个比较值可以使用8次
PWM1->PWMCR = (0x1 << 26)|(0x1 << 16)|(65 << 4)|(0x3 << 1);
PWM1->PWMIR |= (1 << 0); //使能队列空中断
set_compare(100);
PWM1->PWMPR &= ~(0XFFFF << 0);
PWM1->PWMPR = (998<< 0); //设置PWM频率为1KHz
request_irq(PWM1_IRQn, pwm_handler);
PWM1->PWMCR |= (1 << 0); //使能PWM
在中断服务函数中重新向FIFO写入比较值,即可实现PWM不间断生成,关于中断配置,可以翻看之前的文章,这里不再重复。