• <div id="0yoao"><tr id="0yoao"></tr></div>
    <dl id="0yoao"></dl>
  • <sup id="0yoao"></sup>
    <div id="0yoao"><tr id="0yoao"></tr></div>
  • <div id="0yoao"><tr id="0yoao"></tr></div>
  • ?

    通过点亮LED的方法调试嵌入式代码

    作者:wowo 发布于:2016-6-12 22:10 分类:软件开发

    1. 前言

    在软件开发的过程中,debug(调试)是一个很重要的事情,因为没有百分之百正确的代码,一旦结果不符合预期,我们需要知道问题出在哪里了。

    在PC环境下开发应用程序,我们不需要太操心,因为有各式各样的模拟器、调试器可供使用,我们可以追踪到每一行代码的执行过程和执行结果,找出问题只是时间问题而已。但在嵌入式环境下,就有些麻烦了,能用的手段,无外乎两种:

    1)使用硬件仿真器定位问题。

    2)使用日志输出定位问题。

    对嵌入式工程师(特别是linux工程师)而言,鉴于使用硬件仿真器的诸多不便(成本高,无法保证人手一个;硬件连接复杂,需要预留特定接口;使用不方便;等等),日志输出几乎成为必备且唯一的debug手段。但是,总会有例外:

    系统刚刚启动,在日志输出的通道(通常是UART接口)ready之前,怎么debug?

    在不得不使用仿真器之前,我们还有一个简单的方法,就是点LED灯,本文将结合“X Project”“【任务2?#31185;?#21160;到u-boot command line”实现的过程,对这个方法进行简单的介绍和总结。

    2. 思路

    从本质上讲,软件debug最高效的手段,是良好的设计、优秀的编码、细致的代码检查,当然,百密总有一疏。但大多数时候,我们只要能找到出现问题的大概位置,再辅以代码的检查,就可以百分之九十九的解决问题,这也是通过日志输出的方法定位问题的基本逻辑。

    因此,在日志输出通道ready之前,我们也可以使用同样的思路,借助LED灯,实现问题的定位。大致思路如下:

    1)如果系?#25345;?#26377;一个LED灯,可以在代码中,正?#20998;蔥心?#19968;个步骤之后,点亮LED,以此类推,一步一步检查代码执行的正确与否(其实“X Project”“【任务1?#31185;?#21160;过程-Boot from USB”就是借用了这个思路)。

    2)当然,如果系统有多个LED,例如四个,我们可以将这四个LED编码成一个4bit的数字(0~15),这样就可以表示更多的状态,下面是“X Project”基于bubblegum-96平台,实现的一个简单的接口(代码逻辑很简单,我就不解释了):

    /* https://github.com/wowotechX/u-boot/blob/x_integration/board/actions/bubblegum/board.c */

    /*
     * A simple debug function for early debug, in which,
     * we use four LEDs to display sixteen debug codes, from 0 to 15.
     * Using it, we can know, at least roughly, at where out code is run.
     */
    void bubblegum_early_debug(int debug_code)
    {
    	uint8_t val;
    
    	val = debug_code & 0x1;
    	setbits_le32(GPIOA_OUTEN, 1 << DEBUG_LED0_GPIO);
    	clrsetbits_le32(GPIOA_OUTDAT, 1 << DEBUG_LED0_GPIO,
    			val << DEBUG_LED0_GPIO);
    
    	val = (debug_code >> 1) & 0x1;
    	setbits_le32(GPIOA_OUTEN, 1 << DEBUG_LED1_GPIO);
    	clrsetbits_le32(GPIOA_OUTDAT, 1 << DEBUG_LED1_GPIO,
    			val << DEBUG_LED1_GPIO);
    
    	val = (debug_code >> 2) & 0x1;
    	setbits_le32(GPIOF_OUTEN, 1 << DEBUG_LED2_GPIO);
    	clrsetbits_le32(GPIOF_OUTDAT, 1 << DEBUG_LED2_GPIO,
    			val << DEBUG_LED2_GPIO);
    
    	val = (debug_code >> 3) & 0x1;
    	setbits_le32(GPIOF_OUTEN, 1 << DEBUG_LED3_GPIO);
    	clrsetbits_le32(GPIOF_OUTDAT, 1 << DEBUG_LED3_GPIO,
    			val << DEBUG_LED3_GPIO);
    }

    3. 一个例子

    利用上面的debug接口,在调试串口驱动的时候,发挥了很大的作用,如下:

    /* https://github.com/wowotechX/u-boot/blob/x_integration/drivers/serial/serial_owl.c */

    extern void bubblegum_early_debug(int debug_code);
    static int owl_serial_probe(struct udevice *dev)
    {
    	/* only for UART2, TODO */
    	bubblegum_early_debug(4);
    
    	/* pinmux */
    	setbits_le32(MFP_CTL2, 1 << 22);
    
    	bubblegum_early_debug(5);
    
    	/* device clock enable */
    	setbits_le32(CMU_DEVCLKEN1, 1 << 8);
    
    	bubblegum_early_debug(6);
    
    	/* reset de-assert */
    	setbits_le32(CMU_DEVRST1, 1 << 7);
    
    	bubblegum_early_debug(7);
    
    	/* set default baudrate and enable UART */
    	owl_serial_setbrg(dev, 115200);
    	
    	/* enable uart */
    	setbits_le32(UART2_BASE + UART_CTL, UART_CTL_EN);
    
    	bubblegum_early_debug(8);
    	return 0;
    }

    串口驱动编写好之后,发现系统会死在owl_serial_probe中,于是添加了一系列的"点灯"操作,发现最后停留在“bubblegum_early_debug(5); ”上面(LED2和LED0亮),于是就可以确定这条语句出了问题:

    setbits_le32(CMU_DEVCLKEN1, 1 << 8);

    经过仔细检查,发现CMU_DEVCLKEN1寄存器定义错了(可能是抄Action的代码笔误了)。

    4. 总结

    步骤很简单,之所以要写一篇文章,是想告诉大家,嵌入式开发其实挺简单的,只要有足够的细心和耐心,一切皆有可能。

     

    原创文章,转发请注明出处。蜗窝科技,http://www.71402172.com

    标签: debug LED

    评论:

    misakmm20001
    2016-06-23 23:39
    就算是CMU_DEVCLKEN1写错地址 应该也不会是死在probe里吧?最多就是串口不工作吧?写到别的地址 系统能挂?
    wowo
    2016-06-24 08:50
    @misakmm20001?#21512;?#22312;很多SOC,为了省电,总线设备的寄存器访问是分开控制的,如果指定的模块没有?#31995;紓?#25110;者处于reset状态,寄存器访问时不会产生寻址时钟,会导致总线直接拉死。
    zack
    2016-06-13 21:31
    真是倍感親切的debug方法。
    不過,這年頭要找工作的話,還是得搬些gdb, core dump,反組譯之類的東西出來才行lol
    wowo
    2016-06-13 22:20
    @zack:lol你說的太對了。不過說實話,工作那麼多年,也就是剛畢業那會兒用過?#29366;?#27169;擬器(trace等),至於gdb,說實話,基本沒有用過。大多數時候,printf/printk都能對付了~~
    qdzhaox
    2016-06-13 13:14
    指示灯的作用

    发表评论:

    Copyright @ 2013-2015 蜗窝科技 All rights reserved. Powered by emlog
    连码三全中是什么
  • <div id="0yoao"><tr id="0yoao"></tr></div>
    <dl id="0yoao"></dl>
  • <sup id="0yoao"></sup>
    <div id="0yoao"><tr id="0yoao"></tr></div>
  • <div id="0yoao"><tr id="0yoao"></tr></div>
  • <div id="0yoao"><tr id="0yoao"></tr></div>
    <dl id="0yoao"></dl>
  • <sup id="0yoao"></sup>
    <div id="0yoao"><tr id="0yoao"></tr></div>
  • <div id="0yoao"><tr id="0yoao"></tr></div>
  • 买彩票什么软件可靠 现场开码现场开奖即时开奖结果 一肖中特免费公开 山西11选5开奖5结果 乐彩网发起合买是什么意思 烟台二八杠 欢乐生肖玩法 北京pk三分彩开奖记录 悉尼线上娱乐城 山东时时彩销售 两年无错平特肖 福建体育彩票36选7开奖结果 神算子六肖中特 万博ag真人可信吗 500彩票网能买3d吗