嵌入式Linux裸机开发笔记4(IMX6ULL)—模仿 STM32 驱动开发格式实验(2)

引言

        接下来开始详细编写实验代码,实现led功能。

4.2 硬件原理分析

        本次笔记使用到的硬件资源和i之前笔记一样,就是一个 LED0

4.3 实验程序编写

        创建 VSCode 工程,工作区名字为“ ledc_stm32 ”,新建三个文件: start.S main.c imx6ul.h 。其中 start.S 是汇编文件, start.S 文件的内容和第十章的 start.S 一样,直接复制过来就可以。 main.c和 imx6ul.h C 文件,完成以后如下图 所示:
        文件 imx6ul.h 用来存放外设寄存器定义,在 imx6ul.h 中输入如下代码:
/*
* 外设寄存器组的基地址
*/
1 #define CCM_BASE         ( 0X020C4000 )
2 #define CCM_ANALOG_BASE         ( 0X020C8000 )
3 #define IOMUX_SW_MUX_BASE         ( 0X020E0014 )
4 #define IOMUX_SW_PAD_BASE         ( 0X020E0204 )
5 #define GPIO1_BASE         ( 0x0209C000 )
6 #define GPIO2_BASE         ( 0x020A0000 )
7 #define GPIO3_BASE         ( 0x020A4000 )
8 #define GPIO4_BASE         ( 0x020A8000 )
9 #define GPIO5_BASE         ( 0x020AC000 )
10
11 /*
12 * CCM 寄存器结构体定义,分为 CCM CCM_ANALOG
13 */
14 typedef struct
15 {
16 volatile unsigned int CCR ;
17 volatile unsigned int CCDR ;
18 volatile unsigned int CSR ;
……
46 volatile unsigned int CCGR6 ;
47 volatile unsigned int RESERVED_3 [ 1 ];
48 volatile unsigned int CMEOR ;
49 } CCM_Type ;
50
51 typedef struct
52 {
53 volatile unsigned int PLL_ARM ;
54 volatile unsigned int PLL_ARM_SET ;
55 volatile unsigned int PLL_ARM_CLR ;
56 volatile unsigned int PLL_ARM_TOG ;
……
110 volatile unsigned int MISC2 ;
111 volatile unsigned int MISC2_SET ;
112 volatile unsigned int MISC2_CLR ;
113 volatile unsigned int MISC2_TOG ;
114 } CCM_ANALOG_Type ;
115
116 /*
117 * IOMUX 寄存器组
118 */
119 typedef struct
120 {
121 volatile unsigned int BOOT_MODE0 ;
122 volatile unsigned int BOOT_MODE1 ;
123 volatile unsigned int SNVS_TAMPER0 ;
……
241 volatile unsigned int CSI_DATA04 ;
242 volatile unsigned int CSI_DATA05 ;
243 volatile unsigned int CSI_DATA06 ;
244 volatile unsigned int CSI_DATA07 ;
245 } IOMUX_SW_MUX_Type ;
246
247 typedef struct
248 {
249 volatile unsigned int DRAM_ADDR00 ;
250 volatile unsigned int DRAM_ADDR01 ;
……
419 volatile unsigned int GRP_DDRPKE ;
420 volatile unsigned int GRP_DDRMODE ;
421 volatile unsigned int GRP_DDR_TYPE ;
422 } IOMUX_SW_PAD_Type ;
423
424 /*
425 * GPIO 寄存器结构体
426 */
427 typedef struct
428 {
429 volatile unsigned int DR ;
430 volatile unsigned int GDIR ;
431 volatile unsigned int PSR ;
432 volatile unsigned int ICR1 ;
433 volatile unsigned int ICR2 ;
434 volatile unsigned int IMR ;
435 volatile unsigned int ISR ;
436 volatile unsigned int EDGE_SEL ;
437 } GPIO_Type ;
438
439
440 /*
441 * 外设指针
442 */
443 #define CCM (( CCM_Type *) CCM_BASE )
444 #define CCM_ANALOG (( CCM_ANALOG_Type *) CCM_ANALOG_BASE )
445 #define IOMUX_SW_MUX (( IOMUX_SW_MUX_Type *) IOMUX_SW_MUX_BASE )
446 #define IOMUX_SW_PAD
(( IOMUX_SW_PAD_Type *) IOMUX_SW_PAD_BASE )
447 #define GPIO1 (( GPIO_Type *) GPIO1_BASE )
448 #define GPIO2 (( GPIO_Type *) GPIO2_BASE )
449 #define GPIO3 (( GPIO_Type *) GPIO3_BASE )
450 #define GPIO4 (( GPIO_Type *) GPIO4_BASE )
451 #define GPIO5 (( GPIO_Type *) GPIO5_BASE )
        在编写寄存器组结构体的时候注意寄存器的地址是否连续,有些外设的寄存器地址可能不是连续的,会有一些保留地址,因此我们需要在结构体中留出这些保留的寄存器。比如 CCM 的CCGR6 寄存器地址为 0X020C4080 ,而寄存器 CMEOR 的地址为 0X020C4088 。按照地址顺序递增的原理,寄存器 CMEOR 的地址应该是 0X020C4084 ,但是实际上 CMEOR 的地址是 0X020C4088,相当于中间跳过了 0X020C4088-0X020C4080=8 个字节,如果寄存器地址连续的 话应该只差 4 个字节 (32 ) ,但是现在差了 8 个字节,所以需要在寄存器 CCGR6 CMEOR直接加入一个保留寄存器,这个就是“示例代码 11.3.1 ”中第 47 RESERVED_3[1] 的来源。如果不添加保留位来占位的话就会导致寄存器地址错位!main.c 文件中输入如下所示内容:
