Mini2440开发板PWM驱动与测试程序简要分析

发布者:Huanle666最新更新时间:2024-06-19 来源: elecfans关键字:Mini2440  PWM驱动  测试程序 手机看文章 扫描二维码
随时随地手机看文章

先看下电路原理图

 

#include

#include

#include

#include

#include

#include

#include

#include

 

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

 

#define DEVICE_NAME    'pwm'

 

#define PWM_IOCTL_SET_FREQ              1    //设置pwm的频率

#define PWM_IOCTL_STOP                        0    //停止pwm

 

static struct semaphore lock;           

//定义信号量,此处的信号量是一个互斥信号量,用于PWM设备之多只能被一个进程打开

 

/* freq:  pclk/50/16/65536 ~ pclk/50/16

  * if pclk = 50MHz, freq is 1Hz to 62500Hz

  * human ear : 20Hz~ 20000Hz

  */

static void PWM_Set_Freq( unsigned long freq )

{

        unsigned long tcon;

        unsigned long tcnt;

        unsigned long tcfg1;

        unsigned long tcfg0;

 

        struct clk *clk_p;

        unsigned long pclk;

 

        //set GPB0 as tout0, pwm output

        s3c2410_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0);//功能配置

 

        tcon = __raw_readl(S3C2410_TCON);    //获得定时器控制寄存器的数值

        tcfg1 = __raw_readl(S3C2410_TCFG1);  //获得定时器配置寄存器0的值

        tcfg0 = __raw_readl(S3C2410_TCFG0);  //获得定时器配置寄存器1的值

 

        //prescaler = 50

        tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;

        tcfg0 |= (50 - 1);

 

        //mux = 1/16

        tcfg1 &= ~S3C2410_TCFG1_MUX0_MASK;

        tcfg1 |= S3C2410_TCFG1_MUX0_DIV16;

 

        __raw_writel(tcfg1, S3C2410_TCFG1);

        __raw_writel(tcfg0, S3C2410_TCFG0);

 

        clk_p = clk_get(NULL, 'pclk');

        pclk  = clk_get_rate(clk_p);

        tcnt  = (pclk/50/16)/freq;

       

        __raw_writel(tcnt, S3C2410_TCNTB(0));

        __raw_writel(tcnt/2, S3C2410_TCMPB(0));

                                   

        tcon &= ~0x1f;

        tcon |= 0xb;              //disable deadzone, auto-reload, inv-off, update TCNTB0&TCMPB0, start timer 0

        __raw_writel(tcon, S3C2410_TCON);

       

        tcon &= ~2;                        //clear manual update bit

        __raw_writel(tcon, S3C2410_TCON);

}

 

static void PWM_Stop(void)

{

        s3c2410_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPIO_OUTPUT);

        s3c2410_gpio_setpin(S3C2410_GPB(0), 0);

}

 

static int s3c24xx_pwm_open(struct inode *inode, struct file *file)

{

        if (!down_trylock(&lock))//判断是否设备已经打开,已打开返回EBUSY

                  return 0;

        else

                  return -EBUSY;

}

 

 

static int s3c24xx_pwm_close(struct inode *inode, struct file *file)

{

        PWM_Stop();//停止PWM

        up(&lock);//释放信号量

    return 0;

}

 

 

static int s3c24xx_pwm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)

{

        //printk('ioctl pwm: %x %lxn', cmd, arg);

        switch (cmd) {

        case PWM_IOCTL_SET_FREQ:

                  if (arg == 0)

                            return -EINVAL;

                  PWM_Set_Freq(arg);

                  break;

 

        case PWM_IOCTL_STOP:

                  PWM_Stop();

                  break;

        }

 

        return 0;

}

 

 

static struct file_operations dev_fops = {

    .owner  =  THIS_MODULE,

    .open    =  s3c24xx_pwm_open,

    .release =  s3c24xx_pwm_close,

    .ioctl  =  s3c24xx_pwm_ioctl,

};

 

static struct miscdevice misc = {

        .minor = MISC_DYNAMIC_MINOR,

        .name = DEVICE_NAME,

        .fops = &dev_fops,

};

 

static int __init dev_init(void)

{

        int ret;

 

        init_MUTEX(&lock);

        ret = misc_register(&misc);

 

        printk (DEVICE_NAME'tinitializedn');

            return ret;

}

 

static void __exit dev_exit(void)

{

        misc_deregister(&misc);

}

 

module_init(dev_init);

module_exit(dev_exit);

MODULE_LICENSE('GPL');

MODULE_AUTHOR('FriendlyARM Inc.');

MODULE_DESCRIPTION('S3C2410/S3C2440 PWM Driver');


分析,这个程序的结构比较简单,只实现了open(),ioctl(),close()功能,其中最主要的就是ioctl()功能,在ioctl()中最重要的核心函数为static void PWM_Set_Freq( unsigned long freq );所以说只要分析懂了这个函数,这个驱动也都全懂了。要是做过这个裸机程序的就更简单了。里面出现的一些没分析的,在本博客另一篇LED驱动分析中基本都说过了,不清楚的可以去看那个。

