首页 > 其他分享 >IMX6ULL PWM定时器

IMX6ULL PWM定时器

时间:2023-10-30 16:46:57浏览次数:34  
标签:定时器 FIFO 设置 寄存器 占空比 IMX6ULL PWM bit

1 PWM定时器介绍

一共有 8 路 PWM 信号,每个 PWM 包含一个 16 位的计数器和一个 4 x 16 的数据 FIFO。一路框图如下:
image
①、此部分是一个选择器,用于选择 PWM 信号的时钟源,一共有三种时钟源:ipg_clk,pg_clk_highfreq 和 ipg_clk_32k。
②、这是一个 12 位的分频器,可以对①中选择的时钟源进行分频。
③、这是 PWM 的 16 位计数器寄存器,保存着 PWM 的计数值。
④、这是 PWM 的 16 位周期寄存器,此寄存器用来控制 PWM 的频率。
⑤、这是 PWM 的 16 位采样寄存器,此寄存器用来控制 PWM 的占空比。
⑥、此部分是 PWM 的中断信号,PWM 是提供中断功能的,如果使能了相应的中断的话就会产生中断。
⑦、此部分是 PWM 对应的输出 IO,产生的 PWM 信号就会从对应的 IO 中输出。

2 PWM控制器配置

2.1 PWMx_PWMPR 周期设置

PWM 的 16 位计数器是个上计数器,此计数器会从 0X0000 开始计数,直到计数值等于寄存器PWMx_PWMPR(x=1~8)+ 1,然后计数器就会重新从0X0000 开始计数,如此往复。PWMx_PWMPR设置频率。PWM周期公式如下:

PWM_FRE = PWM_CLK / (PERIOD + 2)
也就是PWMO(Hz) = PCLK(Hz) / (PERIOD + 2)

image

比如当前PWM_CLK=1MHz, 要产生1KHz的PWM,那么PERIOD = 1000000/1K - 2 = 998。,如下设置1000,即可得到PERIOD=998,也就是1khz.

void pwm1_setperiod_value(unsigned int value)
{
	unsigned int regvalue = 0;

	if(value < 2)
		regvalue = 2;
	else 
		regvalue = value - 2;
	PWM1->PWMPR = (regvalue & 0XFFFF);
}

2.2 PWMx_PWMSAR 占空比

设置Sample采样寄存器,Sample数据会写入到FIFO中。当计数器的值小于 SAMPLE 的时候输出高电平(或低电平)。当计数器值大于等于 SAMPLE,小于寄存器PWM1_PWMPR 的 PERIO 的时候输出低电平(或高电平)。
假如我们要设置 PWM 信号的占空比为 50%,那么就可以将 SAMPLE 设置为(PERIOD + 2) / 2 = 1000 / 2=500。
image

如下设置50,即可得到sample=500,也就是占空比50%.

struct backlight_dev_struc
{	
	unsigned char pwm_duty;		/* 占空比	*/
};
struct backlight_dev_struc backlight_dev;

void pwm1_setsample_value(unsigned int value)
{
	PWM1->PWMSAR = (value & 0XFFFF);	
}
void pwm1_setduty(unsigned char duty)
{
	unsigned short preiod;
	unsigned short sample;
	backlight_dev.pwm_duty = duty;
	preiod = PWM1->PWMPR + 2;
	sample = preiod * backlight_dev.pwm_duty / 100;
	pwm1_setsample_value(sample);
}

2.3 PWMCR 控制寄存器

image

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 分频。
SWR(bit3):软件复位,向此位写 1 就复位 PWM,此位是自清零的,当复位完成以后此位会自动清零。
REPEAT(bit2:1):重复采样设置,此位用来设置 FIFO 中的每个数据能用几次。可设置 0~3,分别表示 FIFO 中的每个数据能用 1~4 次。本章我们设置为 0,即 FIFO 中的每个数据只能用一次。
EN(bit0):PWM 使能位,为 1 的时候使能 PWM,为 0 的时候关闭 PWM。

