为u-boot-2016 for tiny4412添加点灯调试代码
2017-01-14 21:10
302 查看
好的,经过前面两篇文章,我们已经能够编译和烧写u-boot到sd卡上了,接下来就是调试,完善功能了。
说到调试,在此之前我想的调试方法是在串口还没有初始化之前,就只能通过点灯大法来调试了; 等到串口初始化完成后,就可以通过串口打印,这样调试就方便多了。不过后来看到了两篇文章,介绍的是通过jlink来进行源码级别的调试,但是我现在一来没有电烙铁,没办法将tiny4412上的jtag接口引出来,所以也就放弃了,有兴趣的朋友可以试一试使用jtag来进行源码级的调试和学习。后续我也会尝试使用jlink来进行调试和学习,毕竟现在也只是学习阶段,通过源码级别的调试,应该能学到更多东西。
blog的链接我就放这里了:
1. http://www.cnblogs.com/humaoxiao/p/4181078.html
2. http://www.cnblogs.com/humaoxiao/p/4166230.html
既然要用点灯调试,那么必然要做点灯的相关代码编写了,因为不确定代码跑到哪里就出现问题了,所以点灯代码还是使用汇编来编写会比较通用写。话不多说,下面开始写代码。
首先要了解的是tiny4412上LED灯的相关信息,截图如下:
看上面的截图可以了解到,只要将GPM4_0,GPM4_1,GPM4_2,GPM4_3设置为输出引脚,要让灯点亮的话,只要将引脚的设置为输出低电平就OK了。
下面编写测试代码:
OK,添加完上面的代码,我们可以通过之前介绍的方法将重新编译的代码烧写到SD卡,启动开发板可以看到四个LED灯都亮起来了,代码代码是OK的。既然已经添加了点灯的代码了,那么熄灯的代码也就简单了,继续添加熄灯的代码如下:
OK,点灯,熄灯和延时函数都能够正常运行了,不过现在还有一个问题,就是怎么在其他汇编文件或者C文件中调用我们编写的点灯和熄灯代码呢?
最简单的方法当然是查看uboot源代码是如何实现的了,我查看代码时就发现如下内容:
在start.s文件中,reset函数最后会有一个bl _main的操作,_main函数就是在./arch/arm/lib/crt0.S中定义的,使用的是ENTRY伪指令来定义的,那么是不是说明,只要是用ENTRY定义了函数都可以在全局中调用,然后我百度看了很多文章,都会这么说ENTRY这个伪指令的用法:ENTRY伪指令用于指定汇编程序的入口点。在一个完整的汇编程序中至少要有一个ENTRY(也可以有多个,当有多个ENTRY时,程序的真正入口点由链接器指定),但在一个源文件里最多只能有一个ENTRY(可以没有)。但是我感觉这个说法明显是不对的啊,在一个源文件中最多只能有一个ENTRY(可以没有)显然是不对的,我们查看start.S最初的代码就可以发现,一个源文件中ENTRY还真不止一个。
好的,说了这么多,最后还是用个实例来说明内容吧,最后我还有一个疑问,希望了解这个的朋友可以留言交流交流。
我们在crt0.S文件中添加LED1和LED2的点灯过程,最后我发现只有LED2_ON是能亮的,但是LED1_ON却不亮,这就是我上面提到的问题了,LED2灯都亮了,表明程序是可以执行到bl LED1_ON那里的,但是为什么不亮呢?这个问题还希望知道为什么的朋友可以告知我一声。
好的,这一篇就到这里了。
说到调试,在此之前我想的调试方法是在串口还没有初始化之前,就只能通过点灯大法来调试了; 等到串口初始化完成后,就可以通过串口打印,这样调试就方便多了。不过后来看到了两篇文章,介绍的是通过jlink来进行源码级别的调试,但是我现在一来没有电烙铁,没办法将tiny4412上的jtag接口引出来,所以也就放弃了,有兴趣的朋友可以试一试使用jtag来进行源码级的调试和学习。后续我也会尝试使用jlink来进行调试和学习,毕竟现在也只是学习阶段,通过源码级别的调试,应该能学到更多东西。
blog的链接我就放这里了:
1. http://www.cnblogs.com/humaoxiao/p/4181078.html
2. http://www.cnblogs.com/humaoxiao/p/4166230.html
既然要用点灯调试,那么必然要做点灯的相关代码编写了,因为不确定代码跑到哪里就出现问题了,所以点灯代码还是使用汇编来编写会比较通用写。话不多说,下面开始写代码。
首先要了解的是tiny4412上LED灯的相关信息,截图如下:
看上面的截图可以了解到,只要将GPM4_0,GPM4_1,GPM4_2,GPM4_3设置为输出引脚,要让灯点亮的话,只要将引脚的设置为输出低电平就OK了。
下面编写测试代码:
diff --git a/arch/arm/cpu/armv7/start.S b/arch/arm/cpu/armv7/start.S index 7eee54b..83eed98 100644 --- a/arch/arm/cpu/armv7/start.S +++ b/arch/arm/cpu/armv7/start.S @@ -85,6 +85,10 @@ switch_to_hypervisor_ret: #endif #endif /* 添加的测试代码,测试LED代码是否正常,测试完毕需要删除 */ + bl LED1_ON + bl LED2_ON + bl LED3_ON + bl LED4_ON bl _main /*------------------------------------------------------------------------------*/ @@ -293,3 +297,81 @@ ENTRY(cpu_init_crit) b lowlevel_init @ go setup pll,mux,memory ENDPROC(cpu_init_crit) #endif + +ENTRY(LED1_ON) + /* + * GPM4CON Address = 0x110002E0 + * GPM4DAT Address = 0x110002E4 + */ + ldr r0, =0x110002E0 + ldr r1, [r0] //读出GPM4CON的值 + bic r1, r1, #0xf //将GPM4CON[0:3]清零 + orr r1, r1, #0x1 //将GPM4_0设置为输出引脚 + str r1, [r0] //将设置的值写回GPM4CON + + ldr r0, =0x110002E4 + ldr r1, [r0] //读出GPM4DAT的值 + bic r1, r1, #0 //将CPM4DAT的第[0]清零,清零就是输出低电平了 + str r1, [r0] //将设置的值写回GPM4DAT + + mov pc, lr //最后不要忘记这一条,将lr的值写回pc,将继续执行 +ENDPROC(LED1_ON) + +ENTRY(LED2_ON) + /* + * GPM4CON Address = 0x110002E0 + * GPM4DAT Address = 0x110002E4 + */ + ldr r0, =0x110002E0 + ldr r1, [r0] //读出GPM4CON的值 + bic r1, r1, #0xf0 //将GPM4CON[4:7]清零 + orr r1, r1, #0x10 //将GPM4_1设置为输出引脚 + str r1, [r0] //将设置的值写回GPM4CON + + ldr r0, =0x110002E4 + ldr r1, [r0] //读出GPM4DAT的值 + bic r1, r1, #2 //将CPM4DAT的第[1]清零,清零就是输出低电平了 + str r1, [r0] //将设置的值写回GPM4DAT + + mov pc, lr //最后不要忘记这一条,将lr的值写回pc,将继续执行 +ENDPROC(LED2_ON) + +ENTRY(LED3_ON) + /* + * GPM4CON Address = 0x110002E0 + * GPM4DAT Address = 0x110002E4 + */ + ldr r0, =0x110002E0 + ldr r1, [r0] //读出GPM4CON的值 + bic r1, r1, #0xf00 //将GPM4CON[8:11]清零 + orr r1, r1, #0x100 //将GPM4_2设置为输出引脚 + str r1, [r0] //将设置的值写回GPM4CON + + ldr r0, =0x110002E4 + ldr r1, [r0] //读出GPM4DAT的值 + bic r1, r1, #4 //将CPM4DAT的第[2]清零,清零就是输出低电平了 + str r1, [r0] //将设置的值写回GPM4DAT + + mov pc, lr //最后不要忘记这一条,将lr的值写回pc,将继续执行 +ENDPROC(LED3_ON) + +ENTRY(LED4_ON) + /* + * GPM4CON Address = 0x110002E0 + * GPM4DAT Address = 0x110002E4 + */ + ldr r0, =0x110002E0 + ldr r1, [r0] //读出GPM4CON的值 + bic r1, r1, #0xf000 //将GPM4CON[12:15]清零 + orr r1, r1, #0x1000 //将GPM4_3设置为输出引脚 + str r1, [r0] //将设置的值写回GPM4CON + + ldr r0, =0x110002E4 + ldr r1, [r0] //读出GPM4DAT的值 + bic r1, r1, #8 //将CPM4DAT的第[3]位清零,清零就是输出低电平了 + str r1, [r0] //将设置的值写回GPM4DAT + + mov pc, lr //最后不要忘记这一条,将lr的值写回pc,将继续执行 +ENDPROC(LED4_ON)
OK,添加完上面的代码,我们可以通过之前介绍的方法将重新编译的代码烧写到SD卡,启动开发板可以看到四个LED灯都亮起来了,代码代码是OK的。既然已经添加了点灯的代码了,那么熄灯的代码也就简单了,继续添加熄灯的代码如下:
diff --git a/arch/arm/cpu/armv7/start.S b/arch/arm/cpu/armv7/start.S index 83eed98..8ed8719 100644 --- a/arch/arm/cpu/armv7/start.S +++ b/arch/arm/cpu/armv7/start.S @@ -89,6 +89,13 @@ switch_to_hypervisor_ret: bl LED2_ON bl LED3_ON bl LED4_ON + + bl DELAY + + bl LED1_OFF + bl LED2_OFF + bl LED3_OFF + bl LED4_OFF bl _main /*----------------------------------------------------------------------------- -*/ ENDPROC(LED4_ON) +ENTRY(LED1_OFF) + /* + * GPM4CON Address = 0x110002E0 + * GPM4DAT Address = 0x110002E4 + */ + ldr r0, =0x110002E0 + ldr r1, [r0] //读出GPM4CON的值 + bic r1, r1, #0xf //将GPM4CON[0:3]清零 + orr r1, r1, #0x1 //将GPM4_0设置为输出引脚 + str r1, [r0] //将设置的值写回GPM4CON + + ldr r0, =0x110002E4 + ldr r1, [r0] //读出GPM4DAT的值 + bic r1, r1, #1 //将CPM4DAT的第[0]位清零,清零就是输出低电平了 + orr r1, r1, #1 //将GPM4DAT的第[0]为设置为1,输出高电平,LED灯熄灭 + str r1, [r0] //将设置的值写回GPM4DAT + + mov pc, lr //最后不要忘记这一条,将lr的值写回pc,将后继续执行 +ENDPROC(LED1_OFF) +ENTRY(LED2_OFF) + /* + * GPM4CON Address = 0x110002E0 + * GPM4DAT Address = 0x110002E4 + */ + ldr r0, =0x110002E0 + ldr r1, [r0] //读出GPM4CON的值 + bic r1, r1, #0xf0 //将GPM4CON[4:7]清零 + orr r1, r1, #0x10 //将GPM4_1设置为输出引脚 + str r1, [r0] //将设置的值写回GPM4CON + + ldr r0, =0x110002E4 + ldr r1, [r0] //读出GPM4DAT的值 + bic r1, r1, #2 //将CPM4DAT的第[1]位清零,清零就是输出低电平了 + orr r1, r1, #2 //将GPM4DAT的第[1]为设置为1,输出高电平,LED灯熄灭 + str r1, [r0] //将设置的值写回GPM4DAT + mov pc, lr //最后不要忘记这一条,将lr的值写回pc,将后继续执行 +ENDPROC(LED2_OFF) +ENTRY(LED3_OFF) + /* + * GPM4CON Address = 0x110002E0 + * GPM4DAT Address = 0x110002E4 + */ + ldr r0, =0x110002E0 + ldr r1, [r0] //读出GPM4CON的值 + bic r1, r1, #0xf00 //将GPM4CON[8:11]清零 + orr r1, r1, #0x100 //将GPM4_2设置为输出引脚 + str r1, [r0] //将设置的值写回GPM4CON + + ldr r0, =0x110002E4 + ldr r1, [r0] //读出GPM4DAT的值 + bic r1, r1, #4 //将CPM4DAT的第[0]位清零,清零就是输出低电平了 + orr r1, r1, #4 //将GPM4DAT的第[0]为设置为1,输出高电平,LED灯熄灭 + str r1, [r0] //将设置的值写回GPM4DAT + + mov pc, lr //最后不要忘记这一条,将lr的值写回pc,将后继续执行 +ENDPROC(LED3_OFF) + +ENTRY(LED4_OFF) + /* + * GPM4CON Address = 0x110002E0 + * GPM4DAT Address = 0x110002E4 + */ + ldr r0, =0x110002E0 + ldr r1, [r0] //读出GPM4CON的值 + bic r1, r1, #0xf000 //将GPM4CON[0:3]清零 + orr r1, r1, #0x1000 //将GPM4_3设置为输出引脚 + str r1, [r0] //将设置的值写回GPM4CON + + ldr r0, =0x110002E4 + ldr r1, [r0] //读出GPM4DAT的值 + bic r1, r1, #8 //将CPM4DAT的第[0]位清零,清零就是输出低电平了 + orr r1, r1, #8 //将GPM4DAT的第[0]为设置为1,输出高电平,LED灯熄灭 + str r1, [r0] //将设置的值写回GPM4DAT + + mov pc, lr //最后不要忘记这一条,将lr的值写回pc,将后继续执行 +ENDPROC(LED4_OFF) +ENTRY(DELAY) + /* + * 延时函数 + */ + ldr r1, =0x000F0000 +LOOP: + sub r1, r1, #0x01 + cmp r1, #0x00 + bne LOOP + mov pc, lr + +ENDPROC(DELAY)
OK,点灯,熄灯和延时函数都能够正常运行了,不过现在还有一个问题,就是怎么在其他汇编文件或者C文件中调用我们编写的点灯和熄灯代码呢?
最简单的方法当然是查看uboot源代码是如何实现的了,我查看代码时就发现如下内容:
在start.s文件中,reset函数最后会有一个bl _main的操作,_main函数就是在./arch/arm/lib/crt0.S中定义的,使用的是ENTRY伪指令来定义的,那么是不是说明,只要是用ENTRY定义了函数都可以在全局中调用,然后我百度看了很多文章,都会这么说ENTRY这个伪指令的用法:ENTRY伪指令用于指定汇编程序的入口点。在一个完整的汇编程序中至少要有一个ENTRY(也可以有多个,当有多个ENTRY时,程序的真正入口点由链接器指定),但在一个源文件里最多只能有一个ENTRY(可以没有)。但是我感觉这个说法明显是不对的啊,在一个源文件中最多只能有一个ENTRY(可以没有)显然是不对的,我们查看start.S最初的代码就可以发现,一个源文件中ENTRY还真不止一个。
好的,说了这么多,最后还是用个实例来说明内容吧,最后我还有一个疑问,希望了解这个的朋友可以留言交流交流。
diff --git a/arch/arm/cpu/armv7/start.S b/arch/arm/cpu/armv7/start.S index 8ed8719..9c5ce83 100644 --- a/arch/arm/cpu/armv7/start.S +++ b/arch/arm/cpu/armv7/start.S @@ -465,7 +465,7 @@ ENTRY(DELAY) /* * 延时函数 * 修改延时时间,这样现象会更清晰点 */ - ldr r1, =0x000F0000 + ldr r1, =0x00F00000 LOOP: sub r1, r1, #0x01 cmp r1, #0x00
diff --git a/arch/arm/lib/crt0.S b/arch/arm/lib/crt0.S index 8415f77..5e28fa7 100644 --- a/arch/arm/lib/crt0.S +++ b/arch/arm/lib/crt0.S @@ -69,6 +69,7 @@ ENTRY(_main) /* * Set up initial C runtime environment and call board_init_f(0). */ + bl LED1_ON #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK) ldr sp, =(CONFIG_SPL_STACK) @@ -82,6 +83,8 @@ ENTRY(_main) #else bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ #endif + + bl LED2_ON mov r0, sp bl board_init_f_alloc_reserve mov sp, r0
我们在crt0.S文件中添加LED1和LED2的点灯过程,最后我发现只有LED2_ON是能亮的,但是LED1_ON却不亮,这就是我上面提到的问题了,LED2灯都亮了,表明程序是可以执行到bl LED1_ON那里的,但是为什么不亮呢?这个问题还希望知道为什么的朋友可以告知我一声。
好的,这一篇就到这里了。
相关文章推荐
- Linux 自检和 SystemTap
- U-Boot源码分析及移植-fs2410
- Python 七步捉虫法
- 解放双手:如何在本地调试远程服务器上的Node代码
- 路由器的配置与调试
- 对于技术人员的出现了运行时间错误,是否要进行调试的解决方法
- 解析NodeJs的调试方法
- C++软件添加dump调试打印日志(推荐)
- 微信小程序下载工具及调试详解
- 在ASP.NET 2.0中操作数据之七十二:调试存储过程
- 讲解WordPress开发中一些常用的debug技巧
- 必备的JS调试技巧汇总
- JavaScript程序设计之JS调试
- 可以用来调试JavaScript错误的解决方案
- jQuery中ajax错误调试分析
- 如何调试异步加载页面里包含的js文件
- jQuery下的Ajax调试步骤
- 调试一段PHP程序时遇到的三个问题
- JavaScript高级程序设计 错误处理与调试学习笔记
- Javascript调试脚本的经验之谈第1/2页