驱动调试方法小结

1 . 调试输入子系统

     在调试输入子系统时,input_system,可以通过hexdump 来打开并且实时读取对于输入设备的值,数值关系如下图所示:

    每一次按键事件上报后,都会有type为0的EV_SYN同步事件触发。value中的1表示按下,0表示松开,2代表重复类事件,设置按键中断为边沿触发,一次按键会触发两次中断。

    如果开启了图形界面,可以打开图形界面的记事本,按相应的按键,可以得到对于的数值

    如果没有图形界面,可以执行 cat /dev/tty1 ,然后按相应的按键,可以得到

    更改输入设备 exec 0 < /dev/tty1

2.  操作一组寄存器

     在设置一些复杂设备的寄存器时,通常需要针对连续地址的多个寄存器进行设置,在Linux环境下,对于有关联关系的多个寄存器的操作,应该采取统一映射,结合将寄存器组合成结构体的方式来操作,这样,操作统一,简洁高效。

    例如:对于显示屏相关寄存器的操作,可以构造如下的结构体:

   1:  struct lcd_regs {
   2:      unsigned long    lcdcon1;        //start addrss : 0x4D00_0000
   3:      unsigned long    lcdcon2;
   4:      unsigned long    lcdcon3;
   5:      unsigned long    lcdcon4;
   6:      unsigned long    lcdcon5;
   7:      unsigned long    lcdsaddr1;
   8:      unsigned long    lcdsaddr2;
   9:      unsigned long    lcdsaddr3;
  10:      unsigned long    redlut;
  11:      unsigned long    greenlut;
  12:      unsigned long    bluelut;         //0x4D00_0028
  13:      unsigned long    reserved[9];    // addr( dithmode - bluelut) = 36 = 4 * 9
  14:      unsigned long    dithmode;        //0x4D00_004C
  15:      unsigned long    tpal;
  16:      unsigned long    lcdintpnd;
  17:      unsigned long    lcdsrcpnd;
  18:      unsigned long    lcdintmsk;
  19:      unsigned long    lpcsel;
  20:  };
  21:  static volatile struct lcd_regs* lcd_regs;
  22:  //    lcd_regs = ioremap(0x4D000000, sizeof(struct lcd_regs));
  23:  //    lcd_regs->lcdcon1  = (4<<8) | (3<<5) | (0x0c<<1);
  24:  //    lcd_regs->lcdcon2  = (3<<24) | (319<<14) | (1<<6) | (0<<0);
  25:  //   ....
  26:  //   release operations : iounmap(lcd_regs);

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

   构造时,注意保留空间的设置,在后续操作时,采用同样的方式进行。

3. 触摸屏优化设置

        在检测到触摸屏发生中断后,如果检测到按下,则设置touch screen XY坐标连续测量模式,并且启动adc,在adc转换完成中断中,读取对于XY轴的电压值,并且通过 input_report来上报事件。

        1. 在初始化adc,设置开始延迟寄存器为最大值,0xffff,稳定adc基准电压。

        2. 在adc转换结果中断中,再次判断触摸屏是否按下。

        3. 设定一个定时器,多次测量adc,求均值来减小误差

        4. 在求均值前,对所有检测到的数据进行基本的误差过滤,去掉偏差较大的读书

        5. 利用定时器来处理 长按和滑动事件

4. 利用Uboot自带命令来测试硬件

     Uboot自带一些简单的命令,我们可以用它来测试一些硬件,这里以读取Nand Flash的Chip ID为例子。启动并且进入Uboot的命令行,因为Uboot是裸机程序,面对的是真实的物理地址,下面是命令示意:

     

     .b w l 分别表示一次读取一个字节、两个字节和四个字节 后面的objects表示读取几次,寄存器长度为4字节。

     读取Nand Flash ID的操作顺序如下:

      选中 nand flash :    使能片选信号,操作设置 NFCONT寄存器的Reg_nCE为0

                                            

      发出Read ID命令:往命令寄存器中写入 READ ID命令(0x90)

                               

      发出地址数据: 往地址寄存器中写入 0x00地址数据

                              

      读取返回值: 连续读取五次,和对应芯片的Read ID读取命令结果,依次相符合,证明 这种Nand Flash 芯片的类型为 K9F2G08U0A 。

          退出读取ID的状态 : 向命令寄存器中写入 RESET命令(0xFF),复位设备。

上述是读取NAN FLASH ID的例子,同样,可以用Uboot的单个命令行来一个字节一个字节的读取nand flash里面存储的内容,也可以用nand dump 0来显示flash中第一页的内容。

5. 分析自带驱动的方法

     一般来讲,内核都自带有标准的驱动,分析的入口,我们可以从内核启动过程中,打印的相关日志信息来作为突破口来入手,在内核代码中搜索对于的字符串信息,从而开始分析。

     在进行内部设备的寄存器设置时,首先需要确保该模块的时钟使能,一般来说,内核在正常运行过程中,为了省电,会关掉一些外设的时钟,因此,在设置寄存器之间,必须要开启该模块的时钟,通用的方法如下:

   1:  struct clk *clk;                               //定义一个时钟结构
   2:  clk = clk_get(NULL,"nand");                    //通过设备id来查找时钟
   3:  clk_enable(clk);                               //实际调用的是 nand类型的时钟使能函数 s3c2410_clkcon_enable
   4:   
   5:  //arch/arm/mach-s3c2410 
   6:  static struct clk init_clocks_disable[] = {
   7:      {
   8:          .name        = "nand",
   9:          .id        = -1,
  10:          .parent        = &clk_h,
  11:          .enable        = s3c2410_clkcon_enable,
  12:          .ctrlbit    = S3C2410_CLKCON_NAND,
  13:      }, {

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

     先使能控制器的时钟,然后对其寄存器进行设置,最后,使能控制器本身,按照这样的操作顺序,一般是不会出错。

     注销设备时,释放相关资源的顺序和注册设备时,要保持相反的顺序,这样比较合理。   

     在设置片内外设控制器和片外设备的时序匹配时,要明确两点,时钟信号都是有主芯片主动发出的,时序有 读时序,写时序、等待时序等等,考虑到一致性,我们只需要对比两边读时序的部分,使得发出和接收两侧的时序保持兼容就行。不确定的寄存器值,保持默认值就行。

6. 快速确定驱动所在内核配置脚本中的位置

     在需要确定内核驱动文件对于的menuconfig中的位置时,可以使用如下的方法来快速查找:

     例如:查找声卡驱动的对于配置选项在哪里?

     首先,我们肯定是可以找到声卡对于的驱动文件里面的Makefile,复制对应文件的CONFIG选项,例如,如果选项配置是 CONFIG_WM8976,那么就复制WM8976,然后进入内核的配置页面,按下“/”,出现如下搜索框:

    

     粘贴选项,回车,就可以发现该选项在内核配置界面中的具体路径了,方便快速,值得一试。

7. 移植madplayer播放器到JZ2440

     参考链接:http://blog.163.com/kang_6530/blog/static/7219155720090525649537/

     依次下载 zlib-1.2.3.tar.gz libid3tag-0.15.1b.tar.gz libad-0.15.1b.tar.gz madplay-0.15.2b.tar.gz 在其共有目录新建tmp文件夹。

     下面以  /home/hao/madplay/tmp目录为例子

     7.1 编译zlib

     ./configure --prefix=/home/hao/madplay/tmp

      然后修改生成的Makefile,修改CC,AR和RANLIB,加上交叉编译前缀arm-linux-

      然后make && make install ,

     7.2 编译libid3tag

      ./configure --prefix=/home/hao/madplay/tmp/ --host=arm-linux --disable-shared CC=arm-linux-gcc CPPFLAGS=-I/home/hao/madplay/tmp/include LDFLAGS=-L/home/hao/madplay/tmp/lib

      make && make install

     7.2 编译 libmad

      ./configure --prefix=/home/hao/madplay/tmp/ CC=arm-linux-gcc --host=arm-linux --disable-shared CPPFLAGS=-I/home/hao/madplay/tmp/include LDFLAGS=-L/home/hao/madplay/tmp/lib

      make && make install

      7.4 编译 madplay

      ./configure --prefix=/home/hao/madplay/tmp/ CC=arm-linux-gcc --host=arm-linux --disable-shared --enable-static CPPFLAGS=-I/home/hao/madplay/tmp/include LDFLAGS=-L/home/hao/madplay/tmp/lib

       make && make install

       注意事项,不要在linux与windows的共享目录中执行编译过程,有可能因为权限问题而失败。

       当出现madplay: error while loading shared libraries: cannot open shared object file: cannot load sharedobject file: No such file or directory,则是因为在编译时没有设置好静态链接和共享库,正确的配置就是在编译libid3tag、libmad 和madplay 时,加上disable-shared 选项,同时(只)在madplay 的配置语句上加上enable-static设置为静态。

8. Windows安装,要求以数字签名的驱动程序

     在安装一些调试工具的驱动时,Windows自带的搜索驱动找不到,指定驱动安装路径也无法正常安装,弹出如下提示:

     

    解决方法:用管理员身份进入命令行窗口,输入cmd,然后执行 bcdedit /set testsigning on ,然后重启电脑,这样,就打开Windows的测试模式,可以安装一些没有经过Windows驱动签名的驱动。

    如果需要取消测试模式,可以输入 bcdedit /set testsigning off ,然后重启,就可以。经过实际测试,是可以工作。

Technorati 标签: linux 调试

时间: 2024-09-29 18:18:35

驱动调试方法小结的相关文章

linux设备驱动第四篇:驱动调试方法

linux设备驱动第四篇:驱动调试方法linux设备驱动第四篇:驱动调试方法linux设备驱动第四篇:驱动调试方法linux设备驱动第四篇:驱动调试方法linux设备驱动第四篇:驱动调试方法linux设备驱动第四篇:驱动调试方法linux设备驱动第四篇:驱动调试方法linux设备驱动第四篇:驱动调试方法linux设备驱动第四篇:驱动调试方法 http://v.17173.com/playlist_18716517.htmlhttp://v.17173.com/playlist_18716521.

Linux环境下段错误的产生原因及调试方法小结(转)

最近在Linux环境下做C语言项目,由于是在一个原有项目基础之上进行二次开发,而且 项目工程庞大复杂,出现了不少问题,其中遇到最多.花费时间最长的问题就是著名的“段错误”(Segmentation Fault).借此机会系统学习了一下,这里对Linux环境下的段错误做个小结,方便以后同类问题的排查与解决. 1. 段错误是什么 一句话来说,段错误是指访问的内存超出了系统给这个程序所设定的内存空间,例如访问了不存在的内存地址.访问了系统保护的内存地址.访问了只读的内存地址等等情况.这里贴一个对于“段

linux设备驱动第四篇:从如何定位oops的代码行谈驱动调试方法

上一篇我们大概聊了如何写一个简单的字符设备驱动,我们不是神,写代码肯定会出现问题,我们需要在编写代码的过程中不断调试.在普通的c应用程序中,我们经常使用printf来输出信息,或者使用gdb来调试程序,那么驱动程序如何调试呢?我们知道在调试程序时经常遇到的问题就是野指针或者数组越界带来的问题,在应用程序中运行这种程序就会报segmentation fault的错误,而由于驱动程序的特殊性,出现此类情况后往往会直接造成系统宕机,并会抛出oops信息.那么我们如何来分析oops信息呢,甚至根据oop

linux设备驱动第四篇:以oops信息定位代码行为例谈驱动调试方法

上一篇我们大概聊了如何写一个简单的字符设备驱动,我们不是神,写代码肯定会出现问题,我们需要在编写代码的过程中不断调试.在普通的c应用程序中,我们经常使用printf来输出信息,或者使用gdb来调试程序,那么驱动程序如何调试呢?我们知道在调试程序时经常遇到的问题就是野指针或者数组越界带来的问题,在应用程序中运行这种程序就会报segmentation fault的错误,而由于驱动程序的特殊性,出现此类情况后往往会直接造成系统宕机,并会抛出oops信息.那么我们如何来分析oops信息呢,甚至根据oop

Linux环境下段错误的产生原因及调试方法小结

最近在Linux环境下做C语言项目,由于是在一个原有项目基础之上进行二次开发,而且项目工程庞大复杂,出现了不少问题,其中遇到最多.花费时间最长的问题就是著名的“段错误”(Segmentation Fault).借此机会系统学习了一下,这里对Linux环境下的段错误做个小结,方便以后同类问题的排查与解决. 1. 段错误是什么 一句话来说,段错误是指访问的内存超出了系统给这个程序所设定的内存空间,例如访问了不存在的内存地址.访问了系统保护的内存地址.访问了只读的内存地址等等情况.这里贴一个对于“段错

【转】【调试技巧】Linux环境下段错误的产生原因及调试方法小结

本文转自:http://www.cnblogs.com/panfeng412/archive/2011/11/06/segmentation-fault-in-linux.html 最近在Linux环境下做C语言项目,由于是在一个原有项目基础之上进行二次开发,而且项目工程庞大复杂,出现了不少问题,其中遇到最多.花费时间最长的问题就是著名的“段错误”(Segmentation Fault).借此机会系统学习了一下,这里对Linux环境下的段错误做个小结,方便以后同类问题的排查与解决. 1. 段错误

Linux环境下段错误的产生原因及调试方法小结(转载)

转载自http://www.cnblogs.com/panfeng412/archive/2011/11/06/2237857.html 最近在Linux环境下做C语言项目,由于是在一个原有项目基础之上进行二次开发,而且项目工程庞大复杂,出现了不少问题,其中遇到最多.花费时间 最长的问题就是著名的“段错误”(Segmentation Fault).借此机会系统学习了一下,这里对Linux环境下的段错误做个小结,方便以后同类问题的排查与解决. 1. 段错误是什么 一句话来说,段错误是指访问的内存超

ARM驱动调试方法、思路总结、笔记

驱动程序的调试一. 打印: prink, 自制proc文件UBOOT传入console=ttySAC0 console=tty11. 内核处理UBOOT传入的参数console_setup add_preferred_console // 我想用名为"ttySAC0"的控制台,先记录下来 2. 硬件驱动的入口函数里: drivers/serial/s3c2410.c register_console(&s3c24xx_serial_console); 3. printk vpr

[RK3288][Android6.0] 音频调试方法小结【转】

本文转载自:http://blog.csdn.net/kris_fei/article/details/70053135 Platform: ROCKCHIPOS: Android 6.0Kernel: 3.10.92 以rt5631为例,后续遇到再增加. 使用tinyalsa工具确定播放音问题是否在驱动层1|[email protected]:/data # tinycap  test.wav                                        Capturing s