Chinaunix首页 | 论坛 | 博客
  • 博客访问: 74455
  • 博文数量: 11
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 94
  • 用 户 组: 普通用户
  • 注册时间: 2015-12-11 15:27
个人简介

给自己一个城堡

文章分类
文章存档

2017年(3)

2016年(8)

我的朋友

分类: LINUX

2016-06-06 16:00:52

1.TQ2440按键资源
    TXD1  --  GPH4
    RXD1  --  GPH5
2.内核介绍
    本驱动基于linux-tq2440,也即天嵌基于TQ2440移植的内核
3.原理
   基于字符设备驱动的一般方法,采用查询法实现串口驱动以及测试。
4.重要数据结构

点击(此处)折叠或打开

  1. struct cdev {
  2.     struct kobject kobj;
  3.     struct module *owner;
  4.     const struct file_operations *ops;
  5.     struct list_head list;
  6.     dev_t dev;
  7.     unsigned int count;
  8. };
    该结构用于描述一个字符设备。同时还有好多与之相关的函数(比如cdev_init用于初始化cdev结构等),具体查阅相关文档
5.驱动程序uart_mod.c

点击(此处)折叠或打开

  1. #include "linux/module.h"
  2. #include "linux/kernel.h"
  3. #include "asm/uaccess.h"
  4. #include "linux/serial_core.h"
  5. #include "asm/io.h"
  6. #include "linux/cdev.h"
  7. #include "plat/regs-serial.h"

  8. #define BUFF_SIZE 100
  9. #define UART_ULCON1 0x50004000
  10. #define UART_UCON1 0x50004004
  11. #define UART_UFCON1 0x50004008
  12. #define UART_UTRSTAT1 0x50004010
  13. #define UART_UTXH1         0x50004020
  14. #define UART_URXH1         0x50004024
  15. #define UART_UBRDIV1         0x50004028

  16. #define GPHCON         0x56000070
  17. #define GPHDAT         0x56000074
  18. #define GPHUP 0x56000078


  19. static int gMajorUart1 = 240;
  20. module_param(gMajorUart1,int,0);

  21. static void __iomem *gUlcon1;
  22. static void __iomem *gUcon1;
  23. static void __iomem *gUfcon1;
  24. static void __iomem *gUtrstat1;
  25. static void __iomem *gUtxh1;

  26. static void __iomem *gUrxh1;
  27. static void __iomem *gUbrdiv1;

  28. static void __iomem *gGphcon;
  29. static void __iomem *gGphup;


  30. int tq2440_uart_open(struct inode *inode,struct file *filp){
  31.     uint32_t conDat;
  32.     int i;
  33.     //ioremap
  34.     gUlcon1 = ioremap(UART_ULCON1,0x04);
  35.     gUcon1 = ioremap(UART_UCON1,0x04);
  36.     gUfcon1 = ioremap(UART_UFCON1,0x04);
  37.     gUtrstat1 = ioremap(UART_UTRSTAT1,0x04);
  38.     gUtxh1 = ioremap(UART_UTXH1,0x04);
  39.     gUrxh1 = ioremap(UART_URXH1,0x04);
  40.     gUbrdiv1 = ioremap(UART_UBRDIV1,0x04);

  41.     gGphcon = ioremap(GPHCON,0x04);
  42.     gGphup = ioremap(GPHUP,0x04);


  43.     iowrite32(0x00faaa, gGphcon);


  44.     conDat = ioread32(gGphup);
  45.     conDat |= (3<<4);
  46.     iowrite32(conDat, gGphup);


  47.     iowrite32(0x51, gUfcon1);
  48.     //iowrite32(0x0, gUfcon1);
  49.     iowrite32(0x3, gUlcon1);
  50.     iowrite32(0x245,gUcon1);
  51.     iowrite32(19,gUbrdiv1); //115200bps

  52.     for(i=0;i<100;i++);
  53.     return 0;
  54. }

  55. ssize_t tq2440_uart_write(struct file *filp,const char __user *buf,size_t count,loff_t *f_ops){
  56.     char wbuf[BUFF_SIZE] = {0};
  57.     int state;
  58.     int i;


  59.     i=0;
  60.     copy_from_user(wbuf,buf,count);

  61.     while(wbuf[i]){
  62.         state = ioread32(gUtrstat1);
  63.         //while(!(state & 0x2));
  64.         if((state & 0x2) == 2){
  65.             iowrite8(wbuf[i],gUtxh1);
  66.             //printk("send dat:%c.\n",wbuf[i]);
  67.             i++;
  68.         }
  69.     }

  70.     return count;
  71. }

  72. ssize_t tq2440_uart_read(struct file *filp,char __user *buf,size_t count,loff_t *f_ops){
  73.     char rbuf[BUFF_SIZE] = {0};
  74.     char tmpDat;
  75.     int i = 0;
  76.     int state;

  77.     printk("uart rcv start....\n");

  78.     while(1){
  79.         state = ioread32(gUtrstat1);
  80.         if((state & 0x1) == 1){
  81.             tmpDat=ioread8(gUrxh1);

  82.             // if you want to print info. you must enable fifo for uart,if not,you may lost some data.
  83.             //printk("uart rcv dat[%d]: %c-%02x\n",i,tmpDat,tmpDat);
  84.             
  85.             if(i < 100){
  86.                 rbuf[i++] = tmpDat;
  87.                 if(tmpDat == '\r'){
  88.                     printk("count = %d\n",i-1);
  89.                     copy_to_user(buf,rbuf,i);
  90.                     break;
  91.                 }
  92.             }
  93.             else{
  94.                 printk("count = %d\n",i-1);
  95.                 copy_to_user(buf,rbuf,100);
  96.                 break;
  97.             }
  98.             
  99.         }
  100.     }

  101.     return i-1;

  102. }

  103. int tq2440_uart_release(struct inode *inode,struct file *filp){
  104.     return 0;
  105. }

  106. struct file_operations tty_fops =
  107. {
  108.     .owner = THIS_MODULE,
  109.     .open = tq2440_uart_open,
  110.     .write = tq2440_uart_write,
  111.     .read = tq2440_uart_read,
  112.     .release = tq2440_uart_release,
  113. };

  114. static struct cdev gUartDev;

  115. static void uart_setup_cdev(struct cdev *dev,int minor, struct file_operations *fops){
  116.     int err;
  117.     int devno = MKDEV(gMajorUart1,minor);
  118.     cdev_init(dev,fops);
  119.     dev->owner = THIS_MODULE;
  120.     dev->ops = fops;
  121.     err = cdev_add(dev,devno,1);
  122.     if(err)
  123.         printk("error %d adding UART_UTRSTAT1 %d\n",err,minor);
  124. }

  125. static int tq2440_tty_init(void){
  126.     int ret;
  127.     dev_t dev = MKDEV(gMajorUart1,0);

  128.     if(gMajorUart1){
  129.         ret = register_chrdev_region(dev,1,"Mytty1");
  130.     }
  131.     else{
  132.         ret = alloc_chrdev_region(&dev,0,1,"Mytty1");
  133.         gMajorUart1 = MAJOR(dev);
  134.     }

  135.     if(ret < 0){
  136.         printk("unable to get major %d \n",gMajorUart1);
  137.         return ret;
  138.     }


  139.     uart_setup_cdev(&gUartDev,0,&tty_fops);

  140.     printk("tq2440 tty module installed,with major %d.\n",gMajorUart1);
  141.     return 0;
  142. }

  143. static void tq2440_tty_cleanup(void){
  144.     iounmap(gUlcon1);
  145.     iounmap(gUcon1);
  146.     iounmap(gUfcon1);
  147.     iounmap(gUtrstat1);
  148.     iounmap(gUtxh1);
  149.     iounmap(gUrxh1);
  150.     iounmap(gUbrdiv1);

  151.     iounmap(gGphcon);
  152.     iounmap(gGphup);


  153.     cdev_del(&gUartDev);
  154.     unregister_chrdev_region(MKDEV(gMajorUart1,0),1);
  155.     printk("tq2440 tty module uninstalled\n");
  156. }

  157. module_init(tq2440_tty_init);
  158. module_exit(tq2440_tty_cleanup);

  159. MODULE_AUTHOR("frankey");
  160. MODULE_LICENSE("Dual BSD/GPL");
    主要是实现cdev结构的fops函数,同时使用remap进行寄存器访问。串口都是采用查询法收发数据。