1 #include "imx6ul.h"
2
3 /*
4 * @description : 使能 I.MX6U 所有外设时钟
5 * @param :
6 * @return :
7 */
8 void 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 */
24 void led_init ( void )
25 {
26 /* 1 、初始化 IO 复用 */
27 IOMUX_SW_MUX -> GPIO1_IO03 = 0X5 ; /* 复用为 GPIO1_IO03 */
28
29
30 /* 2 、配置 GPIO1_IO03 IO 属性
31 *bit 16:0 HYS 关闭
32 *bit [15:14]: 00 默认下拉
33 *bit [13]: 0 kepper 功能
34 *bit [12]: 1 pull/keeper 使能
35 *bit [11]: 0 关闭开路输出
36 *bit [7:6]: 10 速度 100Mhz
37 *bit [5:3]: 110 R0/6 驱动能力
38 *bit [0]: 0 低转换率
39 */
40 IOMUX_SW_PAD -> GPIO1_IO03 = 0X10B0 ;
41
42
43 /* 3 、初始化 GPIO */
44 GPIO1 -> GDIR = 0X0000008 ; /* GPIO1_IO03 设置为输出 */
45
46 /* 4 、设置 GPIO1_IO03 输出低电平,打开 LED0 */
47 GPIO1 -> DR &= ~( 1 << 3 );
48
49 }
50
51 /*
52 * @description : 打开 LED
53 * @param :
54 * @return :
55 */
56 void led_on ( void )
57 {
58 /* GPIO1_DR bit3 清零 */
59 GPIO1 -> DR &= ~( 1 << 3 );
60 }
61
62 /*
63 * @description : 关闭 LED
64 * @param :
65 * @return :
66 */
67 void led_off ( void )
68 {
69 /* GPIO1_DR bit3 1 */
70 GPIO1 -> DR |= ( 1 << 3 );
71 }
72
73 /*
74 * @description : 短时间延时函数
75 * @param - n : 要延时循环次数 ( 空操作循环次数,模式延时 )
76 * @return :
77 */
78 void delay_short ( volatile unsigned int n )
79 {
80 while ( n --){}
81 }
82
83 /*
84 * @description : 延时函数 , 396Mhz 的主频下
85 * 延时时间大约为 1ms
86 * @param - n : 要延时的 ms
87 * @return :
88 */
89 void delay ( volatile unsigned int n )
90 {
91 while ( n --)
92 {
93 delay_short ( 0x7ff );
94 }
95 }
96
97 /*
98 * @description : main 函数
99 * @param :
100 * @return :
101 */
102 int main ( void )
103 {
104 clk_enable (); /* 使能所有的时钟 */
105 led_init (); /* 初始化 led */
106
107 while ( 1 )
/* 死循环
*/
108 {
109 led_off (); /* 关闭 LED */
110 delay ( 500 ); /* 延时 500ms */
111
112 led_on ();
/* 打开 LED */
113 delay ( 500 ); /* 延时 500ms */
114 }
115
116 return 0 ;
117 }
        main.c 中 7 个函数,这 7 个函数的含义和第十章中的 main.c 文件一样,只是函数体写法变了,寄存器的访问采用 imx6ul.h 中定义的外设指针。比如第 27 行设置 GPIO1_IO03 的复用功能就可以通过“IOMUX_SW_MUX->GPIO1_IO03 ”来给寄存 SW_MUX_CTL_PAD_GPIO1_IO03赋值。

4.4.1 编写 Makefile 和链接脚本

Makefile 文件的内容基本和第十章的 Makefile 一样,如下:
1 objs := start.o main.o
2
3 ledc.bin : $(objs)
4 arm-linux-gnueabihf-ld -Timx6ul.lds -o ledc.elf $^
5 arm-linux-gnueabihf-objcopy -O binary -S ledc.elf $@
6 arm-linux-gnueabihf-objdump -D -m arm ledc.elf > ledc.dis
7
8 %.o : %.s
9 arm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o $@ $<
10
11 %.o : %.S
12 arm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o $@ $<
13
14 %.o : %.c
15 arm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o $@ $<
16
17 clean :
18 rm -rf *.o ledc.bin ledc.elf ledc.dis
链接脚本 imx6ul.lds 的内容和上一章一样,可以直接使用上一章的链接脚本文件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值