18_SPI编程

第十八章 SPI编程(有误)

18.1 SPI接口简介

​ SPI(Serial Peripheral Interface)接口是全双工的同步串行通讯总线,支持通过多个不同的片选信号来连接多个外设。SPI接口通常由四根线组成,分别是提供时钟的SCLK,提供数据输出的MOSI,提供数据输入的MISO和提供片选信号的CS。同一时刻只能有一个SPI设备处于工作状态。为了适配不同的外设 ,SPI支持通过寄存器来配置片选信号和时钟信号的极性和相位。(imx6ull支持ecspi,即增强配置型spi,这里为了与其他兼容,统一用spi来称呼)。

18.1.1 SPI硬件连接

​ SPI支持slave和master两种模式,作为APU来说,多数情况下是作为master来使用的。在master模式下,通过不同的片选引脚ssn来连接多个不同的设备。下图为MASTER模式下的SPI单线通讯模式框图,只对设备进行写操作。

18_SPI编程_第1张图片

18.1.2 SPI通讯数据格式

​ 在master模式下,ss、sclk和mosi作为信号输出接口,MISO作为信号输入接口。通过SS片选信号使能外部SPI设备,SCLK同步数据传输。MOSI和MISO信号在SCLK上升沿变化,在下降沿锁存数据。SPI的具体通讯格式如下图所示(默认高位在前,低位在后),输出数据为0xD2,输入数据为0x66。

18_SPI编程_第2张图片

​ 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,因为它们都是在上升沿采样数据,不用去在乎时钟的初始电平是什么,只要在上升沿采集数据就行。极性选什么?格式选什么?通常去参考外接的模块的芯片手册。

18.2 IMX6ULL的SPI控制器操作与寄存器介绍

18.2.1 SPI控制器介绍

IMX6ULL的SPI控制器ECSPI(Enhanced Configurable Serial Peripheral Interface) 为全双工同步四线串行通讯模块,有4路独立的控制器。主要特性如下:

  • 全双工同步串行接口
  • 可配置为MASTER或SLAVE模式
  • 支持多达四个片选信号来连接不同的外设
  • 传输数据长度不限
  • 包含一个64X32的接收FIFO和64X32的发送FIFO
  • 片选信号和时钟信号的极性及相位可配置
  • 支持DMA(Direct Memory Acess)
  • 最大运行频率依赖于参考时钟频率

SPI控制器内部包含位移寄存器、接收和发送FIFO、控制寄存器等相关寄存器。SPI控制器时钟来源于外部,有低频和参考时钟源两个来源。通过时钟发生器提供给状态机进行SPI控制器的状态控制,控制器内部框图如下图所示。

18_SPI编程_第3张图片

18.2.2 SPI控制器初始化流程

SPI控制器在使用时,需要首先进行初始化。具体的初始化流程如下:

  1. 清除CONFREG寄存器的EN位来复位模块
  2. 使能SPI时钟,具体在CCM模块中进行设置
  3. 配置控制寄存器,并使能ECSPI_CONFREG寄存器的EN位来让模块工作
  4. 配置SPI引脚,具体在IOMUX中设置
  5. 根据外部SPI设备规格信息来配置SPI寄存器

在MASTER模式下,对SPI的操作可以参考下图所示的流程进行设置

18_SPI编程_第4张图片

18.2.3 SPI控制器寄存器介绍

IMX6ULL有4路SPI控制器,掌握其中一路SPI控制器即可。其他几路SPI控制器都类似,只需要修改寄存器基址和IO复用管脚即可。这里以SPI3为例进行说明,SPI3的相关寄存器地址如下图所示,其中红框内的寄存器为我们本次实验使用到的寄存器。

此次实验用到的寄存器具体功能如下:

18.2.3.1 ECSPIx_RXDATA

该寄存器用于保存数据传输中从外部设备接收到的外部数据,是只读寄存器。该寄存器与接收数据FIFO的顶端数据相同,只允许四个字节的读操作。当模块被禁止的时候,读取到的是0。

18_SPI编程_第5张图片

18.2.3.2 ECSPIX_TXDATA

