您当前的位置: 首页 >  嵌入式

正点原子

暂无认证

  • 3浏览

    0关注

    382博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

【正点原子Linux连载】第十章C语言版LED灯实验--摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

正点原子 发布时间:2021-03-10 12:35:07 ,浏览量:3

1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-300792-1-1.html 3)对正点原子Linux感兴趣的同学可以加群讨论:935446741

4)关注正点原子公众号,获取最新资料更新 在这里插入图片描述

第十章C语言版LED灯实验

第八章我们讲解了如何用汇编语言编写LED灯实验,但是实际开发过程中汇编用的很少,大部分都是C语言开发,汇编只是用来完成C语言环境的初始化。本章我们就来学习如何用汇编来完成C语言环境的初始化工作,然后从汇编跳转到C语言代码里面去。

10.1 C语言版LED灯简介 第八章的汇编LED灯实验中,我们讲解了如何使用汇编来编写LED灯驱动,实际工作中是很少用到汇编去写嵌入式驱动的,毕竟汇编太难,而且写出来也不好理解,大部分情况下都是使用C语言去编写的。只是在开始部分用汇编来初始化一下C语言环境,比如初始化DDR、设置堆栈指针SP等等,当这些工作都做完以后就可以进入C语言环境,也就是运行C语言代码,一般都是进入main函数。所以我们有两部分文件要做: ①、汇编文件 汇编文件只是用来完成C语言环境搭建。 ②、C语言文件 C语言文件就是完成我们的业务层代码的,其实就是我们实际例程要完成的功能。 其实STM32也是这样的,只是我们在开发STM32的时候没有想到这一点,以STM32F103为例,其启动文件startup_stm32f10x_hd.s这个汇编文件就是完成C语言环境搭建的,当然还有一些其他的处理,比如中断向量表等等。当startup_stm32f10x_hd.s把C语言环境初始化完成以后就会进入C语言环境。 10.2硬件原理分析 本章使用到的硬件资源和第八章一样,就是一个LED0。 10.3实验程序编写 本实验对应的例程路径为:开发板光盘-> 1、裸机例程->2_ledc。 新建VScode工程,工程名字为“ledc”,新建三个文件:start.S、main.c和mian.h。其中start.S是汇编文件,main.c和main.h是C语言相关文件。 10.3.1汇编部分实验程序编写 在STM32中,启动文件 startup_stm32f10x_hd.s就是完成C语言环境搭建的,当然还有一些其他的处理,比如中断向量表等等。startup_stm32f10x_hd.s中堆栈初始化代码如下所示:

示例代码10.3.1.1 STM32启动文件堆栈初始化代码
1  Stack_Size      EQU     0x00000400
2
3                    AREA    STACK, NOINIT, READWRITE, ALIGN=3
4  Stack_Mem       SPACE   Stack_Size
5  __initial_sp
6
7; Heap Configuration
8;  Heap Size (in Bytes)
9;
10
11 Heap_Size       EQU     0x00000200
12
13                 AREA    HEAP, NOINIT, READWRITE, ALIGN=3
14 __heap_base
15 Heap_Mem        SPACE   Heap_Size
16 __heap_limit
17*******************省略掉部分代码***********************
18 Reset_Handler   PROC
19                 EXPORT  Reset_Handler             [WEAK]
20                 IMPORT  __main
21                 IMPORT  SystemInit
22                 LDR     R0,=SystemInit
23                 BLX     R0               
24                 LDR     R0,=__main
25                 BX      R0
26                 ENDP
第1行代码就是设置栈大小,这里是设置为0X400=1024字节。
第5行的__initial_sp就是初始化SP指针。
第11行是设置堆大小。
第18行是复位中断服务函数,STM32复位完成以后会执行此中断服务函数。
第22行调用SystemInit()函数来完成其他初始化工作。
第24行调用__main,__main是库函数,其会调用main()函数。
I.MX6U的汇编部分代码和STM32的启动文件startup_stm32f10x_hd.s基本类似的,只是本实验我们不考虑中断向量表,只考虑初始化C环境即可。在前面创建的start.s中输入如下代码:
示例代码10.3.1.2 start.s文件代码
/***************************************************************
Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名   : start.s
作者     : 左忠凯
版本     : V1.0
描述     : I.MX6U-ALPHA/I.MX6ULL开发板启动文件,完成C环境初始化,
           C环境初始化完成以后跳转到C代码。
其他     : 无
日志     : 初版 2019/1/3 左忠凯修改
**************************************************************/

1.global _start       /* 全局标号 */
2
3/*
4   * 描述: _start函数,程序从此函数开始执行,此函数主要功能是设置C
5   *        运行环境。
6   */
7  _start:
8
9	/* 进入SVC模式 */
10		mrs r0, cpsr
11	bic r0, r0, #0x1f/* 将r0的低5位清零,也就是cpsr的M0~M4    */
12	orr r0, r0, #0x13	/* r0或上0x13,表示使用SVC模式	*/
13	msr cpsr, r0         /* 将r0 的数据写入到cpsr_c中	*/
14
15	ldr sp,=0X80200000	/* 设置栈指针	 */
16	b main              	/* 跳转到main函数       */
第1行定义了一个全局标号_start。
第7行就是标号_start开始的地方,相当于是一个_start函数,这个_start就是第一行代码。
第10~13行就是设置处理器进入SVC模式,在6.2小节的“Cortex-A处理器运行模型”中我们说过Cortex-A有九个运行模型,这里我们设置处理器运行在SVC模式下。处理器模式的设置是通过修改CPSR(程序状态)寄存器来完成的,在6.3.2小节中我们详细的讲解了CPSR寄存器,其中M[4:0](CPSR的bit[4:0])就是设置处理器运行模式的,参考表6.3.2.2,如果要将处理器设置为SVC模式,那么M[4:0]就要等于0X13。11~13行代码就是先使用指令MRS将CPSR寄存器的值读取到R0中,然后修改R0中的值,设置R0的bit[4:0]为0X13,然后再使用指令MSR将修改后的R0重新写入到CPSR中。
第15行通过ldr指令设置SVC模式下的SP指针=0X80200000,因为I.MX6U-ALPHA开发板上的DDR3地址范围是0X80000000~0XA0000000(512MB)或者0X80000000~0X90000000(256MB),不管是512MB版本还是256MB版本的,其DDR3起始地址都是0X80000000。由于Cortex-A7的堆栈是向下增长的,所以将SP指针设置为0X80200000,因此SVC模式的栈大小0X80200000-0X80000000=0X200000=2MB,2MB的栈空间已经很大了,如果做裸机开发的话绰绰有余。
第16行就是跳转到main函数,main函数就是C语言代码了。
至此汇编部分程序执行完成,就几行代码,用来设置处理器运行到SVC模式下、然后初始化SP指针、最终跳转到C文件的mian函数中。如果有玩过三星的S3C2440或者S5PV210的话会知道我们在使用SDRAM或者DDR之前必须先初始化SDRAM或者DDR。所以S3C2440或者S5PV210的汇编文件里面是一定会有SDRAM或者DDR初始化代码的。我们上面编写的start.s文件中却没有初始化DDR3的代码,但是却将SVC模式下的SP指针设置到了DDR3的地址范围中,这不会出问题吗?肯定不会的,DDR3肯定是要初始化的,但是不需要在start.s文件中完成。在9.4.2小节里面分析DCD数据的时候就已经讲过了,DCD数据包含了DDR配置参数,I.MX6U内部的Boot ROM会读取DCD数据中的DDR配置参数然后完成DDR初始化的。

10.3.2 C语言部分实验程序编写 C语言部分有两个文件main.c和main.h,main.h里面主要是定义的寄存器地址,在mian.h里面输入代码:

示例代码10.3.2.1 main.h文件代码
#ifndef __MAIN_H
#define __MAIN_H
/******************************************************************
Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名   : main.h
作者     : 左忠凯
版本     : V1.0
描述     : 时钟GPIO1_IO03相关寄存器地址定义。
其他     : 无
日志     : 初版V1.0 2019/1/3 左忠凯创建
*****************************************************************/

