主题 : 为什么我的2440使用了系统总线后,在linux下总出现乱的读写信号! 复制链接 | 浏览器收藏 | 打印
级别: 新手上路
UID: 21298
精华: 0
发帖: 26
金钱: 130 两
威望: 26 点
综合积分: 52 分
注册时间: 2010-05-14
最后登录: 2017-09-13
楼主  发表于: 2011-04-09 14:56

 为什么我的2440使用了系统总线后,在linux下总出现乱的读写信号!

我最近做了一块板AD板,使用了mini2440的系统总线进行连接,在无系统时能很好的测出A/D转换值,但是到LINUX系统后,在AD芯片的控制引脚上用示波器能发现很多不知从哪里来的乱信号。

我的驱动是仿着友善的按键驱动写的,A/D转换好后的输出信号我连接到EINT3脚上,然后下降沿驱动中断,在中断处理程序中将转换数据读入数组中,然后应用程序就可以read数据了。我读数据时有很多假信号。将驱动一加载就有杂乱干扰信号,但我将驱动rmmod后就无杂乱信号出现。地址选择线我用了nGCS5  对应物理地址是0x28000000,用ioremap将其转换成读写空间基地址addr_base。控制位的设置地址用addr_base +4,读数据地址也是同样。

这是咋回事??不明白!
级别: 新手上路
UID: 21298
精华: 0
发帖: 26
金钱: 130 两
威望: 26 点
综合积分: 52 分
注册时间: 2010-05-14
最后登录: 2017-09-13
1楼  发表于: 2011-04-09 15:05

 所编写的驱动程序,有请大侠们检查!

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/irq.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <linux/sched.h>
#include <linux/gpio.h>
#include <plat/regs-adc.h>

#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/clk.h>
#include <linux/wait.h>
#include <mach/regs-clock.h>
#include <plat/regs-timer.h>
#include <linux/cdev.h>

#define DEVICE_NAME     "adc6126"


//#define  base_addr __va(0x28000000)

static unsigned char c_AD_CONTROL = 0x02;
static void __iomem *base_addr;

#define ADC6126_PA_ADC    0x28000000

#define ADC6126_CON    (0x04)
#define ADC6126_DATA    (0x04)
#define ADC6126_STUT    (0x08)

#define ADC6126CON     (*(volatile unsigned int*)(base_addr + ADC6126_CON))
#define ADC6126DATA     (*(volatile unsigned int*)(base_addr + ADC6126_DATA))
#define ADC6126STUTS      (*(volatile unsigned int*)(base_addr + ADC6126_STUT))

//ioctl(fd,cmd,arg)的第二个参数
#define IO_CTL_MCONA 0
#define IO_CTL_SHDNA 1
#define IO_CTL_CONA  2
#define IO_CTL_CSA   3
#define IO_CTL_STAT  4

volatile unsigned int adcvalue[8];
static unsigned int num_value=0;
static volatile int ev_adc = 0;
static DECLARE_WAIT_QUEUE_HEAD(adc_waitq);


struct adc6126_irq_desc {
    int irq;
    int pin;
    int pin_setting;
    int number;
    char *name;    
};

static struct adc6126_irq_desc adc_irq[] =
    {{IRQ_EINT3 , S3C2410_GPF(3) ,  S3C2410_GPF3_EINT3  , 0, "ADC6126"}
};


static void setCS(void)
{
      c_AD_CONTROL |= (1 <<3);
    ADC6126CON = c_AD_CONTROL;//(1 <<3);
//    outb(c_AD_CONTROL,ADC6126CON);
}
static void clsCS(void)
{
      c_AD_CONTROL &= ~(1 <<3);
    ADC6126CON = c_AD_CONTROL;
//    outb(c_AD_CONTROL,ADC6126CON);

}

static void init_11046(unsigned char data)
{
    unsigned char set_data = data ;
      setCS();
    udelay(2);
    ADC6126STUTS = (0X00 | set_data);
//    outb((0X00 | data),ADC6126CON);

    udelay(2);
      clsCS();

}

static irqreturn_t adc6126_interrupt(int irq, void *dev_id)
{
    struct adc6126_irq_desc *adc_irq = (struct adc6126_irq_desc *)dev_id;
    int down;
    unsigned char i;
      int data;
//    adc_irq = (struct adc6126_irq_desc *)dev_id;
    // udelay(0);
    down = s3c2410_gpio_getpin(S3C2410_GPF(3));
    printk("pin %d:%d\n",adc_irq->pin,down);
    if (down == 0 )
      { // Changed
//    printk("pin %d:%d\n",S3C2410_GPF(3),down);

    setCS();
    num_value = 0 ;
    for(i=0;i<8;i++){
       //      ndelay(1);
        data = ADC6126DATA ;
//        data = inw(ADC6126DATA);
        data = data & 0xffff;
          adcvalue[num_value+i] = data;
    
    }
     //   ndelay(1);
    clsCS();
      ev_adc = 1;
      wake_up_interruptible(&adc_waitq);
        }
    
    return IRQ_RETVAL(IRQ_HANDLED);
}

