栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

Linux裸机开发|SPI实验

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Linux裸机开发|SPI实验

SPI实验 一、SPI介绍 1.1 SPI简介

SPI(Serial Perripheral Interface),串行外围设备接口,是Motorola公司推出的一种同步串行接口技术,是一种高速、全双工的同步通信总线,SPI时钟频率比I2C要高很多,最高可以工作在上百MHz。SPI以主从方式工作,通常是一个主设备和一个或多个从设备,一般需要4根线

  • MISO:主设备数据输入,从设备数据输出
  • MOSI:主设备数据输出,从设备数据输入
  • SCLK:时钟信号,由主设备产生
  • CS:从设备片选信号,由主设备控制

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

SPI总线根据时钟极性(CPOL)和时钟相位(CPHA)的配置不同,可以有四种工作方式:

  • CPOL=0:串行同步时钟的空闲状态为低电平
  • CPOL=1:串行同步时钟的空闲状态为高电平
  • CPHA=0:在串行同步时钟的第一个跳变沿(上升或下降)数据被采样
  • CPHA=1:在串行同步时钟的第二个跳变沿(上升或下降)数据被采样

1.2 IMX6U ECSPI简介

IMX6U自带的SPI外设叫做ECSPI,全称Enhanced Configurable Serial Peripheral Interface,ECSPI有64 *32个接收FIFO(RXFIFO)和64 *32个发送FIFO(TXFIFO)。IMX6U有四个ECSPI,每个ECSPI支持四个片选信号,也就是说如果使用ECSPI的硬件片选信号的话,一个ECSPI可以支持4个外设;如果不使用硬件的片选信号就可以支持无数个外设,因为硬件片选只能使用指定的IO,而软件片选的话可以使用任意的IO

几个重要的ECSPI寄存器

  • ECSPIx_ConREG 寄存器:ECSPI控制寄存器

– BURST_LENGTH:突发传输数据长度,一般为8bit
– CHANNEL_SELECT:硬件片选信号通道选择
– DRCTL:SPI_RDY信号控制位,为0表示不关心SPI_RDY信号,为1边沿触发,为2电平触发SPI_DRY信号
– PRE_DIVIDER:SPI预分频器
– POST_DIVIDER:SPI分频值
– CHANNEL_MODE:通道主从模式设置
– SMC:开始模式控制,只在主模式下起作用
– XCH:控制SPI突发访问的开启,只在主模式下起作用
– HT:HT模式使能位,IMX6U不支持
– EN:SPI使能位,为0关闭,为1使能

  • ECSPIx_ConFIGREG 寄存器:ECSPI配置寄存器

– HT_LENGTH:HT模式下的消息长度设置,IMX6U不支持
– SCLK_CTL:设置SCLK信号线空闲状态电平
– DATA_CTL:设置DATA信号线空闲状态电平
– SS_POL:设置SPI片选信号极性
– SCLK_POL:设置SPI时钟信号极性
– SCLK_PHA:设置SPI时钟相位,也就是CPHA

  • ECSPIx_PERIODREG 寄存器:ECSPI采样周期寄存器

– CSD_CTL:片选信号延时控制位,用于设置片选信号和第一个时钟信号之间的时间间隔
– CSRC:SPI时钟源选择,为0选择SPI CLK,为1选择32.678KHz,一般设为0

  • ECSPIx_STATREG 寄存器:ECSPI状态寄存器

– TC:传输完成标志位,为0表示正在传输,为1表示传输完成
– RO:RXFIFO溢出标志位,为0表示无溢出,为1表示溢出
– RF:RXFIFO空标志位,为0表示不为空,为1表示为空
– RDR:RXFIFO数据请求标志位
– RR:RXFIFO就绪标志位,为0表示没有数据,为1表示至少有一个字的数据
– TF:TXFIFO满标志位,为0表示不为满,为1表示为满
– TDR:TXFIFO数据请求标志位
– TE:TXFIFO空标志位,为0表示至少有一个字的数据,为1表示为空

  • ECSPIx_TXDATA 寄存器:若要发送数据就向该寄存器写入数据
  • ECSPIx_RXDATA 寄存器:读取该寄存器里面的数据就可以得到刚刚接收到的数据
1.3 ICM-20608简介

ICM-20608是一款6轴MEMS传感器,包括3轴加速度和3轴陀螺仪,其内部有一个512字节的FIFO,加速度和陀螺仪的量程范围都可以编程设置,陀螺仪和加速度计都是16位的ADC,并支持I2C和SPI两种协议。ICM-20608的3轴方向如下图

ICM-20608的结构框图如下

ICM-20608的详细寄存器和位的介绍请参考ICM-20608寄存器手册,这里不做介绍

二、硬件介绍

本例程使用到的硬件资源如下:

  • LED0
  • RGB LCD屏幕
  • ICM20608
  • 串口
三、程序编写
  • 新建spi文件夹,在文件夹中创建实时时钟驱动文件bsp_spi.c和bsp_spi.h
void spi_init(ECSPI_Type *base);
unsigned char spich0_readwrite_byte(ECSPI_Type *base, unsigned char txdata);
void spi_init(ECSPI_Type *base)
{
	
	base->ConREG = 0; 
	base->ConREG |= (1 << 0) | (1 << 3) | (1 << 4) | (7 << 20); 

	
	base->ConFIGREG = 0; 		
	
	
	base->PERIODREG = 0x2000;		

	
	base->ConREG &= ~((0XF << 12) | (0XF << 8));	
	base->ConREG |= (0X9 << 12);					
}


unsigned char spich0_readwrite_byte(ECSPI_Type *base, unsigned char txdata)
{ 
	uint32_t  spirxdata = 0;
	uint32_t  spitxdata = txdata;

    
	base->ConREG &= ~(3 << 18);
	base->ConREG |= (0 << 18);

  	while((base->STATREG & (1 << 0)) == 0){} 
		base->TXDATA = spitxdata;
	
	while((base->STATREG & (1 << 3)) == 0){} 
		spirxdata = base->RXDATA;
	return spirxdata;
}
  • 新建icm20608文件夹,在文件夹中创建实时时钟驱动文件bsp_icm20608.c和bsp_icm20608.h
#define ICM20608_CSN(n)    (n ? gpio_pinwrite(GPIO1, 20, 1) : gpio_pinwrite(GPIO1, 20, 0))   

#define ICM20608G_ID			0xAF	
#define ICM20608D_ID			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


struct icm20608_dev_struc
{
	signed int gyro_x_adc;		
	signed int gyro_y_adc;		
	signed int gyro_z_adc;		
	signed int accel_x_adc;		
	signed int accel_y_adc;		
	signed int accel_z_adc;		
	signed int temp_adc;		

	
	signed int gyro_x_act;		
	signed int gyro_y_act;		
	signed int gyro_z_act;		
	signed int accel_x_act;		
	signed int accel_y_act;		
	signed int accel_z_act;		
	signed int temp_act;		
};

struct icm20608_dev_struc icm20608_dev;	


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);
struct icm20608_dev_struc icm20608_dev;	


unsigned char icm20608_init(void)
{	
	unsigned char regvalue;
	gpio_pin_config_t cs_config;

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

	
	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);
	
	
	spi_init(ECSPI3);	

	icm20608_write_reg(ICM20_PWR_MGMT_1, 0x80);		
	delayms(50);
	icm20608_write_reg(ICM20_PWR_MGMT_1, 0x01);		
	delayms(50);

	regvalue = icm20608_read_reg(ICM20_WHO_AM_I);
	printf("icm20608 id = %#Xrn", regvalue);
	if(regvalue != ICM20608G_ID && regvalue != ICM20608D_ID)
		return 1;
		
	icm20608_write_reg(ICM20_SMPLRT_DIV, 0x00); 	
	icm20608_write_reg(ICM20_GYRO_CONFIG, 0x18); 	
	icm20608_write_reg(ICM20_ACCEL_CONFIG, 0x18); 	
	icm20608_write_reg(ICM20_CONFIG, 0x04); 		
	icm20608_write_reg(ICM20_ACCEL_CONFIG2, 0x04); 	
	icm20608_write_reg(ICM20_PWR_MGMT_2, 0x00); 	
	icm20608_write_reg(ICM20_LP_MODE_CFG, 0x00); 	
	icm20608_write_reg(ICM20_FIFO_EN, 0x00);		
	return 0;
}

	

void icm20608_write_reg(unsigned char reg, unsigned char value)
{
	
	reg &= ~0x80;	
	
	ICM20608_CSN(0);						
	spich0_readwrite_byte(ECSPI3, reg); 	 
	spich0_readwrite_byte(ECSPI3, value);	
	ICM20608_CSN(1);						
}	


unsigned char icm20608_read_reg(unsigned char reg)
{
	unsigned char reg_val;	   	

	
	reg |= 0x80; 	
	
   	ICM20608_CSN(0);               					
  	spich0_readwrite_byte(ECSPI3, reg);     		 
  	reg_val = spich0_readwrite_byte(ECSPI3, 0xFF);	
 	ICM20608_CSN(1);                				
  	return(reg_val);               	 				
}


void icm20608_read_len(unsigned char reg, unsigned char *buf, unsigned char len)
{  
	unsigned char i;
	
	
	reg |= 0x80; 
		
   	ICM20608_CSN(0);               				
  	spich0_readwrite_byte(ECSPI3, reg);			   	   
 	for(i = 0; i < len; i++)					
 	{
		buf[i] = spich0_readwrite_byte(ECSPI3, 0xFF);	
	}
 	ICM20608_CSN(1);                			
}


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


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

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;
}
  • 主函数main.c中编写测试程序
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); 
}



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


 void imx6ul_hardfpu_enable(void)
{
	uint32_t cpacr;
	uint32_t fpexc;

	
	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)
{
	unsigned char state = OFF;

	imx6ul_hardfpu_enable();	
	int_init(); 				
	imx6u_clkinit();			
	delay_init();				
	clk_enable();				
	led_init();					
	beep_init();				
	uart_init();				
	lcd_init();							

	tftlcd_dev.forecolor = LCD_RED;
	lcd_show_string(50, 10, 400, 24, 24, (char*)"ALPHA-IMX6U SPI TEST");  
	lcd_show_string(50, 40, 200, 16, 16, (char*)"ICM20608 TEST");  
	lcd_show_string(50, 60, 200, 16, 16, (char*)"ATOM@ALIENTEK");  
	lcd_show_string(50, 80, 200, 16, 16, (char*)"2019/3/27");  
	
	while(icm20608_init())		
	{
		lcd_show_string(50, 100, 200, 16, 16, (char*)"ICM20608 Check Failed!");
		delayms(500);
		lcd_show_string(50, 100, 200, 16, 16, (char*)"Please Check!        ");
		delayms(500);
	}	

	lcd_show_string(50, 100, 200, 16, 16, (char*)"ICM20608 Ready");
	
	lcd_show_string(50, 130, 200, 16, 16, (char*)"accel x:");  
	lcd_show_string(50, 150, 200, 16, 16, (char*)"accel y:");  
	lcd_show_string(50, 170, 200, 16, 16, (char*)"accel z:");  
	lcd_show_string(50, 190, 200, 16, 16, (char*)"gyro  x:"); 
	lcd_show_string(50, 210, 200, 16, 16, (char*)"gyro  y:"); 
	lcd_show_string(50, 230, 200, 16, 16, (char*)"gyro  z:"); 
	lcd_show_string(50, 250, 200, 16, 16, (char*)"temp   :"); 

	lcd_show_string(50 + 181, 130, 200, 16, 16, (char*)"g");  
	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*)"o/s"); 
	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*)"C");
	
	tftlcd_dev.forecolor = LCD_BLUE;

	while(1)					
	{		
		icm20608_getdata();
		integer_display(50 + 70, 130, 16, icm20608_dev.accel_x_adc);
		integer_display(50 + 70, 150, 16, icm20608_dev.accel_y_adc);
		integer_display(50 + 70, 170, 16, icm20608_dev.accel_z_adc);
		integer_display(50 + 70, 190, 16, icm20608_dev.gyro_x_adc);
		integer_display(50 + 70, 210, 16, icm20608_dev.gyro_y_adc);
		integer_display(50 + 70, 230, 16, icm20608_dev.gyro_z_adc);
		integer_display(50 + 70, 250, 16, icm20608_dev.temp_adc);

		decimals_display(50 + 70 + 50, 130, 16, icm20608_dev.accel_x_act);
		decimals_display(50 + 70 + 50, 150, 16, icm20608_dev.accel_y_act);
		decimals_display(50 + 70 + 50, 170, 16, icm20608_dev.accel_z_act);
		decimals_display(50 + 70 + 50, 190, 16, icm20608_dev.gyro_x_act);
		decimals_display(50 + 70 + 50, 210, 16, icm20608_dev.gyro_y_act);
		decimals_display(50 + 70 + 50, 230, 16, icm20608_dev.gyro_z_act);
		decimals_display(50 + 70 + 50, 250, 16, icm20608_dev.temp_act);

#if 0		
		printf("accel x = %drn",icm20608_dev.accel_x_adc);
		printf("accel y = %drn",icm20608_dev.accel_y_adc);
		printf("accel z = %drn",icm20608_dev.accel_z_adc);
		printf("gyrp  x = %drn",icm20608_dev.gyro_x_adc);
		printf("gyro  y = %drn",icm20608_dev.gyro_y_adc);
		printf("gyro  z = %drn",icm20608_dev.gyro_z_adc);
		printf("temp    = %drn",icm20608_dev.temp_adc);
#endif
		delayms(120);
		state = !state;
		led_switch(LED0,state);	
	}
	return 0;
}
四、下载验证
  • 修改Makefile文件:修改TARGET为icm20608,追加“bsp/spi”和“bsp/icm20608”文件夹
  • 使用imxdownload软件将bin文件下载到SD卡中
  • 烧写成功后,插入SD卡,复位开发板后,LCD屏幕上会显示获取到的传感器数据
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/338642.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号