void pwm1_enable(void)
{
	PWM1->PWMCR |= 1 << 0;	 
}
void pwm1_init(void) {
	PWM1->PWMCR = 0;	/* 寄存器先清零 */
	PWM1->PWMCR |= (1 << 26) | (1 << 16) | (65 << 4);

	/* 设置PWM周期为1000,那么PWM频率就是1M/1000 = 1KHz。 */
	pwm1_setperiod_value(1000);

	/* 设置占空比,默认50%占空比   ,写四次是因为有4个FIFO */
	backlight_dev.pwm_duty = 50;
	for(i = 0; i < 4; i++)
	{
		pwm1_setduty(backlight_dev.pwm_duty);	
	}

	/* 使能FIFO空中断,设置寄存器PWMIR寄存器的bit0为1 */
	PWM1->PWMIR |= 1 << 0;
	system_register_irqhandler(PWM1_IRQn, (system_irq_handler_t)pwm1_irqhandler, NULL);	/* 注册中断服务函数 */
	GIC_EnableIRQ(PWM1_IRQn);	/* 使能GIC中对应的中断 */
	PWM1->PWMSR = 0;			/* PWM中断状态寄存器清零 */

	pwm1_enable();				/* 使能PWM1 */
}
  • bit[27:26] : 01 当FIFO中空余位置大于等于2的时候FIFO空标志值位
    • bit[25] :0 停止模式下PWM不工作
    • bit[24] : 0 休眠模式下PWM不工作
    • bit[23] : 0 等待模式下PWM不工作
    • bit[22] : 0 调试模式下PWM不工作
    • bit[21] : 0 关闭字节交换
    • bit[20] : 0 关闭半字数据交换
    • bit[19:18] : 00 PWM输出引脚在计数器重新计数的时候输出高电平,在计数器计数值达到比较值以后输出低电平
    • bit[17:16] : 01 PWM时钟源选择IPG CLK = 66MHz
    • bit[15:4] : 65 分频系数为65+1=66,PWM时钟源 = 66MHZ/66=1MHz
    • bit[3] : 0 PWM不复位
    • bit[2:1] : 00 FIFO中的sample数据每个只能使用一次。
    • bit[0] : 0 先关闭PWM,后面再使能

2.4 PWM1_PWMIR中断控制寄存器

image
CIE(bit2):比较中断使能位,为 1 的时候使能比较中断,为 0 的时候关闭比较中断。
RIE(bit1):翻转中断使能位,当计数器值等于采样值并回滚到 0X0000 的时候就会产生此中断,为 1 的时候使能翻转中断,为 0 的时候关闭翻转中断。
FIE(bit0):FIFO 空中断,为 1 的时候使能,为 0 的时候关闭。前面代码写的是使能FIFO空中断.

	/* 使能FIFO空中断,设置寄存器PWMIR寄存器的bit0为1 */
	PWM1->PWMIR |= 1 << 0;

2.5 PWM1_PWMSR 状态寄存器

image
FWE(bit6):FIFO 写错误事件,为 1 的时候表示发生了 FIFO 写错误。
CMP(bit5):FIFO 比较事件发标志位,为 1 的时候表示发生 FIFO 比较事件。
ROV(bit4):翻转事件标志位,为 1 的话表示翻转事件发生。
FE(bit3):FIFO 空标志位,为 1 的时候表示 FIFO 位空。
FIFOAV(bit2:0):此位记录 FIFO 中的有效数据个数,有效值为 0~4,分别表示 FIFO 中有0~4 个有效数据

初始化先清0,中断服务程序读取状态,并且清中断。FIFO 中的采样值每个周期都会少一个,所以需要不断的向 FIFO 中写入采样值,防止其为空。我们可以使能 FIFO 空中断,这样当 FIFO 为空的时候就会触发相应的中断,然后在中断处理函数中向 FIFO 写入采样值。

void pwm1_irqhandler(void) {
	if(PWM1->PWMSR & (1 << 3)) 	/* FIFO为空中断 */
	{
		/* 将占空比信息写入到FIFO中,其实就是设置占空比 */
		pwm1_setduty(backlight_dev.pwm_duty);
		PWM1->PWMSR |= (1 << 3); /* 写1清除中断标志位 */
	}
}

system_register_irqhandler(PWM1_IRQn, (system_irq_handler_t)pwm1_irqhandler, NULL);	/* 注册中断服务函数 */
GIC_EnableIRQ(PWM1_IRQn);	/* 使能GIC中对应的中断 */
PWM1->PWMSR = 0;			/* PWM中断状态寄存器清零 */
pwm1_enable();				/* 使能PWM1 */

3 测试

初始化时设置占空比为50%,测试代码读取按键,每次该按键按下就对占空比加10%,如果占空比超过100%,重新从10%开始。

