SHT3x ADSP 驱动调试(供应商无驱动,使用已经调试好的驱动hts221修改)

SHT3x 简介

sht3x 是一个温度湿度类型的sensor,该系列有sht30、sht31、sht35 误差精度等是各不相同的,当然价格也是不同的。 可以在网上搜索Sensirion_Humidity_Sensors_SHT3x_Datasheet_digital了解更更多。

IIC读写

ADSP 中的iic读写默认是寄存器地址是八位,sht3x从手册上看,没有寄存器地址这个概念。 取而代之是command,分为高八位和低八位,这个可以理解为16位寄存器地址。看下图可以, 这个是设置sensor周期模式的设置方式,首先写iic地址得到ack后,再写cmd MSB得到ack后,最后写cmd LSB得到ack,没有以后了。 按照传统的iic读写。后面应该读写这个地址的数据。这个比较特殊,本人还是第一次见到。

在这里插入图片描述下图是读取sensor的温湿度数据(周期性,提前设置的读取频率想关),严格按照时序要求,可以获取温湿度数据以及crc校验,来验证读写的数据的正确性。
crc验证,文档上和网上都有,这里不再赘述。
在这里插入图片描述

MCU 读写

一开始没有sht3x msm9809w平台下(ADSP)的驱动,找个一块stm32板子飞线先调试通,再使用hts221驱动去改,代码如下:

void sht3x_init()
{
	u8 err= 0;
	delay_ms(250); 
	//0x2130  表示周期模式 周期1ms
	IIC_Start();
	IIC_Send_Byte(0x88);
	err = IIC_Wait_Ack();
	if(err)
		printf("\r\nack err 1");
	IIC_Send_Byte(0x21);
	err = IIC_Wait_Ack();
	if(err)
		printf("\r\nack err 2");
	IIC_Send_Byte(0x30);
	err = IIC_Wait_Ack();
	if(err)
		printf("\r\nack err 3");
	IIC_Stop();
	
	delay_ms(150); 
	printf("\r\n sht3x_init");
}	
void sht30_read_temp_humi(u8 *p)
{
	u8 err;
	u8 i;
	IIC_Start();
	IIC_Send_Byte(0x88);
	err = IIC_Wait_Ack();
	if(err)
		printf("\r\nack err 1");
	IIC_Send_Byte(0xe0);
	err = IIC_Wait_Ack();
	if(err)
		printf("\r\nack err 2");
	IIC_Send_Byte(0x00);
	err = IIC_Wait_Ack();
	if(err)
		printf("\r\nack err 3");

	IIC_Start();
	IIC_Send_Byte(0x89);
	err = IIC_Wait_Ack();
	if(err)
		printf("\r\nack err 4");
		
	p[0] = IIC_Read_Byte(1);
	p[1] = IIC_Read_Byte(1);
	p[2] = IIC_Read_Byte(1);
	p[3] = IIC_Read_Byte(1);
	p[4] = IIC_Read_Byte(1);
	p[5] = IIC_Read_Byte(0);
	IIC_Stop();
	//打印读取读取数据
	printf("\r\nread data= ");
	for(i=0; i<6; i++){
		printf("-0x%02x",p[i]);
	}
}

int sht30_data(u8 *p)
{
	u16 data;
	u8 crc_result;
	float temp,humi;

	sht30_read_temp_humi(p);
	//crc校验
	crc_result=sht30_crc8_check(p,2,p[2]);//crc 没有贴出来
	if(crc_result==0)
	{
		data=((u16)p[0] << 8) | p[1];
		temp = ((175.0 * ((float)data) / 65535.0 - 45.0) );
		printf("\r\ntemp=%f",temp);
	}else	{
		printf("\r\n crc temp err");
		return 1;
	}
	//crc校验
	crc_result=sht30_crc8_check(p+3,2,p[5]);
	if(crc_result==0){
		//参考上面温度的代码
		data=((u16)p[3] << 8) | p[4];
		humi = ((100.0 * (float)data / 65535.0) );
		printf("\r\nhumi=%f",humi);
		return 0;
	}else{
		printf("\r\n crc humi");
		return 2;
	}
}



周期性调用sht30_data 可以读取温湿度

MSM8909w 平台下的调试

