GPIO

2023-05-16

一、什么是GPIO?
 
    首先应该理解什么是GPIO。GPIO,英文全称为General-Purpose IO ports,也就是通用IO口。 在嵌入式系统中常常有数量众多,但是结构却比较简单的外部设备/电路,对这些设备/电路有的需要CPU为之提供控制手段有的则需要被CPU用作输入信号而且,许多这样的设备/电路只要求一位,即只要有开/关两种状态就够了,比如灯亮与灭。对这些设备/电路的控制,使用传统的串行口或并行口都不合适。所以在微控制器芯片上一般都会提供一个“通用可编程IO接口”,即GPIO。 接口至少有两个寄存器,即“通用IO控制寄存器”与“通用IO数据寄存器”数据寄存器的各位都直接引到芯片外部,而对数据寄存器中每一位的作用,即每一位的信号流通方向时输入还是输出,则可以通过控制寄存器中对应位独立的加以设置。这样,有无GPIO接口也就成为微控制器区别于微处理器的一个特征。
 
    在实际的MCU中,GPIO是有多种形式的。比如, 有的数据寄存器可以按照位寻址,有些却不能按照位寻址,这在编程时就要区分了。比如传统的8051系列,就区分成可位寻址和不可位寻址两种寄存器。另外,为了使用的方便,很多mcu把glue logic等集成到芯片内部,增强了系统的稳定性能, 比如GPIO接口除去两个标准寄存器必须具备外,还提供上拉寄存器,可以设置IO的输出模式是高阻,还是带上拉的电平输出,或者不带上拉的电平输出。这在电路设计中,外围电路就可以简化不少。
 
    明白了这个道理,不同的MCU,提供的GPIO口的数目不同,可选择的glue logic也不同。所以,在了解共性的基础上去了解个性。
 
    另外需要注意的是, 对于不同的计算机体系结构,设备可能是端口映射,也可能是内存映射的。如果系统结构支持独立的IO地址空间,并且是端口映射,就必须使用汇编语言完成实际对设备的控制,因为C语言并没有提供真正的“端口”的概念。如果是内存映射,那就方便的多了。举个例子,比如像寄存器A(地址假定为0x48000000)写入数据0x01,那么就可以这样设置了。
 

#define A (*(volatile unsigned long *)0x48000000)

...

    A = 0x01;

...

 
    这实际上就是内存映射机制的方便性了。其中volatile关键字是嵌入式系统开发的一个重要特点。这个就不再这里总结了。上述表达式拆开来分析,首先(volatile unsigned long *)0x48000000的意思是把0x48000000强制转换成volatile unsigned long类型的指针,暂记为p,那么就是#define A *p,即A为P指针指向位置的内容了。这里就是通过内存寻址访问到寄存器A,可以读/写操作。
我们在这里就来看看通常在嵌入式c编程中是如何来操作这些可内存寻址的寄存器:
#define CTL_REG_READ(addr)  (*(volatile unsigned long *)(addr))
#define CTL_REG_WRITE(addr, val) (*(volatile unsigned long *)(addr)=(var))
 
二、S3C2410的GPIO的特点
 
    首先看看introduction。
 

· 117-bit general purpose I/O ports / 24-ch external interrupt source

 
    可见,s3c2410的GPIO有117pin,下面应该到9 IO ports看看详细部分了。
 

