正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-24.5,6 SPI驱动实验-ICM20608 ADC采样值

前言:

本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM(MX6U)裸机篇”视频的学习笔记,在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。

引用:

正点原子IMX6U仓库 (GuangzhouXingyi) - Gitee.com

《【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.5.2.pdf》

正点原子资料下载中心 — 正点原子资料下载中心 1.0.0 文档

SPI学习参考资料:

简述SPI通信协议-01_cpha选择为第一个边沿-CSDN博客

SPI中的CPHA,CPOL详解-CSDN博客

一文搞懂SPI通信协议_spi协议-CSDN博客

摩托罗拉 《SPI Block Guide V03.06》 手册

链接:https://pan.baidu.com/s/1_mvR5AD0-OBI2bYyx2i4Sw?pwd=f4bo 
提取码:f4bo

正文:

本文是 “正点原子[第二期]Linux之ARM(MX6U)裸机篇--第24讲 SPI驱动。本节将参考正点原子的视频教程第24讲和配套的正点原子开发指南文档进行学习。

0. 概述

通I2C一样,SPI是很常用的通信接口,也可以通过SPI来连接众多的传感器。相比I2C接口,SPI接口的通信速度很快,I2C最多400KHz,但是SPI可以到达几十MHz。I.MX6U 也有4个SPI接口,可以通过这4个SPI接口来连接一些SPI外设。I.MX6U-ALHPA使用SPI3接口连接了一个6周传感器 ICM-20608,本章我们就来学习如何使用I.MX6U的SPI接口来驱动ICM-20608,读取ICM-20608的六轴数据。

1. ICM20608 6轴传感器量程

icm20608 6轴传感器,支持陀螺仪x,y,z三轴的角速度测量和加速度计x,y,z三轴的加速度计测量。icm20608 陀螺仪的量程范围可选配置为±250,±500,±1000和±2000 °/s,角速度计的量程范围可选配置为±2g,±4g,±8g和±16g。icm20608 x,y,z 轴的输出是一个 16位的 ADC 采样值,16位值的有符号数(补码)表示范围为 -32768~32767,一共可以表示65536个数值,那么采样值和量程范围的关系是什么哪?

参考链接:

IMX6ULL裸机篇之SPI实验-ICM20608传感器_icm20608数据手册-CSDN博客

  • 陀螺仪量程

如果陀螺仪所设置的分辨率范围为 ±250,即 -250~+250,也就是 500°/s
ADC数据的位数为 16位,即 0~65535,也就是 65536。那么一度对应多大的数据呢?
65536/500 = 131.07

举例说明:

如果所设置的分辨率范围为 ±250,读取到的  ADC值是 1000,那么陀螺仪的角速度是多少?

当前陀螺仪的角速度为:

1000 / 131  = 7.6°/s

  • 加速度计量程

加速度计计算公式与陀螺仪相似。

 举例说明:
如果加速度计设置的分辨率范围为 ±2,即 -2~+2,也就是 4
ADC值的位数为 16位,即 0~65535,也就是 65536。一度则对应多大的 ADC值呢?
65536/4 = 16384

如果此时读取到的 ADC值为 16384,则这时的加速度计的加速度是多少?
16384 / 16384  = 1g

2. ICM20608传感器ADC采样值计算

ADC值是16位,表示值范围为0~65535,一共65536个;量程范围为 ±2000,一共是4000,计算出来多少个ADC值代表一个角速度:

16.4 = 65536/(4000°/s)

例如,icm20608 加速度的量程范围选择为±16g,icm20608 加速度计z轴读取出来的值为2041,因为icm20608 ADC的值是16位其中存放的是一个有符号短整型数(unsigned short)的补码形式,计算处量程范围为±16g,icm20608 加速度计z轴ADC的值为2041的实际加速读值为:

acc_z = (ADC值 * 量程)/ADC位数无符号整型范围

           =(2041 * 32)/65536

           = 0.99g 

其中ADC的值是从icmp20608寄存器里读取出来相应轴的ADC采样值,是有符号短整型数,有正负符号。

3. 源码编写

源码编写读取icm20608传感器6个轴的采样值,源码如下:

bsp_icm2060.h

#ifndef __BSP_20608_H__
#define __BSP_20608_H__

