驱动调试之打印

发布者:EtherealBeauty最新更新时间:2024-08-19 来源: cnblogs关键字:驱动调试  打印  ARM 手机看文章 扫描二维码
随时随地手机看文章


1046 register_console(&s3c24xx_serial_console);//注册控制台


1901 static struct console s3c24xx_serial_console =

1902 {

1903    .name        = S3C24XX_SERIAL_NAME,//控制台名称ttySAC

1904     .device        = uart_console_device,//以后使用/dev/console时,用来狗仔设备节点

1905     .flags        = CON_PRINTBUFFER,//控制台可以之前,printk已经在缓1907 冲区打印了,CON_PRINTBUFFER表示可以打印以前的信息了

1906     .index        = -1,

1907    .write        = s3c24xx_serial_console_write,//打印函数

1908    .setup        = s3c24xx_serial_console_setup.//设置函数

1090 };


150 #define S3C24XX_SERIAL_NAME    'ttySAC'


大致看一下prink的函数过程,从调用过程可以看出打印的信息会存在log_buf这个变量中,而我们也可以通过查看cat /proc/kmsg来得到prink的数据,这句命令的作用就是从log_buf这个缓冲区中读出数据。


prink

    vprintk

        /* Emit the output into the temporary buffer */

        // 先把输出信息放到临时的buffer

        vscnprintf

        

        // Copy the output into log_buf

        // 把临时缓冲区的数据稍作处理(处理打印级别),再写入log_buf

        // 比如prink('abc')会得到'<4>abc',再写入log_buf

        // 可以用dmesg把log_buf里的数据打印出来重现内核的输出信息

        

        // 调用硬件的write函数输出

        release_console_sem();

            call_console_drivers(_con_start, _log_end);

                // 从log_buf得到数据,算出级别

                _call_console_drivers(start_print, cur_index, msg_level);

                    // 如果够级别可以打印

                    __call_console_drivers(0, end & LOG_BUF_MASK);

                        con->write(con, &LOG_BUF(start), end - start);


2、prink的使用


prink的使用其实很简单,与我们平时使用C语言的printf差不多。一般如果在某个地方出错的话,会使用二分法的方法定位到最终的问题。下面举一个列子,引入了一个错误,我们在使用CPU的寄存器时没有使用虚拟地址,而是直接使用物理地址。


#include

#include

#include

#include

#include

#include

#include

#include

#include

#include


static struct class *firstdrv_class;

static struct class_device    *firstdrv_class_dev;


volatile unsigned long *gpfcon = NULL;

volatile unsigned long *gpfdat = NULL;



static int first_drv_open(struct inode *inode, struct file *file)

{

    //printk('first_drv_openn');

    /* 配置GPF4,5,6为输出 */

    printk(KERN_DEBUG'%s %s %dn', __FILE__, __FUNCTION__, __LINE__);

    *gpfcon &= ~((0x3<<(4*2)) | (0x3<<(5*2)) | (0x3<<(6*2)));

    printk(KERN_DEBUG'%s %s %dn', __FILE__, __FUNCTION__, __LINE__);

    *gpfcon |= ((0x1<<(4*2)) | (0x1<<(5*2)) | (0x1<<(6*2)));

    printk(KERN_DEBUG'%s %s %dn', __FILE__, __FUNCTION__, __LINE__);

    return 0;

}


static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)

{

    int val;


    //printk('first_drv_writen');


    copy_from_user(&val, buf, count); //    copy_to_user();


    if (val == 1)

    {

        // 点灯

        *gpfdat &= ~((1<<4) | (1<<5) | (1<<6));

    }

    else

    {

        // 灭灯

        *gpfdat |= (1<<4) | (1<<5) | (1<<6);

    }

    

    return 0;

}


static struct file_operations first_drv_fops = {

    .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */

    .open   =   first_drv_open,     

    .write    =    first_drv_write,       

};



int major;

static int first_drv_init(void)

{

    printk(KERN_DEBUG'%s %s %dn', __FILE__, __FUNCTION__, __LINE__);

    major = register_chrdev(0, 'first_drv', &first_drv_fops); // 注册, 告诉内核


    printk(KERN_DEBUG'%s %s %dn', __FILE__, __FUNCTION__, __LINE__);

    firstdrv_class = class_create(THIS_MODULE, 'firstdrv');


    printk(KERN_DEBUG'%s %s %dn', __FILE__, __FUNCTION__, __LINE__);

    firstdrv_class_dev = class_device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, 'xyz'); /* /dev/xyz */


    printk(KERN_DEBUG'%s %s %dn', __FILE__, __FUNCTION__, __LINE__);

    gpfcon = (volatile unsigned long *)0x56000050; //引入错误

    gpfdat = gpfcon + 1;


    return 0;

}


static void first_drv_exit(void)

{

    unregister_chrdev(major, 'first_drv'); // 卸载


    class_device_unregister(firstdrv_class_dev);

    class_destroy(firstdrv_class);

    iounmap(gpfcon);

}


module_init(first_drv_init);

module_exit(first_drv_exit);



MODULE_LICENSE('GPL');


当我们使用程序测试这个驱动时就会出错,出错时我们就利用printk(KERN_DEBUG'%s %s %dn', __FILE__, __FUNCTION__, __LINE__);这条打印语句定位到最终程序执行到哪里导致的出错,其中__FILE__可以打印出文件、__FUNCTION__可以打印出函数、__LINE__可以打印出哪一行。而KERN_DEBUG是打印等级,值越小打印等级越高。当我们调试成功后就不需要打印了,那么可以把打印等级的数值变大。而内核的设置的默认打印等级一般为4,我们可以通过两种方法更改打印等级。


cat /proc/sys/kernel/printk 更改这个文件可以改变打印级别

修改loglevel这个uboot传入的参数可以更改内核的打印级别


[1] [2]
关键字:驱动调试  打印  ARM 引用地址:驱动调试之打印

上一篇:Linux内核源码阅读记录一之分析存储在不同段中的函数调用过程
下一篇:Linux驱动之一个简单的输入子系统程序编写

推荐阅读最新更新时间:2024-11-13 19:28

