树莓派高级开发——“IO口驱动代码的编写“ 包含总线地址、物理/虚拟地址、BCM2835芯片手册知识

本文详细介绍了树莓派的GPIO驱动开发,涉及微机总线地址、物理地址与虚拟地址的区别,以及BCM2835芯片手册中的GPIO寄存器配置。通过ioremap和iounmap函数实现IO口的驱动代码,讲解了如何将物理地址映射到虚拟地址并配置GPIO引脚为输出。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

微机总线地址

地址总线:

  • 百度百科解释: 地址总线 (Address Bus;又称:位址总线) 属于一种电脑总线 (一部份),是由CPU 或有DMA 能力的单元,用来沟通这些单元想要存取(读取/写入)电脑内存元件/地方的实体位址。
  • 地址总线 = cpu能够访问内存的范围
    用一个现象来解释地址总线:
    装了32位的win7系统,明明内存条8G,可是系统只识别了3.8G,装了64位,才能识别到8G。
    32位能表示/访问 4,294,967,296 bit
kbit——mbit——gbit 差1024
bit 4,294,967,296
kbit 4,194,304 K
mbit 4,096 M
gbit 4 G
  • 地址总线 = CPU寻找外部的内存单元靠的是地址总线传输的数据
    如果CPU有8根地址总线,每根线上传输0或1,那么传输的数据范围为00000000~ 11111111,每一个数值都对应内存中的一个内存单元,所以可以找到编号为00000000~ 11111111号的内存单元。如果传输的数据为00110011,那么就会找到00110011号内存单元,如果传输的数据为10110111,那么就会找到10110111号内存单元。编号不在[00000000,11111111]范围内的CPU就寻找不到,例如100000000号内存单元,CPU就寻找不到。寻址能力就是计算CPU能寻找多少个内存单元00000000~11111111号内存单元,一共有256个,一个内存单元的大小为1byte,这256个内存单元的大小为256byte
  • CPU通过地址总线来指定存储单元的。
  • 地址总线决定了cpu所能访问的最大内存空间的大小
    eg: 10根地址线访问的最大的内存为1024(2的10次方)位二进制数据(1B)
  • 地址总线是地址线数量之和。若CPU的地址总线宽度是32位,那么CPU的寻址范围是4G(2的32次方位),所以最多支持4G内存.
  • 比如上面我们说的那个现象:装了32位的win7系统,明明内存条8G,可系统只是别了3.8G
    ,装了64位才能识别到8G。装了32位的操作系统CPU的访问范围是2^32bit,就是4194304kbit,就是4096Mbit,等于4G。树莓派也是32位 ,一个G的内存,但它只能访问949M剩下的挪作他用。

数据总线:

  • CPU通过地址总线寻址,然后通过数据总线与外部设备互换信息。
  • 是CPU与内存或其他器件之间的数据传送的通道。
  • 数据总线的宽度决定了CPU和外界的数据传送速度。
  • 每条传输线一次只能传输1位二进制数据。eg: 8根数据线一次可传送一个8位二进制数据(即一个字节)。
  • 数据总线是数据线数量之和,数据总线的位数决定CPU单次通信能交换的信息数量。

数据总线的宽度对CPU的性能的影响:

  • 首先,总线的速度(即:CPU的主频,CPU的性能指标之一)决定CPU和外设互换信息的速度。
  • 其次,数据总线的宽度也是表示CPU性能的参数之一(通常,我们说“64位的CPU”是指CPU的数据总线的宽度是64位)。
    如:64位数据总线的CPU一次就能取出64bit的数据,8位数据总线的CPU一次只能取出8bit的数据,在相同频率的情况下,8位数据总线的CPU就得连续取8次数据,数据量才能和64位数据总线一次取出的数据量相同,单就比较取数据的性能就相差8倍。况且,通常CPU中的寄存器的位数与数据总线的宽度一样,所以在数据处理方面,64位的CPU又比8位的CPU快很多。
  • CPU的地址总线位数和数据总线可以不同(典型代表就是51单片机),但是一般都相同。16位机有16根数据总线,20根地址总线,能访问1M(2的20次方),32位机有32根数据总线,32根地址总线,能访问4G(2的32次方),64位机确实有64根数据总线。