#include "imx6u.h"


#define ICM20608G_ID						0xAF
#define ICM20608N_ID						0xAE

#define ICM20608_REG_SMLPRT_DIV				0x19
#define ICM20608_REG_CONFIG					0x1A
#define ICM20608_REG_GYRO_CONFIG			0x1B
#define ICM20608_REG_ACCEL_CONFIG			0x1C
#define ICM20608_REG_ACCEL_CONFIG2			0x1D
#define ICM20608_REG_LP_MODE_CFG			0x1E
#define ICM20608_REG_ACCEL_WOM_THR			0x1F
#define ICM20608_REG_FIFO_EN				0x23
#define ICM20608_REG_ACCEL_XOUT_H			0x3B
#define ICM20608_REG_ACCEL_XOUT_L			0x3C
#define ICM20608_REG_ACCEL_YOUT_H			0x3D
#define ICM20608_REG_ACCEL_YOUT_L			0x3E
#define ICM20608_REG_ACCEL_ZOUT_H			0x3F
#define ICM20608_REG_ACCEL_ZOUT_L			0x40
#define ICM20608_REG_TEMP_OUT_H				0x41
#define ICM20608_REG_TEMP_OUT_L				0x42
#define ICM20608_REG_GYRO_XOUT_H			0x43
#define ICM20608_REG_GYRO_XOUT_L			0x44
#define ICM20608_REG_GYRO_YOUT_H			0x45
#define ICM20608_REG_GYRO_YOUT_L			0x46
#define ICM20608_REG_GYRO_ZOUT_H			0x47
#define ICM20608_REG_GYRO_ZOUT_L			0x48
#define ICM20608_REG_PWR_MGMT_1				0x6B
#define ICM20608_REG_PWR_MGMT_2				0x6C
#define ICM20608_REG_WHO_AM_I				0x75
#define ICM20608_REG_XA_OFFSET_H			0x77
#define ICM20608_REG_XA_OFFSET_L			0x78
#define ICM20608_REG_YA_OFFSET_H			0x7A
#define ICM20608_REG_YA_OFFSET_L			0x7B
#define ICM20608_REG_ZA_OFFSET_H			0x7D
#define ICM20608_REG_ZA_OFFSET_L			0x7E


copy from 正点原子示例程序 
/* 陀螺仪和加速度自测(出产时设置,用于与用户的自检输出值比较) */
#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

copy from 正点原子示例程序 



struct icm20608_device {
	/* ADC 采样值,原始数据 */
	signed short accel_x_adc;
	signed short accel_y_adc;
	signed short accel_z_adc;
	signed short temperature_adc;
	signed short gyro_x_adc;
	signed short gyro_y_adc;
	signed short gyro_z_adc;

	/* 计算得到的实际值 */
	signed short accel_x_act;
	signed short accel_y_act;
	signed short accel_z_act;
	signed short temperature_act;
	signed short gyro_x_act;
	signed short gyro_y_act;
	signed short gyro_z_act;
};

extern struct icm20608_device icm20608_dev;

#define  ICM20608_CSN(n) 	do{n ? gpio_pinwrite(GPIO1, 20, 1) : gpio_pinwrite(GPIO1, 20, 0);} while(0)

void icm20608_init(void);
unsigned char icm20608_read_reg(ECSPI_Type *base, unsigned char reg);
void icm20608_write_reg(ECSPI_Type *base, unsigned char reg, unsigned char value);
void icm20608_read_len(ECSPI_Type *base, unsigned char reg, unsigned char len, unsigned char *buf);
void icm20608_read_dev_accel_gyro(struct icm20608_device *idev);
int icm20608_gyroscale_get(void);
int icm20608_accelscale_get(void);

#endif

bsp_icm2060.c

#include "bsp_icm20608.h"
#include "bsp_gpio.h"
#include "bsp_spi.h"
#include "bsp_delay.h"
#include "stdio.h"

