I2c help, writing to 24/32 bit registers on ADE7953 (similar to Becky)

I have a new board, nominally working using the ADE7953 IC. With the code from the Becky reference design I got off to a fast start but then hit a 4 hour brick wall trying to write to the 24 bit registers.

I am getting either no change to the register or else i get the wrong value written.

I simplified my code down a bit and tested it to make sure what I pasted below still works the same way. The main point is in this area:

//B100000000000000000000 - as startup
//B110000000000000000000 - I wanted this value of 180000h
//B 11000000110000 - is what I got. 12336 in the log - I assume it is decimal

This is the code that does not give the desired result
write (i2c,0x22C, "\\x180000");//IRQENA try to set the 19th bit

I tried to flip just one bit by writing the new/modified register value and this is my best result - I actually got the register value to change but not to the correct number

Some questions:

  • Where can I find some documentation on the format command. I cannot seem to find this in the squirrel docs or the imp api.

  • any help on what is going on with the register writing? The example code is a bit fancy compared to my skill; I do get the part where the number of bytes is auto-detected by the address number. I get a little bit turned around when it comes to strings and hex numbers - especially pertaining to squirrel code.

thanks in advance for any help. : )


Code Derived from
electric imp [[becky]]

Trace: • becky
Electric Imp Developer Wiki


