SPX-17873 Power Meter in Python

Hi, I’m working on accessing the 17873 Power Meter with a Qwiic HAT on a Raspberry Pi, and am struggling to unlock the ACS37800 for write operations using Python. Based on the datasheet and using the SparkFun Arduino library as reference, it seems like this should be simple, but the following is not working for me:

import smbus
bus = smbus.SMBus(1)
bus.write_byte_data(0x60, 0x2F, 0x4F70656E)
val = bus.read_byte_data(0x60, 0x30)
print(val)  # Should return 1 if write access is enabled?

I know 0x60 is still the proper device address, since I can query some of the non-zero EEPROM parameters and get non-zero values (for example, register 0x0F). I’ve also tried writing the access code as hex, binary, and numeric with the same result.

I’m sure I’m missing something basic here. Can anyone help? Thanks in advance!

This is kind of a shot in the dark, but it might need some delays…try this and see if it works?

import smbus

import time

bus = smbus.SMBus(1)

Unlock sequence

bus.write_byte_data(0x60, 0x2F, 0x45)

time.sleep(0.1) # Delay for stability

bus.write_byte_data(0x60, 0x30, 0x78)

time.sleep(0.1) # Delay for stability

Now you can perform write operations

For example, writing to register 0x10 with value 0x55

bus.write_byte_data(0x60, 0x10, 0x55)

To read back the value you just wrote, you can use:

val = bus.read_byte_data(0x60, 0x10)

print(val) # This should print 85 (0x55 in decimal)

Hi,

I think the problem is that bus.write_byte_data(0x60, 0x2F, 0x4F70656E) is probably not writing the four bytes correctly? It is probably just writing a single byte. And - just to complicate things - it needs to write them in little-endian format. The 0x6E needs to be written first…

So, in Python smbus, I think the code will be something like:

bus.write_i2c_block_data(0x60, 0x2F, [0x6E, 0x65, 0x70, 0x4F])

If you stick a logic analyzer on the I2C bus, you should see:

0xC0, 0x2F, 0x6E, 0x65, 0x70, 0x4F

(The 0xC0 is 0x60 shifted left by one bit. The LS Bit is zero for the write.)

Helpful tip: read all the registers first - and write the values down somewhere! So you can write them back again if you mess anything up. :wink: I’m pretty sure the qvo_fine and sns_fine values are chip-specific and programmed at the factory. Be careful f you change those. It may throw the readings off completely… (Been there. Done that…)

I hope this helps,

Paul

Just in case it wasn’t clear: all the registers are 32-bit. You always need to read and write four bytes from/to each register. And always in little-endian format…

TS-Russell:
This is kind of a shot in the dark, but it might need some delays…try this and see if it works?

The delay addition was a good idea - I had actually tried that as well but forgot to note it in my first post. That has certainly been my issue in previous projects, but this time around it didn’t seem to make any difference!

PaulZC:
Hi,

I think the problem is that bus.write_byte_data(0x60, 0x2F, 0x4F70656E) is probably not writing the four bytes correctly? It is probably just writing a single byte. And - just to complicate things - it needs to write them in little-endian format. The 0x6E needs to be written first…

So, in Python smbus, I think the code will be something like:

bus.write_i2c_block_data(0x60, 0x2F, [0x6E, 0x65, 0x70, 0x4F])

Paul, this was exactly the issue. This is the first device with 32-bit registers that I’ve interacted with so I completely overlooked that reality, and even if I’d stumbled onto it the little-endian format would have done me in. Everything else I’ve done register editing on has been 8-bit, so the bus.write_byte_data() function was sufficient.

I have the ACS37800 unlocked now, so I’m off to the races. Thanks for the help. By the way, good advice on documenting the initial register values. Doing that right now…