pwm频率输出不对解决思路

平台:全志R16 Android4.4
内核:Linux3.4
概述:需要在底层使用pwm1进行IR模拟通信,发现pwm输出频率不正常

解决思路

一、调整周期和占空比

将pwm周期设为1ms,占空比为50%

	pwm_period_ns = 1000000;
	pwm_duty_ns = pwm_period_ns/2;	
 	pwm_config(ir_remote_pwm_dev, pwm_duty_ns, pwm_period_ns);

通过示波器测量发现频率有变化,说明pwm1是受控的,但周期放大了120倍。

二、通过读取寄存器查看当前pwm的状态

根据User_Manual我们可以找的pwm的基地址为0x01c21400
pwm频率输出不对解决思路_第1张图片
pwm频率输出不对解决思路_第2张图片

root@astar-evb30:/sys/class/sunxi_dump # echo 0x01c21400 > dump;cat dump
echo 0x01c21400 > dump;cat dump
0x0028005f		//第15-18位为000,为120分频
root@astar-evb30:/sys/class/sunxi_dump # echo 0x01c21408 > dump;cat dump
echo 0x01c21408 > dump;cat dump
0x5dbf2ee0 		//高16位为周期,低16位为active时间

具体时钟看高16位0x5dbf换算10进制位23,999
clk=24Mhz/(23,999+1) = 1,000
T=1/clk=1ms
结果很明显要么是在T=1ms时需要使用120分频,但数据未进行相应的转换,要么就是不需要使用分频时使用了分频。

三、查看代码

linux-3.4\drivers\pwm\pwm-sunxi.c

static int sunxi_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
		int duty_ns, int period_ns)
{

    #elif defined(CONFIG_ARCH_SUN8IW3P1) || defined(CONFIG_ARCH_SUN8IW5P1)

    __u32 pre_scal[11][2] = {{15, 1}, {0, 120}, {1, 180}, {2, 240}, {3, 360}, {4, 480}, {8, 12000}, {9, 24000}, {10, 36000}, {11, 48000}, {12, 72000}};
    __u32 freq;
    __u32 pre_scal_id = 0;
    __u32 entire_cycles = 256;
    __u32 active_cycles = 192;
    __u32 entire_cycles_max = 65536;
    __u32 temp;

    if(period_ns < 10667)
        freq = 93747;
    else if(period_ns > 1000000000)
        freq = 1;
    else
        freq = 1000000000 / period_ns;

    entire_cycles = 24000000 / freq / pre_scal[pre_scal_id][1];
	printk("PWM _TEST: entire_cycles=%d\n",entire_cycles);
    while(entire_cycles > entire_cycles_max) {
        pre_scal_id++;

        if(pre_scal_id > 10)
            break;

        entire_cycles = 24000000 / freq / pre_scal[pre_scal_id][1];
		printk("PWM _TEST: entire_cycles=%d\n",entire_cycles);
        }

    if(period_ns < 5*100*1000)
        active_cycles = (duty_ns * entire_cycles + (period_ns/2)) /period_ns;
    else if(period_ns >= 5*100*1000 && period_ns < 6553500)
        active_cycles = ((duty_ns / 100) * entire_cycles + (period_ns /2 / 100)) / (period_ns/100);
    else
        active_cycles = ((duty_ns / 10000) * entire_cycles + (period_ns /2 / 10000)) / (period_ns/10000);

    temp = sunxi_pwm_read_reg(0);
    if(pwm->pwm == 0)
        temp = (temp & 0xfffffff0) |pre_scal[pre_scal_id][0]; //pwm0命令
    else
        temp = (temp & 0xfff87fff) |(pre_scal[pre_scal_id][0]<<15); //将其修改为左移15位

    sunxi_pwm_write_reg(0, temp);			//写命令
    sunxi_pwm_write_reg((pwm->pwm + 1)  * 0x04, ((entire_cycles - 1)<< 16) | active_cycles);//写数据

    pwm_debug("PWM _TEST: duty_ns=%d, period_ns=%d, freq=%d, per_scal=%d, period_reg=0x%x\n", duty_ns, period_ns, freq, pre_scal_id, temp);
    #endif

    return 0;
}

发现其pwm1为进行相应的移位处理,移位后完美解决

root@astar-evb30:/sys/class/sunxi_dump # echo 0x01c21408 > dump;cat dump
echo 0x01c21408 > dump;cat dump
0x5dbf0bb8
root@astar-evb30:/sys/class/sunxi_dump # echo 0x01c21400 > dump;cat dump
echo 0x01c21400 > dump;cat dump
0x0028005f

附常用pwm操作

#include

struct pwm_device *pwm_request(int pwm_id, const char *label);
							//0/1:对应pwm编号
void pwm_free(struct pwm_device *pwm);

int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns);
                                        //占空时间      周期时间
int pwm_enable(struct pwm_device *pwm);

void pwm_disable(struct pwm_device *pwm);
//pwm极性
int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity);

enum pwm_polarity {
	PWM_POLARITY_NORMAL,
	PWM_POLARITY_INVERSED,
};

你可能感兴趣的:(学习记录,linux,驱动开发,arm开发)