资讯详情

【正点原子Linux连载】第二十七章 SPI实验 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

1)实验平台:正原子阿尔法Linux开发板 2)平台采购地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码 手册 视频下载地址:http://www.openedv.com/thread-300792-1-1.html 3)正点原子Linux感兴趣的学生可以加入小组讨论:935446741 4)关注正点原子公众号,获取最新资料更新 在这里插入图片描述

第二十七章 SPI实验

同I2C一样,SPI它是一种非常常见的通信接口,也可以通过SPI连接多个传感器。相比I2C接口,SPI接口通信速度快,I2C最多400KHz,但是SPI可达几十MHz。I.MX6U也有4个SPI这四个接口可以通过SPI连接一些接口SPI外设。I.MX6U-ALPHA使用SPI3接口连接六轴传感器ICM-本章将学习如何使用20608I.MX6U的SPI接口来驱动ICM-20608,读取ICM-六轴数据20608。 

27.1 SPI & ICM-20608简介 27.1.1 SPI简介 我们解释了上一章I2C,I2C是串行通信的一种,主机和从机之间的通信只需要两条线,但是I2C最高速度只有400KHz,如果要求访问速度比价高,I2C不合适。让我们从这一章中学习另一个和I2C同样广泛使用的串行通信:SPI,SPI全称是Serial Perripheral Interface,即串行外围设备接口。SPI是Motorola公司推出的同步串行接口技术是高速全双工同步通信总线,SPI与时钟频率相比I2C要高很多,最高可以工作几百MHz。SPI以主从方式工作,通常有一个主设备和一个或多个设备SPI需要四条线,但也可以使用三条线(单向传输)。本章将解释标准的四条线SPI,这四条线如下: ①、CS/SS,Slave Select/Chip Select,这是选择需要通信的于选择需要通信的设备。I2C主机通过发送从机设备地址来选择需要通信的从机设备,SPI主机不需要发送从机设备,直接降低相应的从机设备片选择信号。 ②、SCK,Serial Clock,串行时钟,和I2C的SCL一样,为SPI通信提供时钟。 ③、MOSI/SDO,Master Out Slave In/Serial Data Output,简称主出从入信号线,只能用于主机向从机发送数据,即主机输出和从机输入。 ④、MISO/SDI,Master In Slave Out/Serial Data Input,简称主进出信号线,该数据线只能由用户从机发送到主机,即主机输入,从机输出。 SPI通信由主机发起,需要提供通信时钟信号。主机通过SPI从设备的结构如图27所示.1.1.1所示:

图27.1.1.1 SPI设备连接图 SPI串行时钟极性有四种工作模式(CPOL)和相位(CPHA)获得四种工作模式: ①、CPOL=0.串行时钟的空闲状态为低电平。 ②、CPOL=1.串行时钟的空闲状态为高电平,此时可配置时钟相位(CPHA)选择具体的传输协议。 ③、CPHA=0.串行时钟的第一个跳变沿(上升或下降)采集数据。 ④、CPHA=1.串行时钟的第二个跳变沿(上升或下降)采集数据。 这四种工作模式如图27所示.1.1.2所示:

图27.1.1.2 SPI四种工作模式 跟I2C一样,SPI也有时序图,以CPOL=0,CPHA=以这种工作模式为例,SPI全双工通信顺序如图27所示.1.1.3所示:

图27.1.1.3 SPI时序图 从图27.1.1.3可以看出,SPI时序图很简单,不像I2C也分为读时序和写时序,因为SPI全双工,读写时序可以一起完成。图27.1.1.3中,CS片选信号先降低,从设备中选择通信,然后通过MOSI和MISO这两条数据线收发数据,MOSI数据线发出0XD这个数据给设备,也通过设备MISO线返回0给主设备X66这个数据。这个就是SPI时序图。 关于SPI在这里,我们来看看。I.MX6U自带的SPI外设:ECSPI。 27.1.2 I.MX6U ECSPI简介 I.MX6U自带的SPI外设叫做ECSPI,全称是Enhanced Configurable Serial Peripheral Interface,别看前面加了个EC以为和标准SPI有什么区别?其实就是SPI。ECSPI有6432个接收FIFO(RXFIFO)和6432个发送FIFO(TXFIFO),ECSPI特性如下: ①、全双工同步串行接口。 ②、可配置的主/从模式。 ③、支持多从机的四片选信号。 ④、发送和接收32x64的FIFO。 ⑤、片选信号SS/CS,时钟信号SCLK极性可配置。 ⑥、支持DMA。 I.MX6U的ECSPI我们可以在主模式或从模式中工作,本章使用主模式,I.MX6U有4个ECSPI,每个ECSPI支持四个片选信号,也就说,如果你要使用ECSPI如果硬件片选择信号,一个ECSPI可支持4个外设。如果不使用硬件选择信号,我们可以支持无数的外设实验不使用硬件片选信号,因为硬件片选信号只能使用指定的片选信号IO,如果选择软件片,可以使用任何软件片IO。 接下来我们来看看ECSPI先看几个重要的寄存器。ECSPIx_CONREG(x=1~4)寄存器,这是ECSPI的控制寄存器,此寄存器结构如图27.1.2.1所示:

图27.1.2.1 寄存器ECSPIx_CONREG结构 寄存器ECSPIx_CONREG含义如下: BURST_LENGTH(bit31:24):突发长度,设置SPI突然传输数据的长度是一次SPI最大发送212bit数据。可设置0X000~0XFFF,分别对应1~212bit。我们通常把突发长度设置为字节,即8bit,BURST_LENGTH=7。 CHANNEL_SELECT(bit19:18):SPI通道选择,一个ECSPI有四个硬件片选择信号,每个片选择信号都是硬件通道。虽然本章实验使用的软件片选择,但SPI通道通道。可以设置为0三、分别对应通道03。I.MX6U-ALPHA开发板上的ICM-20608年片选信号连接ECSPI3_SS0,也就是ECSPI3通道0,本章实验设置为0。 DRCTL(bit17:16):SPI的SPI_RDY用于设置信号控制位SPI_RDY信号,如果是0,不在乎SPI_RDY信号;为1SPI_RDY边缘触发信号;如果是2,SPI_DRY是电平触发。 PRE_DIVIDER(bit15:12):SPI预分频,ECSPI分频采用时钟频率两成时钟频率。这个位置是第一步,可以设置015,分别对应116分频。 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,只要是1TXFIFO开始写入数据SPI突发访问。 XCH(bit2):这个位置只在主模式下工作,当SMC如果是0,此位用于控制SPI开启突发访问。 HT(bit1):HT模型使能位,I.MX6ULL不支持。 EN(bit0):SPI如果使能位为0,则关闭使能位SPI,为1的话使能SPI。 接下来看看寄存器ECSPIx_CONFIGREG,这个也是ECSPI该寄存器的配置如图27所示.1.2.2所示:

图27.1.2.2 寄存器ECSPIx_CONFIGREG结构 寄存器ECSPIx_CONFIGREG使用的重要性如下: HT_LENGTH(bit28:24):HT设置模式下的消息长度,I.MX6ULL不支持。 SCLK_CTL(bit23:20):设置SCLK信号线空闲状态电平,SCLK_CTL[3:0]分别对应通道3~0,为0的话SCLK空闲状态为低电平,为的话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的采样周期寄存器,此寄存器结构如图27.1.2.3所示:

图27.1.2.3 寄存器ECSPIx_PERIODREG结构 寄存器ECSPIx_PERIODREG用到的重要位如下: CSD_CTL(bit21:16):片选信号延时控制位,用于设置片选信号和第一个SPI时钟信号之间的时间间隔,范围为0~63。 CSRC(bit15):SPI时钟源选择,为0的话选择SPI CLK为SPI的时钟源,为1的话选择32.768KHz的晶振为SPI时钟源。我们一般选择SPI CLK作为SPI时钟源,SPI CLK时钟来源如图27.1.2.4所示:

