Search code examples
pythonraspberry-pii2c

Write data to register with i2c in python


I need to change value in MLX96014 temperature sensors eeprom with raspberry pi and python. I can read its ram and eeprom without problems, but I cant write to it. Also every python MLX96014 library that I find dont have this function implemented for some reason. I tried to do this with arduino and it works great with this function:

void Adafruit_MLX90614::write16(uint8_t a, uint16_t v) {
  // a is register address
  // v value to write to eeprom 
  // _addr is device address (0x5a)
  uint8_t pec;
  uint8_t pecbuf[4];

  pecbuf[0] = _addr << 1;
  pecbuf[1] = a;
  pecbuf[2] = v & 0xff;
  pecbuf[3] = v >> 8;
  pec = crc8(pecbuf, sizeof pecbuf);

  Wire.beginTransmission(_addr); // start transmission to device
  Wire.write(a);                 // sends register address to write
  Wire.write(v & 0xff);          // lo
  Wire.write(v >> 8);            // hi
  Wire.write(pec);               // pec
  Wire.endTransmission(true);    // end transmission
}

So I tried to rewrite this function in python:

import board
import busio as io
import adafruit_mlx90614
import time
from smbus2 import SMBus, i2c_msg
import crc8
import sys

i2c = io.I2C(board.SCL, board.SDA, frequency=100000)
mlx = adafruit_mlx90614.MLX90614(i2c)

buf = bytearray(4)
buf[0] = 0x5a<<1
buf[1] = 0x24
buf[2] = 0 & 0xff
buf[3] = 0 >>8
pec = crc8.crc8()
pec.update(buf)
pec = pec.hexdigest() # = 0x28

i2c.writeto(0x5a, bytes([0x24]), stop=False)
buffer = bytearray(3)
buffer[0] = 0 & 0xFF
buffer[1] = (0 >> 8) & 0xFF
buffer[2] = 0x28
i2c.writeto(0x5a, buffer, stop=True)

i2cbus = SMBus(1)
emissivity=i2cbus.read_word_data(0x5a,0x24)
print(emissivity) # prints 65535 which is default

Code executes without errors. i2c.writeto() returns "None". So what im missing there?

Edit:

I found this (link) in datasheet but it confuses me. In datasheet it says that write comand bit is low and read is high. But in example both operations uses low. Also it looks like im supposed to send 0xb4 byte instead of 0x5a, but where to put it in pyhton code? If I put it in i2c.writeto() first parameter then I get I/O error because module is on address 5a (i2cdetect shows that).

By the way, I dont have access to osciloscope right now.

communication example


Solution

  • I dont know exactly why provided python code doesnt work but I have tried other i2c library and it started working. Here is the code snippet:

    import board
    import busio as io
    import crc8
    import adafruit_mlx90614
    import adafruit_bus_device.i2c_device as ada_i2c
    import time
    
    def change_emissivity(value,i2c):
        new_emissivity=round(65535*value)
        buf=bytearray(4)
        buf[0]=0x24
        buf[1]=0x00
        buf[2]=0x00
        buf[3]=0x28  # kai irasomi nuliai
        
        device=ada_i2c.I2CDevice(i2c,0x5a)
        
        with device:
            device.write(buf)
            
        time.sleep(0.01)
        
        buf[0]=0x5a<<1
        buf[1]=0x24
        buf[2]=new_emissivity & 0xff
        buf[3]=(new_emissivity >> 8) & 0xFF
        pec=crc8.crc8()
        pec.update(buf)
        pec=int(pec.hexdigest(),base=16)
        
        buf[0]=0x24
        buf[1]=new_emissivity & 0xff
        buf[2]=(new_emissivity >> 8) & 0xFF
        buf[3]=pec
        
        print(new_emissivity)
        
    i2c = io.I2C(board.SCL, board.SDA, frequency=100000)
    mlx = adafruit_mlx90614.MLX90614(i2c)
    change_emissivity(0.8, i2c)
    
    print("New emissivity: %.2f" %mlx._read_16(0x24))
    
    while(True):
        
        print("Ambient Temp: %.2f" %mlx.ambient_temperature
        print("Object Temp: %.2f" %mlx.object_temperature
    
        time.sleep(3)