免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 6362 | 回复: 14
打印 上一主题 下一主题

[求助]驱动中寄存器操作问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-09-05 17:56 |只看该作者 |倒序浏览
刚刚接触Linux驱动,最近在做一个串口扩展芯片的驱动,现在已经可以在内核挂载驱动模块了,测试代码也可以正常进入ioctl\write函数操作。但是无法对扩展芯片的寄存器进行操作,cpu是ARM的2440,串口扩展芯片连接8位数据总线,地址空间为BANK5。大家帮忙分析下问题,现在自己没什么思路。

//TL16C554 address map
//扩展芯片寄存器物理地址到虚拟地址映射,这个函数在模块加载_init中调用
int tl1A_AddressMap(void)
{
  tl1A.vBase = (unsigned char *)ioremap_nocache(tl1A.nAddress, ;
  if(tl1A.vBase == NULL)
  return -1;

  tl1A.RBR = (int)(tl1A.vBase);
  tl1A.THR = (int)(tl1A.vBase);
  tl1A.LSR = (int)(tl1A.vBase + 5);
  tl1A.MSR = (int)(tl1A.vBase + 6);
  tl1A.LCR = (int)(tl1A.vBase + 3);
  tl1A.FCR = (int)(tl1A.vBase + 2);
  tl1A.MCR = (int)(tl1A.vBase + 4);
  tl1A.DLL = (int)(tl1A.vBase);
  tl1A.DLM = (int)(tl1A.vBase + 1);
  tl1A.IER = (int)(tl1A.vBase + 1);
  tl1A.SPR = (int)(tl1A.vBase + 7);
  tl1A.IIR = (int)(tl1A.vBase + 2);

  return 0;
}
//外设芯片的初始化
//TL1A初始化
void Init_TL1A(void)
{
volatile unsigned char byRx = 0;
int i = 0;

//初始化接收缓冲区指针
tl1A.sRecvHead = 0;
tl1A.sRecvTail = 0;

//FIFO控制寄存器
  //设置FCR.FIFO使能,RXD复位,TXD复位,mode=1,触发为14;轮询方式触发设置无效
  writeb(0xcf, tl1A.FCR);

  //*(volatile unsigned char *)(tl1A.FCR) = 0xcf;
  for(i=0; i<100; i++);

  //set FCR.RXD复位,TXD复位
  writeb(0xc9, tl1A.FCR);
  printk("FCR = %x\n", readb(tl1A.FCR));
  printk("FCR L = %x\n", readl(tl1A.FCR));
  printk("FCR * = %x\n",*(volatile unsigned char *)(tl1A.FCR));

  // *(volatile unsigned char *)(tl1A.FCR) = 0xc9;
  //设置MCR3=0,外部中断使能
  writeb(0x08, tl1A.MCR);
  //*(volatile unsigned char *)(tl1A.MCR) = 0x08;
  //LCR7置位,设置DLL/DLM,选择波特率
  writeb(0x80, tl1A.LCR);
  //*(volatile unsigned char *)(tl1A.LCR) = 0x80;
  // DLM DLL BUADRATE
  // 00 0x0C 9600BPS
  // 00 0x06 19200BPS   
  writeb(BAUDBASE, tl1A.DLL);
  //*(volatile unsigned char *)(tl1A.DLL) = BAUDBASE;
  writeb(0x00, tl1A.DLM);
  
  //LCR7清零,8位数据,无奇偶校验
  writeb(0x03, tl1A.LCR);
  //设置IER,发送保持、接收中断
  writel(0x01, tl1A.IER);

//空读一次
  byRx = readl(tl1A.RBR);
  
  //读空
  while(1)
  {
  byRx = readl(tl1A.LSR);
  // byRx = *(volatile unsigned char *)(tl1A.LSR);
  if(byRx & 0x01) //检查接收状态
  {
  byRx = readl(tl1A.RBR);
  // byRx = *(volatile unsigned char *)(tl1A.RBR);
  }
  else
  break;
  //防止死循环
  i++;
  if(i > 4096) //每个通道最多只能缓存16个字节
  break;
}
}

//应用程序调用ioctl进行内存初始化,打印寄存器信息
static int TL1A_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
switch(cmd)  
{
case TL_INIT:
printk("IER = 0x%x \n",readb(tl1A.IER));
printk("LCR = 0x%x \n",readb(tl1A.LCR));
printk("DLL = 0x%x \n",readb(tl1A.DLL));
printk("DLM = 0x%x \n",readb(tl1A.DLM));
Init_TL1A();
printk("IER = 0x%x \n",readb(tl1A.IER));
  printk("LCR = 0x%x \n",readb(tl1A.LCR));
  printk("DLL = 0x%x \n",readb(tl1A.DLL));
  printk("DLM = 0x%x \n",readb(tl1A.DLM));

break;
default:
return -EINVAL;
}

现在的问题就是初始化前后的寄存器和设定值不同,有个疑问:
1.自己做的板子,在内核中没有进行虚拟地址和物理地址的映射设定,程序采用动态映射,是否有影响?
2.刚接触Linux驱动,我现在要操作的是外部设备寄存器,采用动态地址映射是否可以?驱动读写ARM控制寄存器是正常的
初始化代码、读写代码在无OS情况下都验证过了,读写都没有问题。
自己已经调试两天了,有点焦头烂额,只好来论坛求助了~~~,大家帮帮忙

论坛徽章:
0
2 [报告]
发表于 2010-09-06 10:20 |只看该作者
自己做的板子,在内核中没有进行虚拟地址和物理地址的映射设定,程序采用动态映射,是否有影响
答: 肯定没有影响。君不见, 很多driver都是使用ioremap来配置映射表的吗?不过ioremap是以一个page为单位的。

初始化代码、读写代码在无OS情况下都验证过了,读写都没有问题
问: 你所说的无OS, 都是在2440上操作的吗? TL16C554我没接触过, 但是若TL16C554有特殊的标记, 如芯片ID号等, 可ioremap后, 尝试读取一些特殊寄存器, 看看能否读取到数据, 挂在地址总线上, 还得保证芯片能跟得上总线的速度。有逻辑分析仪可勾看一下。

论坛徽章:
0
3 [报告]
发表于 2010-09-06 10:42 |只看该作者
回复 2# kamingli

刚接触Linux驱动,对很多内容还没搞透彻,所以疑问比较多。没有OS也是在2440上跑的,读写都是正常的,当时的CPU主频也是400M,和现在跑OS的主频是一样的,应该不存在TL16C554速度跟不上的问题吧。另外,寄存器虚拟地址这样设置是否有问题:
tl1A.vBase = (unsigned char *)ioremap_nocache(tl1A.nAddress, ;
tl1A.RBR = (int)(tl1A.vBase);
  tl1A.THR = (int)(tl1A.vBase);
  tl1A.LSR = (int)(tl1A.vBase + 5);
  tl1A.MSR = (int)(tl1A.vBase + 6);
  tl1A.LCR = (int)(tl1A.vBase + 3);
  tl1A.FCR = (int)(tl1A.vBase + 2);
  tl1A.MCR = (int)(tl1A.vBase + 4);
  tl1A.DLL = (int)(tl1A.vBase);
  tl1A.DLM = (int)(tl1A.vBase + 1);
  tl1A.IER = (int)(tl1A.vBase + 1);
  tl1A.SPR = (int)(tl1A.vBase + 7);
  tl1A.IIR = (int)(tl1A.vBase + 2);

物理地址是连续的8个寄存器,先将基地址映射成虚拟地址,加上偏移获得其它寄存器地址,不知道这样进行虚拟地址映射是否有问题?

论坛徽章:
0
4 [报告]
发表于 2010-09-07 10:00 |只看该作者
我没看出有什么问题. 建议, 在driver里收索一下有关ioremap的函数, 看看别人的driver是怎么写的, 跟自己的比对一下. ioremap后, 映射表也是以一个page为单位来转换的, 但是有个问题是, 串口芯片的物理地址是否32位对齐? ioremap返回的虚拟地址所对应的物理地址是32位对齐的.

论坛徽章:
0
5 [报告]
发表于 2010-09-07 10:01 |只看该作者
我写错了, 是page对齐. 串口芯片的物理地址必须是page对齐.

论坛徽章:
0
6 [报告]
发表于 2010-09-08 09:05 |只看该作者
回复  kamingli

刚接触Linux驱动,对很多内容还没搞透彻,所以疑问比较多。没有OS也是在2440上跑的,读 ...
ytz963 发表于 2010-09-06 10:42



    tl1A.vBase = (unsigned char *)ioremap_nocache(tl1A.nAddress, ;
tl1A.RBR = (int)(tl1A.vBase);
  tl1A.THR = (int)(tl1A.vBase);
  tl1A.LSR = (int)(tl1A.vBase + 5);
  tl1A.MSR = (int)(tl1A.vBase + 6);
  tl1A.LCR = (int)(tl1A.vBase + 3);
  tl1A.FCR = (int)(tl1A.vBase + 2);
  tl1A.MCR = (int)(tl1A.vBase + 4);
  tl1A.DLL = (int)(tl1A.vBase);
  tl1A.DLM = (int)(tl1A.vBase + 1);
  tl1A.IER = (int)(tl1A.vBase + 1);
  tl1A.SPR = (int)(tl1A.vBase + 7);
  tl1A.IIR = (int)(tl1A.vBase + 2);

物理地址是连续的8个寄存器,先将基地址映射成虚拟地址,加上偏移获得其它寄存器地址,不知道这样进行虚拟地址映射是否有问题?


寄存器是32位还是8位的??

从tl1A.vBase = (unsigned char *)ioremap_nocache(tl1A.nAddress, 看tl1a.vBase是 (unsigned char *) 8位的,但为什么后面的映射都加(int)难道又是32位的??

tl1A.vBase + 3是想把tl1A.vBase加上3个bytes呢还是加上3个int呢,如果tl1A.vBase是(unsigned char *) ,(int)(tl1A.vBase + n)加的是n个bytes。

这个乱的。

论坛徽章:
0
7 [报告]
发表于 2010-09-08 09:24 |只看该作者
readkernel看得真仔细, 其实他想把地址都存到相应的变量中, 因此就先是unsigned char 再 int, 说起int,
是不是使用unsigned int会更好呢.

"物理地址是连续的8个寄存器,先将基地址映射成虚拟地址,加上偏移获得其它寄存器地址,不知道这样进行虚拟地址映射是否有问题?"  这样是没有问题的.

从程序上看来是没有多大问题的, 但是某些细节得注意, 如readl(tl1A.RBR); tl1A的结构体内的变量不是
volatile型, 或许会被优化掉, 对了会使用到readl吗? 数据线有32位?

论坛徽章:
0
8 [报告]
发表于 2010-09-08 10:37 |只看该作者
谢谢kamingli一直关注我的帖子,也谢谢readkernel。强制转换成int是为了得到每个寄存器虚拟内存地址,外设寄存器是8位的,所以ioremap强转成unsigned char,readl问题自己也注意到了,后面进行了修改

论坛徽章:
0
9 [报告]
发表于 2010-09-10 09:37 |只看该作者
结果如何?调通了吗?

论坛徽章:
0
10 [报告]
发表于 2010-09-14 17:23 |只看该作者
本帖最后由 ytz963 于 2010-09-14 17:25 编辑

谢谢kamingli的一直关注,最近一直在调试这个问题,还是没有调通。
讲一下这阶段的调试过程:
1.最初是怀疑自己地址映射有问题,通过驱动读状态寄存器的值和手册中复位后的值是一致的,说明虚拟地址映射是正常的;奇怪的是,寄存器无法写入,状态寄存器始终是复位值,芯片的复位管脚连接也是正确的,于是开始怀疑是写的时序问题
2.逻辑分析仪抓取带OS和无OS的时序,带OS的时序也是正常的,和无OS下操作基本相同。自己的分析是否有什么问题?
上图:
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP