前言:
目前针对ARM Cortex-A7裸机开发文档及视频进行了二次升级持续更新中,使其内容更加丰富,讲解更加细致,全文所使用的开发平台均为华清远见FS-MP1A开发板(STM32MP157开发板)
针对对FS-MP1A开发板,除了Cortex-A7裸机开发篇外,还包括其他多系列教程,包括Cortex-M4开发篇、FreeRTOS篇、Linux基础及应用开发篇、Linux系统移植篇、Linux驱动开发篇、硬件设计篇、人工智能机器视觉篇、Qt应用编程篇、Qt综合项目实战篇等。除此之外计划针对Linux系统移植篇、Linux驱动开发篇均会进行文档及视频的二次升级更新敬请关注!
开发板更多资料可关注华清远见在线实验室(微信号:hqyjlab)领取``
Cortex-A7 GPIO 实验
Cortex-A7 GPIO 点灯编程
GPIO 控制技术是接口技术中最简单的一种。本章通过介绍 STM32MP157 芯片的 GPIO 控制方法,
让读者初步掌握控制硬件接口的方法。本章的主要内容:
GPIO 功能介绍
STM32MP157 芯片的 GPIO 控制器详解
STM32MP157 的 GPIO 应用
GPIO 功能介绍
首先应该理解什么是 GPIO。GPIO 的英文全称为 General-Purpose IO ports,也就是通用 IO 接口。在嵌入式系统中常常有数量众多,但是结构却比较简单的外部设备/电路,对这些设备/电路,有的需要 CPU 为之提供控制手段,有的则需要被 CPU 用做输入信号。而且,许多这样的设备/电路只要求一位,即只要有开/关两种状态就够了。比如,控制某个 LED 灯亮与灭,或者通过获取某个引脚的电平属性来达到判断外围设备的状态。对这些设备/电路的控制,使用传统的串行口或并行口都不合适。所以在微控制器芯片上一般都会提供一个“通用可编程 IO 接口”,即 GPIO。接口至少有两个寄存器,即“通用 IO 控制寄存器”与“通用 IO 数据寄存器”。数据寄存器的各位都直接引到芯片外部,而对这种寄存器中
每一位的作用,即每一位的信号流通方向,则可以通过控制寄存器中对应位独立地加以设置。比如,可以设置某个引脚的属性为输入、输出或其他特殊功能。
在实际的 MCU 中,GPIO 是有多种形式的。比如,有的数据寄存器可以按照位寻址,有些却不能按照位寻址,这在编程时就要区分了。比如传统的 8051 系列,就区分成可位寻址和不可位寻址两种寄存器。另外,为了使用的方便,很多 MCU 的 GPIO 接口除必须具备两个标准寄存器外,还提供上拉寄存器,可以设置 IO 的输出模式是高阻,还是带上拉的电平输出,或者不带上拉的电平输出。这在电路设计中,外围电路就可以简化不少。
STM32MP1 芯片的 GPIO 控制器详解
每个通用 I/O 端口有四个 32 位配置寄存器(GPIOx_MODER,GPIOx_OTYPE,GPIOx_OSPEEDR 和GPIOx_PUPDR),两个 32 位数据寄存器(GPIOx_IDR 和 GPIOx_ODR)和 32 位设置/重置寄存器(GPIOx_BSRR)。此外,所有 GPIO 都有一个 32 位的锁定寄存器(GPIOx_LCKR)和两个 32 位的备用函数选择寄存器(GPIOx_AFRH 和 GPIOx_AFRL)。
主要特征
每个通用 I/O (GPIO)端口的端口位都可以通过软件在几种模式下单独配置:
浮空输入
浮空输入在 VDD 和 VSS 所在路径的两个开关同时断开。此时没有上拉和下拉的情况,所以当IO 口没有接输入的时候,此时的电平会是一个不确定的值,也就是我们所说的浮空。电平会处于一个跳变的状态,一会高,一会低。只有输入了一个高/低电平才会确定下来。
这么做的优势在于输入模式的电平会完全取决于外部电路而与内部电路无关。但是在没有外部电路接入的时候,IO 脚浮空会使得电平不确定TTL
施密特触发器由于电源的特性,或者是由于外部开关输入的特性,输入的数字信号,极有可能会出现脉冲等噪声的影响,为了让我们的波形更好看,或者信号更加清晰,所以就设置了 TTL施密特触发器这个东西。经过之后,我们就会把这个数字信息存储在输入数据寄存器中。这样我们就读到了 IO 过来的数字信号
输入上拉
输入上拉 VDD 所在上拉电阻开关闭合,下拉电阻的开关断开。
此时的电平就是 VDD 的电平,此时读取到的电平就是高电平。如果输入了一个高电平,VDD 和 O点(上拉电阻和下拉电阻中间)之间就几乎没有电势差,此时 O 点(上拉电阻和下拉电阻中间)的电平就仍然是高电平,读取到的电平就是高电平。但是由于在没有电压输入的时候,电平也是高电平,所以这一种输入情况下是没有办法确定信号是否输入了。
当输入信号是一个低电平的时候,此时 O 点(上拉电阻和下拉电阻中间)的电平的电平就会变成低电平,那么 VDD 和 O 点(上拉电阻和下拉电阻中间)之间形成了电势差,但是因为上拉电阻的存在,所以不会出现一个大电流。此时主控制器读取到的一个电平就是一个低电平。
在上拉输入的情况下,低电平的是能够非常明显的读取到的。
上拉输入的好处就是输入的电平不会上下浮动而导致输入信号不稳定,在没有信号输入的情况下可以稳定在高电平。
注意:上拉和下拉电阻电路的开关在实际应用中一般使用 MOS 管来代替开关来提到。
输入下拉
VDD 所在上拉电阻开关断开,下拉电阻的开关闭合。
此时 O 点(上拉电阻和下拉电阻中间)电平就是 VSS 的电平,此时读取到的电平就是低电平。此时输入的电平如果是一个低电平,就没有办法和之前的情况进行区分。但如果输入的是一个高电平,O 点(上拉电阻和下拉电阻中间)和 VSS 之间同样形成了电势差,O 点(上拉电阻和下拉电阻中间)的电平会变成外部的高电平,那么主控得到的就是一个高电平信号。
下拉输入的好处就是输入的电平不会上下浮动而导致输入信号不稳定,在没有信号输入的情况下可以稳定在低电平。
注意:上拉和下拉电阻电路的开关在实际应用中一般使用 MOS 管来代替开关来提到。
模拟输入
有时候我们需要用 AD 采集 IO 口上面的真实电压。这就有了我们所需要的模拟输入。为了让外部的电压真实的读取到单片机的 AD 模块,我们既不能闭合上拉和下拉的开关,也不能让信号经过施密特触发器。
开漏输出
在开漏输出中 P-MOS 不工作,这里我们只考虑 N-MOS。我们可以把这一个 MOS 管当成一个三极管,对于图中所示的这种三极管我们可以简单的理解成一个水龙头,左侧就是一个水龙头开关,当通过控制器给一个高电平的时候,信号经过输出控制电路会对该信号取反,既当控制器给出高电平时会输出低。此时 N-MOS 不工作,O 点(P-MOS 和 N-MOS 中间)和 VSS 就会导通。O 点(P-MOS和 N-MOS 中间)的输出就是一种反向器的输出,也就是 O 点(P-MOS 和 N-MOS 中间)的电平会和左侧 MOS 的栅极(三极管的基极)相反
所以说,开漏输出就很好理解了。当我们给一个高电平的时候,MOS 管关闭,此时输出的电压就是一个浮空,即不确定的电压。如果给一个低电平,那么 MOS 管导通,相当于 IO 口与 VSS 相连,此处就输出了一个低电平电压。
这样做有以下两个好处
一、虽然我们可以看到开漏输出是没有办法在内部输出一个高电平,但是这一个看似是缺点。其实实际上是一种优点。我们可以得到,当给一个高电平的时候,MOS 管没有导通,此时电压不确定导致无法输出高电平,但是一旦我们在外部增加一个上拉,那么这一个缺点就会被有效避免。并且,因为是我们自己设计一个上拉,这个上拉的电压是由我们自己确定,这样我们就可以根据外部电路需要多少 V 的高电平来给这一个上拉的电压
二、开漏输出的实质其实就是一个 OD 门(OD:漏极输出(Open Drain))。而在数电中,OD 门有一个非常重要的特性就是可以实现线与的功能,简单来说,就是在像 IIC 这样的总线协议中,只要有一个给低电平,那么总线都会被拉低。
推挽输出
推挽输出就是可以需要利用两个不同的 MOS 管来实现输出。
P-MOS 和 N-MOS 是不同的控制方式,当给一个高电平的时候经过输出控制电路后被转换为低电平,P-MOS 导通,N-MOS 不导通,此时 IO 口接通在 VDD,此时输出的是高电平。当给一个低电平的时候,则是 N-MOS 导通,P-MOS 不导通,此时 IO 口接通在 VSS 电源上面,此时输出的是高电平。使用 MOS 管的优势在于带载能力强。
推挽复用功能和开漏复用功能
复用推挽和复用开漏其实很简单,在你理解了开漏和推挽的原理之后,如果你不想用单片机内部来输出,那么你可以进行复用,将输出转移到其他外设上面
寄存器每个 I/O 端口位都是自由可编程的,然而 I/O 端口寄存器必须是以 32 位字、半字或字节的形式访问。GPIOx_BSRR 和 GPIOx_BRR 寄存器允许对任何 GPIOx_ODR 进行原子读/修改访问寄存器。这样,在读取和修改之间就没有发生 IRQ 的风险访问。
下面介绍在 GPIO 控制时常用的寄存器。
汇编控制点灯实验
实验目的
本示例将利用汇编语言控制 STM32MP157 开发板的三个 LED 发光二极管,使其有规律闪烁。通过本实例熟悉、掌握汇编语言的使用方法。
实验内容
本次实验以 PZ5 管脚所对应的 LED1 为例进行编程,由原理图可知 LED1 对应 D35,当 PZ5 为高电平时 D35 点亮,当 PZ5 为低电平时 D35 熄灭。
1.寄存器设置
查看原理图可得, LED1 对应可由 PZ5 引脚控制,为了实现控制 LED 灯的目的,首先使能对应 GPIO 时钟,需要通过配置 MODER 寄存器将对应的端口配置成输出模式,通过 OTYPER 设置输出类 型,然后可以通过 ODR 寄存器实现 LED 灯的点亮与熄灭。
2.程序编写
查看原理图可得, LED1 对应可由 PZ5 引脚控制,为了实现控制 LED 灯的目的,首先使能对应GPIO 时钟,需要通过配置 MODER 寄存器将对应的端口配置成输出模式,通过 OTYPER 设置输出类型,然后可以通过 ODR 寄存器实现 LED 灯的点亮与熄灭。
相关代码如下
示例代码 47-1 汇编 GPIO 控制代码
1 .equ MODER, 0x54004000
2 .equ OTYPER, MODER+0X04
3 .equ ODR, MODER+0X14
4
5 .text
6 .global _start
7 _start:
8 ldr r0,=MODER
9 mov r1,#0x0
10 str r1,[r0]
11
12 ldr r0,=MODER
13 mov r1,#(0x15 << 10)
14 str r1,[r0]
15
16 ldr r0,=OTYPER
17 mov r1,#0x0
18 str r1,[r0]
19
20 loop:
21 ldr r0,=ODR
22 mov r1,#(0x7 << 5)
23 str r1,[r0]
24 bl delay
25
26 ldr r0,=ODR
27 mov r1,#0x0
28 str r1,[r0]
29 bl delay
30
31 b loop
32
33 delay:
34 ldr r2,=50000000
35 del:
36 sub r2,r2,#1
37 nop
38 cmp r2,#0
39 bne del
40 mov pc, lr
41
42 stop:
43 b stop
44
45 .end
实验步骤
1、 导入工程源码
相关内容请参考导入一个已有工程章节导入已有工程。
光盘实验源码路径:【资料光盘\华清远见-FS-MP1A 开发资料-2020-11-06\02-程序源码\03-ARM 体系结构与接口技术\Cortex-A7\h_led】
2、 连接好开发板,打开调试工具,准备调试
具体方法可以参考 Eclipse Debug 调试章节,当程序正常运行时,可以发现 LED 灯有规律的闪烁
GPIO 控制点灯实验
本章节通过一个简单实例说明 STM32MP157 的 GPIO 接口的输出功能
实验目的
本示例将利用 STM32MP157 的 PZ5 这个 I/O 引脚控制开发板中 LED 发光二极管,使其有规律闪烁。
实验内容
关于 LED 灯的原理图可以参考汇编控制点灯实验章节。
程序编写
相关代码如下
示例代码 47-2 GPIO 控制主要代码
1 void mydelay_ms(int ms)
2 {
3 volatile int i = 0, j = 0 ;
4 while(ms--) {
5 for (i = 0; i < 1000; i++)
6 for (j = 0; j < 1000; j++);
7 }
8 }
9
10 int main()
11 {
12 GPIOZ->MODER = (GPIOZ->MODER &= ~(0x3 << 10)) | 0x1 << 10; //设置为输出模式
13 GPIOZ->OTYPER &= ~(0x1 << 5); //推娩输出
14
15 GPIOZ->OSPEEDR &= ~(0x3 << 10); //低速
16
17 while(1) {
18 GPIOZ->ODR = (GPIOZ->ODR &= ~(0x1 << 5)) | 0x1 << 5;
19 mydelay_ms(30);
20
21 GPIOZ->ODR &= ~(0x1 << 5);
22 mydelay_ms(30);
23 }
24
25 return 0;
26 }
实验步骤
1、 导入工程源码
相关内容请参考导入一个已有工程章节导入已有工程。
光盘实验源码路径:【资料光盘\华清远见-FS-MP1A 开发资料-2020-11-06\02-程序源码\03-ARM 体系结构与接口技术\Cortex-A7\c_led】
2、 连接好开发板,打开调试工具,准备调试
具体方法可以参考 Eclipse Debug 调试章节,当程序正常运行时,可以发现 LED 灯有规律的闪烁。
Cortex-A7 GPIO 按键编程
在本章实验中,同样对 GPIO 编程,测试 I/O 的输入功能,对于 GPIO 的有关描述不在赘述,本节以按键为例进行实验。
实验目的
本次实验以采集按键状态为例,轮询检测按键是否按下,以 LED 灯的亮灭进行检测。
实验内容
1.寄存器设置
查看原理图可得,STM32MP157 主板的按键对应 PA0 这个 I/O 引脚,需要通过配置 GPIOZ_MODER寄存器将 PA0 端口配置成输入模式,然后在 while 循环中通过 GPIOZ_IDR 轮询检测是否有输入值,另外可以参考 GPIO 控制点灯实验配置 LED 灯。
2.编码设置
相关代码如下
示例代码 47-3 轮询方式读取按键
1 void mydelay_ms(int ms)
2 {
3 volatile int i = 0, j = 0 ;
4 while(ms--)
5 {
6 for (i = 0; i < 1000; i++)
7 for (j = 0; j < 1000; j++);
8 }
9 }
10
11 int main()
12 {
13 GPIOZ->MODER = (GPIOZ->MODER &= ~(0x3 << 10)) | 0x1 << 10; //设置为输出模式
14 GPIOZ->OTYPER &= ~(0x1 << 5); //推娩输出
15
16 GPIOA->MODER &= ~(0x3 << 0); // 按键,输入模式
17
18 while(1)
19 {
20 while((GPIOA->IDR & 0x0001)); //判断是否按下
21 GPIOZ->ODR = (GPIOZ->ODR &= ~(0x1 << 5)) | 0x1 << 5;
22
23 mydelay_ms(10);
24 GPIOZ->ODR &= ~(0x1 << 5);
25 }
26 return 0;
27 }
实验步骤
1、 导入工程源码
相关内容请参考导入一个已有工程章节导入已有工程。
光盘实验源码路径:【资料光盘\华清远见-FS-MP1A 开发资料-2020-11-06\02-程序源码\03-ARM体系结构与接口技术\Cortex-A7\c_key】
2、 连接好开发板,打开调试工具,准备调试
具体方法可以参考 Eclipse Debug 调试章节,当程序正常运行时,可以发现当按键按下时,LED1灯点亮,当按键抬起,LED1 灯一直处于熄灭状态。