SPI(Serial Peripheral Interface)接口是全双工的同步串行通讯总线,支持通过多个不同的片选信号来连接多个外设。SPI接口通常由四根线组成,分别是提供时钟的SCLK,提供数据输出的MOSI,提供数据输入的MISO和提供片选信号的CS。同一时刻只能有一个SPI设备处于工作状态。为了适配不同的外设 ,SPI支持通过寄存器来配置片选信号和时钟信号的极性和相位。(imx6ull支持ecspi,即增强配置型spi,这里为了与其他兼容,统一用spi来称呼)。
SPI支持slave和master两种模式,作为APU来说,多数情况下是作为master来使用的。在master模式下,通过不同的片选引脚ssn来连接多个不同的设备。下图为MASTER模式下的SPI单线通讯模式框图,只对设备进行写操作。
在master模式下,ss、sclk和mosi作为信号输出接口,MISO作为信号输入接口。通过SS片选信号使能外部SPI设备,SCLK同步数据传输。MOSI和MISO信号在SCLK上升沿变化,在下降沿锁存数据。SPI的具体通讯格式如下图所示(默认高位在前,低位在后),输出数据为0xD2,输入数据为0x66。
SPI支持不同的SPI时钟和CS片选相位和极性设置,通过设置POL和PHA值的不同来设置相对相位和极性。POL:表示SPICLK的初始电平,0为电平,1为高电平 ;CHA:表示相位,即第一个还是第二个时钟沿采样数据,0为第一个时钟沿,1为第二个时钟沿。具体如下表所示:
POL | PHA | 模式 | 含义 |
---|---|---|---|
0 | 0 | 0 | 初始电平为低电平,在第一个时钟沿采样数据 |
0 | 1 | 1 | 初始电平为低电平,在第二个时钟沿采样数据 |
1 | 0 | 2 | 初始电平为高电平,在第一个时钟沿采样数据 |
1 | 1 | 3 | 初始电平为高电平,在第二个时钟沿采样数据 |
实际时钟和相位关系如下图所示,我们常用的是模式0和模式3,因为它们都是在上升沿采样数据,不用去在乎时钟的初始电平是什么,只要在上升沿采集数据就行。极性选什么?格式选什么?通常去参考外接的模块的芯片手册。
IMX6ULL的SPI控制器ECSPI(Enhanced Configurable Serial Peripheral Interface) 为全双工同步四线串行通讯模块,有4路独立的控制器。主要特性如下:
SPI控制器内部包含位移寄存器、接收和发送FIFO、控制寄存器等相关寄存器。SPI控制器时钟来源于外部,有低频和参考时钟源两个来源。通过时钟发生器提供给状态机进行SPI控制器的状态控制,控制器内部框图如下图所示。
SPI控制器在使用时,需要首先进行初始化。具体的初始化流程如下:
在MASTER模式下,对SPI的操作可以参考下图所示的流程进行设置
IMX6ULL有4路SPI控制器,掌握其中一路SPI控制器即可。其他几路SPI控制器都类似,只需要修改寄存器基址和IO复用管脚即可。这里以SPI3为例进行说明,SPI3的相关寄存器地址如下图所示,其中红框内的寄存器为我们本次实验使用到的寄存器。
此次实验用到的寄存器具体功能如下:
该寄存器用于保存数据传输中从外部设备接收到的外部数据,是只读寄存器。该寄存器与接收数据FIFO的顶端数据相同,只允许四个字节的读操作。当模块被禁止的时候,读取到的是0。
该寄存器用于保存数据传输中发送给外部设备的数据,是只写寄存器。该寄存器与发送数据FIFO有关,只允许四个字节的写操作。当模块被禁止的时候,写入的数据将被忽略。
该寄存器用于设置SPI控制器的操作模式,包括时钟频率,相关控制方式和数据传输长度等。
该寄存器用于配置每个不同SPI片选通道的控制方式,包括SPI时钟和片选信号的模式相位和极性等。
该寄存器只有低8位有效,用于指示SPI控制器的操作状态,包括发送和接收FIFO的状态等信息。如果模块被禁止的话,读取到的值为0x00000003。
该寄存器提供了一个测试方式,通过软件在SPI控制器内部将接收和发送区域连接起来。通过该寄存器,将接收和发送连接起来了,可以用于测试。不会影响到设备的输出,同时外部的输入将会被忽略。
为了使用SPI控制器,我们需要初始化对应的IO引脚为spi3引脚。PAD的功能设置框图如下图所示,需要设置引脚工作模式、引脚上下拉和工作速度等。
初始化引脚为SPI3,涉及到的引脚模式配置的寄存器如下图所示。
这四组引脚涉及到的具体寄存器如下
该寄存器用于设置SPI3的SS0片选引脚,由于需要设置为SPI3_SS0模式(如果要求CS片选有效和时钟有效间隔较大,可以将该引脚设置为普通GPIO来进行拉高拉低操作来代替默认片选功能,此时应将该引脚设置成GPIO模式)。
该寄存器用于设置SPI3的SCLK引脚,需要设置为SPI3_SCLK模式。
该寄存器用于设置SPI3的MOSI引脚,需要设置为SPI3_MOSI模式。
该寄存器用于设置SPI3的MISO引脚,需要设置为SPI3_MISO模式。
初始化引脚为SPI3之后,需要设置引脚的上下拉和工作速度等,涉及到的SW_CTL_PAD下图所示。
这四组引脚涉及到的具体寄存器如下
该寄存器用于设置引脚UART2_TX_DATA上下拉、速度和驱动能力等,具体如下图所示。
该寄存器用于设置引脚UART2_RX_DATA上下拉、速度等,具体如下图所示。
该寄存器用于设置引脚UART2_CTS_B上下拉、速度等,具体如下图所示。
该寄存器用于设置引脚UART2_RTS_B上下拉、速度等,具体如下图所示。
ICM-20608-G采用LGA16 封装(大小为330.75m),6轴姿态传感器,包括3轴加速度和3轴角速度,具有如下特性:
ICM-20608-G内部框图如下所示:
ICM-20608-G支持SPI和I2C去操作,这里选择SPI接口进行控制。具体连接方式如下图所示,通过SPI接口连接到imx6ull上,使用imx6ull的spi3接口去读写ICM-206068-G设备。
ICM-20608-G内部有多个寄存器,可以通过spi接口来选择不同寄存器地址来实现读取设备ID、温度、加速度和加速度等多个信息,也可以通过SPI接口来设置ICM-20608-G的相关工作方式。相关寄存器地址具体如下图所示,其中红框里的是此次实验涉及到的寄存器。
相关寄存器的含义具体如下:
该寄存器用于设置采样频率,该值用于产生采样频率来控制传感器数据输出和FIFO采样率。
该寄存器用于设置设备的工作模式,包括FIFO、加速度、温度和加速度输出等。
该寄存器用于配置加速度传感器,包括量程选择、是否自测等信息
该寄存器用于配置加速度传感器,包括量程选择、是否自测等。
该寄存器也同时用于配置加速度传感器,包括采样速度等
该寄存器用于设置ICM-20608-G是否处于低功耗模式以及唤醒频率
该寄存器用于设置数据存储FIFO是否进行使用,为1表示使用,为0表示禁止FIFO。
该寄存器用于设置ICM-20608-G时钟来源、电源模式、以及是否清楚全部寄存器到默认状态等
该寄存器用于设置是否使能相关传感器、包括加速度和角速度传感器
该寄存器存储设备ID,ICM-20608-G的默认值为0xAF。
该寄存器存储角速度的测量结果,一共6个地址,每两个地址为一组X/Y/Z轴角速度的高低字节,具体内容如下图所示。
该寄存器用于存储温度测量结果,由高低两个字节构成。
该寄存器存储加速度的测量结果,一共6个地址,每两个地址为一组X/Y/Z轴加速度的高低字节,具体内容如下图所示。
板卡通过spi3接口连接到ICM-20608-G,因此这里针对spi3进行相关编程说明,其他的spi接口可通过修改寄存器地址和初始化相关引脚来实现。
在这里,我们首先进行SPI控制器的编程。要想实现SP控制器的顺利使用,我们首先需要将对应的SPI控制器引脚初始化为SPI功能引脚,然后设置SPI控制器。SPI控制器的设置包括时钟的配置、传输数据长度、工作模式和电平极性等。SPI控制的具体部分的设置可以参考以下几个部分。
我们使用的是SPI3控制器,连接到ICM-20608-G的引脚如下图红框处所示。
我们首先设置引脚的工作模式,然后设置引脚上下拉和驱动能力等
设置SPI3的SCLK引脚,需要将IOMUXC_SW_MUX_CTL_PAD_UART2_RX_DATA设置为ALT8模式。
设置SPI3的MOSI引脚,需要将IOMUXC_SW_MUX_CTL_PAD_UART2_CTS_B设置为ALT8模式。
设置SPI3的MISO引脚,需要将IOMUXC_SW_MUX_CTL_PAD_UART2_RTS_B设置为ALT8模式。
接下来通过寄存器SW_PAD_CTL_PAD来设置引脚上下拉和驱动能力等,我们使用默认值,不进行处理。
SPI3引脚初始化代码如下所示,将CS片选引脚设置成ALT5模式,其他设置成ALT8模式。
这部分的代码在**裸机Git仓库 NoosProgramProject/18_SPI编程(001_spi_init/spi.c)**中第87行~第96行。
//引脚初始化
iomuxc_sw_set(UART2_TX_BASE,5);//设置为GPIO作为片选来进行使用。GPIO1_IO20
GPIO1_GDIR = (volatile unsigned int *)(0x209C000 + 0x4);
GPIO1_DR = (volatile unsigned int *)(0x209C000);
*GPIO1_GDIR |= (1<<20);//设置为输出
*GPIO1_DR |= (1<<20);
iomuxc_sw_set(UART2_RX_BASE,8);
iomuxc_sw_set(UART2_RTS_BASE,8);
iomuxc_sw_set(UART2_CTS_BASE,8);
我们需要设置SPI控制器时钟来源并进行使能,然后通过CONREG寄存器设置实际提供给SPI控制器的时钟频率。
SPI控制器的时钟来源如下图所示,起始于PLL3,经过分频之后提供给SPI控制器进行使用。PLL3频率为480MHz,经过8分频之后提供60MHz的时钟给SPI控制器进行使用。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Efx5UoJu-1642060457332)(https://cdn.jsdelivr.net/gh/DongshanPI/HomeSite-Photos@main/IMX6ULL-BareMetal/SPI_program_bare_metal_image-20220107164924325.png)]
具体对应的寄存器为CCM_CSCDR2和CCM_CCGR1。CCM_CSCDR2涉及到SPI控制器的相关设置如下图所示,我们选择默认值。时钟来源于PLL3,分频倍数为1,因此提供给SPI控制器的时钟即为60MHz。
在选择时钟来源之后,我们需要使能SPI控制器时钟,对应的寄存器CCM_CCGR1相关设置位如下图红框所示。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qKQYl1GZ-1642060457332)(https://cdn.jsdelivr.net/gh/DongshanPI/HomeSite-Photos@main/IMX6ULL-BareMetal/SPI_program_bare_metal_image-20220107164946111.png)]
CG的设置参考值如下图所示,我们将bit5:4的值设置为2’b11,在所有模式下SPI控制器时钟都进行使能(除STOP模式之外)。因为所有的外设时钟都在文件《imximage.cfg.cfgtmp》进行了初始化,所有我们不需要进行设置,。
为了与外部设备时钟相匹配,我们将实际的SPI时钟SCLK设置为4MHz。涉及到的寄存器为步骤1的CONREG寄存器Bit15:12和Bit11:8,计算公式如下所示:
根据上述公式,为了将SPI控制器频率设置为4MHz,我们需要将bit15:11设置为14即可,计算结果如下
因此,我们需要在原先CONREG寄存器值的基础上,设置bit115:11为14,即将CONREG寄存器值或上14<<11。
SPI时钟设置相关代码如下所示,这部分的代码在**裸机Git仓库 NoosProgramProject/18_SPI编程(001_spi_init/spi.c)**第71行~第85行。
/*设置时钟相关的*/
/*
从RM手册chapter18中,我们得知时钟来源为PLL3
1、pll3_sw_clk_sel为0,则选择pll3;为1则选择ccm_pll3_bys,时钟 默认选择pll3 。输出pll3_sw_clk给spi进行使用 输出给spi的时钟为480M/8=60Mhz
75 2、我们需要使能spi的时钟进行使用,通过CCM_CCGR1的bit5:2来进行设置 这部分在制作.imx文件的时候初始化,可以不处理
3、计算时钟频率 CONREG寄存器
bit15:12 div_1
bit11:8 div_2
最终提供给spip的时钟为
60M/(div+1)*(2^div_2))
假设我们要使用的时钟是4M
则我们设置bit15:12 = 15即可 60M/4 = 15Mhz
*/
uc_num->CONREG &= ~(0xf<<12|0xf<<8);//清除原先的时钟频率设置
uc_num->CONREG |= (14<<12); //设置clk = 60/(14+1) = 4M
在这里,我们将SPI控制器作为master来连接外部设备,按照如下流程来对SPI控制器编程进行初始化,具体相关设置如下所示
CONREG寄存器相关设置如下图所示:
具体值的含义如下:
根据以上描述,我们需要先将寄存器CONREG值清零,然后设置该寄存器,设置为master模式,每次传输为一个字节,使能立即传输并使能模块,具体对应的值为:
(7<<20)|(1<<4)|(1<<3)|(1<<0)
CONFIGREG寄存器相关设置如下图所示:
具体值的含义如下:
根据以上描述,我们将CONFIGREG寄存器值设置为0。
具体在IOMUX中设置(引脚已在上一小节初始化,这里不再赘述)。
SPI初始化相关代码如下所示,,这部分的代码在**裸机Git仓库 NoosProgramProject/18_SPI编程(001_spi_init/spi.c)**第40行~第70行。
/*
1、清除CONREG寄存器的EN位 来复位模块
2、在ccm中使能spi时钟
3、配置control register,然后设置CONREG的EN位来使spi模块退出复位
4、配置spi对应的IOMUX引脚
5、根据外部spi设备规格来合适的配置spi寄存器
*/
printf("spi 初始化开始\n\r") ;
/**/
uc_num->CONREG = 0;// clear all bits
/*
bit0:使能SPI
bit3:写入TXDATA之后,立即发送
bit4:设置通道0为master mode
bit31:20 设置burst length ,7表示为8bits,一个字节
*/
uc_num->CONREG |= (7<<20)|(1<<4)|(1<<3)|(1<<0);
/* CONFIGREG采用默认设置
*
*bit0 PHA=0
*bit7:4 sclk高电平有效
*bit11:8 通道片选信号,当SMC =1的时候,无效(当前处于SMC=1模式)
*bit15:12 POL=0
*bit19:16 数据线空闲为高电平
*bit23:20 sclk空闲为低电平
*bit28:24 设置消息长度 ,该产品不进行使用
*
*/
uc_num->CONFIGREG = 0;//
TESTREG寄存器存储提供了在控制器内部将接收和发送连接起来的方式,可以用于查看接收和发送FIFO的内容。
TESTREG寄存器具体设置如下图所示,其中最高位为1表示进入测试模式,即接收和发送区域内部连接成回环模式。Bit14:8表示接收FIFO的深度,Bit6:0表示发送FIFO的深度。
可以通过将bit32设置为1,然后进行数据发送并统计发送的数量,之后读取接收fifo的内容和数量进行对比,从而测试SPI控制器是否正常。
这两个寄存器分别用于发送和接收数据,可以通过将值写入TXDATA来发送,通过读取RXDATA来获取设备值。
发送和接收的代码如下所示,这部分的代码在程序文件《spi.c》中spi_writeread函数。
while(!(spi_num->STATREG&(1<<0)));//如果FIFO时空的话,则填充数据以开始下一次发送
spi_num->TXDATA = uc_txdata;
while(!(spi_num->STATREG&(1<<3)));//等待接收数据完成,当为1的时候表示有接收数据存在,可以进行读取
return spi_num->RXDATA;
通过SPI接口连接ICM-20608-G,ICM-20608-G的操作要求如下:
数据传输首先传输MSB位,最后传输LSB位
数据在sclk上升沿被锁存
数据应当在sclk的下降沿被传输
最大支持8MHz的时钟频率
数据读写操作在16个或者更多的时钟周期内完成。第一字节位寄存器地址,接下来的字节为相关数据。
支持单字节或者多字节读写操作
在SPI控制器初始化完成之后,我们可以对ICM-20608-G进行使用设置。ICM-20608-G内部包含有多个寄存器,我们可以通过SPI对不同的地址进行操作读写操作来实现。
ICM-20608-G的SPI传输的地址和数据格式如下图所示,可以看到地址最高位MSB表示读写操作,为1表示独操作,为0表示写操作。
为了使用ICM-20608-G,我们需要进行初始化。首先需要使传感器退出复位模式(设备在刚上电的时候,处于复位模式)。之后,我们需要设置传感器的采样率、加速度和角速度传感器的量程、加速度和角速度的相关滤波器以及是否使用低功耗模式。当我们设置完成之后,我们使能传感器。之后,就可以读取相关传感器数据了。具体的ICM-20608-G操作过程如以下几部分所述。
该寄存器地址为0x19,用于设置采样率。AMPLE_RATE = INTERNAL_SAMPLE_RATE / (1 + SMPLRT_DIV) Where INTERNAL_SAMPLE_RATE = 1kHz。具体如下图所示,我们选择采用了为1K,因此该寄存器值设定为0.
该寄存器地址为0x1A,可以设置FIFO的模式、外部FSYNC引脚功能以及DLPF配置,具体如下图所示。我们将低通滤波器设定为250Hz,其余采用默认,因此该寄存器值为0x00。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Du1lZgqb-1642060457336)(https://cdn.jsdelivr.net/gh/DongshanPI/HomeSite-Photos@main/IMX6ULL-BareMetal/SPI_program_bare_metal_image-20220107170311178.png)]
低通滤波器DLPF_CFG的设定值范围如下所示,我们选择20Hz。
该寄存器地址为0x1B,可以设置角速度传感器自测和量程范围以及低通滤波器的范围,具体如下图所示。我们选择量程范围为±250dps,其余使用默认值,因此该寄存器值设定为0x00。
该寄存器地址为0x1C,可以设置加速度传感器自测和量程范围以及低通滤波器的范围,具体如下图所示。我们选择量程范围为±2g,其余使用默认值,因此该寄存器值设定为0x00。
该寄存器地址为0x1D,可以设置加速度传感器采样和低通滤波器的范围,具体如下图所示。我们选择低通滤波器为218.1Hz,其余使用默认值,因此该寄存器值设定为0x00。
该寄存器地址为0x1E,可以设置低功耗模式和低功耗模式下唤醒频率等,具体如下图所示。我们不需要低功耗模模式,因此将该寄存器设置为0,关闭低功耗模式。
该寄存器地址为0x23,用于使能传感器的FIFO,具体如下图所示。由于我们不需要FIFO,因此我们将该寄存器值设定为0,关闭所有FIFO。
该寄存器地址为0x6B,可以控制设备复位、传感器休眠等,具体如下图所示。在最开始的时候,为了安全,在初始化ICM-20608-G的时候,我们首先将该寄存器设置为0x80来复位整个芯片(在复位完成之后,该值自动清零)。等复位完成之后 ,我们将该值设置为0x01,表示禁止传感器休眠,使能温度传感器并自动选择合适的时钟源。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5YME4JgU-1642060457338)(https://cdn.jsdelivr.net/gh/DongshanPI/HomeSite-Photos@main/IMX6ULL-BareMetal/SPI_program_bare_metal_image-20220107170351662.png)]
该寄存器地址为0x6C,可以设置传感器使能等,具体如下图所示。我们使用所有的传感器,因此将该值设置为0x00。
ICM20608-G相关初始化代码如下所示,这部分的代码在**裸机Git仓库 NoosProgramProject/18_SPI编程(003_spi_read_icm20608_id)和裸机Git仓库 NoosProgramProject/18_SPI编/004_read_sensor_data)**程序文件《icm20608g.c》的icm20608g_init函数中。
icm20608_write_addr(ICM20608G_PWR_MGMT_1,0x80);//设备复位
icm20608g_write_addr(ICM20608G_PWR_MGMT_1,0x01);//设备退出复位
icm20608g_write_addr(ICM20608G_SMPLRT_DIV,0x00);//采样率默认1K
icm20608g_write_addr(ICM20608G_CONFIG, 0x00);//禁止FIFO
icm20608g_write_addr(ICM20608G_GYRO_CONFIG,0x00);//使用默认量程和低通滤波器
icm20608g_write_addr(ICM20608G_ACC_CONFIG,0x00);//使用默认量程
icm20608g_write_addr(ICM20608G_ACC_CONFIG2,0x00);//使用默认低通滤波器
icm20608g_write_addr(ICM20608G_LP_MODE_CFG,0x00);//关闭低功耗模式
icm20608g_write_addr(ICM20608G_FIFO_EN,0x00);//禁止传感器FIFO
icm20608g_write_addr(ICM20608G_PWR_MGMT_2,0x00);//使能传感器
设备ID,该寄存器地址为0x75,可以读取WHO_AM_I信息。WHO_AM_I是一个8位设备ID,该值默认为0xAF,具体如下图所示。
读取设备ID相关的代码如下所示,这部分的代码在**裸机Git仓库 NoosProgramProject/18_SPI编程/003_spi_read_icm20608_id)和裸机Git仓库 NoosProgramProject/18_SPI编程/004_read_sensor_data)**程序文件《icm20608g.c》的icm20608g_init函数第62行~第69行。
//读取设备id并对比,如果不等于0xaf,则退出初始化
uc_dev_id = icm20608g_read_addr(ICM20608G_WHO_AM_I);
printf("read icm20608g id is 0x%x\n\r",uc_dev_id);
if(uc_dev_id!=0xAF)
{
printf("read id fail\n\r");
return -1;
}
温度传感器数据,该值分为高低两个字节,分别对应寄存器地址0x41和0x42。对应计算公司为Temp_degC = (Temp_out-RoomTemp_Offset)/Temp_sensitivity)+25degC。具体如下图所示
读取温度相关的代码如下所示,这部分的代码在**裸机Git仓库 NoosProgramProject/18_SPI编程/004_read_sensor_data/icm20608g.c)**的icm20608g_read_temp函数。
icm20608g_read_len(0x41,uc_buf,2);
icm20608g_get.temp_adc = (signed short)((uc_buf[0]<<8)|uc_buf[1]);
ICM-20608-G支持加速度测量,对应地址为从寄存器地址59到64。其中59和60地址对应X轴加速度高低字节,61和62地址对应Y轴加速度高低字节,63和64地址对应Z轴高低字节。高低字节拼接之后进行处理即可。具体如下图所示
读取加速度相关的代码如下所示,这部分的代码在**裸机Git仓库 NoosProgramProject/18_SPI编程/004_read_sensor_data/icm20608g.c)**的icm20608g_read_acc函数。
icm20608g_read_len(0x3b,uc_buf,6);
icm20608g_get.acc_x_adc = (signed short)((uc_buf[0]<<8)|uc_buf[1]);
icm20608g_get.acc_y_adc = (signed short)((uc_buf[2]<<8)|uc_buf[3]);
icm20608g_get.acc_z_adc = (signed short)((uc_buf[4]<<8)|uc_buf[5]);
ICM-20608-G支持角速度测量,对应地址为从寄存器地址67到72。其中67和68地址对应X轴角速度高低字节,69和70地址对应Y轴角速度高低字节,71和72地址对应Z轴角速度高低字节。高低字节拼接之后进行处理即可。具体如下图所示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JiU6T5Ft-1642060457339)(https://cdn.jsdelivr.net/gh/DongshanPI/HomeSite-Photos@main/IMX6ULL-BareMetal/SPI_program_bare_metal_image-20220107170545413.png)]
读取角速度相关的代码如下所示,这部分的代码在**裸机Git仓库 NoosProgramProject/18_SPI编程/004_read_sensor_data/icm20608g.c)**的icm20608g_read_gyro函数。
icm20608g_read_len(0x43,uc_buf,6);
icm20608g_get.gyro_x_adc = (signed short)((uc_buf[0]<<8)|uc_buf[1]);
icm20608g_get.gyro_y_adc = (signed short)((uc_buf[2]<<8)|uc_buf[3]);
icm20608g_get.gyro_z_adc = (signed short)((uc_buf[4]<<8)|uc_buf[5]);
执行函数spi_init(ESCPI3_BASE);即可初始化SPI控制器,通过spi_writeread(0x54)执行向外数据的输出,可以通过测试控制器的输出时钟SCLK来测试控制器是否初始化成功。
这部分的试验代码在裸机Git仓库 NoosProgramProject/18_SPI编程/001_spi_init/main.c),具体代码如下所示:
int main()
{
unsigned char uc_cnt;
spi_init(ESCPI3_BASE);
return 0;
}
进入**裸机Git仓库 NoosProgramProject/18_SPI编程/001_spi_init)**源码目录进行编译。
实验结果如图所示:
该实验主要用于测试SPI控制器本身功能,通过将收发连接到一块来进行测试。
首先实现该函数在**裸机Git仓库 NoosProgramProject/18_SPI编程/002_spi_loopback/spi.c)中spi_test_rw函数,然后在裸机Git仓库 NoosProgramProject/18_SPI编程/002_spi_loopback/main.c)**中进行调用.
首先设置SPI控制器进入回环模式,然后开始写入数据.每次写入之后就读出数据,循环20次。读写完成之后将写入和读出的数据进行比较,如果一致则表示回环模式测试成功。在最后成功完成测试的时候需要退出循环模式。
spi_test_rw函数代码在**裸机Git仓库 NoosProgramProject/18_SPI编程/002_spi_loopback/spi.c)**中,具体如下所示:
//设置进入loop模式,进行测试
spi_num->TESTREG = (1<<31);
printf("spi进入回环测试模式\n\r");
//造数
for(uc_cnt=0;uc_cnt<20;uc_cnt++)
{
uc_buf_write[uc_cnt] = 0x20+uc_cnt;
}
//进行读写测试
for(uc_cnt=0;uc_cnt<20;uc_cnt++)
{
printf("write_cnt %d\t",uc_cnt);
spi_writeread(spi_num,uc_buf_write[uc_cnt]);
printf("write %d\t",uc_buf_write[uc_cnt]);
uc_buf_read[uc_cnt]=spi_writeread(ESCPI3_BASE,0xff);
printf("read %d\n\r",uc_buf_read[uc_cnt]);
}
//进行数据对比
for(uc_cnt=0;uc_cnt<20;uc_cnt++)
{
if(uc_buf_read[uc_cnt]!=uc_buf_write[uc_cnt])
{/*表示回环测试失败,存在问题*/
printf("!!!spi回环测试失败\n\r");
return -1;
}
}
printf("@@@spi回环测试成功\n\r");
printf("spi退出回环测试模式\n\r");
//exit loopback mode
spi_num->TESTREG = 0;
之后在裸机Git仓库NoosProgramProject/18_SPI编程/002_spi_loopback/main.c)中调用spi_test_rw实现回环测试,调用代码如下所示:
进入 **裸机Git仓库 NoosProgramProject/18_SPI编程/002_spi_loopback)**源码目录进行编译。
测试结果记录如下,可以看到读取和写入的数据相同
该实验用于测试读取与ICM-20608-G的SPI通讯接口功能正常与否。如果能够正确的读取到设备ID,则表示SPI接口通讯正常。
在裸机Git仓库 NoosProgramProject/18_SPI编程/003_spi_read_icm20608_id/main.c)中调用icm20608g_init实现ICM-20608-G的初始化和ID的读取,调用代码如下所示:
int main()
{
unsigned char uc_cnt;
icm20608g_init();//初始化传感器ICM-20608-G
return 0;
}
进入**裸机Git仓库 NoosProgramProject/18_SPI编程/003_spi_read_icm20608_id/)**源码目录进行编译。
测试结果如下所示,可以看到读取到的ID是0xAF,与ICM-20608-G的ID一致。
通过读取寄存器的值读取传感器信息,包括温度、三轴角速度和加速度值。
在裸机Git仓库 NoosProgramProject/18_SPI编程/004_read_sensor_data/main.c)中调用icm20608g_read_acc、icm20608g_read_ac和icm20608g_read_temp函数来实现传感器数值读取,调用代码如下所示:
int main()
{
unsigned char uc_cnt;
icm20608g_init();//初始化传感器ICM-20608-G
for(uc_cnt=0;uc_cnt<1;uc_cnt++)
{
icm20608g_read_acc();
icm20608g_read_gyro();
icm20608g_read_temp();
}
return 0;
}
进入 **裸机Git仓库 NoosProgramProject/18_SPI编程/004_read_sensor_data)**源码目录进行编译。
测试结果记录如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RaiAJwpb-1642060457339)(https://cdn.jsdelivr.net/gh/DongshanPI/HomeSite-Photos@main/IMX6ULL-BareMetal/SPI_program_bare_metal_image-20220107170705702.png)]