c-通过SMBus/I2C使用bcm2835更改mlx90614的从属地址



如何使用bcm2835库更改mlx90614的从属地址?我已经尝试了以下代码。。。

int main()
{
// Buffer, where I store data which I'll send
unsigned char buf[6];
// bcm2835 i2c module intialisation code
bcm2835_init();
bcm2835_i2c_begin();
bcm2835_i2c_set_baudrate(25000);
bcm2835_i2c_setSlaveAddress(0x00);
// For debug purposes, I read what reason codes operations give.
bcm2835I2CReasonCodes why;
bcm2835_i2c_begin();
// function which reads and prints what value eeprom address 0x0e has. 
// See below the main.
printf("Initial checkn");
check(); // this time it prints a factory default value 0x5a.
// To access eeprom, the command must start with 0x2X, where x determines the          
// address, resulting 0x2e.
buf[0] = 0x2e;
// According to datasheet, I first have to clear the address before 
// real write operation.
buf[1] = 0x00;
buf[2] = 0x00;
why = bcm2835_i2c_write(buf,3);
reason(why); // resolves and prints the reason code. This time it prints OK
// according to datasheet, eeprom needs 5ms to make a write operation,
// but I give it 2 seconds.       
sleep(2); 
// Then I check did the value in eeprom 0x0e change. IT DOESN'T!
printf("Check after clearn");       
check();
// Then I try to write a new address to the eeprom but since the clearing 
// the register didn't work, this is very unlikely to work either.
buf[0] = 0x2e;
buf[1] = 0x4b;
buf[2] = 0x00;
why = bcm2835_i2c_write(buf,3);
reason(why);
sleep(2); 
// The datasheet says that I have to reset the power supply and after that
// the device should respond to the new slave address.
// I do that by pluging off the jumper wires and reconnecting them 
// after the program has finnished.
bcm2835_i2c_end();
return 0;
}
// The function I use to determine what the reason code was.
void reason(bcm2835I2CReasonCodes why)
{
printf("Reason is: ");
if(why == BCM2835_I2C_REASON_OK)
{
printf("OK");
}else if(why == BCM2835_I2C_REASON_ERROR_NACK){
printf("NACK");
}else if(why == BCM2835_I2C_REASON_ERROR_CLKT){
printf("Clock stretch");
}else if(why == BCM2835_I2C_REASON_ERROR_DATA ){
printf("Data error");
}else{
printf("Dunno lol");
}
printf("n");
return;
}
// Here I read eeprom 0x2e.
void check()
{
unsigned char buf[6];
unsigned char reg = 0x2e;
bcm2835I2CReasonCodes why;
// better safe than sorry with the buffer :)
buf[0] = 0;
buf[1] = 0;
buf[2] = 0;
why = bcm2835_i2c_write (&reg, 1);
reason(why);
why = bcm2835_i2c_read_register_rs(&reg,&buf[0],3);
reason(why);
printf("Buffer values are: %x ; %x ; %x n", buf[0], buf[1], buf[2]);
}

程序的输出如下:

Initial check
Reason is: OK
Reason is: OK
Buffer values are: 5a ; be ; dc
Reason is: OK
Check after clear
Reason is: OK
Reason is: OK
Buffer values are: 5a ; be ; dc
Reason is: OK

如果我在那之后运行i2cdetect-y 1,该设备不会出现在表中,但它会响应从0x00或0x5a调用它的程序。在我使用了这样的程序后,i2cdetect会从地址0x5a正常检测设备。

所以我想真正的问题是,为什么我不能清除并重写eeprom 0x0e

Mlx90614 SMBus通信的描述如下。最相关的页面是IMO第19页,它实际上给出了我试图做的伪代码示例。http://www.melexis.com/Assets/SMBus-communication-with-MLX90614-5207.aspx

这是mlx90614的数据表http://www.melexis.com/Assets/IR-sensor-thermometer-MLX90614-Datasheet-5152.aspx

这是bcm2835的文档www.airspayce.com/mikem/bcm2835/group_i2c.html

您必须添加一个错误字节。请查看此网站了解解释:https://sf264.wordpress.com/2011/03/10/howto-mlx90614-und-pwm/

计算CCD_ 1的CRC-8得到CCD_。

我曾在这个网站上计算CRC-8:http://smbus.org/faq/crc8Applet.htm

我还没有测试过,但我认为这应该有效:

buf[0] = 0x2e;
buf[1] = 0x4b;
buf[2] = 0x00;
buf[3] = 0xa3;
why = bcm2835_i2c_write(buf,4);

我的mlx90614s遇到了完全相同的问题。这是我用来解决它的写例程(请注意,在调用该例程之前,bcm2835库已正确初始化)。

