主题 : 同时使用mini6410上的pwm输出和定时器中断的问题 复制链接 | 浏览器收藏 | 打印
级别: 新手上路
UID: 69823
精华: 0
发帖: 2
金钱: 10 两
威望: 2 点
综合积分: 4 分
注册时间: 2012-05-11
最后登录: 2019-06-07
楼主  发表于: 2012-07-02 18:22

 同时使用mini6410上的pwm输出和定时器中断的问题

最近想使用mini6410开发板做个红外遥控器,需要用PWM Timer1输出38khz的载波;并用PWM Timer2产生中断实现红外遥控的协议。但是驱动一加载到板子上就发现跑马灯明显变慢了,而且就连在超级终端上敲字符都变慢了,请各位大侠帮忙看看驱动是哪里出了问题,感激不尽!

我自己做实验发现问题应该就是pwm_timer_init()这个函数里寄存器配置的问题,但是我就是不知道问题错在哪??

———————————————————————————————驱动源码————————————————————————————————————————
#include <linux/module.h>
#include <linux/kernel.h>  
#include <linux/init.h>    
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>

#include <asm/io.h>      
#include <asm/uaccess.h>  
#include <linux/delay.h>  
//#include <asm/delay.h>

#include <linux/clk.h>      
//#include <plat/regs-clock.h>

//#include <mach/hardware.h>    
#include <linux/interrupt.h>
#include <linux/irq.h>

#include <plat/regs-timer.h>

#include <mach/gpio.h>
#include <plat/gpio-cfg.h>
#include <plat/regs-gpio.h>

//#include <plat/gpio-bank-f.h>
//#include <plat/gpio-bank-k.h>

#include "ir_send.h"

MODULE_AUTHOR("tech");
MODULE_LICENSE("GPL");
MODULE_VERSION("1.0");

#define  IR_SEND_MAJOR   0
#define  IR_SEND_DEV_NUM   1
//#define  EFAULT   1
#define  DEVICE_NAME   "ir_send"

#define  BASE_FREQ   38000    //ir BASEBAND:38kHz
#define  M    (1000*1000/560)

/* internal api */
static void pwm_timer_init(void);
static void pwm_timer_start(void);
static void pwm_timer_stop(void);
static void gpio_init(void);
//static void ir_code(u8 code);

//static void ir_code_send(u8 addr_code,u8 data_code);


/* driver api */
static irqreturn_t timer2_int_handler(int irq, void *dev_id);
static int ir_send_open(struct inode * inode, struct file * filp);
static int ir_send_ioctl(struct inode * inode, struct file * file,unsigned int cmd, unsigned long arg);
static int ir_send_close(struct inode * inode,struct file * filp);

static const struct file_operations fops_ir_send =
{
   .owner  =   THIS_MODULE,
              .ioctl  =   ir_send_ioctl,
              .open   =   ir_send_open,
              .release=   ir_send_close,
};

/* static variables */
static struct cdev cdev;
static struct class *class = NULL;
static int ir_send_major = IR_SEND_MAJOR;

/* global variables */
u8 i = 0, j = 0;
u8 a = 2, b = 4;
u8 N = 1;
u32 code;

/* driver api */
static irqreturn_t timer2_int_handler(int irq, void *dev_id)
{  
   // unsigned long tint_stat;
    i++;
   //tint_stat = __raw_readl(S3C_TINT_CSTAT);
   //tint_stat |= (1<<7);
   //__raw_writel(tint_stat, S3C_TINT_CSTAT);
    if(((i-1)/8 ==1)&&(j=0))
      gpio_set_value(S3C64XX_GPK(8),0);
    else if(((i-1)/8 == 2)&&(j=0))
      {gpio_set_value(S3C64XX_GPK(8),1); i = 0; j = 1;}
    else if((j = 1)&&(N <= 32))
      { switch (i)
        {case 1: gpio_set_value(S3C64XX_GPK(8),0); break;
         default: {
            if(i<(((code&0x01)==0)?a:b))
              gpio_set_value(S3C64XX_GPK(8),0);
            else {
                gpio_set_value(S3C64XX_GPK(8),1);
                i = 0;
                code = code >> 1; N++;
                 }
          }
         }
       }
    else
        pwm_timer_stop();
    return (IRQ_HANDLED);

};

