> 文章列表 > 19_I.MX6ULL_SPI实验

19_I.MX6ULL_SPI实验

19_I.MX6ULL_SPI实验

目录

SPI简介

I.MX6U ECSPI简介

相关寄存器

ICM-20608简介

实验源码 


SPI简介

同I2C一样,SPI是很常用的通信接口,也可以通过SPI来连接众多的传感器。相比I2C接口, SPI接口的通信速度很快, I2C最多400KHz,但是SPI可以到达几十MHz。I.MX6U也有4个SPI接口,可以通过这4个SPI接口来连接一些 SPI外设。

I2C是串行通信的一种,只需要两根线就可以完成主机和从机之间的通信,但是I2C的速度最高只能到400KHz,如果对于访问速度要求比价高的话I2C就不适合了。另外一个和I2C一样广泛使用的串行通信: SPI, SPI全称是SerialPerripheral Interface,也就是串行外围设备接口。SPI是Motorola公司推出的一种同步串行接口技术,是一种高速、全双工的同步通信总线,SPI 时钟频率相比I2C要高很多,最高可以工作在上百MHz。SPI以主从方式工作,通常是有一个主设备和一个或多个从设备,一般SPI需要4根线,但是也可以使用三根线(单向传输),标准的4线SPI,这四根线如下:

1.CS/SS, Slave Select/Chip Select,这个是片选信号线,用于选择需要进行通信的从设备。I2C主机是通过发送从机设备地址来选择需要进行通信的从机设备的,SPI主机不需要发送从机设备,直接将相应的从机设备片选信号拉低即可。

2.SCK, Serial Clock,串行时钟,和I2C的SCL一样,为SPI通信提供时钟。

3.MOSI/SDO, Master Out Slave In/Serial Data Output,简称主出从入信号线,这根数据线只能用于主机向从机发送数据,也就是主机输出,从机输入。

4.MISO/SDI, Master In Slave Out/Serial Data Input,简称主入从出信号线,这根数据线只能用户从机向主机发送数据,也就是主机输入,从机输出。

SPI通信都是由主机发起的,主机需要提供通信的时钟信号。主机通过SPI线连接多个从设备的结构如图所示:

SPI有四种工作模式,通过串行时钟极性(CPOL)和相位(CPHA)的搭配来得到四种工作模式:

1.CPOL=0,串行时钟空闲状态为低电平。

2.CPOL=1,串行时钟空闲状态为高电平,此时可以通过配置时钟相位(CPHA)来选择具体的传输协议。

3.CPHA=0,串行时钟的第一个跳变沿(上升沿或下降沿)采集数据。

4.CPHA=1,串行时钟的第二个跳变沿(上升沿或下降沿)采集数据。

这四种工作模式如图所示:

 

 跟I2C一样, SPI也是有时序图的,以CPOL-0, CPHA=0这个工作模式为例, SPI进行全双工通信的时序如图所示:

 从图可以看出,SPI的时序图很简单,不像I2C那样还要分为读时序和写时序,因为SPI是全双工的,所以读写时序可以一起完成。图中CS片选信号先拉低,选中要通信的从设备,然后通过MOSI和MISO这两根数据线进行收发数据, MOSI数据线发出了0XD2这个数据给从设备,同时从设备也通过MISO线给主设备返回了0X66这个数据。这个就是 SPI 时序图。关于 SPI 就讲解到这里,看一下I.MX6U自带的SPI外设:ECSPI。

I.MX6U ECSPI简介

I.MX6U自带的SPI外设叫做ECSPI,全称是Enhanced Configurable Serial Peripheral Interface,别看前面加了个"EC”就以为和标准SPI有啥不同的,其实就是SPI。ECSPI有64*32个接收FIFO(RXFIFO)和64*32个发送FIFO(TXFIFO),ECSPI 特性如下:

1.全双工同步串行接口。

2.可配置的主/从模式。

3.四个片选信号,支持多从机。

4.发送和接收都有一个32x64的FIFO。

5.片选信号SS/CS,时钟信号SCLK极性可配置。

6.支持DMA。

相关寄存器

ECSPIx_CONREG(x=1-4)寄存器

BURST_LENGTH(bit31:24):突发长度,设置SPI的突发传输数据长度,在一次SPI发送中最大可以发送2^12bit数据。可以设置0X000-0XFFF,分别对应1~2^12bit。我们一般设置突发长度为一个字节,也就是 8bit,BURST_LENGTH=7。

CHANNEL_SELECT(bit19:18):SPI通道选择,一个ECSPI有四个硬件片选信号,每个片选信号是一个硬件通道,虽然实验使用的软件片选,但是SPI通道还是要选择的。可设置为0-3,分别对应通道0-3。