6.测试程序

点击(此处)折叠或打开

  1. #include "stdio.h"
  2. #include "string.h"
  3. #include "fcntl.h"

  4. #define BUFF_SIZE 100

  5. int main(int argc,char **argv){
  6.     int fd,ret;

  7.     char buff[BUFF_SIZE];
  8.     char *msg = "my tty1 test.\n";
  9.     fd = open("/dev/mytty1",O_RDWR);
  10.     if(fd<0){
  11.         printf("Error:open /dev/Mytty1 error!\n");
  12.         return 1;
  13.     }

  14.     printf("open file success. ready for reading...\n");

  15.     ret = write(fd,msg,strlen(msg));
  16.     if(ret<0){
  17.         printf("Error:write msg error\n");
  18.         return 1;
  19.     }
  20.     printf("write tty ok.\n");

  21.     memset(buff,0,sizeof(buff));
  22.     ret = read(fd,buff,BUFF_SIZE);
  23.     if(fd<0){
  24.         printf("Error:readread device error\n");
  25.         return 1;
  26.     }
  27.     printf("read device ok.[%d]\n",ret);
  28.     buff[ret+1] = 0;
  29.     if(buff[0]){
  30.         printf("Rcv:%s\n",buff);
  31.     }
  32.     else{
  33.         printf("Rcv:no data\n");
  34.     }

  35.     return 0;

  36. }
    测试程序采用阻塞方式操作设备文件。
7.测试结果
(1)加载模块并创建设备文件

(2)运行测试程序,交互

    运行测试程序后,测试程序发送“my tty test”给pc电脑。电脑通过串口工具发送“hello world”字串给开发板,同时字串结尾发送'\r',表明字串结束。从上图可以看出,开发板通过串口接收到了正确的字串。
8.注意
    由于本驱动采用的是查询法实现数据接收的,故最开始我在read实现这里,为了进行调试,增加了printk打印函数,导致每次接收的数据都是不完整的,存在很严重的丢数据现场,进过多次排查。重要定位到了问题,我的初始化里头,初始化串口字符设备的时候,使用的是iowrite32(0x0, gUfcon1);禁止了fifo功能,所以在接收数据的时候,又调用了printk函数,导致数据接收不正常,在此次去掉打印函数就可以正常,同时另一个方法,要想实现打印调试,可以使用iowrite32(0x53, gUfcon1);来使能串口的硬件FIFO功能,就可以在此处做打印调试了。
    同时串口初始化波特率也是最开始的时候出现了问题,数据接收不对。
         iowrite32(19,gUbrdiv1); //115200bps
    主要是这句话不对,这个波特率的设置要根据具体的内核初始化之后的pclk的时钟来计算ubrdiv寄存器的值。最后经过源码分析,内核初始化pclk的结果为37.5MHz,故在115200bps下,ubrdiv寄存器赋值应该为19.


    
阅读(4799) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~