// ------------------- READ ------------------------
static int adc6126_read (struct file *filp, char __user *buff, size_t count, loff_t *offp)
{
//    int len;
    unsigned long err=-EINVAL;


    if (!ev_adc) {
    if (filp->f_flags & O_NONBLOCK)
        return -EAGAIN;
    else
        wait_event_interruptible(adc_waitq, ev_adc);
    }
      ev_adc = 0;
    num_value = 0 ;
    if(count <0)
        return -EINVAL;

    err=copy_to_user(buff,(const char *)adcvalue,min(sizeof(adcvalue),count));
//    memset((void *)adcvalue,0,sizeof(adcvalue));
    //}    
    return err ? -EINVAL:min(sizeof(adcvalue),count);
}    


// ------------------- IOCTL -----------------------
static int adc6126_ioctl (struct inode * inode ,struct file * file, unsigned int cmd, unsigned long data)
{
    switch (cmd)
        {
//c_AD_CONTROL BIT:      7..4      .3        .2        .1        .0
// defined            undefined    /cs        CONA        SHDNA        MCONA
//effect Bit                1:can R/W    1:auto10KHz    1:shutPOWER whenCONA=0,
//                                whenMCONA=0    0:POWER ON    conclk=MCONA,1:effect    

//ADC_STUTAS  (DB):       7..4      .3        .2            .1        .0
// defined            undefined    INT/EXT REF    Data Format        Reserved      CONVST Mode
//effect Bit                0:INT,1:EXT    0:OFFSET,1:two'scomplement    0:control,1:acquistion    whenCONA=0,conclk=MCONA,1:effect    


        case IO_CTL_MCONA : {
                 if(data == 0) {
                      c_AD_CONTROL &= ~(1 <<0);
                //    ADC6126CON = c_AD_CONTROL;
                //    outb(c_AD_CONTROL,ADC6126CON);
                }
                         else{
                      c_AD_CONTROL |= (1 <<0);
                //    ADC6126CON = c_AD_CONTROL;
                //    outb(c_AD_CONTROL,ADC6126CON);
                }
                    ADC6126CON = c_AD_CONTROL;
                         break;}
        case IO_CTL_SHDNA : {
                 if(data == 0) {
                      c_AD_CONTROL &= ~(1 <<1);
                //    ADC6126CON = c_AD_CONTROL;
                //    outb(c_AD_CONTROL,ADC6126CON);
                }
                         else{
                      c_AD_CONTROL |= (1 <<1);
                //    ADC6126CON = c_AD_CONTROL;
                //    outb(c_AD_CONTROL,ADC6126CON);
                }
                    ADC6126CON = c_AD_CONTROL;
                         break;}
        case IO_CTL_CONA : {
                 if(data == 0) {
                      c_AD_CONTROL &= ~(1 <<2);
                //    ADC6126CON = c_AD_CONTROL;
                //    outb(c_AD_CONTROL,ADC6126CON);
                }
                         else{
                      c_AD_CONTROL |= (1 <<2);
                //    ADC6126CON = c_AD_CONTROL;
                //    outb(c_AD_CONTROL,ADC6126CON);
                }
                    ADC6126CON = c_AD_CONTROL;
                         break;}
        case IO_CTL_CSA : {
                 if(data == 0) {
                      c_AD_CONTROL &= ~(1 <<3);
                //    ADC6126CON = c_AD_CONTROL;
                //    outb(c_AD_CONTROL,ADC6126CON);
                }
                         else{
                      c_AD_CONTROL |= (1 <<3);
                //    ADC6126CON = c_AD_CONTROL;
                //    outb(c_AD_CONTROL,ADC6126CON);
                }
                    ADC6126CON = c_AD_CONTROL;
                         break;}
        case IO_CTL_STAT : {
                 ADC6126STUTS = (unsigned char)(data &0x0f);
                //    outb((unsigned char)(data &0x0f),ADC6126STUTS);
                         break;}
        
                default :
                        {
//                printk ("ADC control : no cmd run  [ --kernel-- ]\n");
                return (-EINVAL);}
        }
    return 0;
    
}