图27.1.2.4 SPI CLK时钟源 图27.1.2.4中各部分含义如下: ①、这是一个选择器,用于选择根时钟源,由寄存器CSCDR2的位ECSPI_CLK_SEL来控制,为0的话选择pll3_60m作为ECSPI根时钟源。为1的话选择osc_clk作为ECSPI时钟源。本章我们选择pll3_60m作为ECSPI根时钟源。 ②、ECSPI时钟分频值,由寄存器CSCDR2的位ECSPI_CLK_PODF来控制,分频值为2^ECSPI_CLK_PODF。本章我们设置为0,也就是1分频。 ③、最终进入ECSPI的时钟,也就是SPI CLK=60MHz。 SAMPLE_PERIO:采样周期寄存器,可设置为00X7FFF分别对应032767个周期。 接下来看一下寄存器ECSPIx_STATREG,这个是ECSPI的状态寄存器,此寄存器结构如图27.1.2.5所示:

图27.1.2.5 寄存器ECSPIx_STATREG寄存器 寄存器ECSPIx_STATREG用到的重要位如下: 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为空。 最后就是两个数据寄存器,ECSPIx_TXDATA和ECSPIx_RXDATA,这两个寄存器都是32位的,如果要发送数据就向寄存器ECSPIx_TXDATA写入数据,读取及存取ECSPIx_RXDATA里面的数据就可以得到刚刚接收到的数据。 关于ECSPI的寄存器就介绍到这里,关于这些寄存器详细的描述,请参考《I.MX6ULL参考手册》第805页的20.7小节。 27.1.3 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。I.MX6U-ALPHA开发板上的ICM-20608通过SPI接口和I.MX6U连接在一起。ICM-20608特性如下: ①、陀螺仪支持X,Y和Z三轴输出,内部集成16位ADC,测量范围可设置:±250,±500,±1000和±2000°/s。 ②、加速度计支持X,Y和Z轴输出,内部集成16位ADC,测量范围可设置:±2g,±4g,±4g,±8g和±16g。 ③、用户可编程中断。 ④、内部包含512字节的FIFO。 ⑤、内部包含一个数字温度传感器。 ⑥、耐10000g的冲击。 ⑦、支持快速I2C,速度可达400KHz。 ⑧、支持SPI,速度可达8MHz。 ICM-20608的3轴方向如图27.1.3.1所示:

图27.1.3.1 ICM-20608检测轴方向和极性 ICM-20608的结构框图如图27.1.3.2所示:

图27.1.3.2 ICM-20608框图 如果使用IIC接口的话ICM-20608的AD0引脚决定I2C设备从地址的最后一位,如果AD0为0的话ICM-20608从设备地址是0X68,如果AD0为1的话ICM-20608从设备地址为0X69。本章我们使用SPI接口,跟上一章使用AP3216C一样,ICM-20608也是通过读写寄存器来配置和读取传感器数据,使用SPI接口读写寄存器需要16个时钟或者更多(如果读写操作包括多个字节的话),第一个字节包含要读写的寄存器地址,寄存器地址最高位是读写标志位,如果是读的话寄存器地址最高位要为1,如果是写的话寄存器地址最高位要为0,剩下的7位才是实际的寄存器地址,寄存器地址后面跟着的就是读写的数据。表27.1.3.1列出了本章实验用到的一些寄存器和位,关于ICM-20608的详细寄存器和位的介绍请参考ICM-20608的寄存器手册: 寄存器地址 位 寄存器功能 描述 0X19 SMLPRT_DIV[7:0] 输出速率设置 设置输出速率,输出速率计算公式如下: SAMPLE_RATE=INTERNAL_SAMPLE_RATE/ (1 + SMPLRT_DIV) 0X1A DLPF_CFG[2:0] 芯片配置 设置陀螺仪低通滤波。可设置0~7。 0X1B FS_SEL[1:0] 陀螺仪量程设置 0:±250dps;1:±500dps;2:±1000dps 3:±2000dps 0X1C ACC_FS_SEL[1:0] 加速度计量程设置 0:±2g;1:±4g;2:±8g;3:±16g 0X1D A_DLPF_CFG[2:0] 加速度计低通滤波设置 设置加速度计的低通滤波,可设置0~7。 0X1E GYRO_CYCLE[7] 陀螺仪低功耗使能 0:关闭陀螺仪的低功耗功能。 1:使能陀螺仪的低功耗功能。 0X23 TEMP_FIFO_EN[7] FIFO使能控制 1:使能温度传感器FIFO。 0:关闭温度传感器FIFO。 XG_FIFO_EN[6] 1:使能陀螺仪X轴FIFO。 0:关闭陀螺仪X轴FIFO。 YG_FIFO_EN[5] 1:使能陀螺仪Y轴FIFO。 0:关闭陀螺仪Y轴FIFO。 ZG_FIFO_EN[4] 1:使能陀螺仪Z轴FIFO。 0:关闭陀螺仪Z轴FIFO。 ACCEL_FIFO_EN[3] 1:使能加速度计FIFO。 0:关闭加速度计FIFO。 0X3B ACCEL_XOUT_H[7:0] 数据寄存器 加速度X轴数据高8位 0X3C ACCEL_XOUT_L[7:0] 加速度X轴数据低8位 0X3D ACCEL_YOUT_H[7:0] 加速度Y轴数据高8位 0X3E ACCEL_YOUT_L[7:0] 加速度Y轴数据低8位 0X3F ACCEL_ZOUT_H[7:0] 加速度Z轴数据高8位 0X40 ACCEL_ZOUT_L[7:0] 加速度Z轴数据低8位 0X41 TEMP_OUT_H[7:0] 温度数据高8位 0X42 TEMP_OUT_L[7:0] 温度数据低8位 0X43 GYRO_XOUT_H[7:0] 陀螺仪X轴数据高8位 0X44 GYRO_XOUT_L[7:0] 陀螺仪X轴数据低8位 0X45 GYRO_YOUT_H[7:0] 陀螺仪Y轴数据高8位 0X46 GYRO_YOUT_L[7:0] 陀螺仪Y轴数据低8位 0X47 GYRO_ZOUT_H[7:0] 陀螺仪Z轴数据高8位 0X48 GYRO_ZOUT_L[7:0] 陀螺仪Z轴数据低8位 0X6B DEVICE_RESET[7] 电源管理寄存器1 1:复位ICM-20608。 SLEEP[6] 0:退出休眠模式;1,进入休眠模式 0X6C STBY_XA[5] 电源管理寄存器2 0:使能加速度计X轴。 1:关闭加速度计X轴。 STBY_YA[4] 0:使能加速度计Y轴。 1:关闭加速度计Y轴。 STBY_ZA[3] 0:使能加速度计Z轴。 1:关闭加速度计Z轴。 STBY_XG[2] 0:使能陀螺仪X轴。 1:关闭陀螺仪X轴。 STBY_YG[1] 0:使能陀螺仪Y轴。 1:关闭陀螺仪Y轴。 STBY_ZG[0] 0:使能陀螺仪Z轴。 1:关闭陀螺仪Z轴。 0X75 WHOAMI[7:0] ID寄存器,ICM-20608G的ID为0XAF, ICM-20608D的ID为0XAE。 表27.1.3.1 ICM-20608寄存器表 ICM-20608的介绍就到这里,关于ICM-20608的详细介绍请参考ICM-20608的数据手册和寄存器手册。 27.2 硬件原理分析 本试验用到的资源如下: ①、指示灯LED0。 ②、 RGB LCD屏幕。 ③、ICM20608 ④、串口 ICM-20608是在I.MX6U-ALPHA开发板底板上,原理图如图27.2.1所示:

图27.2.1 ICM-20608原理图 27.3 实验程序编写 本实验对应的例程路径为:开发板光盘-> 1、裸机例程-> 18_spi。 本章实验在上一章例程的基础上完成,更改工程名字为“icm20608”,然后在bsp文件夹下创建名为“spi”和“icm20608”的文件。在bsp/spi中新建bsp_spi.c和bsp_spi.h这两个文件,在bsp/icm20608中新建bsp_icm20608.c和bsp_icm20608.h这两个文件。bsp_spi.c和bsp_spi.h是I.MX6U的SPI文件,bsp_icm20608.c和bsp_icm20608.h是ICM20608的驱动文件。在bsp_spi.h中输入如下内容: 示例代码27.3.1 bsp_spi.h文件代码

