驱动库解读过程中遇到的问题

1、为什么对设备地址或寄存器地址的宏定义都要在后面加上U?

比如在LSM9DS1的驱动库头文件中,对IMU的I2C设备地址的定义如下:

#define LSM9DS1_IMU_I2C_ADD_L    0xD5U    //SA0 = 0
#define LSM9DS1_IMU_I2C_ADD_H    0xD7U    //SA0 = 1

 起初我对这个U很好奇,然后我搜了一下,收获还是挺多的(不过大部分都会触及汇编知识,此处并没有涉及,只做了最粗浅的理解):

  1. 0x规定了这个地址是以一个16进制整型数据进行储存的,每一个数据占用四bit的内存单元,我们定义几位数据就会占用几个四bit内存单元,确保内存不会被浪费(比如0x00占用1字节内存,而0会被识别成int类型,在不同的编译器上会占用4到8字节)
  2. U规定了这个数据是一个无符号类型,我的理解是无符号类型的整数所有位都可以用来存放数据,比如8位的无符号类型数据的取值范围为0~255,而有符号类型在进行数据转换时会将最高位作为符号位,1为负,0为正,如8位有符号类型数据的取值范围为-128~127

为什么我们编写C代码是,为一个变量赋值一般没有加U的习惯呢,因为这个数据的类型是可以省略的,而编译器在编译过程中则会按其默认的规定类型(一般是有符号型)将其转化为计算机可以读懂的二进制形式,但毕竟每个编译器的编译规则不同,为了保证在不同平台都LSM9DS1_IMU_ I2C_ADD_L都可以表示为无符号类型的0xD5,因此ST在编写该文件时对其进行了类型约束。

2、Two's complement是什么?