物理地址(PA)

  • 百度百科解释:
    网卡物理地址存储器中存储单元对应实际地址称物理地址,与逻辑地址相对应。网卡的物理地址通常是由网卡生产厂家写入网卡的EPROM(一种闪存芯片,通常可以通过程序擦写),它存储的是传输数据时真正赖以标识发出数据的电脑和接收数据的主机的地址

  • 这里说的 物理地址是内存中的内存单元实际地址,不是外部总线连接的其他电子元件的地址!物理地址属于比较好理解的,物理地址就是内存中每个内存单元的编号,这个编号是顺序排好的,物理地址的大小决定了内存中有多少个内存单元,物理地址的大小由地址总线的位宽决定!
    物理地址是硬件实际地址或绝对地址

虚拟地址(VA)

  • 虚拟地址是Windows程序时运行在386保护模式下,这样程序访问存储器所使用的逻辑地址(基于算法的地址[软件层面的地址:假地址])称为虚拟地址,与实地址模式下的分段地址类似,虚拟地址也可以写为“段:偏移量”的形式,这里的段是指段选择器。而linux没有各种保护模式,本来用的就是虚拟地址。
  • 虚拟地址是CPU保护模式下的一个概念,保护模式是80286系列和之后的x86兼容CPU操作模式,在CPU引导完操作系统内核后,操作系统内核会进入一种CPU保护模式,也叫虚拟内存管理,在这之后的程序在运行时都处于虚拟内存当中,虚拟内存里的所有地址都是不直接的,所以你有时候可以看到一个虚拟地址对应不同的物理地址,比如A进程里的call函数入口虚拟地址是0x001,而B也是,但是它俩对应的物理地址却是不同的,操作系统采用这种内存管理方法。
  • 是防止程序对物理地址写数据造成一些不可必要的问题,比如知道了A进程的物理地址,那么向这个地址写入数据就会造成A进程出现问题,在虚拟内存中运行程序永远不知道自己处于内存中那一段的物理地址上!现在操作系统运行在保护模式下即便知道其他进程的物理地址也不允许向其写入!但是可以通过操作系统留下的后门函数获取该进程上的虚拟地址空间所有控制权限并写入指定数据。
  • 虚拟内存管理采用一种拆东墙补西墙的形式,所以虚拟内存的内存会比物理内存要大许多。在进入虚拟模式之前CPU以及Bootloader(BootLoader是在操作系统内核运行之前运行。可以初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境),操作系统内核均运行在实模式下,直接对物理地址进行操作!虚拟内存中也有分页管理,这种管理方法是为了确保内存中不会出现内存碎片,当操作系统内核初始化完毕内存中的分页表后CPU的分页标志位会被设置,这个分页标志位是给MMU看的!
  • MMU是Memory Management Unit的缩写,中文名是内存管理单元,它是中央处理器(CPU)中用来管理虚拟存储器、物理存储器的控制线路,同时也负责虚拟地址映射为物理地址,以及提供硬件机制的内存访问授权,多用户多进程操作系统。作用有两点,地址翻译和内存保护。MMU将虚拟地址翻译为物理地址。

有关各种地址介绍的博文:

物理地址、虚拟地址、总线地址
物理地址和总线地址区别

页表(MMU的单元)

分页管理:
在这里插入图片描述

  • 内存分页其实就是我们所说的4G空间,内存的所有内存被操作系统内核以4G为每页划分开,当我们程序运行时会被加载到内存中的4G空间里,其实说是有4G其实并没有真正在的4G空间,4G空间中有一小部分被映射到了物理内存中,或者被映射到了硬盘的文件上(fopen),或者没有被映射,还有一部分在内存当中就会被划分栈,堆,其中有大片大片的内存是没有被映射的,同样物理内存也是被分页了用来与虚拟内存产生映射关系。将虚拟地址映射为物理地址有一个算法(页表)决定了将虚拟地址映射到物理地址的哪个位置,页表是通过MMU(分页内存管理单元)来管理的,就是设计完页表后通过MMU来执行将虚拟地址映射为物理地址。
  • 其实真正情况下只有3G用户空间,假如你的内存是4G的那么其中有1G是给操作系统内核使用的,所谓的4G空间只是操作系统基于虚拟内存这种拆东墙补西墙的形式给你一种感觉每个进程都有4G的可用空间一样!这里来说一下拆东墙补西墙,当我们程序被加载进4G空间时其实根本用不了所谓的4G空间,其中有大片内存被闲置,那么这个时候呢,其他程序被加载进来时发现内存不够了,就把其他程序里的4G空间里闲置部分拿出来给这个进程用,换之这个进程内存不够时就会把其他进程里闲置的空间拿过来给该进程使用。银行也是如此!
  • 当我们要对物理地址做操作时比如if语句要根据CPU的状态标志寄存器来做不同的跳转,那么这个时候就要对CPU额状态寄存器做操作了就必须知道它的物理地址,内存中有一个电子元件叫MMU负责从操作系统已经初始化好的内存映射表里查询与虚拟地址对应的物理地址并转换,比如mov
    0x4h8这个是虚拟地址,当我们要对这个虚拟地址里写数据时那么MMU会先判断CPU的分页状态寄存器里的标志状态是否被设定,如果被设定那么MMU就会捕获这个虚拟地址物理并在操作系统内核初始化好的内存映射表里查询与之对应的物理地址,并将其转换成真正的实际物理地址,然后在对这个实际的物理地址给CPU,在由CPU去执行对应的命令,相反CPU往内存里读数据时比如A进程要读取内存中某个虚拟地址的数据,A进程里的指令给的是虚拟地址,MMU首先会检查CPU的分页状态寄存器标志位是否被设置,如果被设置MMU会捕获这个虚拟地址并将其转换成相应的物理地址然后提交给CPU,在由CPU到内存中去取数据!