ARM的22个概念总结
1.ARM中一些常见英文缩写解释 MSB:最高有效位; LSB:最低有效位; AHB:先进的高性能总线; VPB:连接片内外设功能的VLSI外设总线; EMC:外部存储器控制器; MAM:存储器加速模块; VIC:向量中断控制器; SPI:全双工串行接口; CAN:控制器局域网,一种串行通讯协议; PWM:脉宽调制器; ETM:嵌入式跟踪宏; CPSR:当前程序状态寄存器; SPSR:程序保护状态寄存器; 2.MAM 使用注意事项 当改变 MAM 定时值时,必须先通过向 MAMCR 写入 0 来关闭 MAM,然后将新值写入 MAMTIM。最后,将需要的操作模式的对应值写入MA
[单片机]
大模型为边缘AI带来新动能,Arm推出支持Transformer的Ethos-U85 NPU
2023年无疑是生成式AI的元年,从ChatGPT的出现到‘千模大战’,Transformer架构受到了极大的关注。 于 2017 年问世的Transformer 架构彻底改变了生成式 AI,并成为许多新型神经网络的首选架构。基于 Transformer 架构的模型可利用注意力机制处理序列数据,并在机器翻译、自然语言理解、语音识别、分割和图像字幕生成等多项 AI 任务中实现优异的效果。 值得注意的是,这些模型可被调整和压缩,在不过多影响准确度的情况下,能高效运行于边缘设备上,并在许多边缘侧和端侧用例中发挥领先的优势。 也正因此,边缘AI在当年CNN和RNN火了一轮之后,又再一次燃了起来。 除了手机、PC,其他更多应
[嵌入式]
大模型为边缘AI带来新动能,<font color='red'>Arm</font>推出支持Transformer的Ethos-U85 NPU
autossh 移植到arm
一、环境介绍 1.1 宿主机 Ubuntu 1404 32 位 1.2 嵌入式平台 ATMEL AT91SAM9X25 1.3 交叉工具链 arm-none-linux-gnueabi autossh源码下载地址 二、交叉编译 tar xvf autossh-1.4b.tgz cd autossh-1.4b/ ./configure --prefix=$PWD/tmp --host=arm-none-linux-gnueabi --build=i686-linux make make install 执行完安装之后,将安装目录的可执行文件拷贝到目标板即可
[单片机]
STM32与LPC系列ARM资源比较
由于有周立公开发板的影响,LPC系列的开发板在工程师心目中一般是入门的最好型号之一。这次刚好有STM32的竞赛,正好将两者的资源进行比较一下(LPC系列以LPC213X为例)。 LPC213X包括LPC2131、2132、2138等, 是基于一个支持实时仿真和跟踪的16/32 位ARM7TDMI-STM CPU,并带有32kB、64kB 和512kB 嵌入的高速Flash 存储器。128 位宽度的存储器接口和独特的加速结构使32 位代码能够在最大时钟速率下运行。对代码规模有严格控制的应用可使用16 位Thumb 模式将代码规模降低超过30%,而性能的损失却很小。 而 STM32 则大致分为两类,一种是基本型,一种是增强型。这同51内
[单片机]
51学习笔记之使用printf打印串口数据
#include reg51.h #include stdio.h void UartInit(void) //初始化波特率为9600 { SCON=0x50; TMOD=0x20; TCON=0x40; TH1=0xfd; TI=1; TR1=1; } void main() { UartInit(); printf( hello world ); //输出一次数据 while(1); }
[单片机]
基于ARM微处理器TCP/IP协议栈LwlP实现
  0 引 言   随着嵌入式系统与网络的日益结合,越来越多的嵌入式设备需要实现Internet网络化,支持嵌入式设备接入网络,已成为嵌入式领域重要的研究方向。而目前嵌入式系统中大量应用低速处理器,受内存和速度限制,实现完整的TCP/IP协议较为困难,LwIP作为较为成熟的嵌入式TCP/IP协议栈受到了广泛的应用。   1 硬件平台   本通信系统的硬件平台由以下几个部分组成:S3C2410主CPU芯片控制嵌入式外围设备的存储、通信、保护、调试、显示等操作;DSP和FPGA负责信号数据的采集和处理;CS8900A负责网络数据的收发;其他部分还包括串口RS232的通信、LCD的数据显示、数据存储FLASH和SDRAM以及其他硬
[单片机]
基于<font color='red'>ARM</font>微处理器TCP/IP协议栈LwlP实现
ARM联合创始人:若英伟达收购arm将会导致灾难性后果
ARM联合创始人Hermann Hauser对BBC表示,他认为英国政府应该进行干预,如果将ARM卖给英伟达将是灾难性的。 Hermann Hauser是CPU公司(Cambridge Processing Unit)的创始人之一,1979年,CPU公司改名为Acorn计算机公司。Acorn便是ARM的前身。 Hermann Hauser表示,英国政府应该帮助ARM重新成为一家独立的英国企业。 ARM突破性的IP商业模式,打造了一个基于ARM体系的全球生态链,几乎所有移动芯片均都依赖于ARM设计的架构。2016年,软银以320亿美元的价格收购了ARM,政府称这是对脱欧后的英国投下的信任票。 但Hauser博士
[嵌入式]
<font color='red'>ARM</font>联合创始人:若英伟达收购<font color='red'>arm</font>将会导致灾难性后果
德州仪器推出具有 ARM® Cortex™-M3 微控制器的业界最高集成度 ZigBee® 单芯片解决方案满足智能能源基础设施、家庭楼宇自动化以及智能照明系统需
日前,德州仪器 (TI) 宣布推出 CC2538 片上系统 (SoC),简化支持 ZigBee® 无线连接功能的智能能源基础设施、家庭楼宇自动化以及智能照明网关开发。业界最高度集成度 ZigBee 解决方案 CC2538 在单个硅芯片上高度集成 ARM®Cortex™-M3 MCU、存储器以及硬件加速器,具有极高的成本效益。CC2538 支持 ZigBeePRO、ZigBee Smart Energy 及 ZigBee Home Automation 以及照明标准,能与现有及未来 ZigBee 产品实现互操作。此外,该 SoC 还支持采用 IEEE 802.15.4 及 6LoWPAN IPv6 网络的 IP 标准化开发,可实现最
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved