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

发布时间:2024-06-19  

先看下电路原理图

 

#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

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>