static int __init ir_send_init(void)
{    
     int ret;
     dev_t devno;
    
     /* register devno for ir_send */
     devno = MKDEV(ir_send_major, 0);
     if(ir_send_major > 0)
         ret = register_chrdev_region(devno, IR_SEND_DEV_NUM, DEVICE_NAME);
     else
         {
         ret = alloc_chrdev_region(&devno, 0, IR_SEND_DEV_NUM, DEVICE_NAME);
        ir_send_major = MAJOR(devno);
        }
     printk ("ir_send init major:%d...\n",ir_send_major);
     if (ret < 0)
         {
         printk ("%s can't register\n", DEVICE_NAME);
        return ret;
        }
     /* add the device to kernel */
     cdev_init(&cdev, &fops_ir_send);
     cdev.owner = THIS_MODULE;
     ret = cdev_add(&cdev, MKDEV(ir_send_major,0), IR_SEND_DEV_NUM);
     if(ret)
         printk("Error %d\n", ret);
     else
         printk("have finish add\n");
    
     class =class_create(THIS_MODULE,DEVICE_NAME);
     device_create(class, NULL, MKDEV(ir_send_major, 0), NULL, DEVICE_NAME);

     //init ir_send configuration
     pwm_timer_init();
     gpio_init();
     /*ret = request_irq(IRQ_TIMER2, timer2_int_handler, IRQF_DISABLED, DEVICE_NAME, NULL);
     if(ret) {
         printk("Register IRQ_TIMER2 failed!\n");
        return ret;
     }    
     */
     printk("%s Initialized \n",DEVICE_NAME);
     return 0;
}

static void __exit ir_send_exit(void)
{  
    device_destroy(class,MKDEV(ir_send_major, 0));
    cdev_del(&cdev);
    class_destroy(class);
    unregister_chrdev_region(MKDEV(ir_send_major, 0), 1);
    free_irq(IRQ_TIMER2, NULL);
    printk("unregister ir_send\n");
}

static int ir_send_open(struct inode * inode, struct file * filp)
{  
    return 0;
}

static int ir_send_ioctl(struct inode * inode, struct file * file,unsigned int cmd, unsigned long arg)
{
  u32 addr_code, addr_code1;
  u32 data_code, data_code1;
  ir_drv_args_t ir_args;
  
  switch(cmd)
      {
       case IR_SEND_START:
        if(copy_from_user(&ir_args, (void*)arg, sizeof(ir_drv_args_t)))
            {
                printk("fail to copy from user!\n");
                return -EFAULT;
            }
        addr_code = ir_args.addr_code;
        addr_code1 = ~ir_args.addr_code;
        data_code = ir_args.data_code;
        data_code1 = ~ir_args.data_code;
        code = data_code1<<24|data_code<<16|addr_code1<<8|addr_code;
        gpio_set_value(S3C64XX_GPK(8),1);
        pwm_timer_start();
        break;
        
     case IR_SEND_STOP:    
     default:
         pwm_timer_stop();
        break;
      }
  
  return 0;
}

static int ir_send_close(struct inode *inode,struct file *filp)
{
  //free_irq(IRQ_TIMER2, NULL);
  return 0;
}

module_init(ir_send_init);
module_exit(ir_send_exit);



