Изменение адреса подчиненного устройства mlx90614 на bcm2835 через SMBus / I2C

Как изменить подчиненный адрес mlx90614 с помощью библиотеки bcm2835? Я пробовал следующий код ...

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

Вывод программы следующий:

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


person TukeV    schedule 10.02.2014    source источник


Ответы (3)


Вы должны добавить байт ошибки. Посетите этот веб-сайт, чтобы получить объяснение: 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);
person Fux    schedule 03.05.2015

Боролся с точно такой же проблемой с моим mlx90614s. Вот подпрограмма записи, которую я использовал для ее решения (обратите внимание, что библиотека bcm2835 была правильно инициализирована перед вызовом подпрограммы).

Сначала я вызвал процедуру записи с «правильным» подчиненным адресом, command = 0x2E (EEPROMAccess | SMBusAddressReg) и data = 0x0000 (для стирания). «Правильный» адрес подчиненного устройства может быть 0x00 или заводским значением по умолчанию 0x5a (или любым другим, что является истинным адресом чипа).

После стирания я использовал ту же процедуру записи, но теперь с data = 0x005b, чтобы изменить заводскую настройку 0x5a на 0x5b, выполнил сброс при выключении питания (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, его заводское состояние по умолчанию после включения - это выход ШИМ. При подключении mlx90614 в заводском состоянии PWM к шине I2C на RPi2, i2cdetect сообщает о сотнях устройств I2C на шине. Попытка получить доступ к mlx90614 с помощью библиотеки bcm2835 завершается неудачей. Что требуется, так это вывести mlx90614 из состояния ШИМ, удерживая низкий уровень вероятности нежелательной почты не менее 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 в eeprom mlx90614 (отключить вывод pwm и принудительно использовать SDA для OpenDrain). Я использовал процедуру записи, как описано ранее, с command = 0x22 (т.е. EEPROMAccess | PWMCTRLAddressRegister), и после стирания содержимого pwmctrl-register я написал ему 0x0200 (первые 3 полубайта были 020 на моих устройствах ...). Power Off Reset (POR) и устройство запустилось в режиме SMBus (без заклинивания шины I2C). Mlx90614 - хитрый маленький компонент ...

person SteinarK    schedule 10.05.2015

Также, если вы используете пакет I2C-tools из любого дистрибутива Linux (в моем случае я использую дистрибутив 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
person Enmanuel Medina    schedule 03.07.2020