I.MX6U C语言运行环境构建及驱动开发格式

1.设置处理器模式

设置6ULL处于SVC模式下。设置下CPSR寄存器的bit4-0,也就是M[4:0]为10011=0x13.。读写状态寄存器需要用到MRS和MSR指令。MRS将CPSR寄存器数据读出到通用寄存器里面,MSR指令将通用寄存器的值写入到CPSR寄存器里面去。

2.设置SP指针

SP可以指向内部RAM,也可以指向DDR,我们将其指向DDR。SP设置到哪里?512MB的范围0x80000000---0x9FFFFFFF。栈大小,0x20000000=2MB。处理器栈增长方式,对于A7而言是向下增长的。

3.跳转到C语言

使用b指令,跳转到C语言函数,比如MAIN函数

1汇编部分实验程序编写
I.MX6U 的汇编部分代码和 STM32 的启动文件 startup_stm32f10x_hd.s 基本类似的,只是本
实验我们不考虑中断向量表,只考虑初始化 C 环境即可。在前面创建的 start.s 中输入如下代码:

2 C 语言部分实验程序编写

 main.h

#ifndef __MAIN_H
#define __MAIN_H/* 
* CCM 相关寄存器地址
*/
#define CCM_CCGR0 *((volatile unsigned int *)0X020C4068)
#define CCM_CCGR1 *((volatile unsigned int *)0X020C406C)
#define CCM_CCGR2 *((volatile unsigned int *)0X020C4070)
#define CCM_CCGR3 *((volatile unsigned int *)0X020C4074)
#define CCM_CCGR4 *((volatile unsigned int *)0X020C4078)
#define CCM_CCGR5 *((volatile unsigned int *)0X020C407C)
#define CCM_CCGR6 *((volatile unsigned int *)0X020C4080)/* 
* IOMUX 相关寄存器地址
*/
#define SW_MUX_GPIO1_IO03 *((volatile unsigned int *)0X020E0068)
#define SW_PAD_GPIO1_IO03 *((volatile unsigned int *)0X020E02F4)/* 
* GPIO1 相关寄存器地址
*/
#define GPIO1_DR *((volatile unsigned int *)0X0209C000)
#define GPIO1_GDIR *((volatile unsigned int *)0X0209C004)
#define GPIO1_PSR *((volatile unsigned int *)0X0209C008)
#define GPIO1_ICR1 *((volatile unsigned int *)0X0209C00C)
#define GPIO1_ICR2 *((volatile unsigned int *)0X0209C010)
#define GPIO1_IMR *((volatile unsigned int *)0X0209C014)
#define GPIO1_ISR *((volatile unsigned int *)0X0209C018)
#define GPIO1_EDGE_SEL *((volatile unsigned int *)0X0209C01C)#endif
main.c
1 #include "main.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 复用, 复用为 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 */
53 void led_on(void)
54 {
55 /* 
56 * 将 GPIO1_DR 的 bit3 清零 
57 */
58 GPIO1_DR &= ~(1<<3);
59 }
60 
61 /*
62 * @description : 关闭 LED 灯
63 * @param : 无
64 * @return : 无
65 */
66 void led_off(void)
67 {
68 /* 
69 * 将 GPIO1_DR 的 bit3 置 1
70 */
71 GPIO1_DR |= (1<<3);
72 }
73 
74 /*
75 * @description : 短时间延时函数
76 * @param - n : 要延时循环次数(空操作循环次数,模式延时)
77 * @return : 无
78 */
79 void delay_short(volatile unsigned int n)
80 {
81 while(n--){}
82 }
83 
84 /*
85 * @description : 延时函数,在 396Mhz 的主频下延时时间大约为 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 }
clk_enable 函数是使能
CCGR0~CCGR6 所控制的所有外设时钟。 led_init 函数是初始化 LED 灯所使用的 IO ,包括设置
IO 的复用功能、 IO 的属性配置和 GPIO 功能,最终控制 GPIO 输出低电平来打开 LED 灯。
led_on led_off 这两个函数看名字就知道,用来控制 LED 灯的亮灭的。 delay_short() delay()
这两个函数是延时函数, delay_short() 函数是靠空循环来实现延时的, delay() 是对 delay_short()
的 简 单 封 装 ,在 I.MX6U 工作 在 396MHz(Boot ROM 设 置的 396MHz) 的 主 频 的 时候

delay_short(0x7ff)基本能够实现大约 1ms 的延时,所以 delay()函数我们可以用来完成 ms 延时。

main 函数就是我们的主函数了,在 main 函数中先调用函数 clk_enable() led_init() 来完成时钟
使能和 LED 初始化,最终在 while(1) 循环中实现 LED 循环亮灭,亮灭时间大约是 500ms
编写 Makefile
1 行定义了一个变量 objs objs 包含着要生成 ledc.bin 所需的材料: start.o main.o ,也
就是当前工程下的 start.s main.c 这两个文件编译后的 .o 文件。这里要注意 start.o 一定要放到
最前面!因为在后面链接的时候 start.o 要在最前面,因为 start.o 是最先要执行的文件!
3 行就是默认目标,目的是生成最终的可执行文件 ledc.bin ledc.bin 依赖 start.o main.o
如果当前工程没有 start.o main.o 的时候就会找到相应的规则去生成 start.o main.o 。比如
start.o start.s 文件编译生成的,因此会执行第 8 行的规则。
4 行是使用 arm-linux-gnueabihf-ld 进行链接,链接起始地址是 0X87800000 ,但是这一行
用到了自动变量“ $^ ”,“ $^ ”的意思是所有依赖文件的集合,在这里就是 objs 这个变量的值:
start.o main.o 。链接的时候 start.o 要链接到最前面,因为第一行代码就是 start.o 里面的,因
此这一行就相当于:
5 行使用 arm-linux-gnueabihf-objcopy 来将 ledc.elf 文件转为 ledc.bin ,本行也用到了自动变量
$@ ”,“ $@ ”的意思是目标集合,在这里就是“ledc.bin”,那么本行就相当于:
6 行使用 arm-linux-gnueabihf-objdump 来反汇编,生成 ledc.dis 文件。
8~15 行就是针对不同的文件类型将其编译成对应的 .o 文件,其实就是汇编 .s(.S) .c
件,比如 start.s 就会使用第 8 行的规则来生成对应的 start.o 文件。第 9 行就是具体的命令,这 行也用到了自动变量“$@ ”和“ $< ”,其中“ $< ”的意思是依赖目标集合的第一个文件。比如 start.s 要编译成 start.o 的话第 8 行和第 9 行就相当于:
17 行就是工程清理规则,通过命令“ make clean ”就可以清理工程。
Makefile 文件就讲到这里,我们可以将整个工程拿到 Ubuntu 下去编译,编译完成以后可以使用 软件 imxdownload 将其下载到 SD 卡中,命令如下:
链接脚本
在上面的 Makefile 中我们链接代码的时候使用如下语句:
上面语句中我们是通过“ -Ttext ”来指定链接地址是 0X87800000 的,这样的话所有的文件
都会链接到以 0X87800000 为起始地址的区域。但是有时候我们很多文件需要链接到指定的区 域,或者叫做段里面,比如在 Linux 里面初始化函数就会放到 init 段里面。因此我们需要能够 自定义一些段,这些段的起始地址我们可以自由指定,同样的我们也可以指定一个文件或者函 数应该存放到哪个段里面去。要完成这个功能我们就需要使用到链接脚本,看名字就知道链接 脚本主要用于链接的,用于描述文件应该如何被链接在一起形成最终的可执行文件。其主要目 的是描述输入文件中的段如何被映射到输出文件中,并且控制输出文件中的内存排布。比如我 们编译生成的文件一般都包含 text 段、 data 段等等。

TMD,太难了,哪来的missing seperator艹艹 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/468523.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在小区门口开什么店比较好?把握商机从这里开始

作为一位资深的鲜奶吧创业者&#xff0c;我已经在这个行业摸爬滚打了五年。这五年的时间里&#xff0c;我见证了社区商业的繁荣与变迁&#xff0c;也深刻体会到了在小区门口开店的商机与挑战。今天&#xff0c;我想和大家分享一些关于在小区门口开店的见解&#xff0c;特别是针…

LLVM的中间表示

概括 选择编译器IR的决策很重要&#xff0c;它决定了优化过程将拥有多少信息来使代码运行得更快。 一方面非常高层级的IR允许优化器轻松地提取原始源代码的相关信息。 另一方面&#xff0c;低层的IR更加贴近目标机器&#xff0c;这样编译器更容易为特定的硬件生成相应的代码…

高斯模糊滤镜

高斯模糊滤镜 import cv2# 读取图像 image cv2.imread(1.jpg)# 高斯模糊滤镜 blurred cv2.GaussianBlur(image, (15, 15), 0)# 保存处理后的图像 cv2.imwrite(blurred_image.jpg, blurred)# 显示原始图像和处理后的图像 cv2.imshow(Original Image, image) cv2.imshow(Blurre…

Java的Cloneable接口和深拷贝

Java 中内置了一些很有用的接口, Clonable 就是其中之一。 Object 类中存在一个 clone 方法, 调用这个方法可以创建一个对象的 "拷贝"。 但是要想合法调用 clone 方法, 必须要先实现 Clonable 接口, 否则就会抛出 CloneNotSupportedException 异常。 浅拷贝&#xff…

C# CAD2016 判断多边形的方向正时针或逆时针旋转

方法一&#xff1a;基于相邻顶点相对位置判断顺时针排列 // 计算当前子序列是否为顺时针排列 for (int i 1; i < outerPoints.Count; i) {int index (startVertexIndex i) % outerPoints.Count;int prevIndex (startVertexIndex i - 1) % outerPoints.Count;Point2d c…

linux应用 进程间通信之信号量(System V)

1、定义 System V 信号量是一种用于进程间同步和互斥的机制&#xff0c;它是 System V IPC&#xff08;Inter-Process Communication&#xff0c;进程间通信&#xff09;机制的一部分。信号量通常用于控制对共享资源的访问&#xff0c;以避免竞争条件&#xff08;race conditi…

Zotero插件分享(第二弹)

今天紧接上一篇文章&#xff08;Zotero常用插件分享&#xff09;&#xff0c;继续分享关于Zotero常用插件的相关内容。&#xff08;排名不分先后&#xff09; 1.Translate for Zotero 英文文献阅读辅助工具&#xff0c;可以实现将pdf中选中的文字翻译为指定语言&#xff0c;并…

模型 RFM(最近、频率、金额)

系列文章 主要是 分享 思维模型&#xff0c;涉及各个领域&#xff0c;重在提升认知。衡量客户价值。 1 RFM(最近、频率、金额)模型的应用 1.1 RFM模型在服装店运营中的应用分析 这里以服装门店为例&#xff0c;具体的会员R、F、M值分布如下所示&#xff1a; R值&#xff08;…

位运算总结(Java)

目录 位运算概述 位运算符 位运算的优先级 位运算常见应用 1. 给定一个数n&#xff0c;判断其二进制表示中的第x位是0还是1 2. 将数n的二进制表示中的第x位修改为1 3. 将数n的二进制表示中的第x位修改为0 4. 位图 例题&#xff1a;判断字符是否唯一 5. 提取数n的二进制…

寒假思维训练day21

今天更新一道不错的状态压缩DP题&#xff0c;顺带总结一下状态压缩DP。 摘要&#xff1a; Part1 浅谈状态压缩DP的理解 Part2 浅谈对状态机DP的理解 Part3 关于状态压缩DP的1道例题 Part1 状态压缩DP 1、状态压缩DP&#xff1a; 事物的状态可能包含多个特征&#xff0c;…

伦敦金是现货黄金吗?

伦敦金属现货黄金交易的一种形式。投资者可以通过伦敦金市场直接买卖黄金&#xff0c;以实现投资收益。伦敦金市场具有高度流动性和透明度&#xff0c;是全球投资者广泛参与的贵金属交易市场之一。 什么是现货黄金&#xff1f; 现货黄金是指实物黄金的交易&#xff0c;投资者可…

【STM32 CubeMX】HAL库的本质读写寄存器

文章目录 前言一、HAL库的本质1.1 HAL库的本质是操作寄存器1.2 自己实现HAL_GPIO_WritePin寄存器通过寄存器的操作点灯代码概况Port bit set/reset register寄存器 总结 前言 在嵌入式系统开发中&#xff0c;HAL&#xff08;Hardware Abstraction Layer&#xff09;库是一个重…