wiki:二进制补码(Two's complement)是一种数学运算,用于可逆地将正二进制数转换为具有等效(但为负)值的负二进制数,使用具有最大位置值的二进制数字(大数中最左边的位,小端数中最右边的位)来指示二进制数是正数还是负数(符号)

在LSM9DS1手册中的提到的什么存储输出数据的寄存器都是以这种格式存储的,如:LSM9DS1_OUT_TEMP_L,LSM9DS1_OUT_X_L_G等都是16位的寄存器,其运算方式便是使用了上述的二进制补码方式,来保证IMU采集到的数据有正负之分来区分不同的方向。

3、寄存器地址自动递增功能

在阅读手册时遇到了一个寄存器位是IF_ADD_INC,我找到了相应位的解释,但不太明白什么意思

其大意便是在进行串行通信时,当访问寄存器的数据高于原本的寄存器字节数时,寄存器地址会自动的增加,来保证容纳下所有进行访问的数据字节。

 在阅读驱动库的程序时,我终于知道这样做的意义了

 我们可以看到上述程序中,会从LSM9DS1_OUT_X_L_M寄存器中读取6字节的数据,但查阅手册你会发现LSM9DS1_OUT_X_L_M寄存器大小仅为1字节,如果我们使能了上述的寄存器地址递增功能,在读取完LSM9DS1_OUT_X_L_M寄存器中的数据后会继续向更高的寄存器地址读取数据,直到读取完6字节数据。

我们再看排在LSM9DS1_OUT_X_L_M寄存器地址之上的寄存器,其地址分布情况如下

 这样我们如果需要读取6个字节的数据,就可以从X轴低位开始一次性将磁力计记录的X,Y,Z轴的数据全部读取出来,并且按照上面程序的存储方式,将磁力计记录的X,Y,Z轴的数据存储到val数组中

4、小端对齐和大端对齐对寄存器数据存储的影响

我们知道计算机中只要是数据就需要空间去存储,存储时所需的空间大小与数据的类型有关,并且数据在计算机中是以二进制的形式存储的,每个整数都有有三种二进制表示方法:

  • 原码:直接将整型数据按照正负数的形式翻译成二进制数据
  • 反码:根据数据的原码形式,符号位不变,数据位全部取反
  • 补码:反码+1

计算机中存储的数据都是以该数据的二进制补码的形式存储的,为什么呢,简单点说我们可以发现上述三种格式的介绍是,只有补码是可以在其他两种格式的基础上直接参与运算的,这一特点对计算机来说非常重要。

那这种形式的数据又是怎么放入内存中的呢,通常来说一字节需要占据一个内存单元,每个内存单元都有一个对应的地址,这个地址就像是这块内存单元的门牌号,我们顺着门牌号就可以找到这个这个内存单元,而这个内存单元里住的就是我们具体的一字节的数据。换句话说每个字节都唯一对应着一个内存地址,这个内存地址会帮助我们访问到对应的数据。但是对于高位的计算机而言,很多时候我们存入的数据都不止一个字节,这不可避免的会涉及到每一字节的数据存储顺序的问题。

比如:0x11223344,这是一个四字节数据,其中0x11是数据的最高位,0x44是数据的最低位,

那么这四个字节的数据在存入内存中时,由应该怎么排放呢?

假设我们的计算机为这四字节的数据开辟了四个内存单元,其地址分别是0x0001,0x0002,0x0003,0x0004,我们总要按一定顺序将数据一一存入这个地址对应的内存单元总,这便涉及到了我们内存存储模式的知识。

在计算机中数据存储是有两种模式的,一种是大端对齐,另一种是小端对齐。

  • 大端对齐:又称高尾端存储,是将数据的最低位存放在内存的高地址中。
  • 小端对齐:又称低尾端存储,是将数据的最低位存放在内存的低地址中。

在思考这个过程是,我们可以先假定在C编程中数据类型的存储是从内存的低地址位向高地址位扩展,在进行取值运算&时,每次取到的都是最低地址位,那么这样来看,若最低位0x44存入最低地址位0x0001的内存单元中,其他高位字节按照位次依次向高地址端存储,在取地址访问数据时最先取到的是数据的最低位,则为小端对齐;若最低端0x44存入地址的最大位0x0004的内存单元中,其他高位字节按照位次依次向低地址端存储,在取地址访问数据时最先取到的是数据的最高位,则为大端对齐。

但是这和寄存器的数据存储有什么关系呢?有关系但关系不大,如果一个2字节大小的寄存器存放着我们想要的数据,但是我们只想取数据的低字节,那么我们就必须要知道这两字节数据数据在寄存器中的储存模式,否则就可以取出错误的数据。

除此之外,对于一个字节的数据而言,其内部的数据位的存储顺序在我们操作寄存器时也显得十分重要,由于我们在编写设备的寄存器库时要对每一个寄存器中的每一位数据对进行定义,对此我们也可以人为的定义单字节中数据为的对齐方式。

如下所示:我们在定义寄存器信息时人为的定义了每个字节中各数据位的排列顺序,这样在我们调用某一寄存器中的某一寄存位的数据时,就可以清楚的知道字节的低位是与寄存器的低位相对应,还是与寄存器的高位相对应。(图中bit0为字节的二进制低位,其存在结构体前面代表结构体的低位,结构体是定义了寄存器的存储空间,也即寄存器的数据低位)

如果你看上图很懵的话,那大概是因为结构体知识不太牢固(其实是汇编知识,不知道也无伤大雅,只是在阅读寄存器底层书写时才会遇到),我们可以看到上图中结构体的成员为8个UINT8_t类型的成员变量,每个成员变量都占据一个字节,但是我们每个成员变量中只需要存储一位的数据信息,用不了一字节(8位),于是我们对其添加了位域限制,这样每个成员变量就只占用几位数据了,可以大大节省存储空间。

5、Burst传输

burst传输被翻译过来是突然传输的意思,其实可以简单理解为连续传输的意思。是指在同一行中相邻的存储单元连续进行数据传输的方式,只要指定起始地址突发长度(Burst lengths,可以理解为跨度),控制器就会依次自动对后面相同数量的存储单元进行读/写操作,而不需要控制器连续提供列地址。

上面介绍的寄存器地址递增功能便是实现这种传输的基础。

Burst其实是内存相关的知识,常见的SRAM,DDR就是,是作为芯片中存储数据的重要部分,当CPU要访问读某个存储单元时,必须首先给出地址,送入存储器的地址寄存器,然后经译码电路选取相应的存储单元,从存储单元读出的信息要先送入存储器的数据寄存器,在传送给目的部件。如果是写操作,同样是要先把数据放入数据寄存器,在根据给定的地址,写入存储单元中去。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值