The S3C2410X has 117 multi-functional input/output port pins. The ports are:
— Port A (GPA): 23-output port
— Port B (GPB): 11-input/output port
— Port C (GPC): 16-input/output port
— Port D (GPD): 16-input/output port
— Port E (GPE): 16-input/output port
— Port F (GPF): 8-input/output port
— Port G (GPG): 16-input/output port
— Port H (GPH): 11-input/output port

 
    这么多的IO口,相当于把117个io port划分为8个组,每个组也叫一个Port,每个Port控制相应数量个port,其实很多是复合功能的, 既可以作为普通的IO口使用,也可以作为特殊外设接口。在程序设计时, 要对整体的资源有所规划,初始化时就应该把所有资源安排合理。这样才会避免出现问题。当然,仅仅做一个最简单的led灯实验,倒是省去了很多步骤。
 
    现在的8个端口,针对于每个端口都存在上面提到的两个寄存器,其寄存器是相似的。除了两个通用寄存器 GPxCON、GPxDAT外,还提供了 GPxUP用于确定是否使用内部上拉电阻(其中x为A-H,需要注意的是没有GPAUP)。应用的主要步骤就是:
 
    · 设置GPIO控制寄存器GPxCON
    ·设置GPIO上拉寄存器GPxUP
 
    初始化完成后,就可以通过对GPxDAT的操作来实现相应的应用了。其中, PORT A与PORT B-H在功能选择方面有所不同GPACON的每一位对应一根引脚(共23pin有效)。当某位设为0,相应引脚为输出引脚,因为Port A控制的23个pin只能进行输出,所以也就没有输入的控制此时往GPADAT对应的位中写0/1,可以让引脚输出低电平/高电平当某位设为1,则相应引脚为地址线,或者用于地址控制,此时GPADAT没有用了。一般而言,GPACON通常全设为1,以便访问外部存储器件。PORT B-H在寄存器操作方面完全相同。 GPxCON中每两位控制一根引脚00表示输入,01表示输出,10表示特殊功能,11保留。GPxDAT用于读/写引脚: 当引脚设为输入时,读此寄存器可知相应引脚状态是高/低;当引脚设为输出时,写此寄存器相应位可以使相应引脚输出低电平或高电平。GPxUP:某位设为0,相应引脚无内部上拉;为1,相应引脚使用内部上拉。关于特殊功能,那就得结合特殊外设来进行设置了。
 
    这算是最简单的部分。完成一个led灯实验,可以用来做后续实验的调试手段。
 
基本实验一:LED灯循环点亮
 
    在EDUKIT-III实验箱上,有四个LED灯,与IO口的对应关系为GPF[7:4]----LED[4:1]。当IO引脚输出为低电平的时候,LED灯被点亮。只需要关注三个寄存器 GPFCONGPFDATGPFUP。由于硬件电路的关系,设置上拉电阻与否并不影响LED灯的点亮,所以GPFUP可以不必考虑。剩下的就是GPFCON和GPFDAT。
 
    我参考了《S3C2410完全开发》和vivi源代码,对前者的源代码进行了完善和修正,形成了两个版本。版本1是采用ARM汇编语言完成,版本2采用C语言完成。版本1练习了宏定义函数,子程序等,相对而言比较简单。版本2重点练习了软件架构,虽然短小,但是仍然模仿了vivi的软件架构。只是没有必要写复杂的Makefile,所以只写了比较简单的Makefile。在编写过程中,发现自己对ld,objcopy,和一些细节没有很好的把握,经过查看资料,已经基本掌握,后续工作需要就这些工具进行深入的学习,目标是能够熟练掌握。
 