local function read(i2c, addr) {

// registers 0-ff are 8 bit, 100-1ff are 16 bit, 200-2ff are 24 bit and
// 300-3ff are 32 bit

//local res = i2c.read(0x70, format("%c%c", addr>>8, addr&0xff), 1+(addr>>8));

local res = i2c.read(0x71, format("%c%c", addr>>8, addr&0xff), (1+(addr>>8))); //71 for read (70 for write)

local resv = 0;

if (res != null) {

foreach (b in res) resv = (resv<<8) + b;
    return resv;
    server.log("result is null");

return 0;


// Signed read
local function reads(i2c, addr) {
local r = read(i2c, addr);
local length = 1 + (addr>>8);
local mask = 1<<(length<<3);
if (r > (mask>>1)) return r-mask;
return r;

local function write(i2c, addr, data) {
// registers 0-ff are 8 bit, 100-1ff are 16 bit, 200-2ff are 24 bit and
// 300-3ff are 32 bit

local length = 1 + (addr>>8);

//server.log (typeof addr);
//server.log (typeof data);

i2c.write(0x70, format("%c%c", addr>>8, addr&0xff) + data);


// Pin1-2= I2C i2c12
// Pin5 = Pin CF2
// Pin7 = Pin CF1
// Pin8 = IRQ
// Pin9 = RESET

i2c <- hardware.i2c12;


write(i2c, 0xFE, “\xAD”);
write(i2c, 0x120, “\x30”);

server.log(read(i2c, 0xFE) + " required register unlock");//page 18
write(i2c, 0xFE, “\xAD”);
server.log(read(i2c, 0x120) + " required register setting");//page 18

// configure current gain to 1 (500mV swing max)
write(i2c, 0x008, “\x0”);

server.log(read(i2c, 0x008) + " register 8");
//server.log(read(i2c, 0x702) + " silicon number");

// configure voltage gain to 1 (500mV P-P swing max) but our nominal signal is 170mV, allowing for waveform errors
write(i2c, 0x007, “\x0”);
//server.log(read(i2c, 0x007) + " register 7");

// configure active energy line accumulation mode on current channel A, clear on read
write(i2c, 0x004, “\x41”);

//server.log(read(i2c, 0x004) + " register 4");

write (i2c,0x000,"\xFF");//set sag to 255ms as this is the max allowed
//server.log(read(i2c, 0x000) + " SAGCYC Register"); //this line WORKS - puts out 255The number of cycles for sensing this

server.log(read(i2c, 0x107) + " should be 768");
server.log(read(i2c, 0x102) + " is the CONFIG register"); //'1000000000000100


//IRQENA registers are 0x22C and 0x32C

server.log(read(i2c, 0x22C) + " IRQENA Register default is 1048576"); //bit-wise configuration, first read as 1048576, as mentioned in the datasheet

write (i2c,0x22C, “\x180000”);//IRQENA try to set the 19th bit

server.log(read(i2c, 0x22C) + " IRQENA Register after writing 0x180000"); //bit-wise configuration, first read as 1048576 Decimal

//100,000h change to 180000h
//1048576 change to 1572864
//B100000000000000000000 change to B110000000000000000000

//This code results in the DECIMAL result of 12336, hex of 3030 and BIN of
//B100000000000000000000 - as startup
//B110000000000000000000 - I wanted this value of 180000h
//B 11000000110000 - is what I got. 12336 in the log - I assume it is decimal

//the 19th bit enables the SAG interrupt, the 20th is always enables


//write (i2c,0x200, “\x2512D”);//SAGLVL register, set to 4V RMS

write (i2c, 0x200, “\x02\x51\x2D”);//SAGLVL register, set to 4V RMS

server.log(read(i2c, 0x200) + " SAGLVL Register"); //The number of cycles for sensing this


server.log(“about to write to 0x203 (515)”);

write (i2c, 0x203, “\xE434”);//AP_NOLOAD register

//writesag (i2c, 0x203, “\xFF”);//AP_NOLOAD register

server.log(read(i2c, 0x203) + " AP_NOLOAD Register default reads 58393"); //
server.log(read(i2c, 0x284) + " AVA GAIN: should read 4194304"); //

server.log(read(i2c, 0x2FF) + " value of the last good 24bit register write"); //

server.log(hardware.pin8.read() + " pin 8");


function reporter() {
imp.wakeup(05, reporter);
local awatt = reads(i2c, 0x0212);

// Debug if we want more detail
local cyclecount = read(i2c, 0x010e);
local vrms = read(i2c, 0x21c);
local peak = read (i2c,0x227); //0x226 is voltage peak, 0x227 peak with reset
local Irms = read (i2c, 0x21a);//1773 counts with the power off 4773 counts with voltage applied (crosstalk?)
// No negative readings
if (awatt < 0.0) awatt = 0.0;

// Scaling
local watts = (286.0 * awatt) / 236000.0;
watts = math.floor(watts * 10 + 0.5) / 10.0;

server.log(1.0 * vrms + "  ,  " + (223747.0/(cyclecount+1)) + " , " + 1.0 * peak + " " + awatt + " , " + Irms); //nominal counts scalar is 223000



// Appear on planner

imp.configure("Fancy Power Meter-Proconn", [], []);

// Start reporting

These notes were in the original code that I started with
becky.txt · Last modified: 2013/02/06 18:34 by hugo

Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution-Share Alike 3.0 Unported



I found part of my answer - at least enough to get by. To write a value of

1572864 (decimal)
110000000000000000000 (binary)
180000 (hex)

write (i2c,0x22C, "\\x18\\x00\\x00");

worked, given the write function in the original Becky code.

I am not sure if it is the best way.

I am still wondering where the format command is coming from. I have seen references to it in other languages but so far not in the imp or squirrel documentation.

That is the right way to do it. The string you’re writing is a 3 byte string (for 24 bits) not a single 24 bit number, hence you need to break it down into 3 bytes.

Format is part of the squirrel standard library. See http://www.squirrel-lang.org/doc/sqstdlib3.html

thanks Hugo, I don’t know how I missed that. maybe because I was sleepy… and also because I started by looking in the PDF reference manual.

in the link you sent I found this helpful statement

"The format string follows the same rules as the printf family of standard C functions( the "*" is not supported)"

I am currently working with ade7953 IC.Can any one help me with a C code to power up the IC.

It will power up on its own assuming the hardware is in good condition. The only special thing I know of is the datasheet says to write these two things first.

writei2c(i2c, 0xFE, “\xAD”);
writei2c(i2c, 0x120, “\x30”);

They are on page 18 of the latest version of the datasheet. I think this used to be page 11.

It also says to either wait 100ms before trying to communicate or else wait for the interrupt on the IRQ pin

An external interrupt is triggered on the IRQ pin. The reset interrupt is enabled by default and cannot be disabled, hence an external interrupt always occurs at the end of a power-up procedure, hardware or software reset.

Other than that I don’t think there is anything special, you may begin reading the registers as you wish. Request 3 bytes to get the 24-bit registers. I have never bothered with the 32-bit addresses because the values are all 24-bit.

You say you are using “C” ? Sorry, I wouldn’t be able to help there. The easy way in C is to find a good library for i2c or SPI.

So what kind of programming you use to communicate with the IC? Im using raspberry pi to communicate with IC using C programming.I went through the test circuit given in the Data sheet and made the connection as mentioned in it.

Depending on your connections it is i2c or SPI or UART. I don’t know how to do this with C or raspberry pi so you could consider asking on the forum for the pi.

raspberry pi forum

can you tell me how you did this