最近想使用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);
}