首先修改iic读写,默认8位寄存器地址,改成16位寄存器地址,参考其他该平台下的驱动可以做找到

 // change I2C config to use 16-bit register addresses 
    device_info[0].port_config.bus_config.i2c->reg_addr_type = SNS_DDF_I2C_REG_ADDR_16BIT;  //add huangcheng 2020-05-06 16bit iic address
     // Open communication port to the device.
    status = sns_ddf_open_port(&state->port_handle, &device_info->port_config);

添加device_info[0].port_config.bus_config.i2c->reg_addr_type = SNS_DDF_I2C_REG_ADDR_16BIT; 寄存器地址就变成16读写了。接下来就是验证,

	reg[0] = 0x30;//Set sampling period 0x2130
	reg[1] = 0x21;
	status = sns_dd_hts222_write_regs(0x3021, reg, 0);  //2130(cmd)1hz get data, force write 1 byte ,1->0 write 0 byte ??? --OK
	if (status!=SNS_DDF_SUCCESS){
        DD_MSG_0(ERROR, "HC write 0x2130 failed");
		return status;
	}

按照MCU的去写器件地址应该写0x2130,尝试了好久iic读写不成功,用示波器抓图看到第二个数据没返回ack,仔细对了下数据发现写的是0x30 0x21,和文档上的刚好是相反的,把0x2130 改成0x3021 iic能正常读写。写个数,一开始不知道可不可以写0个,写个了两个,把0x3021再写一遍可以成功,测试使用0 也是可以成功的。
在这里插入图片描述上述已经把iic 搞定了。

ADSP获取数据里面的坑!!!

由于是拿hts221 驱动修改过来的,首先看懂hts221 驱动的代码,代码阅读能力差,只能多加打印信息,看代码的probe init getdata 等相关的函数调用
首先proble 有读iic chipid 的不成功直接返回了,直接注释掉。init 也用也注释掉,设置sht3x读频率0x3021(1s一次)。由于注释reset 导致上层怎样也看不到数据,底层根本没报数据,继续添加打印,才找到这个问题,根本原因在于对hts221驱动不熟悉,没办法重新研究hts221寄存器手册,结合代码对比,有些运行要通过寄存器的状态来判读,修改验证了N多次,终于可以读到数据了,数据不对,crc 是OK的。这个折腾了3天,才找到原因。主要原因总结下
1 、iic 的问题和驱动需要修改的问题上述已经说明
2、iic继续报错,温湿度是分开读取的,设置周期1s一次,不能间隔小于这个时间,不能分开读取,在某个一读取后,利用全局变量供另一个使用。
3、数据计算不对,没有找到打印小数的函数,自带的函数%f 打印不出来,其他驱动也没找到,就扩大100,这样打印的数据OK

	humid_adc=(uint16_t)((reg[3]<<8)|reg[4]);
	humi = (10000.0*((float)humid_adc)/65535.0);		// x 100, 32.32 -> 3232
	DD_MSG_1(MED, "tmpt %d", humi);
	humi_h = (humi/100) << 16;
	humi_l = (humi%100)*65536/100;
	DD_MSG_1(MED, "humi_h %d", humi_h);
	DD_MSG_1(MED, "humi_l %d", humi_l);
	humi = humi_h + humi_l;
	DD_MSG_1(MED, "humi h<<16 + l*65536/100 %d", humi);
	*humid = humi;
	DD_MSG_1(MED, "tmptx100 %d", *humid);
	DD_MSG_1(MED, " humi %d", *humid);

4、数据上报不对

#define Q16INT(a)     ((a)>>16)
#define Q16DEC2(a)    ((((a)>=0?(a):-(a))&0x0000FFFF)*100/65536)

这是打印转化的函数,反过来推理上报数据的格式,高16 位放整数部分,低16位放大100倍放小数,这样反过来推精度有点误差,实际验证相差0.01(100倍的情况下),这样上层能获取的数据,基本调试通,但是按照驱动的要求休眠,复位,以及单次、周期、状态信息的读取还没完善,以后完善补充本文。最有一句,没有驱动提供,对于新手来说真是个坑!
2020-05-14

猜你喜欢

转载自blog.csdn.net/HC_huangcheng/article/details/106115358