while(1) {
	keyvalue = key_getvalue();
	if(keyvalue == KEY0_VALUE)
	{
		duty += 10;				/* 占空比加10% */
		if(duty > 100)			/* 如果占空比超过100%,重新从10%开始 */
			duty = 10;
		lcd_shownum(50 + 72, 90, duty, 3, 16);
		pwm1_setduty(duty);		/* 设置占空比 */
	}
	
	delayms(10);
}

占空比10%时亮度波形如下,亮度很暗。
image
image
占空比90%时亮度如下:
image

标签:定时器,FIFO,设置,寄存器,占空比,IMX6ULL,PWM,bit
From: https://www.cnblogs.com/fuzidage/p/17797804.html

相关文章

  • 定时器相关面试问题
    非活动连接,定时器怎么实现的,最小堆和升序链表(会不会修改,有点忘了,应该是会改的,我记得有umap,就说了)怎么设计分布式定时器(单实例定时器挂了怎么处理),主节点和从节点逻辑不一样假设LRU缓存的数据,需要过期时间,怎么设计(答:和webserver的定时器差不多,每个缓存开启一个定时器,使用时间堆......
  • 51单片机-定时器-proteus仿真
    这是代码#include"reg51.h"#defineu16unsignedint#defineu8unsignedchar#defineFOSC11059200L#defineBAUD9600sbitkaiguan=P1^0;u8codeleddat[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x81,0x82,0x84,......
  • Android定时器
    Timer和TimerTask这是常规的实现方式,对于大多数人的选择都会采用这种方式实现定时任务。这种实现方式的生命周期和Acticity的生命周期一样,当Activity销毁后,该定时任务也会结束。即退出该应用时,定时任务结束。Timertimer=newTimer();TimerTasktimerTask=......
  • 08_555定时器及应用
    555定时器及应用原理周期占空比占空比可调电路设计题目、产生1KHZ,占空比可调电路555定时器构成单稳态触发器单稳态电路原理设计一个延时1s的电路延时时间:Tp=1.1XR2XC2......
  • 关于高级定时器 重复计数值寄存器的使用介绍
    来源:https://www.cnblogs.com/liaigu/p/17782198.html在使用高级定时器进行初始化的时候,相较于通用定时器,在初始化的时候会有一个重复计数的配置,如下图:该位主要是对重复计数值寄存器进行配置,如下图:关于该配置的使用说明,具体如下:以定时器中断为例:1、一般默认情况下,将重复计......
  • PWM方式发送红外码值(NEC协议)
    1//红外发送代码2//【注意 : NEC默认为38khz频率。 更改参数时,记得查看频率是否正确。】3#include"sendremote.h"45//根据合适引脚配置6staticvoidpwmout_gpio_config(void){7rcu_periph_clock_enable(RCU_GPIOB);8gpio_mod......
  • Unity打造Timer定时器框架
    1:为什么我们要自己造轮子来做定时器系统传统的Unity做定时器的方式有三种,总结如下:对啦!这里有个游戏开发交流小组里面聚集了一帮热爱学习游戏的零基础小白,也有一些正在从事游戏开发的技术大佬,欢迎你来交流学习。(1)在组件类里面定义一个变量,每次Update的时候,累积时间,当时间......
  • IMX6ULL SPI应用-6轴陀螺仪加速度传感器ICM-20608-G
    16轴陀螺仪加速度传感器ICM-20608-G1.1概述TheICM-20608-Gisa6-axisMotionTrackingdevicethatcombinesa3-axisgyroscope,anda3-axisaccelerometerinasmall3x3x0.75mm(16-pinLGA)package.Thegyroscopehasaprogrammablefull-scalerangeof±250,......
  • 关于高级定时器 重复计数值寄存器的使用介绍
    在使用高级定时器进行初始化的时候,相较于通用定时器,在初始化的时候会有一个重复计数的配置,如下图:该位主要是对重复计数值寄存器进行配置,如下图:关于该配置的使用说明,具体如下:以定时器中断为例:1、一般默认情况下,将重复计数值设置为0。配置为向上计数时,当从0计数到arr值的时候......
  • IMX6ULL SPI控制器
    1IMX6ULLSPI控制器NXP的6ull参考手册第Chapter20介绍了SPI控制器,EnhancedConfigurableSPI(ECSPI)。1.1特点①、全双工同步串行接口。②、可配置的主/从模式。③、四个硬件片选信号,支持多从机。④、发送和接收都有一个32x64的FIFO。⑤、片选信号SS/CS,时钟信号S......