您的位置:首页 > 编程语言

为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了。

 下面编写测试代码:

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那里的,但是为什么不亮呢?这个问题还希望知道为什么的朋友可以告知我一声。

 好的,这一篇就到这里了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  u-boot 调试