beta_guo
驱动牛犊
驱动牛犊
  • 注册日期2005-11-22
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分40分
  • 威望5点
  • 贡献值0点
  • 好评度4点
  • 原创分0分
  • 专家分0分
阅读:2582回复:0

linux外设(SJA1000)驱动问题

楼主#
更多 发布于:2007-03-09 11:18
  在做一个ARM9-AT91RM9200挂CAN-SJA1000芯片的linux驱动时,出现以下问题:
把实地址通过ioremap映射到内核虚拟地址以后,对CAN的测试寄存器进行读写
的时候,出现不稳定的状况,写数进去,然后再读出来,这样写读26万多次,总会出现
一些读出来的数与写进去的不一致的现象,有时候多到几百次不一致,有时候
少,大概就几次。大家帮忙分析一下可能是什么原因导致的?谢谢了。

linux内核版本:linux-2.4.19 CPU:AT91RM9200
启动过程如下:9200-boot -> u-boot-1.1.4 -> linux-2.4.19
CAN芯片的片选初始化在 9200-boot 中进行,初始化过程如下:
void AT91F_Initcs4cs5()
{
    //* Setup MEMC to support CS4=smc
    AT91C_BASE_EBI->EBI_CSA |= AT91C_EBI_CS4A_SMC;
    

    //* Setup Flash
    AT91C_BASE_SMC2->SMC2_CSR[4] = (AT91C_SMC2_NWS & 0x7f) | AT91C_SMC2_WSEN
                                    | (AT91C_SMC2_TDF & 0x300) | AT91C_SMC2_BAT | AT91C_SMC2_DBW_8;
    AT91C_BASE_SMC2->SMC2_CSR[5] = (AT91C_SMC2_NWS & 0x7f) | AT91C_SMC2_WSEN
                                    | (AT91C_SMC2_TDF & 0x300) | AT91C_SMC2_BAT | AT91C_SMC2_DBW_8;
}
在u-boot中定义 CONFIG_SKIP_LOWLEVEL_INIT 这样boot中的cpu初始化配置就不会被改写了。

有一个现象必须提一下,我在 9200-boot中用如下代码测试则写读都正确,测试多少次都不会
出现不一致的现象。
============9200-boot的can测试代码 开始=================
#define CAN0 (volatile char*)0x50040000
volatile char  *BASEADD;

void setcanport(unsigned int reg, unsigned char data1)
{
    BASEADD = CAN0;
    *(BASEADD+8)=reg;
    *(BASEADD)=data1;
}
unsigned char getcanport(unsigned char reg)
{    
    unsigned char temp;
     BASEADD = CAN0;
    *(BASEADD+8)=reg;
    temp=*BASEADD;
    return (temp);
}
//寄存器读写测试
int RWtest(unsigned char chanal)
{
    unsigned char    temp = 0;
    int i,j,readErr = 0, readOk = 0;
    
    for(i=0; i < 10240; i++)
    {
        for(j=0;j<256;j++)
        {
             setcanport(9,j);
             temp = getcanport(9);
             if(temp != j)
                 readOk += 1;
             else
                 readErr += 1;
    
        }                
    
    }
    return readErr;
}
============9200-boot的can测试代码 结束=================

============linux下的can驱动 开始=================
#define CAN_SYS_HWADDR_BASE 0x50040000
static void  *can_sys_v_addr;                    //map can phy_addr to linux_addr

static void setcanport(unsigned char reg, unsigned char data)
{
    writeb(reg,can_sys_v_addr+0x8);//模拟ALE锁存地址,发地址信号; CAN的ale信号线接A3脚
    writeb(data,can_sys_v_addr);   //发送数据到地址
}

static unsigned char getcanport(unsigned char reg)
{
    unsigned char temp = 0;
    writeb(reg,can_sys_v_addr+0x8);   //模拟ALE锁存地址,发地址信号;
    temp=readb(can_sys_v_addr);       //从指定地址读取数据
    return (temp);
}

/******************************************************************
 * 函 数 名: rw_test                                              
 * 功    能: can芯片寄存器读写测试                                              
 * 入口参数: unsigned char chanal //can端口选择                                                  
*******************************************************************/
static int rw_test()
{
    unsigned char    temp = 0xBB;
    int i,j,readErr = 0, readOk=0;
    
    for(j=0; j < 1024; j++ )
    {
        for(i=0; i < 256; i++)
        {
            setcanport(9,i);
            temp = getcanport(9);
    
            if( temp!= i)
            {
                readErr += 1;
            }
            else
            {
                readOk +=1;
            }
        }
    }
    printk("========[Test end.] readErr = %d  readOk = %d======\n", readErr, readOk);

    return num;
}

/*--linux设备文件结构定义---*/
static struct file_operations can_fops = {
//   owner:      THIS_MODULE,
     read :      read_can,
     write:      write_can,
     ioctl:         ioctl_can,
     open :         open_can,
     release:    release_can,

};

#ifdef CONFIG_DEVFS_FS
static devfs_handle_t devfs_can_dir, devfs_can_ram;
#endif

static int __init test_can_init(void)
{
    int result;
    int i = 0;
    struct resource *res;

    AT91F_PIOB_CfgPMC();

    result=register_chrdev(0,DEVICE_NAME,&can_fops);  //注册一个设备,得到驱动的主设备号,动态

    if(result<0)
    {
        printk("cannot get can major number\n");  //没有成功
        return result;
    }

    canMajor = result;

    printk("CAN are successful registed major:%d\n", canMajor);

    #ifdef CONFIG_DEVFS_FS
    devfs_can_dir = devfs_mk_dir(NULL, "can_b", NULL);
    devfs_can_ram = devfs_register(devfs_can_dir, DEV_FILE_NAME , DEVFS_FL_DEFAULT,
                    canMajor, CAN_MINOR ,
                    S_IFCHR | S_IRUSR | S_IWUSR, &can_fops, NULL);
    #endif

    res = request_mem_region(CAN_SYS_HWADDR_BASE, 0x10, "can_b");
    if(res == NULL)
    {
        printk("<1>request_mem_region:can_b failed!\n");
        return -1;
    }
    can_sys_v_addr = ioremap(CAN_SYS_HWADDR_BASE,0x10);//映射物理地址到IO内存,可以让软件直接访问IO内存
    if(can_sys_v_addr == NULL)
    {
        printk("<1>ioremap:can_b failed!\n");
        return -1;
    }
    }
    
    #ifdef DEBUG_PRINT
    printk(DEVICE_NAME "initialized\n");
    #endif

    return 0;

}

static void __exit test_can_exit(void)
{
    unsigned int i = 0;

    #ifdef CONFIG_DEVFS_FS
    devfs_unregister(devfs_can_ram);
    devfs_unregister(devfs_can_dir);
    #endif

    iounmap(can_sys_v_addr);
    release_mem_region(CAN_SYS_HWADDR_BASE, 0x10);
        
    unregister_chrdev(canMajor,DEVICE_NAME);

}

/*--linux 模块驱动注册函数---*/
module_init(test_can_init);
module_exit(test_can_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("dddd");
MODULE_DESCRIPTION("CAN driver for at91rm9200");
============linux下的can驱动 结束=================
游客

返回顶部