1  /* 
2   * CCM相关寄存器地址
3   */
4  #define CCM_CCGR0            	*((volatileunsignedint*)0X020C4068)
5  #define CCM_CCGR1            	*((volatileunsignedint*)0X020C406C)
6  #define CCM_CCGR2            	*((volatileunsignedint*)0X020C4070)
7  #define CCM_CCGR3            	*((volatileunsignedint*)0X020C4074)
8  #define CCM_CCGR4            	*((volatileunsignedint*)0X020C4078)
9  #define CCM_CCGR5            	*((volatileunsignedint*)0X020C407C)
10#define CCM_CCGR6            	*((volatileunsignedint*)0X020C4080)
11
12/* 
13  * IOMUX相关寄存器地址
14  */
15 #define SW_MUX_GPIO1_IO03	*((volatileunsignedint*)0X020E0068)
16 #define SW_PAD_GPIO1_IO03    *((volatileunsignedint*)0X020E02F4)
17
18/* 
19  * GPIO1相关寄存器地址
20  */
21 #define GPIO1_DR             	*((volatileunsignedint*)0X0209C000)
22 #define GPIO1_GDIR          	*((volatileunsignedint*)0X0209C004)
23 #define GPIO1_PSR            	*((volatileunsignedint*)0X0209C008)
24 #define GPIO1_ICR1           	*((volatileunsignedint*)0X0209C00C)
25 #define GPIO1_ICR2           	*((volatileunsignedint*)0X0209C010)
26 #define GPIO1_IMR            	*((volatileunsignedint*)0X0209C014)
27 #define GPIO1_ISR            	*((volatileunsignedint*)0X0209C018)
28 #define GPIO1_EDGE_SEL      	*((volatileunsignedint*)0X0209C01C)
29
30 #endif
在mian.h中我们以宏定义的形式定义了要使用到的所有寄存器,后面的数字就是其地址,比如CCM_CCGR0寄存器的地址就是0X020C4068,这个很简单,很好理解。
接下看一下main.c文件,在mian.c里面输入如下所示代码:
示例代码10.3.2.2  main.c文件代码
/**************************************************************
Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名   :  mian.c
作者     : 左忠凯
版本     : V1.0
描述     : I.MX6U开发板裸机实验2 C语言点灯
使用C语言来点亮开发板上的LED灯,学习和掌握如何用C语言来
完成对I.MX6U处理器的GPIO初始化和控制。
其他     : 无
日志     : 初版V1.0 2019/1/3 左忠凯创建
**************************************************************/
1#include "main.h"
2
3 /*
4  * @description : 使能I.MX6U所有外设时钟
5* @param       : 无
6  * @return      : 无
7 */
8void clk_enable(void)
9{
10      CCM_CCGR0 =0xffffffff;
11      CCM_CCGR1 =0xffffffff;
12      CCM_CCGR2 =0xffffffff;
13      CCM_CCGR3 =0xffffffff;
14      CCM_CCGR4 =0xffffffff;
15      CCM_CCGR5 =0xffffffff;
16      CCM_CCGR6 =0xffffffff;
17}
18
19/*
20   * @description : 初始化LED对应的GPIO
21   * @param       : 无
22   * @return      : 无
23   */
24void led_init(void)
25{
26/* 1、初始化IO复用,复用为GPIO1_IO03 */
27      SW_MUX_GPIO1_IO03 =0x5;
28
29/* 2、配置GPIO1_IO03的IO属性
30       *bit 16:0 HYS关闭
31       *bit [15:14]: 00 默认下拉
32       *bit [13]: 0 kepper功能
33       *bit [12]: 1 pull/keeper使能
34       *bit [11]: 0 关闭开路输出
35       *bit [7:6]: 10 速度100Mhz
36       *bit [5:3]: 110 R0/6驱动能力
37       *bit [0]: 0 低转换率
38       */
39      SW_PAD_GPIO1_IO03 =0X10B0;
40
41/* 3、初始化GPIO, GPIO1_IO03设置为输出 */
42      GPIO1_GDIR =0X0000008;
43
44/* 4、设置GPIO1_IO03输出低电平,打开LED0 */
45      GPIO1_DR =0X0;
46}
47
48/*
49   * @description : 打开LED灯
50   * @param       : 无
51   * @return      : 无
52   */
53void led_on(void)
54{
55/* 
56       * 将GPIO1_DR的bit3清零
57       */
58      GPIO1_DR &=~(1            
关注
打赏
1665308814
查看更多评论
0.0455s