ARM汇编版本:
@ register address
.equ WTCON, 0x53000000
.equ GPFCON, 0x56000050
@ offset value
.equ oGPFDAT, 0x04
@ macro defination LED_ON
@ you should initial IO pins about leds in order to use this macro
.macro LED_ON led_value //注意 在这里定义了一段宏,相当于函数,在下面可以直接通过宏名+参数值来调用该宏
 ldr r1, =/led_value
 str r1, [r0, #oGPFDAT] //将r1中的值赋给0x5300000054寄存器中,也就是GPFDAT寄存器
 bl delay //调用延时子程序
.endm
.text
.global _start @ specified by GNU ld. Here is
  @ ultimately 0x00000000,and you
  @ can fine this in Makefile.
_start:
 @ disable watch dog timer
 @ otherwise mcu will reset at fixed interval, and
 @ you will find led on and off in abnormal way.
 mov r0, #WTCON
 mov r1, #0x00
 str r1, [r0]
 @ initial IO pins: GPF[7:4]
 @ please read datasheet //开始初始化pin对应的Port控制寄存器和上拉寄存器
 ldr r0, =GPFCON
 ldr r1, =0x5500  //为什么要将GPFCON寄存器设置为0x5500就要一位位的来分析GPFCON寄存器,因为4个LED灯与IO口的对应关系为:GPF[7:4]----LED[4:1],我们知道在Port F中每两位来控制一个引脚,而且要将引脚设置为输出才能控制LED,所以GPF7也就是[15:14]=01,GPF6也就是[13:12]=01,同理GPF5也就是[11:10]=01,GPF4也就是[9:8]=01,所以GPFCON要被设置为0x5500
 str r1, [r0]
 @ start to light the leds
 @ led on when low voltage
1:  //循环的依次点亮4个LED灯,也就是依次将下面的值设置给GPFDAT寄存器,通过下面的0xd0,0x70,0xe0,0xb0可以知道在GPFDAT寄存器中的[7:4]来控制LED的亮灭。
 LED_ON 0xd0
 LED_ON 0x70
 LED_ON 0xe0
 LED_ON 0xb0
 
 b 1b
 @ meaningless but readable
stop:
 b stop
@
@ SUB Routine
@
@ not accurately, but good effect
delay:
 mov r2, #0x10000
2:
 subs r2, r2, #0x1
 bne 2b
 mov pc, lr
.end
    (1)我采用了延时子程序,但是上电复位后,WDT默认是打开的。所以在程序的开始要禁用WDT。
    (2)关于ARM的跳转指令B、BL、BX要区分开。B一般用于本段内的指令跳转,而BL用于子程序调用,BX用于ARM和THUMB状态的切换。特别地说,BL指令会将下一条指令的地址拷贝到LR中,然后跳转到指定的地址运行程序。所以,子程序调用的模型为:
    bl delay
    ...
 
delay:
    ...
    mov pc, lr
 
    明确了这两条,程序就不难理解了。源代码见上传的附件。
 
C语言版本:
 
    (1)软件架构仿照了vivi,也可以说是Linux Kernel。当然,仅仅写这么小的程序用不到这么麻烦,但是可以训练这种架构,为写中型大型程序打好基础。
    (2)注意C语言下实现寄存器读写的(*(volatile unsigned long *)(addr))。其实就是要掌握volatile和指针的用法,明白在嵌入式环境中,为什么要这样操作。
    (3)写c时,要注意头文件如何处理。写Makefile时,要注意是否采用隐含规则,如果不采用,就要自己定义明确规则,就像vivi里面的Rules.make。在这里,因为只是涉及到.s的编译不采用隐含规则,所以没有把Rules.make单独拿出,事实上可以单独写为Rules.make,然后在Makefile后加入include Rules.make就可以了。
    (4) 要调用C子程序,必须分配堆栈空间。因为子程序调用时,要进行入栈出栈处理。又因为从nand flash启动,而nand flash在S3C2410下的特点规定堆栈不能超过4K。
先来看看利用C语言时对寄存器的操作:
#define GPIO_CTL_BASE 0x56000000  //定义GPIO控制寄存器的起始地址也就是GPACON的地址
#define bGPIO(p, o) CTL_REG_READ(GPIO_CTL_BASE + (p) + (o))
/* offset */
#define oGPIO_CON 0x0
#define oGPIO_DAT 0x4
#define oGPIO_UP 0x8
 
#define oGPIO_F  0x50  //GPFCON寄存器相对应与GPADAT的偏移
/* registers */
#define GPFCON  bGPIO(oGPIO_F, oGPIO_CON)
#define GPFDAT  bGPIO(oGPIO_F, oGPIO_DAT)
#define GPFUP  bGPIO(oGPIO_F, oGPIO_UP)
然后来看看C代码:
#define DELAYTIME 0x5000
void delay(unsigned long n);
int main(void)
{
 unsigned char i;
 unsigned long led[4] = {0xd0, 0x70, 0xe0, 0xb0};
 GPFCON = vGPFCON; //同样vGPFCON已经初始化为0x00005500,将这个值赋值给GPFCON
 while (1) {
  for (i=0; i<4; i++) {
   GPFDAT = led[i];
   delay(DELAYTIME);
  }
 }
 return 0;
}
/* delay some time */
void delay(unsigned long n)
{
 while (n--) {
  ;
 }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

GPIO 的相关文章

  • xilinx ZYNQ 7000 AXI GPIO

    0AXI GPIO 第一部分 PS 和 PL之间的通讯有一个接口称为AXI AXI总线具体的内容这边不去深究 xff0c 可以理解为一种特殊协议的通讯方式 AXI GPIO是什么意思 xff1f PL是FPGA它可以做成任何你想要的东西 x
  • 树莓派GPIO控制

    树莓派GPIO 控制 陈拓 2018 06 09 2018 06 10 0 概述 本文介绍树莓派 Zero W的GPIO控制 xff0c 并用LED看效果 也适宜于树莓派3B 43 0 1 树莓派GPIO编号方式 功能物理引脚 从左到右 x
  • c语言 gpio指针定义,#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)这句话的具体作用是什么啊...

    一 GPIO Init函数解析 1 1 参数GPIO TypeDef 1 2 参数GPIO InitStruct 2 3 函数代码详解 4 4 备注 6 一 GPIO Init函数解析 首先来看一下GPIO Init函数的原型void GP
  • NVIDIA Jetson Xavier NX 控制GPIO

    NVIDIA Jetson Xavier NX 控制GPIO 文章目录 NVIDIA Jetson Xavier NX 控制GPIO前言一 简介二 代码实例1 gpio h2 gpio cpp 三 拓展 前言 在linux系统中以文件io的
  • stm32简介+gpio的C语言封装

  • jetson nano GPIO控制说明

    文章目录 一 GPIO介绍二 安装GPIO库python库C 43 43 库 三 几种常用的通信协议UARTPWMI2CI2SSPI 四 控制函数说明python xff08 参考 https pypi org project Jetson
  • Arduino通过继电器控制电机(5V小马达)ESP8266-12F同理(小白初学)

    用Arduino ESP8266 12F控制电机 一 实验环境 IDE Arduino 材料 Arduino UNO ESP82266 12F 4 5V电池盒子 继电器 6脚 5V电机一个 5V小马达 面包板 杜邦线若干 二 接法 参照37
  • 关于stm32的GPIO的操作

    首先先了解一下输出的模式 比较常用的是 推挽输出 1 GPIO Mode AIN 模拟输入 2 GPIO Mode IN FLOATING 浮空输入 3 GPIO Mode IPD 下拉输入 4 GPIO Mode IPU 上拉输入 5 G
  • Linux的GPIO子系统解析 ( 一 ) 之 gpiolib.c

    文章目录 Linux的GPIO子系统解析 一 之 gpiolib c 绪论 关于GPIO子系统库文件的gpiolib c解析 drivers gpio gpiolib c gpio desc结构体 gpio chip结构体 gpio ens
  • 【树莓派】error: command ‘/usr/bin/arm-linux-gnueabihf-gcc‘ failed with exit code 1(已解决)

    输入以下命令 export CFLAGS fcommon pip3 install RPi GPIO 参考网址 https askubuntu com questions 1290037 error while installing rpi
  • 使用HAL库开发STM32:GPIO口基础使用与外部中断

    文章目录 目的 GPIO口基础使用 基础说明 初始化设置 输出与控制 读取端口值 GPIO口与外部中断 总结 目的 对于MCU来说GPIO口的使用是最基础的内容 仅使用GPIO口和延时等 就可以完成很多功能了 GPIO口基础使用 基础说明
  • RK3568-GPIO控制

    RK3568 GPIO控制 1 Sysfs接口 实现逻辑 芯片的GPIO由芯片的GPIO控制器来管理 GPIO控制器封装在芯片内部 控制器的驱动芯片厂家已经写好了 RK3568有五组GPIO控制器 每组管理32个引脚 对应 dev下的gpi
  • ESP32引脚参考

    原文链接 ESP32引脚参考 您应该使用哪个GPIO引脚 360doc个人图书馆 总结的相当全面 ESP32简单易懂的GPIO使用注意事项 首先上图 GPIO建议列表 特别的在硬件上要注意使用外接模块时不能将GPIO12拉高 否则将导致ES
  • ESP32C3解锁使用IO11

    目录 1 使用pip安装esptool 2 安装idf开发命令行环境 可参考 3 将开发板插入电脑 4 打开IDF CMD命令行 5 打开命令行窗口 源自官方wiki 本篇介绍如何给ESP32C3多释放一个io ESP32C3的GPIO11
  • Raspberry Pi 上 ROS 服务器/客户端通过GPIO 驱动硬件

    ROS 服务 现在 想象一下你在你的电脑后面 你想从这个服务中获取天气 你 在你身边 被认为是客户端 在线天气服务是服务器 您将能够通过带有 URL 的 HTTP 请求访问服务器 将 HTTP URL 视为 ROS 服务 首先 您的计算机将
  • 如何在Python中运行后一段时间内禁用Raspberry Pi GPIO事件?

    每当我的 Raspberry Pi 的 GPIO 引脚出现下降沿时 我就会创建一个事件 但是 我想在每次运行后禁用此事件一段时间 例如 5 秒 我希望在该时间段之后再次启用该事件 我的第一个想法就是使用sleep 5 在实际的事件函数中 但
  • 使用多个线程多次调用一个方法

    我想要一个 LED 闪烁 同时我的 Raspberry 上正在做一些工作 我在 Python 脚本中使用 LED 线程 初始代码 import RPi GPIO import time import threading pinLED 10
  • mmap 比 ioremap 慢

    我正在为运行 Linux 2 6 37 的 ARM 设备进行开发 我正在尝试尽快切换 IO 引脚 我制作了一个小内核模块和一个用户空间应用程序 我尝试了两件事 使用以下命令直接从内核空间操作 GPIO 控制寄存器ioremap mmap G
  • Sphinx:如何排除自动模块中的导入?

    我有一个用 Python 编写的 Raspberry Pi 项目 它使用 RPi GPIO 模块 代码上的所有工作都是在 Windows 机器上完成的 其中 RPi GPIO 不会安装 每次我尝试运行 autodoc 时 它都会崩溃 说它无
  • Beaglebone GPIO 输入不起作用

    我正在使用 beaglebone 通过 sysfs 接口访问特定引脚的数字输入 我可以更改输出状态 但不能更改输入 我所做的是 我有两个引脚 pinA 和 pinB pinA 我将其输出 pinB 我将其输入 将 pinA 连接到 pinB

随机推荐

  • opencv小程序练习——createBackgroundSubtractorMOG2()实现跟踪

    思想 xff1a 使用createBackgroundSubtractorMOG2 使用运动物体背景分割 使用findContours 查找轮廓并画出 实现一定感官上的跟踪功能 代码如下 xff1a include lt opencv2 o
  • opencv_tutorial_code学习——canny边缘检测后findContours

    tutorial code ShapeDescriptors findContours demo cpp 步骤 xff1a 1 灰度化 2 滤波 3 canny边缘检测 4 findContours canny output contour
  • idea开发工具右侧没有maven工具栏

    一 解决方式一 依次点击 View gt Tool Windows gt Maven xff0c 如下图 xff1a 二 解决方式二 点击如图所示IDEA界面最左下角的按钮 xff0c 如下图 xff1a 三 解决方式三 1 打开项目的 p
  • 语义分割与实例分割的区别

    目前的分割任务主要有两种 xff1a xff08 1 xff09 像素级别的语义分割 xff08 2 xff09 实例分割 这个有意思 xff0c 什么叫实例分割呢 xff1f 它与语义分割有什么区别与联系呢 xff1f 顾名思义 xff0
  • tiny-dnn配置运行

    tiny dnn是一个轻量级的CNN xff08 卷积神经网络 xff09 xff0c 不需要各种依赖和GPU xff0c 由三千多行C 43 43 代码完成 适配android平台的话 xff0c 感觉这个比较好做一点 下载地址 xff1
  • SSM笔记

    进入数据库 xff1a 34 D Program Files x86 mysql 5 7 20 winx64 bin mysql exe 34 u root p admin 展示数据库 xff1a show databases 创建数据库
  • 工程编译那点事:Makefile和cmake(一)

    makefile 前言Makefile介绍 Makefile规则make是如何工作的Makefile使用变量让make自动推导另类风格的Makefilemake中的函数文件搜索绝对顶级的大型工程Makefile 前言 一个项目 xff0c
  • 头文件相互包含问题

    先来看看以下这个例子 xff1a Keyboard h的代码为 span class token macro property span class token directive hash span span class token di
  • 解决roslaunch启动stage_ros节点仿真时输出rostopic hz速率较低的问题(始终为10Hz)

    问题描述 xff1a 在实验过程中偶然间发现无论是odom还是laser scan的输出频率都只有10Hz clock输出速率有50Hz 直接使用命令 rosrun stage ros stageros test world能够正常输出50
  • STM32八种IO口模式区别

    xff08 1 xff09 GPIO Mode AIN 模拟输入 xff08 2 xff09 GPIO Mode IN FLOATING 浮空输入 xff08 3 xff09 GPIO Mode IPD 下拉输入 xff08 4 xff09
  • linux下C++实现Http请求类(GET,POST,上传,下载)

    linux下C 43 43 实现Http请求类 GET xff0c POST xff0c 上传 xff0c 下载 Http协议简述 协议 xff1a 网络协议的简称 xff0c 网络协议是通信计算机双方必须共同遵从的一组约定 如怎么样建立连
  • 正点原子MiniFly V1.2学习笔记四---txQueue队列数据哪来

    笔记二的第四点中 xff0c 把解包出来的指令发送到 rxQueue队列里 xff0c 然后从txQueue队列取数据发送到串口 那么txQueue队列的数据从哪里来的 一 txQueue数据从哪里来 xff1f 二 什么地方会调用radi
  • redis链接工具

    redis链接工具 今天推荐一款redis链接工具 xff0c 其实世面上连接redis的工具很多 xff0c 但是好用的很少 例如 xff1a redis desktop manager这款工具也不错 xff0c 但是我个人不能使用 xf
  • Linux 网络编程——UDP编程

    一 概述 UDP 是 User Datagram Protocol 的简称 xff0c 中文名是用户数据报协议 xff0c 是一个简单的面向数据报的运输层协议 xff0c 在网络中用于处理数据包 xff0c 是一种无连接的协议 UDP 不提
  • 给指定的寄存器地址:0x0001eea7 ,赋值

    coretexM0平台上给指定的寄存器地址 xff1a 0x0001eea7 赋值100 怎么实现 xff1f xff08 volatile char xff09 0x0001eea7 61 100 xff1b 常见错误1 xff1a xf
  • 常见cmake命令总结

    常见cmake命令总结 cmake常见命令 cmake minimum required 指定CMake的最小版本要求 cmake minimum required VERSION 2 8 project 定义工程名称 project PR
  • 利用Qt Phonon框架制作音视频播放器

    Phonon严格来说其实非为Qt的library xff0c Phonon原本就是KDE 4的开放源代码多媒体API xff0c 後来与Qt合并与开发 xff0c 所以简单来说就是Qt使用Phonon这个多媒体框架来提供一般影音多媒体档案的
  • 主设备号和次设备号

    Linux的设备管理是和文件系统紧密结合的 xff0c 各种设备都以文件的形式存放在 dev目录下 xff0c 称为设备文件 应用程序可以打开 关闭和读写这些设备文件 xff0c 完成对设备的操作 xff0c 就像操作普通的数据文件一样 为
  • Makefile中的wildcard用法

    在Makefile规则中 xff0c 通配符会被自动展开 但在变量的定义和函数引用时 xff0c 通配符将失效 这种情况下如果需要通配符有效 xff0c 就需要使用函数 wildcard xff0c 它的用法是 xff1a wildcard
  • GPIO

    一 什么是GPIO xff1f 首先应该理解什么是GPIO GPIO xff0c 英文全称为General Purpose IO ports xff0c 也就是通用IO口 在嵌入式系统中常常有数量众多 xff0c 但是结构却比较简单的外部设