I'm experiencing an issue with I2C communication between the SEN5X sensor and multiple nRF9160 DK boards. The problem manifests as an crc error during I2C read operations, specifically a -EIO
error, indicating an Input/Output error. This issue occurs on some nRF9160 DK boards but not all, which suggests it might be a hardware or configuration issue.
The output is like this.
*** Booting nRF Connect SDK v3.5.99-ncs1-1 ***
Welcome to IOTPM running on nrf9160dk_nrf9160
Start the Sen55
SEN5X: write: 0xd304
Get the sensor information
SEN5X: write: 0xd014
SEN5X: Error i2c read
crc error: byte 0: found: 0x05, expected 0xc2
crc error: byte 2: found: 0x63, expected 0x7b
crc error: byte 4: found: 0x00, expected 0x02
crc error: byte 6: found: 0x41, expected 0x81
crc error: byte 8: found: 0x80, expected 0x81
crc error: byte 10: found: 0x00, expected 0xaa
crc error: byte 12: found: 0x00, expected 0x49
crc error: byte 14: found: 0x3f, expected 0xfb
crc error: byte 16: found: 0x80, expected 0x81
crc error: byte 18: found: 0x00, expected 0xaa
crc error: byte 20: found: 0x00, expected 0x49
crc error: byte 22: found: 0x3f, expected 0xfb
crc error: byte 24: found: 0x80, expected 0x81
crc error: byte 26: found: 0x00, expected 0xaa
crc error: byte 28: found: 0x00, expected 0x49
crc error: byte 30: found: 0x3f, expected 0xfb
SEN5X: write: 0xd033
SEN5X: Error i2c read
crc error: byte 0: found: 0x05, expected 0xc2
crc error: byte 2: found: 0x63, expected 0x7b
crc error: byte 4: found: 0x00, expected 0x02
crc error: byte 6: found: 0x41, expected 0x81
crc error: byte 8: found: 0x80, expected 0x81
crc error: byte 10: found: 0x00, expected 0xaa
crc error: byte 12: found: 0x00, expected 0x49
crc error: byte 14: found: 0x3f, expected 0xfb
crc error: byte 16: found: 0x80, expected 0x81
crc error: byte 18: found: 0x00, expected 0xaa
crc error: byte 20: found: 0x00, expected 0x49
crc error: byte 22: found: 0x3f, expected 0xfb
crc error: byte 24: found: 0x80, expected 0x81
crc error: byte 26: found: 0x00, expected 0xaa
crc error: byte 28: found: 0x00, expected 0x49
crc error: byte 30: found: 0x3f, expected 0xfb
SEN5X: Device name: 8
SEN5X: Serial number: 8
Connect to the LTE
I have an overlay with the following &uart0 {
status = "okay";
};
&i2c2 {
status = "ok";
clock-frequency = <100000>;
compatible = "nordic,nrf-twim";
pinctrl-0 = <&i2c2_default>;
pinctrl-1 = <&i2c2_sleep>;
sen55: sen55@69{
// compatible = "nordic,nrf-twim";
compatible = "i2c-device";
reg = <0x69>;
label = "sensirion i2c sen55";
};
};
&i2c2_default {
group1 {
psels = <NRF_PSEL(TWIM_SDA, 0, 30)>, <NRF_PSEL(TWIM_SCL, 0, 31)>;
bias-pull-up;
};
};
The errer is coming from the readmany() function below.#include <zephyr/drivers/i2c.h>
#include <sen5x/sen5x.h>
const struct device * sen5x_dev;
bool sen5x_init(const struct device * dev){
sen5x_dev=dev;
if(!device_is_ready(sen5x_dev)){ printk("SEN5X: I2C device not ready\n"); return false;}
uint32_t i2c_cfg = I2C_SPEED_SET(I2C_SPEED_STANDARD) | I2C_MODE_CONTROLLER;
int32_t ret=i2c_configure(sen5x_dev, i2c_cfg);
if(ret){printk("SEN5X: Error configuring I2C\n");return false;}
return true;
}
void sen5x_write_short(uint16_t command){
uint8_t data[2];
data[0]=(command&0xFF00)>>8;
data[1]=(command&0x00FF)>>0;
printk("SEN5X: write: 0x%02x%02x\n",data[0],data[1]);
i2c_write(sen5x_dev,data,2,PM_I2C_ADDRESS);
}
void sen5x_write(uint8_t * data, uint8_t len){
int32_t ret=i2c_write(sen5x_dev, data, len, PM_I2C_ADDRESS);
if(ret){printk("SEN5X: Error i2c write\n");}
}
void sen5x_read(uint8_t * data, uint8_t len){
int32_t ret=i2c_read(sen5x_dev, data, len, PM_I2C_ADDRESS);
if(ret){printk("SEN5X: Error i2c read\n");}
}
void sen5x_read_many(uint8_t * many, uint8_t len){
uint8_t data[100];
uint8_t mlen=len+(len/2);
sen5x_read((uint8_t*)data,mlen);
//printk("SEN5X: many (%i)",mlen);
//for(uint32_t i=0;i<mlen;i++){printk("%02x",(uint32_t)data[i]);}
//printk("\n");
for(uint32_t i=0;i<len/2;i++){
many[2*i] =data[3*i];
many[2*i+1]=data[3*i+1];
if(data[3*i+2]!=sen5x_crc(&many[2*i],2)){printk("crc error: byte %i: found: 0x%02x, expected 0x%02x\n",(2*i),data[3*i+2],sen5x_crc(&many[2*i],2));}
}
}
uint8_t sen5x_crc(const uint8_t * data, uint8_t len){
uint8_t crc = 0xFF;
for (uint32_t current_byte = 0; current_byte < len; ++current_byte) {
crc ^= (data[current_byte]);
for (uint8_t crc_bit = 8; crc_bit > 0; --crc_bit) {
if(crc & 0x80)
crc = (crc << 1) ^ 0x31;
else
crc = (crc << 1);
}
}
return crc;
}
void sen5x_reset(){
sen5x_write_short(0xD304);
k_msleep(100);
}
void sen5x_get_serial(char * serial, uint8_t len){
sen5x_write_short(0xD033);
for(uint32_t i=0;i<len;i++){ serial[i]=0; }
k_msleep(500);
sen5x_read_many(serial,len);
}
void sen5x_get_name(char * name, uint8_t len){
sen5x_write_short(0xD014);
for(uint32_t i=0;i<len;i++){ name[i]=0; }
k_msleep(500);
sen5x_read_many(name,len);
}
void sen5x_get_version(struct sen5x_version * pmv){
sen5x_write_short(0xD100);
k_msleep(500);
sen5x_read_many((uint8_t*)pmv,8);
}
void sen5x_start(){
sen5x_write_short(0x0021);
k_msleep(500);
}
void sen5x_stop(){
sen5x_write_short(0x0104);
k_msleep(50);
}
void sen5x_get_measurement(struct sen5x_measurement * pmm){
sen5x_write_short(0x03C4);
k_msleep(20);
uint8_t data[16];
sen5x_read_many(&data[0],16);
pmm->mass_concentration_pm1p0=data[0]<<8|data[1];
pmm->mass_concentration_pm2p5=data[2]<<8|data[3];
pmm->mass_concentration_pm4p0=data[4]<<8|data[5];
pmm->mass_concentration_pm10p0=data[6]<<8|data[7];
pmm->ambient_humidity=data[8]<<8|data[9];
pmm->ambient_temperature=data[10]<<8|data[11];
pmm->voc_index=data[12]<<8|data[13];
pmm->nox_index=data[14]<<8|data[15];
}
void sen5x_print_measurement(struct sen5x_measurement * pmm){
printk("Mass concentration pm1p0: %.2f ug/m3\n", (pmm->mass_concentration_pm1p0 / 10.0f));
printk("Mass concentration pm2p5: %.2f ug/m3\n", (pmm->mass_concentration_pm2p5 / 10.0f));
printk("Mass concentration pm4p0: %.2f ug/m3\n", (pmm->mass_concentration_pm4p0 / 10.0f));
printk("Mass concentration pm10p0: %.2f ug/m3\n", (pmm->mass_concentration_pm10p0 / 10.0f));
printk("Ambient humidity: %.2f %%RH\n", (pmm->ambient_humidity / 100.0f));
printk("Ambient temperature: %.3f C\n", (pmm->ambient_temperature / 200.0f));
printk("Voc index: %.2f\n", (pmm->voc_index / 10.0f));
printk("Nox index: %.2f\n", (pmm->nox_index / 10.0f));
}
void sen5x_get_info(struct sen5x_info * info){
sen5x_get_name(info->name,32);
sen5x_get_serial(info->serial,32);
}
void sen5x_print_info(struct sen5x_info * info){
printk("SEN5X: Device name: %s\n", info->name);
printk("SEN5X: Serial number: %s\n", info->serial);
}
void sen5x_print_details(){
char name[32];
sen5x_get_name(name,32);
printk("SEN5X: Device name: %s\n",name);
char serial[32];
sen5x_get_serial(serial,sizeof(serial));
printk("SEN5X: Serial number: %s\n", serial);
struct sen5x_version pmv;
sen5x_get_version(&pmv);
printk("SEN5X: FW: %u.%u.%u\n", pmv.firmware_major,pmv.firmware_minor, pmv.firmware_debug);
printk("SEN5X: HW: %u.%u\n", pmv.hardware_major,pmv.hardware_minor);
printk("SEN5X: PR: %u.%u\n", pmv.protocol_major,pmv.protocol_minor);
}