首先,我用"正确"的从地址调用写入例程,命令=0x2E(EEPROM访问|SMBusAddressReg),数据=0x0000(用于擦除)。"正确"的从地址可以是0x00或工厂默认的0x5a(或者芯片的真实地址)。

擦除后,我使用了相同的写入例程,但现在数据=0x005b,从出厂默认值0x5a更改为0x5b,进行了断电重置(POR),设备显示为使用i2cdetect的新地址(0x5b)。

uint8_t memWriteI2C16(uint8_t SlaveAddress, uint8_t command, uint16_t data)
{    
unsigned char arr[5];
uint8_t status;
//Prepare for CRC8 calc
arr[0] = SlaveAddress<<1;        //NB! 7 bit address + a 0 write bit.      
arr[1] = command;                //Command byte in packet       
arr[2] = *((uint8_t *)(&data));  //Extract data low byte
arr[3] = *((uint8_t *)(&data)+1);//Extract data high byte
arr[4] = crc8(&arr[0],4)&0xFF;   //Calculate PEC by CRC8
bcm2835_i2c_setSlaveAddress(SlaveAddress);//Transmit address byte to I2C/SMBus
status = bcm2835_i2c_write (&arr[1], 4);  //Transmit Command,DataL, DataH and PEC       
bcm2835_delay(5);                         //Delay at least 5ms
return (status);
}

我使用的CRC8程序是:

// Return CRC-8 of the data, using x^8 + x^2 + x + 1 polynomial.  
// A table-based algorithm would be faster, but for only a few bytes 
// it isn't worth the code size. 
// Ref: https://chromium.googlesource.com/chromiumos/platform/vboot_reference/+/master/firmware/lib/crc8.c
uint8_t crc8(const void *vptr, int len)
{
const uint8_t *data = vptr;
unsigned crc = 0;
int i, j;
for (j = len; j; j--, data++) {
crc ^= (*data << 8);
for(i = 8; i; i--) {
if (crc & 0x8000)
crc ^= (0x1070 << 3);
crc <<= 1;
}
}
return (uint8_t)(crc >> 8);
}

此外:根据mlx90614的数据表,其通电后的默认出厂状态为PWM输出。当将工厂PWM状态下的mlx90614挂接到RPi2上的I2C总线时,i2cdetect会报告总线上的数百个I2C设备。尝试使用bcm2835库访问mlx90614失败。所需的是通过将SCL保持在低电平至少2ms来迫使mlx90614脱离其PWM状态。以下是我所做的:

uint8_t mlx90614SMBusInit()
{
//Hold SCL low for at leat 2ms in order to force the mlx90614 into SMBus-mode
//Ref Melix app note regarding SMBus comm chapter 6.1 and table 5. 
uint8_t SCL1 = 3; //BCM2835 pin no 3 -RPi2 and RevB+. Use if i2cdetect -y 1
uint8_t SCL0 = 1; //BCM2835 pin no 1 -RPi2 and RevB+. Use if i2cdetect -y 0
uint8_t SCL;
SCL = SCL1; 
bcm2835_gpio_fsel(SCL, BCM2835_GPIO_FSEL_OUTP);
bcm2835_gpio_write(SCL ,LOW);
bcm2835_delay( 3); //Delay >2 ms
bcm2835_gpio_write(SCL ,HIGH); 
return (1);
}

然而,这只会持续到下一次通电。因此,需要写入mlx90614的eeprom中的pwmctrl寄存器(禁用pwm输出并强制SDA到OpenDrain)。我使用了前面描述的写例程,命令=0x22(即EEPROM访问|pwmctrl地址寄存器),在擦除pwmctrl寄存器内容后,我向其写入0x0200(我的设备中的前3个半字节是020…)。断电复位(POR),设备在SMBus模式下启动(I2C总线没有干扰)。mlx90614是一个棘手的小部件。。。

此外,如果您使用任何linux发行版的I2C工具包(在我的情况下,我使用的是debian发行版),您可以使用i2cset命令更改地址(https://manpages.debian.org/buster/i2c-tools/i2cset.8.en.html),这里有一个例子:

#Find your I2C bus in your linux with the command i2cdetect -l 
#(in my case is the i2c-1)
i2cdetect -l
i2c-1   i2c             bcm2835 I2C adapter                     I2C adapter
#Write the word 0x0000 to the address 0x2E and append the PEC check byte.
i2cset -y 1 0x5a 0x2E 0x0000 wp 
#Write the new address as a word, to the address 0x2E and append the PEC 
#check byte. In my case the new address is 0x005c
i2cset -y 1 0x5a 0x2E 0x005c wp
#Perform a power cycle of the Mlx90614 device
#Check the new address with the command i2cdetect -y 1
i2cdetect -y 1

相关内容

  • 没有找到相关文章

最新更新