// ------------------- OPEN ------------------------
static int adc6126_open (struct inode * inode ,struct file * file)
{
    int err = 0;
     c_AD_CONTROL = 0x00;

    c_AD_CONTROL = ( c_AD_CONTROL & 0x04); //SHDNA=0 : POWER ON
     ADC6126CON = c_AD_CONTROL ;
//    outb(c_AD_CONTROL,ADC6126CON);
    init_11046(8);
    s3c2410_gpio_cfgpin(adc_irq[0].pin,adc_irq[0].pin_setting);
    set_irq_type(adc_irq[0].irq, IRQ_TYPE_EDGE_FALLING);
//    memset((void *)adcvalue,0,sizeof(adcvalue));

    if (adc_irq[0].irq < 0) {
        return -EINVAL;
    }
        err = request_irq(adc_irq[0].irq, adc6126_interrupt, IRQ_TYPE_EDGE_BOTH,
                          adc_irq[0].name, (void *)&adc_irq[0]);
//    ret = request_irq(IRQ_ADC, adcdone_int_handler, IRQF_SHARED, DEVICE_NAME, &adcdev);

    if (err) {
        return -EBUSY;
        }
    
    ev_adc = 1;
    
    
    return 0;
}    

// ------------------- RELEASE/CLOSE ---------------
static int adc6126_release (struct inode  * inode ,struct file * file)
{
     c_AD_CONTROL = 0x00;
    c_AD_CONTROL = ( c_AD_CONTROL | 0x02);
     ADC6126CON = c_AD_CONTROL ;
//    outb(c_AD_CONTROL,ADC6126CON);

    if (adc_irq[0].irq < 0) {
        return 0;
    }
    
    disable_irq(adc_irq[0].irq);
    free_irq(adc_irq[0].irq, (void *)&adc_irq[0]);

//    printk( "adc6126 closed\n");

    return 0;
}
// -------------------------------------------------
/*
static unsigned int adc6126_poll( struct file *file, struct poll_table_struct *wait)
{
    unsigned int mask = 0;
    poll_wait(file, &adc_waitq, wait);
    if (ev_adc)
        mask |= POLLIN | POLLRDNORM;
    return mask;
}
*/

//struct file_operations adc6126_ctl_ops

static struct file_operations dev_fops={
    .owner    =     THIS_MODULE,
    .open = adc6126_open,
    .read = adc6126_read,
//    .write = adc6126_write,
    .ioctl = adc6126_ioctl,
    .release = adc6126_release,
};

static struct miscdevice misc = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = DEVICE_NAME,
    .fops = &dev_fops,
};


static int __init S3C2410_6126_CTL_init(void)
{
    int  ret = -ENODEV;
//    ret = misc_register(&misc);
    base_addr=ioremap(ADC6126_PA_ADC,0x10);
    if (base_addr == NULL) {
//        printk(KERN_ERR "Failed to remap register block\n");
        return -ENOMEM;
    }

//    printk("init start...1...\n");
    c_AD_CONTROL=0x00;
//    printk("init start...2...\n");

    ADC6126CON =c_AD_CONTROL;// c_AD_CONTROL=0x02;
//    outb(c_AD_CONTROL,ADC6126CON);    

//    printk("--------------------------------------------\n\n");

    ret = misc_register(&misc);

    if( ret < 0 )
    {
    
//          printk (" S3C2410: init_module failed with %d\n", ret);    
        return ret;
    }
    else
    {
//        printk("S3C2410 6126_driver register success!!! \n");
    }
        
    return 0;
}

static void __exit cleanup_6126_ctl(void)
{
    if(adc_irq[0].irq > 0){
    disable_irq(adc_irq[0].irq);
        
    free_irq(adc_irq[0].irq, (void *)&adc_irq[0]);
    }
    misc_deregister(&misc);

}


module_init(S3C2410_6126_CTL_init);
module_exit(cleanup_6126_ctl);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Atangxb");
级别: 新手上路
UID: 21298
精华: 0
发帖: 26
金钱: 130 两
威望: 26 点
综合积分: 52 分
注册时间: 2010-05-14
最后登录: 2017-09-13
2楼  发表于: 2011-04-09 15:10
另外有个疑问,有没有在应用程序中直接读取物理地址的方法吗??那我就不用为这简单的读写再写没用的驱动了!前段时间因为少加了个头文件,害的我没少加班!用了不少printk(),才找出来!
能自学入门Linux的人将可练就一种坚韧不拔的精神。。。
级别: 侠客
UID: 57277
精华: 0
发帖: 53
金钱: 270 两
威望: 54 点
综合积分: 106 分
注册时间: 2011-10-21
最后登录: 2012-01-08
3楼  发表于: 2011-11-20 07:18

 回 2楼(唐先生) 的帖子

我也关注系统总线访问的问题,楼主应该搞定了吧,能不能分享一下你的心得呢?谢谢。。。