貌似俺的配置是正确的,俺是裸奔,没带操作系统!,就是不工作,郁闷!
俺的配置也跟下面这个差不多
AT91C_BASE_EBI->EBI_CSA |= AT91C_EBI_CS4A_SMC;
AT91C_BASE_SMC2->SMC2_CSR[4] = 一个值
下面转一个别人的帖子!
在做一个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驱动 结束================= |