Changing the slave address of mlx90614 with bcm2835 via SMBus / I2C

How to change slave address mlx90614 with bcm2835 library? I tried the following code ...

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 check\n");
   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 clear\n");       
   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]);
}

The output of the program is as follows:

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

If after that I launched i2cdetect -y 1, the device will not appear in the table, but it will respond to programs that call it from 0x00 or 0x5a. After I used such a program, i2cdetect usually detects a device from address 0x5a.

So, I think the real question is: why can't I clear and rewrite eeprom 0x0e?

The communication description of the Mlx90614 SMBus is given below. The most relevant page is IMO, page 19, which actually gives an example of the pseudocode of what I'm trying to do. 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

+3
2

. : https://sf264.wordpress.com/2011/03/10/howto-mlx90614-und-pwm/

CRC-8 00002e4b00 0xa3.

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

mlx90614s. , ( , bcm2835 ).

"" Slaveaddress, = 0x2E (EEPROMAccess | SMBusAddressReg) data = 0x0000 ( ). "" 0x00 factory 0x5a ( - - ).

, = 0x005b, factory 0x5a 0x5b, Power Off Reset (POR), ( 0x5b) i2cdetect.

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, factory PWM. mlx90614 factory PWM I2C RPi2 i2cdetect I2C . mlx90614 bcm2835. , mlx90614 PWM-, SCL 2 . :

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

. , pwmctrl mlx90614 eeprom ( pwm SDA OpenDrain). , = 0x22 (.. EEPROMAccess | PWMCTRLAddressRegister), pwmctrl 0x0200 ( 020 ...). Reset (POR), SMBus ( I2C). Mlx90614 - ...

0

All Articles