/* 初始化ICM20608 */
void icm20608_init(void)
{
	gpio_pin_config_t config;

	/* 1.SPI 引脚的初始化 */
	IOMUXC_SetPinMux(IOMUXC_UART2_RX_DATA_ECSPI3_SCLK, 0);				/* 复用为ECSPI3_SCLK */
	IOMUXC_SetPinMux(IOMUXC_UART2_CTS_B_ECSPI3_MOSI, 0);				/* 复用为ECSPI3_MOSI */
	IOMUXC_SetPinMux(IOMUXC_UART2_RTS_B_ECSPI3_MISO, 0);				/* 复用为ECSPI3_MISO */


	IOMUXC_SetPinConfig(IOMUXC_UART2_RX_DATA_ECSPI3_SCLK, 0x10B1);		/* IO特性 */
	IOMUXC_SetPinConfig(IOMUXC_UART2_CTS_B_ECSPI3_MOSI, 0x10B1);		/* IO特性 */
	IOMUXC_SetPinConfig(IOMUXC_UART2_RTS_B_ECSPI3_MISO, 0x10B1);		/* IO特性 */


	IOMUXC_SetPinMux(IOMUXC_UART2_TX_DATA_GPIO1_IO20, 0);				/* 复用为GPIO1_20 */
	IOMUXC_SetPinConfig(IOMUXC_UART2_TX_DATA_GPIO1_IO20, 0x10B0);		/* IO特性 */
	config.direction = kGPIO_DigitalOutput;
	config.outputLogic = 0;
	gpio_init(GPIO1, 20, &config);


	/* 2.SPI控制器的初始化 */
	spi_init(ECSPI3);


	/* 3.icm20608的初始化 */
	/* 睡眠模式,手册中说icm20608复位之后默认是sleep模式 */
	icm20608_write_reg(ECSPI3, ICM20608_REG_PWR_MGMT_1, 0x80);				/* 复位 */
	delay_ms(50);
	icm20608_write_reg(ECSPI3, ICM20608_REG_PWR_MGMT_1, 0x01);				/* 关闭睡眠模式,时钟选择 */
	delay_ms(50);

	unsigned char value;
	value = icm20608_read_reg(ECSPI3, ICM20608_REG_WHO_AM_I);
	printf("ICM20608G ICM20608_REG_WHO_AM_I=0x%02x\r\n", value);

	icm20608_write_reg(ECSPI3, ICM20608_REG_SMLPRT_DIV, 0x0);				/* 设置采样率输出速率 */
	icm20608_write_reg(ECSPI3, ICM20608_REG_GYRO_CONFIG, 0x18);				/* 陀螺仪量程FS(Full Scale), ±2000dps*/
	icm20608_write_reg(ECSPI3, ICM20608_REG_ACCEL_CONFIG, 0x18);			/* 加速度计量程FS(Full Scale), ±16g */
	icm20608_write_reg(ECSPI3, ICM20608_REG_CONFIG, 0x04);					/* 陀螺仪, BW=20Hz, 低通滤波器DLPF(Digital Low Pass Filter) */
	icm20608_write_reg(ECSPI3, ICM20608_REG_ACCEL_CONFIG2, 0x04);			/* 加速度, BW=20Hz, 低通滤波器DLPF(Digital Low Pass Filter) */
	icm20608_write_reg(ECSPI3, ICM20608_REG_PWR_MGMT_2, 0x00);				/* 启用所有陀螺仪,加速度计 X,Y,Z轴 */
	icm20608_write_reg(ECSPI3, ICM20608_REG_LP_MODE_CFG, 0x00);				/* 关闭低功耗模式,陀螺仪,加速度计的低功耗模式 */
	icm20608_write_reg(ECSPI3, ICM20608_REG_FIFO_EN, 0x00);					/* 关闭FIFO,陀螺仪,加速度计,温度计,FIFO使能 */

}

unsigned char icm20608_read_reg(ECSPI_Type *base, unsigned char reg)
{
	unsigned char rxdata = 0;

	reg |= 0x80;									/* icmp20608 读,最高位为 1 */	
	
	ICM20608_CSN(0);								/* 拉低SPI CS片选信号,选中从设备 */
	spi_readwrite_onebyte(base, reg);				/* icm20608读,寄存器地址 */	
	rxdata = spi_readwrite_onebyte(base, 0xFF);		/* icm20608读,dummy数据*/
	ICM20608_CSN(1);								/* 拉高SPI CS片选信号,去选中从设备 */

	return rxdata;
}

void icm20608_write_reg(ECSPI_Type *base, unsigned char reg, unsigned char value)
{
	reg &= ~0x80;							/* icmp20608 写,最高位清零 */	

	ICM20608_CSN(0);						/* 拉低SPI CS片选信号,选中从设备 */
	spi_readwrite_onebyte(base, reg);		/* icm20608写,寄存器地址 */	
	spi_readwrite_onebyte(base, value);		/* icm20608写,数据*/
	ICM20608_CSN(1);						/* 拉高SPI CS片选信号,去选中从设备 */
}

void icm20608_read_len(ECSPI_Type *base, unsigned char reg, unsigned char len, unsigned char *buf)
{
	int i  = 0;

	// for(i=0; i< len; i++)
	// {
	// 	buf[i] = icm20608_read_reg(base, reg+i);
	// }

	reg |= 0x80;									/* icmp20608 读,最高位为 1 */	
	
	ICM20608_CSN(0);								/* 拉低SPI CS片选信号,选中从设备 */
	spi_readwrite_onebyte(base, reg);				/* icm20608读,寄存器地址 */	
	/* 连续读取多个数据 */
	for(i=0; i<len; i++){
		buf[i] = spi_readwrite_onebyte(base, 0xFF);	/* icm20608读,dummy数据*/
	}
	ICM20608_CSN(1);								/* 拉高SPI CS片选信号,去选中从设备 */

}


void icm20608_read_dev_accel_gyro(struct icm20608_device *idev)
{
	unsigned char buf[14];
	int gyroscale;
	int accescale;

	icm20608_read_len(ECSPI3, ICM20_ACCEL_XOUT_H, 14, buf);

	idev->accel_x_adc = (signed short)((buf[0] << 8) | buf[1]);
	idev->accel_y_adc = (signed short)((buf[2] << 8) | buf[3]);
	idev->accel_z_adc = (signed short)((buf[4] << 8) | buf[5]);

	idev->temperature_adc =  buf[6] << 8;
	idev->temperature_adc |= buf[7];

	idev->gyro_x_adc =  (signed short)((buf[8] << 8) | buf[9]);
	idev->gyro_y_adc =  (signed short)((buf[10] << 8) | buf[11]);
	idev->gyro_z_adc =  (signed short)((buf[12] << 8) | buf[13]);

	gyroscale = icm20608_gyroscale_get();
	accescale = icm20608_accelscale_get();

	/* 乘上100 用来保存小数,用的时候再除以100 */
	idev->accel_x_act = (((signed int)idev->accel_x_adc * accescale)*100)/65536;
	idev->accel_y_act = (((signed int)idev->accel_y_adc * accescale)*100)/65536;
	idev->accel_z_act = (((signed int)idev->accel_z_adc * accescale)*100)/65536;
	idev->gyro_x_act = (((signed int)idev->gyro_x_adc * gyroscale)*100)/65536;
	idev->gyro_y_act = (((signed int)idev->gyro_y_adc * gyroscale)*100)/65536;
	idev->gyro_z_act = (((signed int)idev->gyro_z_adc * gyroscale)*100)/65536;
}


/*
 * @description 	: 获取陀螺仪分辨率(量程)。
 * @param  			: 无
 * @return 			: 无
 */
int icm20608_gyroscale_get(void)
{
	unsigned char rxdata;
	int gyroScale = 0;

	rxdata = icm20608_read_reg(ECSPI3, ICM20608_REG_GYRO_CONFIG);

	switch(((rxdata >> 3) & 0x3))
	{
		case 0:
			gyroScale = 500;			//gyro_scale ±250dps
			break;
		case 1:
			gyroScale = 1000;			//gyro_scale ±500dps
			break;
		case 2:
			gyroScale = 2000;			//gyro_scale ±1000dps
			break;
		case 3:
			gyroScale = 4000;			//gyro_scale ±2000dps
			break;
	}

	printf("%s() rxdata=%02x gyroScale=%d\r\n", __FUNCTION__, rxdata, gyroScale);
	return gyroScale;
}



/*
 * @description 	: 获取加速度计分辨率(量程)。
 * @param  			: 无
 * @return 			: 无
 */
int icm20608_accelscale_get(void)
{
	unsigned char rxdata;
	int accelScale;

	rxdata = icm20608_read_reg(ECSPI3, ICM20608_REG_ACCEL_CONFIG);

	switch(((rxdata >> 3) & 0x3))
	{
		case 0:
			accelScale = 4;			//accel_scale ±2g
			break;
		case 1:
			accelScale = 8;			//accel_scale ±4g
			break;
		case 2:
			accelScale = 16;		//accel_scale ±8g
			break;
		case 3:
			accelScale = 32;		//accel_scale ±16g
			break;
	}
	
	printf("%s() rxdata=%02x accelScale=%d\r\n", __FUNCTION__, rxdata, accelScale);
	return accelScale;
}

main.c 文件,打印计算并打印出来从icm20608传感器读取出来的6个轴的采样值,并根据icm20608的量程计算出实际的x,y,z轴的加速度,和x,y,z轴的角速度。

main.c

#include "cc.h"
#include "bsp_clk.h"
#include "bsp_led.h"
#include "bsp_delay.h"
#include "bsp_beep.h"
#include "bsp_gpio.h"
#include "bsp_key.h"
#include "bsp_int.h"
#include "bsp_exti.h"
#include "bsp_epittimer.h"
#include "bsp_keyfilter.h"
#include "bsp_delay.h"
#include "bsp_uart.h"
#include "stdio.h"
#include "bsp_lcd.h"
#include "bsp_lcdapi.h"
#include "bsp_rtc.h"
#include "bsp_ap3216c.h"
#include "bsp_i2c.h"
#include "bsp_spi.h"
#include "bsp_icm20608.h"


char *banner = 	"========================================================\r\n"
				"正点原子I.MX6ULL ALPHA/Mini开发板Linux驱动之ARM裸机开发\r\n" \
				"--Date: 	%s\r\n" \
				"--Author: 	ChenHaoxu, Dimon.chen, 11813202388@qq.com\r\n" \
				"========================================================\r\n";


/*
 * @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);
}

int main(void)
{

	static uint8_t led_state = OFF;
	// static uint8_t beep_state = OFF;

	imx6ul_hardfpu_enable();	/* 使能I.MX6U的硬件浮点 			*/
	int_init();			/* 中断初始化 */
	imx6u_clkinit();	/* 时钟主频初始化,PLL1, PLL2, PLL3 */
	clk_init();			/* 使能所有外设时钟 */
	led_init();			/* led gpio 初始化 */
	beep_init();		/* beep gpio 初始化 */
	//key_init();			/* key gpio 初始化 */
	exti_init();		/* gpio外设中断初始化 */

	//epittimer_init(0, 0, 33000000);	/* EPIT分频frac=0 1分频,EPIT1时钟源66MHz,EPIT1->LR加载值计数器=33MHz,定时周期为500ms */
	//epittimer_init(1, 0, 66000000/20);	/* EPIT分频frac=0 1分频,EPIT1时钟源66MHz,EPIT1->LR加载值计数器=33MHz,定时周期为1000/20=50ms */

	keyfilter_init();
	delay_init();
	uart_init();		/* UART初始化 */
	//lcd_init();			/* LCD 初始化 */
	


	led_switch(LED_0, ON);


	beep_switch(ON);
	delay(200);
	beep_switch(OFF);
	delay(200);
	beep_switch(ON);
	delay(200);
	beep_switch(OFF);

	printf(banner, __DATE__);
	printf("Hello World\r\n");

	lcd_init();			/* LCD 初始化 */
	rtc_init();		
	

	i2c_ap3216c_init();
	icm20608_init();

	// unsigned short ir, ps, als;
	struct icm20608_device icm20608_dev;

	//启用I.MX6U浮点数计算


    while(1){
		led_state = !led_state;
		led_switch(LED_0, led_state);
		delay_ms(1000);

		// ap3216c_readdata(&ir, &ps, &als);
		// printf("ir=%d\r\n", ir);
		// printf("ps=%d\r\n", ps);
		// printf("als=%d\r\n", als);


		icm20608_read_dev_accel_gyro(&icm20608_dev);
		printf("accel %04x x:%hd\r\n", icm20608_dev.accel_x_adc, icm20608_dev.accel_x_adc);
		printf("accel %04x y:%hd\r\n", icm20608_dev.accel_y_adc, icm20608_dev.accel_y_adc);
		printf("accel %04x z:%hd\r\n", icm20608_dev.accel_z_adc, icm20608_dev.accel_z_adc);

		printf("gyro  %04x x:%hd\r\n", icm20608_dev.gyro_x_adc, icm20608_dev.gyro_x_adc);
		printf("gyro  %04x y:%hd\r\n", icm20608_dev.gyro_y_adc, icm20608_dev.gyro_y_adc);
		printf("gyro  %04x z:%hd\r\n", icm20608_dev.gyro_z_adc, icm20608_dev.gyro_z_adc);



		printf("ACT accel %04x x:%hd\r\n", icm20608_dev.accel_x_act, icm20608_dev.accel_x_act);
		printf("ACT accel %04x y:%hd\r\n", icm20608_dev.accel_y_act, icm20608_dev.accel_y_act);
		printf("ACT accel %04x z:%hd\r\n", icm20608_dev.accel_z_act, icm20608_dev.accel_z_act);

		printf("ACT gyro  %04x x:%hd\r\n", icm20608_dev.gyro_x_act, icm20608_dev.gyro_x_act);
		printf("ACT gyro  %04x y:%hd\r\n", icm20608_dev.gyro_y_act, icm20608_dev.gyro_y_act);
		printf("ACT gyro  %04x z:%hd\r\n", icm20608_dev.gyro_z_act, icm20608_dev.gyro_z_act);
    }

    return 0;
}

另一个重要的函数是 imx6ul_hardfpu_enable,这个函数用于开启 I.MX6U 的 NEON 和硬件 FPU(浮点运算单元),因为本章使用到了浮点运算,而 I.MX6U 的Cortex-A7 是支持 NEON 和 FPU(VFPV4_D32)的,但是在使用 I.MX6U 的硬件 FPU 之前是先要开启的。


 

4. 启用I.MX6U 浮点数运算

开启I.MX6U的硬件浮点单元,否则执行浮点运算的时候程序会卡死(float),使用I.MX6U的硬件复点单元的有如下两个步骤:

  1. 开启I.MX6U的硬件浮点单元
  2. 编译时指定启用硬件浮点,指定编译的时候使用硬件浮点指令

VFPFloat Process
VFPFloat Process
FPEXCFloat-Point Execute Control 

通过如下函数写I.MX6U ARM Cortex-A7 协处理器的寄存器来启用硬件浮点运算:

/*
 * @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);
}

在Makefile里加入如下编译选项,指定编译器编译生成汇编源码时使用硬件汇编指令

-march=armv7-a -mfpu=neon-vfpv4 -mfloat-abi=hard

5. 编译烧写SD卡验证结果

编译源码烧录SD卡验证本节的 I.MX6U I2C驱动实验。预期烧录SD卡后正点原子I.MX6ULL ALPHA/Mini 开发板后,可以通过SPI总线读取到ICM20608 6轴传感器的加速度计x,y,z三轴的ADC采集数据和陀螺仪的x,y,z三轴的ADC采样数据,然后根据icm20608配置的量程范围来计算出实际的加速度计x,y,z轴传感器的实际物理值和陀螺仪的x,y,z轴传感器的实际物理值。

我本地验证的结果是可以通过spi接口读取到 icm20608传感器的 加速度计x,y,z三轴的ADC采集数据和陀螺仪的x,y,z三轴的ADC采样数据,计算并打印到串口。

5. 总结和实验遇到问题记录

本实验通过I.MX6U 的硬件spi接口读取到了 icm20608 6轴传感器的寄存器数据,验证了spi可以正常通信,读取了  icm20608 传感器的 chipid 寄存器并打印到串口。本实验也在I.MX6U ARM裸机的情况下直接通过寄存器的操作来初始化spi硬件接口,在实验过程中也熟悉了spi通信的协议,为之后学习打下了基础。

5.1 问题1:icm20608 ADC 采样值是是有符号短整型

icm20608 ADC 采样值是是有符号短整型,在结构体声明里应该将icm20608的 x/y/z 轴的ADC数据声明为 'unsigned short’ 型。这样才能计算处正确的±16g,±2000dps 等加速度和角速度物理量,正负号表示方向。

5.2 问题2:寄存器bit[4:3]应该先右移再和'0x3'进行与运算。

问题2:寄存器bit[4:3]应该先右移再和'0x3F'进行与操作,原来写错了写成了先与'0x3'进行与运算再右移三位,这样就得到了错误的值。

5.3 问题3:需要启用I.MX6U 硬件浮点运算单元,才能使用浮点运算否则程序会卡死

需要启用I.MX6U 硬件浮点运算单元,才能使用浮点运算否则程序会卡死,启用硬件浮点运算之后可以极大的提高浮点运算的速度。

5.4 问题4:使用硬件浮点单元,同时也需要在Makefile里通过编译选项高速编译器使用硬件浮点运算指令。

使用硬件浮点单元,除了开启I.MX6U协处理器的硬件浮点运算单元之后,还需要在Makefile里通过编译选项高速编译器使用硬件浮点运算指令。

-march=armv7-a -mfpu=neon-vfpv4

6. 结束

本文至此结束

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/685751.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[数据集][图像分类]城市异常情况路边倒树火灾水灾交通事故分类数据集15223张8类别

数据集类型&#xff1a;图像分类用&#xff0c;不可用于目标检测无标注文件 数据集格式&#xff1a;仅仅包含jpg图片&#xff0c;每个类别文件夹下面存放着对应图片 图片数量(jpg文件个数)&#xff1a;15223 分类类别数&#xff1a;8 类别名称:[“badroad”,“fallentree”,“f…

【介绍下Spark MLlib机器学习】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

最优化练习题

def f(x):return x*x-4*x5 a0,b01,31、均匀搜索 令 δ ( b 0 − a 0 ) / N , a i a 0 i δ , i 1 , 2 , 3 \delta(b_0-a_0)/N,a_ia_0i\delta,i1,2,3 δ(b0​−a0​)/N,ai​a0​iδ,i1,2,3 while b0-a0>0.1:anp.linspace(a0,b0,5)for i in range(1,4):if f(a[i-1])>f…

RT-Thread

RT-Thread RT-Thread 版权属于上海睿赛德电子科技有限公司&#xff0c;于 2006年 1月首次发布&#xff0c;初始版 本号为0.1.0&#xff0c;经过 10来年的发展&#xff0c;如今主版本号已经升级到3.0&#xff0c;累计开发者达到数百万&#xff0c; 在各行各业产品中装机量达到了…

zabbix“专家坐诊”第241期问答

问题一 Q&#xff1a;华为交换机的100GE 1/0/1口的光模块收光值监测不到&#xff0c;有没有人碰到过这个问题呢&#xff1f;其他的端口都能监测到收光值&#xff0c;但是100GE 1/0/1口监测不到收光值。底层能查到&#xff0c;zabbix 6.0监控不到&#xff0c;以下是端口的报错信…

引用(C++)和内联函数

前言&#xff1a;本文主要讲解C语法中引用如何使用和使用时的一些技巧 基本语法 引用就是取别名 #include <iostream> using namespace std; int main() {int a 10;int& b a;//给a取别名为bcout << a << endl;cout << b << endl;return 0…

Apple开发者macOS描述文件创建

1.选择Profiles然后点击加号创建 2.选择类型为macOS App Development然后点击继续 3.选择描述类型与App ID 然后点击继续 4.选择证书然后点击继续 5.选择设备,然后点击继续 6.输入描述文件后,点击生成 生成成功,点击下载描述文件 下载完成会自动打开描述文件

1.Rust安装

目录 一、安装1.1 在Windows上安装1.2 在Linux下安装 二、包管理工具三、Hello World3.1 安装IDE3.2 输出Hello World 一、安装 1.1 在Windows上安装 点击页面 安装 Rust - Rust 程序设计语言 (rust-lang.org)&#xff0c;选择"下载RUSTUP-INIT.EXE(64位&#xff09;&qu…

一.网络基础——OSI七层模型

一.OSI七层模型 OSI&#xff08;Open System Interconnection&#xff0c;开放系统互连&#xff09;七层网络模型被称为开放式系统互联参考模型&#xff0c;它是一个逻辑上的定义和规范; 它把网络从逻辑上分为了7层. 每一层都有相关、相对应的物理设备&#xff0c;比如路由器&…

SpringBoot高手之路04-Aop

文章目录 AOP 基础AOP概述start依赖,开发某一个功能,只需要下载这一个依赖,关于他的依赖都会下载下来 AOP快速入门AOP核心概念 切入点表达式-execution AOP 基础 AOP概述 AOP 对特定的方法做增强 AOP 快速入门 start依赖,开发某一个功能,只需要下载这一个依赖,关于他的依赖…

python数据文件处理库-pandas

内容目录 一、pandas介绍二、数据加载和写出三、数据清洗四、数据转换五、数据查询和筛选六、数据统计七、数据可视化 pandas 是一个 Python提供的快速、灵活的数据结构处理包&#xff0c;让“关系型”或“标记型”数据的交互既简单又直观。 官网地址: https://pandas.pydata.o…

Polar Web 【简单】- 被黑掉的站

Polar Web 【简单】- 被黑掉的站 Contents Polar Web 【简单】- 被黑掉的站思路EXP运行&总结 思路 如题目所述&#xff0c;这是一个被黑掉的站点&#xff0c;由此不禁要了解该黑客发现了哪些可以入手的路径&#xff0c;或是留下了什么样的文件供持续访问。 目录扫描该站点发…

AI和机器人引领新一轮农业革命

AI和机器人技术在农业领域的应用正在迅速发展&#xff0c;未来它们可能会实现厘米级精度的自主耕作。 精确种植&#xff1a;AI算法可以分析土壤条件、气候数据和作物生长周期&#xff0c;以决定最佳种植地点和时间。 土壤管理&#xff1a;利用传感器和机器学习&#xff0c;机器…

Windows安装运行elasticsearch服务

官方下载地址&#xff1a;Download Elasticsearch | Elastic 我在linux上执行的下载命令&#xff1a;wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.5.3-linux-x86_64.tar.gz Elasticsearch&#xff08;简称ES&#xff09;是一款基于Apache Lu…

JVM学习-Arthas

Arthas Alibaba开源的Java诊断工具&#xff0c;在线排查问题&#xff0c;无需重启&#xff0c;动态跟踪Java代码&#xff0c;实时监控JVM状态Arthas支持JDK6&#xff0c;支持Linux/Mac/Windows&#xff0c;采用命令行交互模式&#xff0c;同时提供丰富的Tab自动补全功能&#…

前端传参数后端变量类型能够接受到List却无法接收到值

问题描述 今天写了个接口&#xff0c;下图所示 ReqVO里是这样的&#xff1a; 然后前端去请求&#xff0c;从请求结果中看发现这里值是在的&#xff08;有经验的可能就看出来了otherInfo.id: 这样以参数后端是接收不到的&#xff0c;但是当时没发现&#xff09; 传进来后端…

【cmake】cmake cache

cmake cache是什么 cmake cache是cmake在配置好后生成的一个CMakeCache.txt的文件&#xff0c;里面存储了一堆变量&#xff0c;这些变量一般都是关于项目的配置和环境的。 比如你用的什么编译器&#xff0c;编译器选项&#xff0c;还有项目目录。 例如&#xff08;在cmakelist…

uniAPP @input时报错

<input :maxlength"8" v-model"item.value" placeholder"请输入金额" input"inputFn" /> 这些些时会报以下错误 定位了好久之后发现input不支持 v-model和input一起使用 改成以下这般就正常啦 <input :maxlength"8&q…

【Cityengine】Cityengine生产带纹理的建筑模型导入UE4/UE5(下)

【Cityengine】Cityengine生产带纹理的建筑模型导入UE4/UE5&#xff08;下&#xff09; 一、导出数据&#xff08;2022中文版案例&#xff09;二、安装datasmith插件三、导入数据四、检查导入材质是否正常五、编辑替换材质六、安装模型编辑插件七、编辑替换建筑规则 一、导出数…

⌈ 传知代码 ⌋ 辅助任务改进社交帖子多模态分类

&#x1f49b;前情提要&#x1f49b; 本文是传知代码平台中的相关前沿知识与技术的分享~ 接下来我们即将进入一个全新的空间&#xff0c;对技术有一个全新的视角~ 本文所涉及所有资源均在传知代码平台可获取 以下的内容一定会让你对AI 赋能时代有一个颠覆性的认识哦&#x…