更详细的地址问题看这里

BCM2835芯片手册

下面截取树莓派芯片手册的一张图:
在这里插入图片描述
BCM2835是树莓派3B CPU的型号,是ARM-cotexA53架构cpu Bus是地址总线00000000~FFFFFFFFCPU寻址的范围(4G)DMA是高速拷贝单元,CPU可以发动DMA直接让DMA进行数据拷贝,直接内存访问单元。物理地址(PA)1G虚拟地址(VA)4G
若程序大于物理地址1G,是不是就跑不了了,不是的,它有个MMU的单元,把物理地址映射成虚拟地址,我们操作的代码基本上都是在虚拟地址,它有一个映射页表(上面提及到过)

  • 通过芯片手册了解树莓派的GPIO:有54条通用I/O GPIO行,分为两行,备用功能通常是外围IO并且可以在每个银行中出现一个外围设备,以允许灵活地选择IO电压。
    在这里插入图片描述

  • GPIO有41个寄存器,所有访问都是32位的。

  • Description是寄存器的功能描述。
    GPFSEL0(寄存器名)
    GPIO Function Select 0(功能选择:输入或输出);
    GPSET0 (寄存器名)
    GPIO Pin Output Set 0(将IO口置0);
    GPSET1(寄存器名)
    GPIO Pin Output Set 1(将IO口置1);
    GPCLR0(寄存器名)
    GPIO Pin Output Clear 0 (清0)下图的地址是:总线地址(并不是真正的物理地址)
    在这里插入图片描述

  • FSELn表示GPIOn,
    在这里插入图片描述
    下图给出第九个引脚的功能选择示例,对寄存器的29-27进行配置,进而设置相应的功能。
    根据图片下方的register 0表示0~9使用的是register 0这个寄存器。
    在这里插入图片描述

  • 输出集寄存器用于设置GPIO管脚。SET{n}字段定义,分别对GPIO引脚进行设置,将“0”写入字段没有作用。如果GPIO管脚为在输入(默认情况下)中使用,那么SET{n}字段中的值将被忽略。然而,如果引脚随后被定义为输出,那么位将被设置根据上次的设置/清除操作。分离集和明确功能取消对读-修改-写操作的需要。GPSETn寄存器为了使IO口设置为1,set4位设置第四个引脚,也就是寄存器的第四位。
    在这里插入图片描述

  • 输出清除寄存器用于清除GPIO管脚。CLR{n}字段定义要清除各自的GPIO引脚,向字段写入“0”没有作用。如果的在输入(默认),然后在CLR{n}字段的值是忽略了。然而,如果引脚随后被定义为输出,那么位将被定义为输出根据上次的设置/清除操作进行设置。分隔集与清函数消除了读-修改-写操作的需要。GPCLRn是清零功能寄存器。
    在这里插入图片描述

配置树莓派的pin4引脚为输出引脚:

功能选择 输出/输入(GPIO Function Select Registers)3214-12    001    =   GPIO Pin4 is an output

只需要将GPFSL0这个寄存器的14~12位设置为001就可以了。只需要将0x6(对应的2进制是110)左移12位·然后取反再与上GPFSL0就可以将13、14这两位配置为0,然后再将0x6(对应2进制110)左移12位,然后或上GPFSL0即可将12位置1。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值