首先分析static void PWM_Set_Freq( unsigned long freq );

static void PWM_Set_Freq( unsigned long freq )

{

        unsigned long tcon;

        unsigned long tcnt;

        unsigned long tcfg1;

        unsigned long tcfg0;

 

        struct clk *clk_p;

        unsigned long pclk;

 

        //set GPB0 as tout0, pwm output

        s3c2410_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0);//功能配置

 

        tcon = __raw_readl(S3C2410_TCON);    //获得定时器控制寄存器的数值

        tcfg1 = __raw_readl(S3C2410_TCFG1);  //获得定时器配置寄存器0的值

        tcfg0 = __raw_readl(S3C2410_TCFG0);  //获得定时器配置寄存器1的值

 

        //prescaler = 50

        tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;

        tcfg0 |= (50 - 1);

    //上面的两句是设置预分频器

        //mux = 1/16

        tcfg1 &= ~S3C2410_TCFG1_MUX0_MASK;

        tcfg1 |= S3C2410_TCFG1_MUX0_DIV16;

    //上面两句设置MUX0

        __raw_writel(tcfg1, S3C2410_TCFG1);

        __raw_writel(tcfg0, S3C2410_TCFG0);

    //上面两句将配置好的数值写入到配置寄存器

        clk_p = clk_get(NULL, 'pclk');

        pclk  = clk_get_rate(clk_p);

    //上面两句用于获取PCLK

        tcnt  = (pclk/50/16)/freq;

        //上面这个数值决定了频率,

        __raw_writel(tcnt, S3C2410_TCNTB(0));

        __raw_writel(tcnt/2, S3C2410_TCMPB(0));

        //上面两句将tcnt寄存器写入到TCNTB0,同时设置S3C2410_TCMPB0,也就是说占空比为50%                       

        tcon &= ~0x1f;    //低五位清零

        tcon |= 0xb;              //disable deadzone, auto-reload, inv-off, update TCNTB0&TCMPB0, start timer 0

        __raw_writel(tcon, S3C2410_TCON);

       

        tcon &= ~2;                        //clear manual update bit

        __raw_writel(tcon, S3C2410_TCON);

}

看几个宏定义:

#define S3C2410_TCFG_PRESCALER0_MASK (255<<0)    //0xff<<0

#define S3C2410_TCFG1_MUX0_MASK  (15<<0)      //0xf<<0

#define S3C2410_TCFG1_MUX0_DIV16  (3<<0)       


分析:static void PWM_Stop(void)

static void PWM_Stop(void)

{

        s3c2410_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPIO_OUTPUT);//配置管脚为输出状态

        s3c2410_gpio_setpin(S3C2410_GPB(0), 0);                  //设置管脚为低电平输出

}

 

以下是测试程序

#include

#include

#include

#include

 

#define PWM_IOCTL_SET_FREQ              1

#define PWM_IOCTL_STOP                        0

 

#define    ESC_KEY            0x1b

 

static int getch(void)