该寄存器用于保存数据传输中发送给外部设备的数据,是只写寄存器。该寄存器与发送数据FIFO有关,只允许四个字节的写操作。当模块被禁止的时候,写入的数据将被忽略。

18_SPI编程_第6张图片

18.2.3.3 ECSPIX_CONREG

该寄存器用于设置SPI控制器的操作模式,包括时钟频率,相关控制方式和数据传输长度等。

18_SPI编程_第7张图片

18.2.3.4 ECSPIX_CONFIGREG

该寄存器用于配置每个不同SPI片选通道的控制方式,包括SPI时钟和片选信号的模式相位和极性等。

image-20220107163353864

18.2.3.5 ECSPIX_STATREG

该寄存器只有低8位有效,用于指示SPI控制器的操作状态,包括发送和接收FIFO的状态等信息。如果模块被禁止的话,读取到的值为0x00000003。

18_SPI编程_第8张图片

18.2.3.6 ECSPIX_TESTREG

该寄存器提供了一个测试方式,通过软件在SPI控制器内部将接收和发送区域连接起来。通过该寄存器,将接收和发送连接起来了,可以用于测试。不会影响到设备的输出,同时外部的输入将会被忽略。

18_SPI编程_第9张图片

18.2.4 SPI控制器介绍

为了使用SPI控制器,我们需要初始化对应的IO引脚为spi3引脚。PAD的功能设置框图如下图所示,需要设置引脚工作模式、引脚上下拉和工作速度等。

18_SPI编程_第10张图片

18.2.4.1 初始化SPI3引脚

初始化引脚为SPI3,涉及到的引脚模式配置的寄存器如下图所示。

18_SPI编程_第11张图片

这四组引脚涉及到的具体寄存器如下

  1. IOMUXC_SW_MUX_CTL_PAD_UART2_TX_DATA

该寄存器用于设置SPI3的SS0片选引脚,由于需要设置为SPI3_SS0模式(如果要求CS片选有效和时钟有效间隔较大,可以将该引脚设置为普通GPIO来进行拉高拉低操作来代替默认片选功能,此时应将该引脚设置成GPIO模式)。

18_SPI编程_第12张图片

  1. IOMUXC_SW_MUX_CTL_PAD_UART2_RX_DATA

该寄存器用于设置SPI3的SCLK引脚,需要设置为SPI3_SCLK模式。

18_SPI编程_第13张图片

  1. IOMUXC_SW_MUX_CTL_PAD_UART2_CTS_B

该寄存器用于设置SPI3的MOSI引脚,需要设置为SPI3_MOSI模式。

18_SPI编程_第14张图片

  1. IOMUXC_SW_MUX_CTL_PAD_UART2_RTS_B

该寄存器用于设置SPI3的MISO引脚,需要设置为SPI3_MISO模式。

18_SPI编程_第15张图片

初始化引脚为SPI3之后,需要设置引脚的上下拉和工作速度等,涉及到的SW_CTL_PAD下图所示。

18.2.4.2 初始化SPI3工作速率

18_SPI编程_第16张图片

这四组引脚涉及到的具体寄存器如下

  1. IOMUXC_SW_PAD_CTL_PAD_UART2_TX_DATA

该寄存器用于设置引脚UART2_TX_DATA上下拉、速度和驱动能力等,具体如下图所示。

18_SPI编程_第17张图片

  1. IOMUXC_SW_PAD_CTL_PAD_UART2_RX_DATA

该寄存器用于设置引脚UART2_RX_DATA上下拉、速度等,具体如下图所示。

18_SPI编程_第18张图片

  1. IOMUXC_SW_PAD_CTL_PAD_UART2_CTS_B

该寄存器用于设置引脚UART2_CTS_B上下拉、速度等,具体如下图所示。

18_SPI编程_第19张图片

  1. IOMUXC_SW_PAD_CTL_PAD_UART2_RTS_B

该寄存器用于设置引脚UART2_RTS_B上下拉、速度等,具体如下图所示。

18_SPI编程_第20张图片

18.3 ICM-20608-G操作方法

18.3.1 ICM-20608-G介绍

ICM-20608-G采用LGA16 封装(大小为330.75m),6轴姿态传感器,包括3轴加速度和3轴角速度,具有如下特性:

  • 支持数字输出X、Y和Z轴角速度传感器(陀螺仪),具有±250、±500、±1000和±2000 ▫/秒的用户可编程量程,内部集成16位ADC
  • 数字输出X、Y和Z轴加速度位±2g、±4g、±8g和±16g的用户可编程满量程,内部集成16位ADC
  • 512字节的FIFO缓冲器,允许应用处理器来读取突然的数据
  • 数字输出温度传感器
  • 支持用户可编程的角速度、加速度和温度传感器滤波设置
  • 支持400kHz的快速模式I2C,或者8MHz的SPI串行接口
  • 支持self-test
  • 支持动作唤醒和低功耗操作

ICM-20608-G内部框图如下所示:

18_SPI编程_第21张图片

18.3.2 ICM-20608-G操作方法

ICM-20608-G支持SPI和I2C去操作,这里选择SPI接口进行控制。具体连接方式如下图所示,通过SPI接口连接到imx6ull上,使用imx6ull的spi3接口去读写ICM-206068-G设备。

18_SPI编程_第22张图片

18.3.3 ICM-20608-G相关寄存器

ICM-20608-G内部有多个寄存器,可以通过spi接口来选择不同寄存器地址来实现读取设备ID、温度、加速度和加速度等多个信息,也可以通过SPI接口来设置ICM-20608-G的相关工作方式。相关寄存器地址具体如下图所示,其中红框里的是此次实验涉及到的寄存器。

18_SPI编程_第23张图片

相关寄存器的含义具体如下:

  1. Sample rate divider

该寄存器用于设置采样频率,该值用于产生采样频率来控制传感器数据输出和FIFO采样率。

  1. Configuration

该寄存器用于设置设备的工作模式,包括FIFO、加速度、温度和加速度输出等。

  1. Gyroscope configuration

该寄存器用于配置加速度传感器,包括量程选择、是否自测等信息

  1. Accelerometer configuration

该寄存器用于配置加速度传感器,包括量程选择、是否自测等。

  1. Accelerometer configuration2

该寄存器也同时用于配置加速度传感器,包括采样速度等

  1. Low power mode configuration

该寄存器用于设置ICM-20608-G是否处于低功耗模式以及唤醒频率

  1. Fifo enable

该寄存器用于设置数据存储FIFO是否进行使用,为1表示使用,为0表示禁止FIFO。

  1. Power management1

该寄存器用于设置ICM-20608-G时钟来源、电源模式、以及是否清楚全部寄存器到默认状态等

  1. Power management2

该寄存器用于设置是否使能相关传感器、包括加速度和角速度传感器

  1. Who am i

该寄存器存储设备ID,ICM-20608-G的默认值为0xAF。

  1. Accelerometer measurements

该寄存器存储角速度的测量结果,一共6个地址,每两个地址为一组X/Y/Z轴角速度的高低字节,具体内容如下图所示。

  1. Temperature measurements

该寄存器用于存储温度测量结果,由高低两个字节构成。

  1. Gyroscope measurement

该寄存器存储加速度的测量结果,一共6个地址,每两个地址为一组X/Y/Z轴加速度的高低字节,具体内容如下图所示。

18.4 SPI控制器编程

板卡通过spi3接口连接到ICM-20608-G,因此这里针对spi3进行相关编程说明,其他的spi接口可通过修改寄存器地址和初始化相关引脚来实现。

在这里,我们首先进行SPI控制器的编程。要想实现SP控制器的顺利使用,我们首先需要将对应的SPI控制器引脚初始化为SPI功能引脚,然后设置SPI控制器。SPI控制器的设置包括时钟的配置、传输数据长度、工作模式和电平极性等。SPI控制的具体部分的设置可以参考以下几个部分。

18.4.1 SPI控制器引脚设置

我们使用的是SPI3控制器,连接到ICM-20608-G的引脚如下图红框处所示。

18_SPI编程_第24张图片

18.4.1.1 设置引脚的工作模式

我们首先设置引脚的工作模式,然后设置引脚上下拉和驱动能力等

  1. 设置SPI3的SS0片选引脚,针对ICM-20608-G,我们将该引脚设置成GPIO,通过拉高拉低来进行片选操作。因此需要将IOMUX_SW_MUX_CTL_PAD_UART2_TX_DATA设置为ALT5模式,作为GPIO进行使用。SPI3的SS0引脚对应的GPIO为GPIO1_20,具体地址如下所示。

image-20220107164214439

  1. 设置SPI3的SCLK引脚,需要将IOMUXC_SW_MUX_CTL_PAD_UART2_RX_DATA设置为ALT8模式。

  2. 设置SPI3的MOSI引脚,需要将IOMUXC_SW_MUX_CTL_PAD_UART2_CTS_B设置为ALT8模式。

  3. 设置SPI3的MISO引脚,需要将IOMUXC_SW_MUX_CTL_PAD_UART2_RTS_B设置为ALT8模式。

接下来通过寄存器SW_PAD_CTL_PAD来设置引脚上下拉和驱动能力等,我们使用默认值,不进行处理。

18.4.1.2 引脚初始化代码

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);

18.4.2 SPI控制器时钟设置

我们需要设置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)]

18.4.2.1 设置SPI时钟
  1. 选择SPI控制器的时钟来源并进行使能

具体对应的寄存器为CCM_CSCDR2和CCM_CCGR1。CCM_CSCDR2涉及到SPI控制器的相关设置如下图所示,我们选择默认值。时钟来源于PLL3,分频倍数为1,因此提供给SPI控制器的时钟即为60MHz。

18_SPI编程_第25张图片

  1. 使能SPI控制器时钟

在选择时钟来源之后,我们需要使能SPI控制器时钟,对应的寄存器CCM_CCGR1相关设置位如下图红框所示。

18_SPI编程_第26张图片

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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》进行了初始化,所有我们不需要进行设置,。

image-20220107164954834

  1. 设置SPI工作时钟

为了与外部设备时钟相匹配,我们将实际的SPI时钟SCLK设置为4MHz。涉及到的寄存器为步骤1的CONREG寄存器Bit15:12和Bit11:8,计算公式如下所示:

image-20220107165210889

根据上述公式,为了将SPI控制器频率设置为4MHz,我们需要将bit15:11设置为14即可,计算结果如下

image-20220107165229108

因此,我们需要在原先CONREG寄存器值的基础上,设置bit115:11为14,即将CONREG寄存器值或上14<<11。

18.4.2.2 SPI时钟设置相关代码

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

18.4.3 SPI控制器控制和配置设置

在这里,我们将SPI控制器作为master来连接外部设备,按照如下流程来对SPI控制器编程进行初始化,具体相关设置如下所示

18.4.3.1 步骤1、配置CONREG寄存器

CONREG寄存器相关设置如下图所示:

18_SPI编程_第27张图片

具体值的含义如下:

  • Bit31:20:表示一次SPI传输的数据长度,一次传输的最大大小为2^12 位。我们一次传输一个字节,因此将该值设置为7
  • Bit19:18:表示SPI通道选择位,值为03分别对应通道03。我们选择通道0,将该值设置为0。
  • Bit17:16:表示SPI_RDY#信号控制。该信号默认不进行使用,因此我们不进行处理。
  • Bit15:12和Bit11:8:用于设置SPI时钟频率,稍后在SPI控制器时钟设置小节进行描述。
  • Bit7:4:设置通道工作模式,分别对应四个通道。每个通道对应位位0表示slave模式。为1表示master模式。我们将通道0设置为master模式
  • Bit3:开始传输控制。该值为0时,表示需要通过控制SPI交换位XCH来控制数据传输,当XCH为1则开始传输。该值为1时,当数据开始写入TXFIFO的时候,立即开始传输。我们将该值设置为1,写入TXFIFO之后立即开始传输
  • Bit2:SPI交换位XCH,这里不进行使用。
  • Bit1:硬件触发使能位。这里不进行使用
  • Bit0:SPI模块使能位,该值位1表示使能SPI控制器。该值必须在写入除CONREG之外的寄存器或开始传输前使能。

根据以上描述,我们需要先将寄存器CONREG值清零,然后设置该寄存器,设置为master模式,每次传输为一个字节,使能立即传输并使能模块,具体对应的值为:

(7<<20)|(1<<4)|(1<<3)|(1<<0)
18.4.3.2 步骤2、配置CONFIGREG寄存器

CONFIGREG寄存器相关设置如下图所示:

image-20220107165549664

具体值的含义如下:

  • Bit28:24:设置HT模式下的数据长度,这里不进行使用。
  • Bit23:20:设置通道SCLK空闲时的电平状态,默认空闲时为低电平,这里使用默认值。
  • Bit19:16:设置通道数据线空闲时的电平状态,默认空闲时为高电平,这里使用默认值。
  • Bit15:12:设置SS片选信号极性设置,默认为低电平有效,这里使用默认值。
  • Bit11:8:通道SS片选信号, 当SMC为1的时候此位无效。
  • Bit7:4:通道SCLK时钟初始电平,为0表示高电平有效,这里使用默认值。
  • Bit3:0:通道SCLK时钟极性选择,为0表示第一个时钟沿采集数据,为1表示第二个时钟沿采集数据。默认第一个时钟沿采集数据,这里使用默认值。

根据以上描述,我们将CONFIGREG寄存器值设置为0。

18.4.3 步骤3、配置SPI引脚

具体在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;//   

 

18.4.4 SPI控制器TESTREG寄存器设置

TESTREG寄存器存储提供了在控制器内部将接收和发送连接起来的方式,可以用于查看接收和发送FIFO的内容。

18_SPI编程_第28张图片

TESTREG寄存器具体设置如下图所示,其中最高位为1表示进入测试模式,即接收和发送区域内部连接成回环模式。Bit14:8表示接收FIFO的深度,Bit6:0表示发送FIFO的深度。

18_SPI编程_第29张图片

可以通过将bit32设置为1,然后进行数据发送并统计发送的数量,之后读取接收fifo的内容和数量进行对比,从而测试SPI控制器是否正常。

18.4.5 SPI控制器TXDATA和RXDATA寄存器

这两个寄存器分别用于发送和接收数据,可以通过将值写入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;

18.5 ICM-20608-G编程

通过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表示写操作。

18_SPI编程_第30张图片

为了使用ICM-20608-G,我们需要进行初始化。首先需要使传感器退出复位模式(设备在刚上电的时候,处于复位模式)。之后,我们需要设置传感器的采样率、加速度和角速度传感器的量程、加速度和角速度的相关滤波器以及是否使用低功耗模式。当我们设置完成之后,我们使能传感器。之后,就可以读取相关传感器数据了。具体的ICM-20608-G操作过程如以下几部分所述。

18.5.1 ICM-20608-G配置初始化

18.5.1.1采样率设置寄存器

该寄存器地址为0x19,用于设置采样率。AMPLE_RATE = INTERNAL_SAMPLE_RATE / (1 + SMPLRT_DIV) Where INTERNAL_SAMPLE_RATE = 1kHz。具体如下图所示,我们选择采用了为1K,因此该寄存器值设定为0.

18_SPI编程_第31张图片

18.5.1.2 配置寄存器

该寄存器地址为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。

18_SPI编程_第32张图片

18.5.1.3 角速度传感器设置

该寄存器地址为0x1B,可以设置角速度传感器自测和量程范围以及低通滤波器的范围,具体如下图所示。我们选择量程范围为±250dps,其余使用默认值,因此该寄存器值设定为0x00。

18_SPI编程_第33张图片

18.5.1.4 加速度传感器设置

该寄存器地址为0x1C,可以设置加速度传感器自测和量程范围以及低通滤波器的范围,具体如下图所示。我们选择量程范围为±2g,其余使用默认值,因此该寄存器值设定为0x00。

18_SPI编程_第34张图片

18.5.1.5 加速度传感器设置2

该寄存器地址为0x1D,可以设置加速度传感器采样和低通滤波器的范围,具体如下图所示。我们选择低通滤波器为218.1Hz,其余使用默认值,因此该寄存器值设定为0x00。

18_SPI编程_第35张图片

18.5.1.6 低功耗模式设置

该寄存器地址为0x1E,可以设置低功耗模式和低功耗模式下唤醒频率等,具体如下图所示。我们不需要低功耗模模式,因此将该寄存器设置为0,关闭低功耗模式。

18_SPI编程_第36张图片

18.5.1.7 FIFO使能设置,

该寄存器地址为0x23,用于使能传感器的FIFO,具体如下图所示。由于我们不需要FIFO,因此我们将该寄存器值设定为0,关闭所有FIFO。

18_SPI编程_第37张图片

18.5.1.8 电源管理设置1

该寄存器地址为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)]

18.5.1.9 电源管理设置2

该寄存器地址为0x6C,可以设置传感器使能等,具体如下图所示。我们使用所有的传感器,因此将该值设置为0x00。

18_SPI编程_第38张图片

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);//使能传感器

18.5.2读取ICM-20608-G的设备ID

设备ID,该寄存器地址为0x75,可以读取WHO_AM_I信息。WHO_AM_I是一个8位设备ID,该值默认为0xAF,具体如下图所示。

18_SPI编程_第39张图片

读取设备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;
        }

18.5.3 读取ICM-20608-G的温度信息

温度传感器数据,该值分为高低两个字节,分别对应寄存器地址0x41和0x42。对应计算公司为Temp_degC = (Temp_out-RoomTemp_Offset)/Temp_sensitivity)+25degC。具体如下图所示

18_SPI编程_第40张图片

读取温度相关的代码如下所示,这部分的代码在**裸机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]);
 

18.5.4 读取ICM-20608-G的加速度信息

ICM-20608-G支持加速度测量,对应地址为从寄存器地址59到64。其中59和60地址对应X轴加速度高低字节,61和62地址对应Y轴加速度高低字节,63和64地址对应Z轴高低字节。高低字节拼接之后进行处理即可。具体如下图所示

18_SPI编程_第41张图片

读取加速度相关的代码如下所示,这部分的代码在**裸机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]);

18.5.5 读取ICM-20608-G的角速度信息

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]);

18.6 上机实验

18.6.1 SPI控制器初始化测试(无示波器可不进行观察试验)

执行函数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;

 }
18.6.1.1 参考章节《4-1.4编译程序》编译程序

进入**裸机Git仓库 NoosProgramProject/18_SPI编程/001_spi_init)**源码目录进行编译。

18.6.1.2 参考章节《3-1.4映像文件烧写、运行》烧写、运行程序

实验结果如图所示:

18.6.2 SPI控制器回环测试

该实验主要用于测试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实现回环测试,调用代码如下所示:

18.6.2.1 参考章节《4-1.4编译程序》编译程序

进入 **裸机Git仓库 NoosProgramProject/18_SPI编程/002_spi_loopback)**源码目录进行编译。

18.6.2. 参考章节《3-1.4映像文件烧写、运行》烧写、运行程序

测试结果记录如下,可以看到读取和写入的数据相同

18_SPI编程_第42张图片

18.6.3 读取ICM-20608-G的设备ID

该实验用于测试读取与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;

 }
18.6.3.1 参考章节《4-1.4编译程序》编译程序

进入**裸机Git仓库 NoosProgramProject/18_SPI编程/003_spi_read_icm20608_id/)**源码目录进行编译。

18.6.3.4 参考章节《3-1.4映像文件烧写、运行》烧写、运行程序

测试结果如下所示,可以看到读取到的ID是0xAF,与ICM-20608-G的ID一致。

image-20220107171628819

18.6.4 读取ICM-20608-G的传感器信息

通过读取寄存器的值读取传感器信息,包括温度、三轴角速度和加速度值。

裸机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;

 }
18.6.4.1 参考章节《4-1.4编译程序》编译程序

进入 **裸机Git仓库 NoosProgramProject/18_SPI编程/004_read_sensor_data)**源码目录进行编译。

18.6.4.2 参考章节《3-1.4映像文件烧写、运行》烧写、运行程序

测试结果记录如下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RaiAJwpb-1642060457339)(https://cdn.jsdelivr.net/gh/DongshanPI/HomeSite-Photos@main/IMX6ULL-BareMetal/SPI_program_bare_metal_image-20220107170705702.png)]

你可能感兴趣的