DRCTL(bit17:16):SPI的SPI_RDY信号控制位,用于设置SPI_RDY信号,为0的话不关心SPI_RDY信号;为1的话SPI_RDY信号为边沿触发;为2的话SPI_DRY是电平触发。

PRE-DIVIDER(bit15:12): SPI预分频, ECSPI时钟频率使用两步来完成分频,此位设置的是第一步,可设置 0-15,分别对应1~16分频。

POST_DIVIDER(bit11:8):SPI分频值,ECSPI时钟频率的第二步分频设置,分频值为2^POST_DIVIDER。

CHANNEL-MODE(bit7:4): SPI通道主/从模式设置, CHANNEL-MODE[3:0]分别对应SPI通道3-0,为0的话就是设置为从模式,如果为1的话就是主模式。比如设置为0x01的话就是设置通道0为主模式。

SMC(bit3):开始模式控制,此位只能在主模式下起作用,为0的话通过XCH位来开启SPI突发访问,为1的话只要向TXFIFO写入数据就开启SPI突发访问。

XCH(bit2):此位只在主模式下起作用,当SMC为0的话此位用来控制SPI突发访问的开启。

HT(bit1):HT模式使能位,I.MX6ULL不支持。

EN(bit0): SPI使能位,为0的话关闭SPI,为1的话使能SPI

寄存器ECSPIx_CONFIGREG,这个也是ECSPI的配置寄存器,此寄存器结构如图所示:

HT_LENGTH(bit28:24):HT 模式下的消息长度设置,I.MX6ULL不支持。

SCLK_CTL(bit23:20):设置SCLK信号线空闲状态电平,SCLK_CTL[3:0]分别对应通道3-0,为0的话SCLK空闲状态为低电平,为1的话SCLK空闲状态为高电平。

DATA-CTL(bit19:16):设置DATA信号线空闲状态电平, DATA-CTL[3:0]分别对应通道3~0,为0 的话DATA空闲状态为高电平,为1的话DATA空闲状态为低电平。

SS_POL(bit15:12):设置SPI片选信号极性设置,SS_POL[3:0]分别对应通道3-0,为0的话片选信号低电平有效,为1的话片选信号高电平有效。

SCLK-POL(bit7:4): SPI时钟信号极性设置,也就是CPOL, SCLK-POL[3:0]分别对应通·道3-0,为0的话SCLK高电平有效(空闲的时候为低电平),为1 的话SCLK低电平有效(空闲的时候为高电平)。

SCLK_PHA(bit3:0):SPI时钟相位设置,也就是CPHA,SCLK_PHA[3:0]分别对应通道3-0,为0的话串行时钟的第一个跳变沿(上升沿或下降沿)采集数据,为1的话串行时钟的第二个跳变沿(上升沿或下降沿)采集数据。

通过SCLK_POL和SCLK_PHA可以设置SPI的工作模式。

寄存器ECSPIx_PERIODREG,这个是ECSPI的采样周期寄存器,此寄存器结构如图所示:

 

CSD_CTL(bit21:16):片选信号延时控制位,用于设置片选信号和第一个 SPI 时钟信号之间的时间间隔,范围为0-63。

CSRC(bit15):SPI时钟源选择,为0的话选择SPI_CLK为SPI的时钟源,为1的话选择32.768KHz 的晶振为SPI时钟源。我们一般选择SPI_CLK作为SPI时钟源, SPI_CLK时钟来源如图所示:

 

1.这是一个选择器,用于选择根时钟源,由寄存器CSCDR2的位ECSPI_CLK_SEL来控制,为0的话选择pll3_60m作为ECSPI根时钟源。为1的话选择osc_clk作为ECSP1时钟源。

2.ECSPI时钟分频值,由寄存器CSCDR2的位ECSPI_CLK_PODF来控制,分频值为2^ECSPI_CLK_PODF。

3.最终进入ECSPI的时钟,也就是SPI_CLK=60MHz。

SAMPLE_PERIO采样周期寄存器,可设置为0-0X7FFF分别对应0~32767个周期。

TC(bit7):传输完成标志位,为0表示正在传输,为1表示传输完成。

RO(bit6):RXFIFO溢出标志位,为0表示RXFIFO无溢出,为1表示RXFIFO溢出。

RF(bit5):RXFIFO空标志位,为0表示RXFIFO不为空,为1表示RXFIFO为空。

RDR(bit4):RXFIFO数据请求标志位,此位为0表示RXFIFO里面的数据不大于RX_THRESHOLD,此位为1的话表示RXFIFO里面的数据大于RX_THRESHOLD

RR(bit3): RXFIFO就绪标志位,为0的话RXFIFO没有数据,为1的话表示RXFIFO中至少有一个字的数据。

TF(bit2):TXFIFO满标志位,为0的话表示TXFIFO不为满,为1的话表示TXFIFO为满。

TDR(bit1):TXFIFO数据请求标志位,为0表示TXFIFO中的数据大于TX_THRESHOLD,为1表示TXFIFO中的数据不大于TX_THRESHOLD

TE(bit0):TXFIFO空标志位,为0表示TXFIFO中至少有一个字的数据,为1表示TXFIFO为空。

ICM-20608简介

ICM-20608是InvenSense出品的一款6轴MEMS 传感器,包括3轴加速度和3轴陀螺仪。ICM-20608尺寸非常小,只有3x3x0.75mm,采用16P的LGA封装。ICM-20608内部有一个 512字节的FIFO。陀螺仪的量程范围可以编程设置,可选择±250,±500,±1000和±2000°/s,加速度的量程范围也可以编程设置,可选择±2g,±4g,±8g和±16g。陀螺仪和加速度计都是 16 位的 ADC,并且支持I2C和SPI两种协议,使用I2C接口的话通信速度最高可以达到400KHz,使用SPI接口的话通信速度最高可达到8MHz。ICM-20608 特性如下:

1.陀螺仪支持X,Y和Z三轴输出,内部集成16位ADC,测量范围可设置:±250,士500,±1000和±2000°/s。

2.加速度计支持X,Y和Z轴输出,内部集成16位ADC,测量范围可设置±2g,±4g,±4g, ±8g和±16g。

3.用户可编程中断。

4.内部包含512字节的FIFO

5.内部包含一个数字温度传感器。

6.耐10000g的冲击。

7.支持快速I2C,速度可达400KHz。

8.支持SPI,速度可达8MHz。

ICM-20608的3轴方向如图所示:

ICM-20608的结构框图如图所示:

 如果使用I2C接口的话ICM-20608的ADO引脚决定12C设备从地址的最后一位,如果ADO为0的话ICM-20608从设备地址是0X68,如果AD0为1的话ICM-20608从设备地址为0X69本次使用SPI接口,跟上一章使用AP3216C一样, ICM-20608也是通过读写寄存器来配置和读取传感器数据,使用SPI接口读写寄存器需要16个时钟或者更多(如果读写操作包括多个字节的话),第一个字节包含要读写的寄存器地址,寄存器地址最高位是读写标志位,如果是读的话寄存器地址最高位要为1,如果是写的话寄存器地址最高位要为0,剩下的7位才是实际的寄存器地址,寄存器地址后面跟着的就是读写的数据。表列出了实验用到的一些寄存器和位,关于ICM-20608的详细寄存器和位的介绍请参考ICM-20608的寄存器手册:

实验源码 

#ifndef __BSP_SPI_H_
#define __BSP_SPI_H_#include "imx6ul.h"void spi_init(ECSPI_Type *base);
unsigned char spich0_readwrite_byte(ECSPI_Type *base, unsigned char txdata);#endif
#include "bsp_spi.h"/ @description		: SPI初始化* @param - base 	: 要初始化的IIC设置* @return 			: 无*/
void spi_init(ECSPI_Type *base)
{/* 配置CONREG寄存器* bit0 : 		1 	使能ECSPI* bit3 : 		1	当向TXFIFO写入数据以后立即开启SPI突发。* bit[7:4] : 	0001 SPI通道0主模式,根据实际情况选择,*            	   	开发板上的ICM-20608接在SS0上,所以设置通道0为主模式* bit[19:18]:	00 	选中通道0(其实不需要,因为片选信号我们我们自己控制)* bit[31:20]:	0x7	突发长度为8个bit。 */base->CONREG = 0; /* 先清除控制寄存器 */base->CONREG |= (1 << 0) | (1 << 3) | (1 << 4) | (7 << 20); /* 配置CONREG寄存器 *// ECSPI通道0设置,即设置CONFIGREG寄存器* bit0:	0 通道0 PHA为0* bit4:	0 通道0 SCLK高电平有效* bit8: 	0 通道0片选信号 当SMC为1的时候此位无效* bit12:	0 通道0 POL为0* bit16:	0 通道0 数据线空闲时高电平* bit20:	0 通道0 时钟线空闲时低电平*/base->CONFIGREG = 0; 		/* 设置通道寄存器 *//*  * ECSPI通道0设置,设置采样周期* bit[14:0] :	0X2000  采样等待周期,比如当SPI时钟为10MHz的时候*  		    0X2000就等于1/10000 * 0X2000 = 0.8192ms,也就是连续*          	读取数据的时候每次之间间隔0.8ms* bit15	 :  0  采样时钟源为SPI CLK* bit[21:16]:  0  片选延时,可设置为0~63*/base->PERIODREG = 0X2000;		/* 设置采样周期寄存器 *// ECSPI的SPI时钟配置,SPI的时钟源来源于pll3_sw_clk/8=480/8=60MHz* 通过设置CONREG寄存器的PER_DIVIDER(bit[11:8])和POST_DIVEDER(bit[15:12])来* 对SPI时钟源分频,获取到我们想要的SPI时钟:* SPI CLK = (SourceCLK / PER_DIVIDER) / (2^POST_DIVEDER)* 比如我们现在要设置SPI时钟为6MHz,那么PER_DIVEIDER和POST_DEIVIDER设置如下:* PER_DIVIDER = 0X9。* POST_DIVIDER = 0X0。* SPI CLK = 60000000/(0X9 + 1) = 60000000=6MHz*/base->CONREG &= ~((0XF << 12) | (0XF << 8));	/* 清除PER_DIVDER和POST_DIVEDER以前的设置 */base->CONREG |= (0X9 << 12);					/* 设置SPI CLK = 6MHz */}/ @description		: SPI通道0发送/接收一个字节的数据* @param - base	: 要使用的SPI* @param - txdata	: 要发送的数据* @return 			: 无*/
unsigned char spich0_readwrite_byte(ECSPI_Type *base, unsigned char txdata)
{ uint32_t  spirxdata = 0;uint32_t  spitxdata = txdata;/* 选择通道0 */base->CONREG &= ~(3 << 18);base->CONREG |= (0 << 18);while((base->STATREG & (1 << 0)) == 0){} /* 等待发送FIFO为空 */base->TXDATA = spitxdata;while((base->STATREG & (1 << 3)) == 0){} /* 等待接收FIFO有数据 */spirxdata = base->RXDATA;return spirxdata;
}
#ifndef __BSP_ICM20608_H_
#define __BSP_ICM20608_H_#include "imx6ul.h"
#include "bsp_gpio.h"/* 宏定义 */
#define ICM20608_CSN(n)    (n ? gpio_pinwrite(GPIO1, 20, 1) : gpio_pinwrite(GPIO1, 20, 0))   /* SPI片选信号	 */#define ICM20608G_ID			0XAF	/* ID值 */
#define ICM20608D_ID			0XAE	/* ID值 *//* ICM20608寄存器 *复位后所有寄存器地址都为0,除了*Register 107(0X6B) Power Management 1 	= 0x40*Register 117(0X75) WHO_AM_I 				= 0xAF或0xAE*/
/* 陀螺仪和加速度自测(出产时设置,用于与用户的自检输出值比较) */
#define	ICM20_SELF_TEST_X_GYRO		0x00
#define	ICM20_SELF_TEST_Y_GYRO		0x01
#define	ICM20_SELF_TEST_Z_GYRO		0x02
#define	ICM20_SELF_TEST_X_ACCEL		0x0D
#define	ICM20_SELF_TEST_Y_ACCEL		0x0E
#define	ICM20_SELF_TEST_Z_ACCEL		0x0F/* 陀螺仪静态偏移 */
#define	ICM20_XG_OFFS_USRH			0x13
#define	ICM20_XG_OFFS_USRL			0x14
#define	ICM20_YG_OFFS_USRH			0x15
#define	ICM20_YG_OFFS_USRL			0x16
#define	ICM20_ZG_OFFS_USRH			0x17
#define	ICM20_ZG_OFFS_USRL			0x18#define	ICM20_SMPLRT_DIV			0x19
#define	ICM20_CONFIG				0x1A
#define	ICM20_GYRO_CONFIG			0x1B
#define	ICM20_ACCEL_CONFIG			0x1C
#define	ICM20_ACCEL_CONFIG2			0x1D
#define	ICM20_LP_MODE_CFG			0x1E
#define	ICM20_ACCEL_WOM_THR			0x1F
#define	ICM20_FIFO_EN				0x23
#define	ICM20_FSYNC_INT				0x36
#define	ICM20_INT_PIN_CFG			0x37
#define	ICM20_INT_ENABLE			0x38
#define	ICM20_INT_STATUS			0x3A/* 加速度输出 */
#define	ICM20_ACCEL_XOUT_H			0x3B
#define	ICM20_ACCEL_XOUT_L			0x3C
#define	ICM20_ACCEL_YOUT_H			0x3D
#define	ICM20_ACCEL_YOUT_L			0x3E
#define	ICM20_ACCEL_ZOUT_H			0x3F
#define	ICM20_ACCEL_ZOUT_L			0x40/* 温度输出 */
#define	ICM20_TEMP_OUT_H			0x41
#define	ICM20_TEMP_OUT_L			0x42/* 陀螺仪输出 */
#define	ICM20_GYRO_XOUT_H			0x43
#define	ICM20_GYRO_XOUT_L			0x44
#define	ICM20_GYRO_YOUT_H			0x45
#define	ICM20_GYRO_YOUT_L			0x46
#define	ICM20_GYRO_ZOUT_H			0x47
#define	ICM20_GYRO_ZOUT_L			0x48#define	ICM20_SIGNAL_PATH_RESET		0x68
#define	ICM20_ACCEL_INTEL_CTRL 		0x69
#define	ICM20_USER_CTRL				0x6A
#define	ICM20_PWR_MGMT_1			0x6B
#define	ICM20_PWR_MGMT_2			0x6C
#define	ICM20_FIFO_COUNTH			0x72
#define	ICM20_FIFO_COUNTL			0x73
#define	ICM20_FIFO_R_W				0x74
#define	ICM20_WHO_AM_I 				0x75/* 加速度静态偏移 */
#define	ICM20_XA_OFFSET_H			0x77
#define	ICM20_XA_OFFSET_L			0x78
#define	ICM20_YA_OFFSET_H			0x7A
#define	ICM20_YA_OFFSET_L			0x7B
#define	ICM20_ZA_OFFSET_H			0x7D
#define	ICM20_ZA_OFFSET_L 			0x7E/ ICM20608结构体*/
struct icm20608_dev_struc
{signed int gyro_x_adc;		/* 陀螺仪X轴原始值 */signed int gyro_y_adc;		/* 陀螺仪Y轴原始值 */signed int gyro_z_adc;		/* 陀螺仪Z轴原始值 */signed int accel_x_adc;		/* 加速度计X轴原始值 */signed int accel_y_adc;		/* 加速度计Y轴原始值 */signed int accel_z_adc;		/* 加速度计Z轴原始值 */signed int temp_adc;		/* 温度原始值 *//* 下面是计算得到的实际值,扩大100倍 */signed int gyro_x_act;		/* 陀螺仪X轴实际值 */signed int gyro_y_act;		/* 陀螺仪Y轴实际值 */signed int gyro_z_act;		/* 陀螺仪Z轴实际值 */signed int accel_x_act;		/* 加速度计X轴实际值 */signed int accel_y_act;		/* 加速度计Y轴实际值 */signed int accel_z_act;		/* 加速度计Z轴实际值 */signed int temp_act;		/* 温度实际值 */
};struct icm20608_dev_struc icm20608_dev;	/* icm20608设备 *//* 函数声明 */
unsigned char icm20608_init(void);
void icm20608_write_reg(unsigned char reg, unsigned char value);
unsigned char icm20608_read_reg(unsigned char reg);
void icm20608_read_len(unsigned char reg, unsigned char *buf, unsigned char len);
void icm20608_getdata(void);#endif
#include "bsp_icm20608.h"
#include "bsp_delay.h"
#include "bsp_spi.h"
#include "stdio.h"struct icm20608_dev_struc icm20608_dev;	/* icm20608设备 *// @description	: 初始化ICM20608* @param		: 无* @return 		: 0 初始化成功,其他值 初始化失败*/
unsigned char icm20608_init(void)
{	unsigned char regvalue;gpio_pin_config_t cs_config;/* 1、ESPI3 IO初始化 * ECSPI3_SCLK 	-> UART2_RXD* ECSPI3_MISO 	-> UART2_RTS* ECSPI3_MOSI	-> UART2_CTS*/IOMUXC_SetPinMux(IOMUXC_UART2_RX_DATA_ECSPI3_SCLK, 0);IOMUXC_SetPinMux(IOMUXC_UART2_CTS_B_ECSPI3_MOSI, 0);IOMUXC_SetPinMux(IOMUXC_UART2_RTS_B_ECSPI3_MISO, 0);/* 配置SPI   SCLK MISO MOSI IO属性	*bit 16: 0 HYS关闭*bit [15:14]: 00 默认100K下拉*bit [13]: 0 keeper功能*bit [12]: 1 pull/keeper使能 *bit [11]: 0 关闭开路输出*bit [7:6]: 10 速度100Mhz*bit [5:3]: 110 驱动能力为R0/6*bit [0]: 1 高转换率*/IOMUXC_SetPinConfig(IOMUXC_UART2_RX_DATA_ECSPI3_SCLK, 0x10B1);IOMUXC_SetPinConfig(IOMUXC_UART2_CTS_B_ECSPI3_MOSI, 0x10B1);IOMUXC_SetPinConfig(IOMUXC_UART2_RTS_B_ECSPI3_MISO, 0x10B1);/* 片选引脚初始化 软件SPI CS 就是配置成GPIO*/IOMUXC_SetPinMux(IOMUXC_UART2_TX_DATA_GPIO1_IO20, 0);IOMUXC_SetPinConfig(IOMUXC_UART2_TX_DATA_GPIO1_IO20, 0X10B0);cs_config.direction = kGPIO_DigitalOutput;cs_config.outputLogic = 0;gpio_init(GPIO1, 20, &cs_config);/* 2、初始化SPI */spi_init(ECSPI3);	icm20608_write_reg(ICM20_PWR_MGMT_1, 0x80);		/* 复位,复位后为0x40,睡眠模式 			*/delay_ms(50);icm20608_write_reg(ICM20_PWR_MGMT_1, 0x01);		/* 关闭睡眠,自动选择时钟 					*/delay_ms(50);regvalue = icm20608_read_reg(ICM20_WHO_AM_I);printf("icm20608 id = %#X\\r\\n", regvalue);if(regvalue != ICM20608G_ID && regvalue != ICM20608D_ID)return 1;icm20608_write_reg(ICM20_SMPLRT_DIV, 0x00); 	/* 输出速率是内部采样率					*/icm20608_write_reg(ICM20_GYRO_CONFIG, 0x18); 	/* 陀螺仪±2000dps量程 				*/icm20608_write_reg(ICM20_ACCEL_CONFIG, 0x18); 	/* 加速度计±16G量程 					*/icm20608_write_reg(ICM20_CONFIG, 0x04); 		/* 陀螺仪低通滤波BW=20Hz 				*/icm20608_write_reg(ICM20_ACCEL_CONFIG2, 0x04); 	/* 加速度计低通滤波BW=21.2Hz 			*/icm20608_write_reg(ICM20_PWR_MGMT_2, 0x00); 	/* 打开加速度计和陀螺仪所有轴 				*/icm20608_write_reg(ICM20_LP_MODE_CFG, 0x00); 	/* 关闭低功耗 						*/icm20608_write_reg(ICM20_FIFO_EN, 0x00);		/* 关闭FIFO						*/return 0;
}/ @description  : 写ICM20608指定寄存器* @param - reg  : 要读取的寄存器地址* @param - value: 要写入的值* @return		 : 无*/
void icm20608_write_reg(unsigned char reg, unsigned char value)
{/* ICM20608在使用SPI接口的时候寄存器地址* 只有低7位有效,寄存器地址最高位是读/写标志位* 读的时候要为1,写的时候要为0。*/reg &= ~0X80;	ICM20608_CSN(0);						/* 使能SPI传输			*/spich0_readwrite_byte(ECSPI3, reg); 	/* 发送寄存器地址		*/ spich0_readwrite_byte(ECSPI3, value);	/* 发送要写入的值			*/ICM20608_CSN(1);						/* 禁止SPI传输			*/
}	/ @description	: 读取ICM20608寄存器值* @param - reg	: 要读取的寄存器地址* @return 		: 读取到的寄存器值*/
unsigned char icm20608_read_reg(unsigned char reg)
{unsigned char reg_val;	   	/* ICM20608在使用SPI接口的时候寄存器地址* 只有低7位有效,寄存器地址最高位是读/写标志位* 读的时候要为1,写的时候要为0。*/reg |= 0x80; 	ICM20608_CSN(0);               					/* 使能SPI传输	 		*/spich0_readwrite_byte(ECSPI3, reg);     		/* 发送寄存器地址  		*/ reg_val = spich0_readwrite_byte(ECSPI3, 0XFF);	/* 读取寄存器的值 			*/ICM20608_CSN(1);                				/* 禁止SPI传输 			*/return(reg_val);               	 				/* 返回读取到的寄存器值 */
}/ @description	: 读取ICM20608连续多个寄存器* @param - reg	: 要读取的寄存器地址* @return 		: 读取到的寄存器值*/
void icm20608_read_len(unsigned char reg, unsigned char *buf, unsigned char len)
{  unsigned char i;/* ICM20608在使用SPI接口的时候寄存器地址,只有低7位有效,* 寄存器地址最高位是读/写标志位读的时候要为1,写的时候要为0。*/reg |= 0x80; ICM20608_CSN(0);               				/* 使能SPI传输	 		*/spich0_readwrite_byte(ECSPI3, reg);			/* 发送寄存器地址  		*/   	   for(i = 0; i < len; i++)					/* 顺序读取寄存器的值 			*/{buf[i] = spich0_readwrite_byte(ECSPI3, 0XFF);	}ICM20608_CSN(1);                			/* 禁止SPI传输 			*/
}/ @description : 获取陀螺仪的分辨率* @param		: 无* @return		: 获取到的分辨率*/
float icm20608_gyro_scaleget(void)
{unsigned char data;float gyroscale;data = (icm20608_read_reg(ICM20_GYRO_CONFIG) >> 3) & 0X3;switch(data) {case 0: gyroscale = 131;break;case 1:gyroscale = 65.5;break;case 2:gyroscale = 32.8;break;case 3:gyroscale = 16.4;break;}return gyroscale;
}/ @description : 获取加速度计的分辨率* @param		: 无* @return		: 获取到的分辨率*/
unsigned short icm20608_accel_scaleget(void)
{unsigned char data;unsigned short accelscale;data = (icm20608_read_reg(ICM20_ACCEL_CONFIG) >> 3) & 0X3;switch(data) {case 0: accelscale = 16384;break;case 1:accelscale = 8192;break;case 2:accelscale = 4096;break;case 3:accelscale = 2048;break;}return accelscale;
}/ @description : 读取ICM20608的加速度、陀螺仪和温度原始值* @param 		: 无* @return		: 无*/
void icm20608_getdata(void)
{float gyroscale;unsigned short accescale;unsigned char data[14];icm20608_read_len(ICM20_ACCEL_XOUT_H, data, 14);gyroscale = icm20608_gyro_scaleget();accescale = icm20608_accel_scaleget();icm20608_dev.accel_x_adc = (signed short)((data[0] << 8) | data[1]); icm20608_dev.accel_y_adc = (signed short)((data[2] << 8) | data[3]); icm20608_dev.accel_z_adc = (signed short)((data[4] << 8) | data[5]); icm20608_dev.temp_adc    = (signed short)((data[6] << 8) | data[7]); icm20608_dev.gyro_x_adc  = (signed short)((data[8] << 8) | data[9]); icm20608_dev.gyro_y_adc  = (signed short)((data[10] << 8) | data[11]);icm20608_dev.gyro_z_adc  = (signed short)((data[12] << 8) | data[13]);/* 计算实际值 */icm20608_dev.gyro_x_act = ((float)(icm20608_dev.gyro_x_adc)  / gyroscale) * 100;icm20608_dev.gyro_y_act = ((float)(icm20608_dev.gyro_y_adc)  / gyroscale) * 100;icm20608_dev.gyro_z_act = ((float)(icm20608_dev.gyro_z_adc)  / gyroscale) * 100;icm20608_dev.accel_x_act = ((float)(icm20608_dev.accel_x_adc) / accescale) * 100;icm20608_dev.accel_y_act = ((float)(icm20608_dev.accel_y_adc) / accescale) * 100;icm20608_dev.accel_z_act = ((float)(icm20608_dev.accel_z_adc) / accescale) * 100;icm20608_dev.temp_act = (((float)(icm20608_dev.temp_adc) - 25 ) / 326.8 + 25) * 100;
}
#include "bsp_clk.h"#include "bsp_delay.h"#include "bsp_led.h"#include "bsp_beep.h"#include "bsp_key.h"#include "bsp_interrupt.h"#include "bsp_uart.h"#include "bsp_lcd.h"#include "bsp_lcdapi.h"#include "bsp_rtc.h"#include "bsp_ap3216c.h"#include "bsp_icm20608.h"#include "bsp_spi.h"#include "stdio.h"/ @description	: 指定的位置显示整数数据* @param - x	: X轴位置* @param - y 	: Y轴位置* @param - size: 字体大小* @param - num : 要显示的数据* @return 		: 无*/void integer_display(unsigned short x, unsigned short y, unsigned char size, signed int num){char buf[200];lcd_fill(x, y, x + 50, y + size, tftlcd_dev.backcolor);memset(buf, 0, sizeof(buf));if(num < 0)sprintf(buf, "-%d", -num);else sprintf(buf, "%d", num);lcd_show_string(x, y, 50, size, size, buf); }/ @description	: 指定的位置显示小数数据,比如5123,显示为51.23* @param - x	: X轴位置* @param - y 	: Y轴位置* @param - size: 字体大小* @param - num : 要显示的数据,实际小数扩大100倍,* @return 		: 无*/void decimals_display(unsigned short x, unsigned short y, unsigned char size, signed int num){signed int integ; 	/* 整数部分 */signed int fract;	/* 小数部分 */signed int uncomptemp = num; char buf[200];if(num < 0)uncomptemp = -uncomptemp;integ = uncomptemp / 100;fract = uncomptemp % 100;memset(buf, 0, sizeof(buf));if(num < 0)sprintf(buf, "-%d.%d", integ, fract);else sprintf(buf, "%d.%d", integ, fract);lcd_fill(x, y, x + 60, y + size, tftlcd_dev.backcolor);lcd_show_string(x, y, 60, size, size, buf); }/ @description	: 使能I.MX6U的硬件NEON和FPU* @param 		: 无* @return 		: 无*/void imx6ul_hardfpu_enable(void){uint32_t cpacr;uint32_t fpexc;/* 使能NEON和FPU */cpacr = __get_CPACR();cpacr = (cpacr & ~(CPACR_ASEDIS_Msk | CPACR_D32DIS_Msk))|  (3UL << CPACR_cp10_Pos) | (3UL << CPACR_cp11_Pos);__set_CPACR(cpacr);fpexc = __get_FPEXC();fpexc |= 0x40000000UL;	__set_FPEXC(fpexc);}/ @description	: main函数* @param 		: 无* @return 		: 无*/int main(void){unsigned char state = OFF;imx6ul_hardfpu_enable();	/* 使能I.MX6U的硬件浮点 */int_init(); 				/* 初始化中断(一定要最先调用!) */imx6u_clkinit();			/* 初始化系统时钟 */delay_init();				/* 初始化延时 */clk_enable();				/* 使能所有的时钟 */led_init();					/* 初始化led */beep_init();				/* 初始化beep	*/uart_init();				/* 初始化串口,波特率115200 */lcd_init();					/* 初始化LCD */tftlcd_dev.forecolor = LCD_RED;	lcd_show_string(30, 30, 200, 16, 16, (char*)"ALPHA-IMX6U IIC TEST");  lcd_show_string(30, 50, 200, 16, 16, (char*)"AP3216C TEST");  lcd_show_string(30, 70, 200, 16, 16, (char*)"Hello");  lcd_show_string(30, 90, 200, 16, 16, (char*)"2023");  while(icm20608_init())		/* 初始化ICM20608	 			*/{lcd_show_string(50, 130, 200, 16, 16, (char*)"ICM20608 Check Failed!");delay_ms(500);lcd_show_string(50, 100, 200, 16, 16, (char*)"Please Check!        ");delay_ms(500);}	lcd_show_string(50, 120, 200, 16, 16, (char*)"ICM20608 Ready");lcd_show_string(50, 150, 200, 16, 16, (char*)"accel x:");  lcd_show_string(50, 170, 200, 16, 16, (char*)"accel y:");  lcd_show_string(50, 190, 200, 16, 16, (char*)"accel z:");  lcd_show_string(50, 210, 200, 16, 16, (char*)"gyro  x:"); lcd_show_string(50, 230, 200, 16, 16, (char*)"gyro  y:"); lcd_show_string(50, 250, 200, 16, 16, (char*)"gyro  z:"); lcd_show_string(50, 270, 200, 16, 16, (char*)"temp   :"); lcd_show_string(50 + 181, 150, 200, 16, 16, (char*)"g");  lcd_show_string(50 + 181, 170, 200, 16, 16, (char*)"g");  lcd_show_string(50 + 181, 190, 200, 16, 16, (char*)"g");  lcd_show_string(50 + 181, 210, 200, 16, 16, (char*)"o/s"); lcd_show_string(50 + 181, 230, 200, 16, 16, (char*)"o/s"); lcd_show_string(50 + 181, 250, 200, 16, 16, (char*)"o/s"); lcd_show_string(50 + 181, 270, 200, 16, 16, (char*)"C");tftlcd_dev.forecolor = LCD_BLUE;while(1)					{		icm20608_getdata();integer_display(50 + 70, 150, 16, icm20608_dev.accel_x_adc);integer_display(50 + 70, 170, 16, icm20608_dev.accel_y_adc);integer_display(50 + 70, 190, 16, icm20608_dev.accel_z_adc);integer_display(50 + 70, 210, 16, icm20608_dev.gyro_x_adc);integer_display(50 + 70, 230, 16, icm20608_dev.gyro_y_adc);integer_display(50 + 70, 250, 16, icm20608_dev.gyro_z_adc);integer_display(50 + 70, 270, 16, icm20608_dev.temp_adc);decimals_display(50 + 70 + 50, 150, 16, icm20608_dev.accel_x_act);decimals_display(50 + 70 + 50, 170, 16, icm20608_dev.accel_y_act);decimals_display(50 + 70 + 50, 190, 16, icm20608_dev.accel_z_act);decimals_display(50 + 70 + 50, 210, 16, icm20608_dev.gyro_x_act);decimals_display(50 + 70 + 50, 230, 16, icm20608_dev.gyro_y_act);decimals_display(50 + 70 + 50, 250, 16, icm20608_dev.gyro_z_act);decimals_display(50 + 70 + 50, 270, 16, icm20608_dev.temp_act);delay_ms(120);state = !state;led_switch(LED0,state);	}return 0;}