1  #ifndef _BSP_SPI_H
2  #define _BSP_SPI_H
3  /*************************************************************** 4 Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved. 5 文件名 : bsp_spi.h 6 作者 : 左忠凯 7 版本 : V1.0 8 描述 : SPI驱动头文件。 9 其他 : 无 10 论坛 : www.openedv.com 11 日志 : 初版V1.0 2019/1/17 左忠凯创建 12 ***************************************************************/
13 #include "imx6ul.h"
14 
15 /* 函数声明 */
16 void spi_init(ECSPI_Type *base);
17 unsigned char spich0_readwrite_byte(ECSPI_Type *base, 
unsigned char txdata);
18 #endif
	文件bsp_spi.h内容很简单,就是函数声明。在文件bsp_spi.c中输入如下内容:
示例代码27.3.2 bsp_spi.c文件代码
/*************************************************************** Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved. 文件名 : bsp_spi.c 作者 : 左忠凯 版本 : V1.0 描述 : SPI驱动文件。 其他 : 无 论坛 : www.openedv.com 日志 : 初版V1.0 2019/1/17 左忠凯创建 ***************************************************************/
1  #include "bsp_spi.h"
2  #include "bsp_gpio.h"
3  #include "stdio.h"
4  
5  /* 6 * @description : 初始化SPI 7 * @param - base : 要初始化的SPI 8 * @return : 无 9 */
10 void spi_init(ECSPI_Type *base)
11 { 
       
12  	/* 配置CONREG寄存器 13 * bit0 : 1 使能ECSPI 14 * bit3 : 1 当向TXFIFO写入数据以后立即开启SPI突发。 15 * bit[7:4]: 0001 SPI通道0主模式,根据实际情况选择,开发板上的 16 * ICM-20608接在SS0上,所以设置通道0为主模式 17 * bit[19:18]: 00 选中通道0(其实不需要,因为片选信号我们我们自己控制) 18 * bit[31:20]: 0x7 突发长度为8个bit。 19 */
20  	base->CONREG = 0; 							/* 先清除控制寄存器 */
21  	base->CONREG |= (1 << 0) | (1 << 3) | (1 << 4) | (7 << 20); 
22 
23  	/* 24 * ECSPI通道0设置,即设置CONFIGREG寄存器 25 * bit0: 0 通道0 PHA为0 26 * bit4: 0 通道0 SCLK高电平有效 27 * bit8: 0 通道0片选信号 当SMC为1的时候此位无效 28 * bit12: 0 通道0 POL为0 29 * bit16: 0 通道0 数据线空闲时高电平 30 * bit20: 0 通道0 时钟线空闲时低电平 31 */
32  	base->CONFIGREG = 0;        			/* 设置通道寄存器 */
33  
34  	/* 35 * ECSPI通道0设置,设置采样周期 36 * bit[14:0] : 0X2000 采样等待周期,比如当SPI时钟为10MHz的时候 37 * 0X2000就等于1/10000 * 0X2000 = 0.8192ms,也就是 38 * 连续读取数据的时候每次之间间隔0.8ms 39 * bit15 : 0 采样时钟源为SPI CLK 40 * bit[21:16]: 0 片选延时,可设置为0~63 41 */
42  	base->PERIODREG = 0X2000;       /* 设置采样周期寄存器 */
43 
44  	/* 45 * ECSPI的SPI时钟配置,SPI的时钟源来源于pll3_sw_clk/8=480/8=60MHz 46 * SPI CLK = (SourceCLK / PER_DIVIDER) / (2^POST_DIVEDER) 47 * 比如我们现在要设置SPI时钟为6MHz,那么设置如下: 48 * PER_DIVIDER = 0X9。 49 * POST_DIVIDER = 0X0。 50 * SPI CLK = 60000000/(0X9 + 1) = 60000000=6MHz 51 */
52  	base->CONREG &= ~((0XF << 12) | (0XF << 8)); /* 清除以前的设置 */
53  	base->CONREG |= (0X9 << 12);          /* 设置SPI CLK = 6MHz */
54 }
55 
56 /* 57 * @description : SPI通道0发送/接收一个字节的数据 58 * @param - base : 要使用的SPI 59 * @param – txdata : 要发送的数据 60 * @return : 无 61 */
62 unsigned char spich0_readwrite_byte(ECSPI_Type *base, 
unsigned char txdata)
63 { 
        
64  	uint32_t  spirxdata = 0;
65  	uint32_t  spitxdata = txdata;
66 
67     	/* 选择通道0 */
68  	base->CONREG &= ~(3 << 18);
69 	 	base->CONREG |= (0 << 18);
70 
71      while((base->STATREG & (1 << 0)) == 0){ 
       } /* 等待发送FIFO为空 */
72      base->TXDATA = spitxdata;
73  
74  	while((base->STATREG & (1 << 3)) == 0){ 
       } /* 等待接收FIFO有数据 */
75      spirxdata = base->RXDATA;
76  	return spirxdata;
77 }
文件bsp_spi.c中有两个函数:spi_init和spich0_readwrite_byte,函数spi_init是SPI初始化函数,此函数会初始化SPI的时钟,通道等。函数spich0_readwrite_byte是SPI收发函数,通过此函数即可完成SPI的全双工数据收发。
接下来在文件bsp_icm20608.h中输入如下内容:

示例代码27.3.3 bsp_icm20608.h文件代码

1  #ifndef _BSP_ICM20608_H
2  #define _BSP_ICM20608_H
3  /*************************************************************** 4 Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved. 5 文件名 : bsp_icm20608.h 6 作者 : 左忠凯 7 版本 : V1.0 8 描述 : ICM20608驱动文件。 9 其他 : 无 10 论坛 : www.openedv.com 11 日志 : 初版V1.0 2019/3/26 左忠凯创建 12 ***************************************************************/
13 #include "imx6ul.h"
14 #include "bsp_gpio.h"
15 
16 /* SPI片选信号 */
17 #define ICM20608_CSN(n)    (n ? gpio_pinwrite(GPIO1, 20, 1) : 
gpio_pinwrite(GPIO1, 20, 0))  
18 
19 #define ICM20608G_ID     	0XAF    /* ID值 */
20 #define ICM20608D_ID    	0XAE    /* ID值 */
21 
22 /* ICM20608寄存器 23 *复位后所有寄存器地址都为0,除了 24 *Register 107(0X6B) Power Management 1 = 0x40 25 *Register 117(0X75) WHO_AM_I = 0xAF或者0xAE 26 */
27 /* 陀螺仪和加速度自测(出产时设置,用于与用户的自检输出值比较) */
28 #define  ICM20_SELF_TEST_X_GYRO    	0x00
29 #define  ICM20_SELF_TEST_Y_GYRO   	0x01
30 #define  ICM20_SELF_TEST_Z_GYRO     	0x02
31 #define  ICM20_SELF_TEST_X_ACCEL   	0x0D
32 #define  ICM20_SELF_TEST_Y_ACCEL    	0x0E
33 #define  ICM20_SELF_TEST_Z_ACCEL   	0x0F
34 /***********省略掉其他宏定义*************/
35 #define  ICM20_ZA_OFFSET_H          	0x7D
36 #define  ICM20_ZA_OFFSET_L         	0x7E
37 
38 /* 39 * ICM20608结构体 40 */
41 struct icm20608_dev_struc
42 { 
       
43  	signed int gyro_x_adc;      	/* 陀螺仪X轴原始值 */
44  	signed int gyro_y_adc;      	/* 陀螺仪Y轴原始值 */
45 	 	signed int gyro_z_adc;      	/* 陀螺仪Z轴原始值 */
46  	signed int accel_x_adc;     	/* 加速度计X轴原始值 */
47  	signed int accel_y_adc;     	/* 加速度计Y轴原始值 */
48  	signed int accel_z_adc;     	/* 加速度计Z轴原始值 */
49  	signed int temp_adc;      	/* 温度原始值 */
50 
51  	/* 下面是计算得到的实际值,扩大100倍 */
52  	signed int gyro_x_act;      	/* 陀螺仪X轴实际值 */
53 	 	signed int gyro_y_act;      	/* 陀螺仪Y轴实际值 */
54  	signed int gyro_z_act;      	/* 陀螺仪Z轴实际值 */
55  	signed int accel_x_act;     	/* 加速度计X轴实际值 */
56  	signed int accel_y_act;     	/* 加速度计Y轴实际值 */
57  	signed int accel_z_act;     	/* 加速度计Z轴实际值 */
58  	signed int temp_act;        	/* 温度实际值 */
59 };
60 
61 struct icm20608_dev_struc icm20608_dev;  /* icm20608设备 */
62 
63 /* 函数声明 */
64 unsigned char icm20608_init(void);
65 void icm20608_write_reg(unsigned char reg, unsigned char value);
66 unsigned char icm20608_read_reg(unsigned char reg);
67 void icm20608_read_len(unsigned char reg, unsigned char *buf, 
unsigned char len);
68 void icm20608_getdata(void);
69 #endif
文件bsp_icm20608.h里面先定义了一个宏ICM20608_CSN,这个是ICM20608的SPI片选引脚。接下来定义了一些ICM20608的ID和寄存器地址。第41行定义了一个结构体icm20608_dev_struc,这个结构体是ICM20608的设备结构体,里面的成员变量用来保存ICM20608的原始数据值和经过转换得到的实际值。实际值是有小数的,本章例程取两位小数,为了方便计算,实际值扩大了100倍,这样实际值就是整数了,但是在使用的时候要除100重新得到小数部分。最后就是一些函数声明,接下来在文件bsp_icm20608.c中输入如下所示内容:
示例代码27.3.4 bsp_icm20608.c文件代码
/*************************************************************** Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved. 文件名 : bsp_icm20608.c 作者 : 左忠凯 版本 : V1.0 描述 : ICM20608驱动文件。 其他 : 无 论坛 : www.openedv.com 日志 : 初版V1.0 2019/3/26 左忠凯创建 ***************************************************************/
1   #include "bsp_icm20608.h"
2   #include "bsp_delay.h"
3   #include "bsp_spi.h"
4   #include "stdio.h"
5   
6   struct icm20608_dev_struc icm20608_dev; /* icm20608设备 */
7   
8   /* 9 * @description : 初始化ICM20608 10 * @param : 无 11 * @return : 0 初始化成功,其他值 初始化失败 12 */
13  unsigned char icm20608_init(void)
14  { 
          
15      unsigned char regvalue;
16      gpio_pin_config_t cs_config;
17  
18      /* 1、ESPI3 IO初始化 19 * ECSPI3_SCLK -> UART2_RXD 20 * ECSPI3_MISO -> UART2_RTS 21 * ECSPI3_MOSI -> UART2_CTS 22 */
23      IOMUXC_SetPinMux(IOMUXC_UART2_RX_DATA_ECSPI3_SCLK, 0);
24      IOMUXC_SetPinMux(IOMUXC_UART2_CTS_B_ECSPI3_MOSI, 0);
25      IOMUXC_SetPinMux(IOMUXC_UART2_RTS_B_ECSPI3_MISO, 0);
26      IOMUXC_SetPinConfig(IOMUXC_UART2_RX_DATA_ECSPI3_SCLK, 0x10B1);
27      IOMUXC_SetPinConfig(IOMUXC_UART2_CTS_B_ECSPI3_MOSI, 0x10B1);
28      IOMUXC_SetPinConfig(IOMUXC_UART2_RTS_B_ECSPI3_MISO, 0x10B1);
29  
30      /* 初始化片选引脚 */
31      IOMUXC_SetPinMux(IOMUXC_UART2_TX_DATA_GPIO1_IO20, 0);
32      IOMUXC_SetPinConfig(IOMUXC_UART2_TX_DATA_GPIO1_IO20, 0X10B0);
33      cs_config.direction = kGPIO_DigitalOutput;
34      cs_config.outputLogic = 0;
35      gpio_init(GPIO1, 20, &cs_config);
36      
37      /* 2、初始化SPI */
38      spi_init(ECSPI3);   
39  
40      icm20608_write_reg(ICM20_PWR_MGMT_1, 0x80);  /* 复位 */
41      delayms(50);
42      icm20608_write_reg(ICM20_PWR_MGMT_1, 0x01);  /* 关闭睡眠 */
43      delayms(50);
44  
45      regvalue = icm20608_read_reg(ICM20_WHO_AM_I);
46      printf("icm20608 id = %#X\r\n", regvalue);
47      if(regvalue != ICM20608G_ID && regvalue != ICM20608D_ID)
48          return 1;
49          
50      icm20608_write_reg(ICM20_SMPLRT_DIV, 0x00);  	/* 输出速率设置 */
51      icm20608_write_reg(ICM20_GYRO_CONFIG, 0x18);  /* 陀螺仪±2000dps */
52      icm20608_write_reg(ICM20_ACCEL_CONFIG, 0x18); /* 加速度计±16G */
53      icm20608_write_reg(ICM20_CONFIG, 0x04);        /* 陀螺BW=20Hz */
54      icm20608_write_reg(ICM20_ACCEL_CONFIG2, 0x04);
55      icm20608_write_reg(ICM20_PWR_MGMT_2, 0x00);   /* 打开所有轴 */
56      icm20608_write_reg(ICM20_LP_MODE_CFG, 0x00);  /* 关闭低功耗 */
57      icm20608_write_reg(ICM20_FIFO_EN, 0x00);   	/* 关闭FIFO */
58      return 0;
59  }
60  
61  /* 62 * @description : 写ICM20608指定寄存器 63 * @param - reg : 要读取的寄存器地址 64 * @param – value : 要写入的值 65 * @return : 无 66 */
67  void icm20608_write_reg(unsigned char reg, unsigned char value)
68  { 
       
69      /* ICM20608在使用SPI接口的时候寄存器地址只有低7位有效, 70 * 寄存器地址最高位是读/写标志位,读的时候要为1,写的时候要为0。 71 */
72      reg &= ~0X80;   
73      
74      ICM20608_CSN(0);                        	/* 使能SPI传输 */
75      spich0_readwrite_byte(ECSPI3, reg);   	/* 发送寄存器地址 */ 
76      spich0_readwrite_byte(ECSPI3, value);	/* 发送要写入的值 */
77      ICM20608_CSN(1);                        	/* 禁止SPI传输 */
78  }   
79  
80  /* 81 * @description : 读取ICM20608寄存器值 82 * @param - reg : 要读取的寄存器地址 83 * @return : 读取到的寄存器值 84 */
85  unsigned char icm20608_read_reg(unsigned char reg)
86  { 
       
87      unsigned char reg_val;      
88  
89      /* ICM20608在使用SPI接口的时候寄存器地址只有低7位有效, 90 * 寄存器地址最高位是读/写标志位,读的时候要为1,写的时候要为0。 91 */
92      reg |= 0x80;    
93      
94      ICM20608_CSN(0);                         	/* 使能SPI传输 */
95      spich0_readwrite_byte(ECSPI3, reg);	/* 发送寄存器地址 */ 
96      reg_val = spich0_readwrite_byte(ECSPI3, 0XFF);/* 读取寄存器的值*/
97      ICM20608_CSN(1);                        	/* 禁止SPI传输 */
98      return(reg_val);                         	/* 返回读取到的寄存器值 */
99  }
100 
101 /* 102 * @description : 读取ICM20608连续多个寄存器 103 * @param - reg : 要读取的寄存器地址 104 * @return : 读取到的寄存器值 105 */
106 void icm20608_read_len(unsigned char reg, unsigned char *buf, 
unsigned char len)
107 { 
         
108     unsigned char i;
109     
110     /* ICM20608在使用SPI接口的时候寄存器地址,只有低7位有效, 111 * 寄存器地址最高位是读/写标志位读的时候要为1,写的时候要为0。 112 */
113     reg |= 0x80; 
114         
115     ICM20608_CSN(0);                       /* 使能SPI传输 */
116     spich0_readwrite_byte(ECSPI3, reg);/* 发送寄存器地址 */         
117     for(i = 0; i < len; i++)             /* 顺序读取寄存器的值 */
118     { 
       
119         buf[i] = spich0_readwrite_byte(ECSPI3, 0XFF);   
120     }
121     ICM20608_CSN(1);                      /* 禁止SPI传输 */
122 }
123 
124 /* 125 * @description : 获取陀螺仪的分辨率 126 * @param : 无 127 * @return : 获取到的分辨率 128 */
129 float icm20608_gyro_scaleget(void)
130 { 
       
131     unsigned char data;
132     float gyroscale;
133     
134     data = (icm20608_read_reg(ICM20_GYRO_CONFIG) >> 3) & 0X3;
135     switch(data) { 
       
136         case 0: 
137             gyroscale = 131;
138 

标签: te511温度lcd显示传感器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台