/* internal api */
static void pwm_timer_init(void)
{
   unsigned long tcnt;
   unsigned long tcfg1;
   unsigned long tcfg0;
   unsigned long tint;
   struct clk *clk_p;
   unsigned long pclk;
   unsigned tmp;

   // set GPF15 as pwm1out
   tmp = readl(S3C64XX_GPFCON);
   tmp &= ~(0x3U << 30);
   tmp |= (0x2U << 30);
   writel(tmp, S3C64XX_GPFCON);
  
   tcfg1 = __raw_readl(S3C_TCFG1);
   tcfg0 = __raw_readl(S3C_TCFG0);
  
   //prescaler0 = 2; prescaler1 = 40
   //tcfg0 &= ~S3C_TCFG_PRESCALER0_MASK;
   //tcfg0 |= ((2 - 1)<<0);  /* the initial state of Prescaler0 is 1 */
   //tcfg0 &= ~S3C_TCFG_PRESCALER1_MASK;
   //tcfg0 |= ((40 - 1)<<8); /* the initial state of Prescaler1 is 39 */
   tcfg0 &= ~(S3C_TCFG_PRESCALER0_MASK|S3C_TCFG_PRESCALER1_MASK);
   tcfg0 |= ((2 - 1)<<0)|((40 - 1)<<8);
  
   //MUX1 = 1/8; MUX2 = 1/8
   //tcfg1 &= ~S3C_TCFG1_MUX1_MASK;
   //tcfg1 |= S3C_TCFG1_MUX1_DIV8;
   //tcfg1 &= ~S3C_TCFG1_MUX2_MASK;
   //tcfg1 |= S3C_TCFG1_MUX2_DIV8<<8;
   tcfg1 &= ~(S3C_TCFG1_MUX1_MASK|S3C_TCFG1_MUX2_MASK);
   tcfg1 |= S3C_TCFG1_MUX1_DIV8|S3C_TCFG1_MUX2_DIV8<<8;
  
   __raw_writel(tcfg1, S3C_TCFG1);
   __raw_writel(tcfg0, S3C_TCFG0);

   //set pwm1out frequency
   clk_p = clk_get(NULL, "pclk");
   pclk  = clk_get_rate(clk_p);
   tcnt  = (pclk/2/8)/BASE_FREQ;    //freq = 38kHz
   __raw_writel(tcnt, S3C_TCNTB(1));
   __raw_writel(tcnt/2, S3C_TCMPB(1));

   //set timer2 interrupt
   tcnt = (pclk/40/8)/M;
   tint = __raw_readl(S3C_TINT_CSTAT);
   tint |= S3C_TINT_CSTAT_T2INTEN;
   __raw_writel(tcnt, S3C_TCNTB(2));
   __raw_writel(tint, S3C_TINT_CSTAT);
}

static void pwm_timer_start(void)
{
    unsigned long tcon;
    tcon = __raw_readl(S3C_TCON);
    tcon &= ~((0xf<<8)|(0xf<<12));
    tcon |= ((0xb<<8)|(0xb<<12));        // auto-reload, inv-off, manual update, start timer 1&timer 2
    __raw_writel(tcon, S3C_TCON);
    tcon &= ~((0x2<<8)|(0x2<<12));        //clear manual update bit
    __raw_writel(tcon, S3C_TCON);

}

static void pwm_timer_stop(void)
{
    unsigned long tcon;
    tcon = __raw_readl(S3C_TCON);
    tcon &= ~((0x1<<8)|(0x1<<12));        // stop timer 1&timer 2
    __raw_writel(tcon, S3C_TCON);
}

static void gpio_init(void)
{
    s3c_gpio_cfgpin(S3C64XX_GPK(8),S3C_GPIO_OUTPUT);  // set gpiok_8 as gpio_output
    s3c_gpio_setpull(S3C64XX_GPK(8),S3C_GPIO_PULL_NONE);
}
Embedded!
级别: 新手上路
UID: 91047
精华: 0
发帖: 35
金钱: 180 两
威望: 36 点
综合积分: 70 分
注册时间: 2013-05-01
最后登录: 2013-09-18
1楼  发表于: 2013-07-12 11:17
顶一个!