{

        struct termios oldt,newt;

        int ch;

 

        if (!isatty(STDIN_FILENO)) {

                  fprintf(stderr, 'this problem should be run at a terminaln');

                  exit(1);

        }

        // save terminal setting

        if(tcgetattr(STDIN_FILENO, &oldt) < 0) {

                  perror('save the terminal setting');

                  exit(1);

        }

 

        // set terminal as need

        newt = oldt;

        newt.c_lflag &= ~( ICANON | ECHO );

[1] [2]
关键字:Mini2440  PWM驱动  测试程序 引用地址:Mini2440开发板PWM驱动与测试程序简要分析

上一篇:linux-2.6.32在mini2440开发板上移植 按键驱动程序移植
下一篇:mini2440 Norflash驱动移植过程

推荐阅读最新更新时间:2024-11-02 18:01

基于mini2440定时器模块的相关总结
一.从文档中我们可以知道,mini2440一共有5个定时器.如下图所示: 其中定时器0,1,2,3四个寄存器是有输出引脚的,是和蜂鸣器结合在一起的。定时器4是没有输出引脚的,所以定时器4是专门用来计时用的。 其中定时器0,1公用一个8位分频器,定时器2,3,4公用一个8位的分频器。 T = 次数 * 周期 = 1/fre(pwm) 其中:周期=1/f = 1/(50M/(prescaler+1)/(divider value). 关于定时器4的有关配置方法: 一.从上面的原理图可以知道,先输入一个PCLK(大小为50M,在启动代码中已经设置好了)。 然后经过一个8位分频器,值可以在(0~255之间)
[单片机]
基于<font color='red'>mini2440</font>定时器模块的相关总结
linux驱动之中断管理(for mini2440
2440处理器的中断组织成两层:主中断 和 次中断,一共可以处理60个中断源。 主中断 和 次中断 经过中断构架的抽象之后,编写驱动程序时,我们不用考虑这两层中断,直接使用 request_irq 注册 60个中断源的某个,就可以直接使用中断了。 err = request_irq(button_irqs .irq, buttons_interrupt, NULL, button_irqs .name, (void *)&button_irqs ); set_irq_type(button_irqs .irq, IRQT_BOTHEDGE); 像上面这样使用中断。 下面是主中断0~31共3
[单片机]
看板用LED驱动IC内建PWM将成趋势
  led显示看板作为讯息传播媒介,应用日趋多元,自单色、双色走向全彩显示后,色彩精准度、解析度、画素密度,与画面更新率等显示规格逐年向上发展,led驱动系统复杂度亦随之提升,LED驱动IC规格要求连带趋于严格。   以LED色彩精准度为例,因应全彩显示应用,LED驱动IC必须对RGB三色LED分别输出不同幅度的恒定电流(constant current),以获得最佳白平衡(white balance)色彩表现,传统用于单色、双色LED看板等色彩精准度要求低、成本也较低的定电压(constant voltage) LED驱动架构已不符需求。   此外,伴随LED长期使用发生的光衰现象,LED驱动IC具备个别LED画素数位点
[电源管理]
mini2440使用jlink烧写superboot到norflash
Jlink版本:J-flash ARM V4.12 J-Flash ARM的配置。 一般说来file-- open project里面会找到一些*.jflash的配置文件,加载他们就行了,但是没找到适合S3C2440的。所以自己建了一个mini2440.jflash,手动进行配置: j-link设置 1. 打开J-Flash ARM,并进入菜单:Options-- Project settings 2.主要设置CPU选项和Flash选项 CPU : Core -- ARM9, Little endian Use target RAM(faster)-- Addr:40000000 4KB(不选很慢
[单片机]
PIC12F629 LED输出测试程序
PIC12F629 LED输出测试程序 GP0,GP1,GP2,GP5输出高电平;GP4输出脉冲(LED闪烁) #include PIC.h __CONFIG(0x3114); //芯片配置字,看门狗关,上电延时开,掉电检测关,低压编程关,加密,4M晶体HS振荡 void delay() { unsigned long i; for(i=0;i 10000;i++); } void main () { TRISIO=0; CMCON=7; // 设置RA口全部为普通数字IO口 GPIO=0x3f; while(1) {
[单片机]
mini2440硬件篇之RTC
硬件原理 实时时钟(RTC)的主要功能是在系统掉电的情况下,利用后备电源使时钟继续运行,从而不会丢失时间信息。 1.1. 时间的设置和获取 s3c2440内部集成了RTC模块,而且用起来也十分简单。其内部的寄存器BCDSEC,BCDMIN,BCDHOUR,BCDDAY,BCDDATE,BCDMON和BCDYEAR分别存储了当前的秒,分,小时,星期,日,月和年,表示时间的数值都是BCD码。这些寄存器的内容可读可写,并且只有在寄存器RTCCON的第0位为1时才能进行读写操作。为了防止误操作,当不进行读写时,要把该位清零。当读取这些寄存器时,能够获知当前的时间;当写入这些寄存器时,能够改变当前的时间。另外需要注意的是,因为有
[单片机]
脉宽调制(PWM) 马达驱动器电源的测试分析(下)
8. 损耗与效率测量 对任意系统,要想对其损耗和效率进行测量,最好对系统输入和输出进行同步测量,如图11 所示。 图11. 效率测量图 对于高效系统( 如脉宽调制驱动器) 来说,这一点特别重要。这是因为,如果对输出和输出分开测量,而且在测量之间关闭系统来切换仪器,那么就不能始终确保两个测量具有完全相同的负载条件。如果忽视负载条件的任何差异,那么都会导致测得损耗的误差。 例如: 设置Number 1 测量输入。 关闭系统,重新连接输出测量,并再次开启系统: 设置Number 2 测量输出( 但条件稍微变化)。 表现损耗 = 1052.6 W - 1020 W = 32.6 W 实际损耗 =
[测试测量]
脉宽调制(<font color='red'>PWM</font>) 马达<font color='red'>驱动</font>器电源的测试分析(下)
MINI2440 QEMU 的 eCos 启动分析
1.总览一下eCos的启动方式 eCos目前默认的启动方式有三种,RAM,ROM,ROMRAM。 RAM启动的意思就是直接在RAM中运行,这种方式一般用于调试,不做必要的硬件初始化。 ROM启动方式的意思是在ROM中直接运行,当然一定要支持XIP的NORFLASH才可以。 ROMRAM的启动方式的意思是,ROM中开始运行然后把所有的代码复制到RAM中继续运行。 2.Mini2440 QEMU的启动方式的选择 MINI2440中目前还没有实现NOR和NAND Flash,(虽然NAND的代码加了,但是里面注名工作不是很正常,我姑且认为不能用吧) 所以,我们必须在RAM中运行eCos,并且还要完成硬件的初始化任务,这也就有了接下
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved