Skip to content

Instantly share code, notes, and snippets.

@whatnick
Created September 30, 2018 11:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save whatnick/de3350164c68dd82e4e5e3154f57b113 to your computer and use it in GitHub Desktop.
Save whatnick/de3350164c68dd82e4e5e3154f57b113 to your computer and use it in GitHub Desktop.
import spidev
# STATUS REGISTERS
SoftReset=0x00 # Software Reset
SysStatus0=0x01 # System Status0
SysStatus1=0x02 # System Status1
FuncEn0=0x03 # Function Enable0
FuncEn1=0x04 # Function Enable1
ZXConfig=0x07 # Zero-Crossing Config
SagTh=0x08 # Voltage Sag Th
PhaseLossTh=0x09 # Voltage Phase Losing Th
INWarnTh0=0x0A # N Current Line Th
INWarnTh1=0x0B # Voltage ADC Th
THDNUTh=0x0C # Voltage THD Th
THDNITh=0x0D # Current THD Th
DMACtrl=0x0E # DMA Int. Control
LastSPIData=0x0F # Last Read/Write SPI Value
# LOW POWER MODE REGISTERS - NOT USED
DetectCtrl=0x10
DetectTh1=0x11
DetectTh2=0x12
DetectTh3=0x13
PMOffsetA=0x14
PMOffsetB=0x15
PMOffsetC=0x16
PMPGA=0x17
PMIrmsA=0x18
PMIrmsB=0x19
PMIrmsC=0x1A
PMConfig=0x10B
PMAvgSamples=0x1C
PMIrmsLSB=0x1D
# CONFIGURATION REGISTERS
ConfigStart=0x30 # Configuration Start
PLconstH=0x31 # High Word of PL_Constant
PLconstL=0x32 # Low Word of PL_Constant
MMode0=0x33 # Metering Mode Config
MMode1=0x34 # Metering Mode Config
PStartTh=0x35 # Startup Power Th (P)
QStartTh=0x36 # Startup Power Th (Q)
SStartTh=0x37 # Startup Power Th (S)
PPhaseTh=0x38 # Startup Power Accum Th (P)
QPhaseTh=0x39 # Startup Power Accum Th (Q)
SPhaseTh=0x3A # Startup Power Accum Th (S)
CSZero=0x3B # Checksum 0
# CALIBRATION REGISTERS
CalStart=0x40 # Cal Start
PoffsetA=0x41 # A Line Power Offset (P)
QoffsetA=0x42 # A Line Power Offset (Q)
PoffsetB=0x43 # B Line Power Offset (P)
QoffsetB=0x44 # B Line Power Offset (Q)
PoffsetC=0x45 # C Line Power Offset (P)
QoffsetC=0x46 # C Line Power Offset (Q)
GainA=0x47 # A Line Calibration Gain
PhiA=0x48 # A Line Calibration Angle
GainB=0x49 # B Line Calibration Gain
PhiB=0x4A # B Line Calibration Angle
GainC=0x4B # C Line Calibration Gain
PhiC=0x4C # C Line Calibration Angle
CSOne=0x4D # Checksum 1
# HARMONIC & ENERGY REGISTERS
HarmStart=0x50 # Harmonic Cal Start
POffsetAF=0x51 # A Fund Power Offset (P)
POffsetBF=0x52 # B Fund Power Offset (P)
POffsetCF=0x53 # C Fund Power Offset (P)
PGainAF=0x54 # A Fund Power Gain (P)
PGainBF=0x55 # B Fund Power Gain (P)
PGainCF=0x56 # C Fund Power Gain (P)
CSTwo=0x57 # Checksum 2
# MEASUREMENT CALIBRATION REGISTERS
AdjStart=0x60 # Measurement Cal Start
UgainA=0x61 # A Voltage RMS Gain
IgainA=0x62 # A Current RMS Gain
UoffsetA=0x63 # A Voltage Offset
IoffsetA=0x64 # A Current Offset
UgainB=0x65 # B Voltage RMS Gain
IgainB=0x66 # B Current RMS Gain
UoffsetB=0x67 # B Voltage Offset
IoffsetB=0x68 # B Current Offset
UgainC=0x69 # C Voltage RMS Gain
IgainC=0x6A # C Current RMS Gain
UoffsetC=0x6B # C Voltage Offset
IoffsetC=0x6C # C Current Offset
IgainN=0x6D # N Current Gain
IoffsetN=0x6E # N Current Offset
CSThree=0x6F # Checksum 3
# ENERGY REGISTERS
APenergyT=0x80 # Total Forward Active
APenergyA=0x81 # A Forward Active
APenergyB=0x82 # B Forward Active
APenergyC=0x83 # C Forward Active
ANenergyT=0x84 # Total Reverse Active
ANenergyA=0x85 # A Reverse Active
ANenergyB=0x86 # B Reverse Active
ANenergyC=0x87 # C Reverse Active
RPenergyT=0x88 # Total Forward Reactive
RPenergyA=0x89 # A Forward Reactive
RPenergyB=0x8A # B Forward Reactive
RPenergyC=0x8B # C Forward Reactive
RNenergyT=0x8C # Total Reverse Reactive
RNenergyA=0x8D # A Reverse Reactive
RNenergyB=0x8E # B Reverse Reactive
RNenergyC=0x8F # C Reverse Reactive
SAenergyT=0x90 # Total Apparent Energy
SenergyA=0x91 # A Apparent Energy
SenergyB=0x92 # B Apparent Energy
SenergyC=0x93 # C Apparent Energy
SVenergyT=0x94 # Total Apparent Energy (Arit)
EnStatus0=0x95 # Metering Status 0
EnStatus1=0x96 # Metering Status 1
########/=0x97 # Reserved Register
SVmeanT=0x98 # Total Apparent Energy (Vect)
SVmeanTLSB=0x99 # LSB of Vector Sum
# FUNDAMENTAL / HARMONIC ENERGY REGISTERS
APenergyTF=0xA0 # Total Forward Fund. Energy
APenergyAF=0xA1 # A Forward Fund. Energy
APenergyBF=0xA2 # B Forward Fund. Energy
APenergyCF=0xA3 # C Forward Fund. Energy
ANenergyTF=0xA4 # Total Reverse Fund Energy
ANenergyAF=0xA5 # A Reverse Fund. Energy
ANenergyBF=0xA6 # B Reverse Fund. Energy
ANenergyCF=0xA7 # C Reverse Fund. Energy
APenergyTH=0xA8 # Total Forward Harm. Energy
APenergyAH=0xA9 # A Forward Harm. Energy
APenergyBH=0xAA # B Forward Harm. Energy
APenergyCH=0xAB # C Forward Harm. Energy
ANenergyTH=0xAC # Total Reverse Harm. Energy
ANenergyAH=0xAD # A Reverse Harm. Energy
ANenergyBH=0xAE # B Reverse Harm. Energy
ANenergyCH=0xAF # C Reverse Harm. Energy
# POWER & P.F. REGISTERS
PmeanT=0xB0 # Total Mean Power (P)
PmeanA=0xB1 # A Mean Power (P)
PmeanB=0xB2 # B Mean Power (P)
PmeanC=0xB3 # C Mean Power (P)
QmeanT=0xB4 # Total Mean Power (Q)
QmeanA=0xB5 # A Mean Power (Q)
QmeanB=0xB6 # B Mean Power (Q)
QmeanC=0xB7 # C Mean Power (Q)
SmeanT=0xB8 # Total Mean Power (S)
SmeanA=0xB9 # A Mean Power (S)
SmeanB=0xBA # B Mean Power (S)
SmeanC=0xBB # C Mean Power (S)
PFmeanT=0xBC # Mean Power Factor
PFmeanA=0xBD # A Power Factor
PFmeanB=0xBE # B Power Factor
PFmeanC=0xBF # C Power Factor
PmeanTLSB=0xC0 # Lower Word (Tot. Act. Power)
PmeanALSB=0xC1 # Lower Word (A Act. Power)
PmeanBLSB=0xC2 # Lower Word (B Act. Power)
PmeanCLSB=0xC3 # Lower Word (C Act. Power)
QmeanTLSB=0xC4 # Lower Word (Tot. React. Power)
QmeanALSB=0xC5 # Lower Word (A React. Power)
QmeanBLSB=0xC6 # Lower Word (B React. Power)
QmeanCLSB=0xC7 # Lower Word (C React. Power)
SAmeanTLSB=0xC8 # Lower Word (Tot. App. Power)
SmeanALSB=0xC9 # Lower Word (A App. Power)
SmeanBLSB=0xCA # Lower Word (B App. Power)
SmeanCLSB=0xCB # Lower Word (C App. Power)
# FUND/HARM POWER & V/I RMS REGISTERS
PmeanTF=0xD0 # Total Active Fund. Power
PmeanAF=0xD1 # A Active Fund. Power
PmeanBF=0xD2 # B Active Fund. Power
PmeanCF=0xD3 # C Active Fund. Power
PmeanTH=0xD4 # Total Active Harm. Power
PmeanAH=0xD5 # A Active Harm. Power
PmeanBH=0xD6 # B Active Harm. Power
PmeanCH=0xD7 # C Active Harm. Power
IrmsN1=0xD8 # N Sampled Current
UrmsA=0xD9 # A RMS Voltage
UrmsB=0xDA # B RMS Voltage
UrmsC=0xDB # C RMS Voltage
IrmsN0=0xDC # N Calculated Current (USE)
IrmsA=0xDD # A RMS Current
IrmsB=0xDE # B RMS Current
IrmsC=0xDF # C RMS Current
PmeanTFLSB=0xE0 # Lower Word (Tot. Act. Fund. Power)
PmeanAFLSB=0xE1 # Lower Word (A Act. Fund. Power)
PmeanBFLSB=0xE2 # Lower Word (B Act. Fund. Power)
PmeanCFLSB=0xE3 # Lower Word (C Act. Fund. Power)
PmeanTHLSB=0xE4 # Lower Word (Tot. Act. Harm. Power)
PmeanAHLSB=0xE5 # Lower Word (A Act. Harm. Power)
PmeanBHLSB=0xE6 # Lower Word (B Act. Harm. Power)
PmeanCHLSB=0xE7 # Lower Word (C Act. Harm. Power)
########/=0xE8 # Reserved Register
UrmsALSB=0xE9 # Lower Word (A RMS Voltage)
UrmsBLSB=0xEA # Lower Word (B RMS Voltage)
UrmsCLSB=0xEB # Lower Word (C RMS Voltage)
########/=0xEC # Reserved Register
IrmsALSB=0xED # Lower Word (A RMS Current)
IrmsBLSB=0xEE # Lower Word (B RMS Current)
IrmsCLSB=0xEF # Lower Word (C RMS Current)
# THD, FREQUENCY, ANGLE & TEMP REGISTERS
THDNUA=0xF1 # A Voltage THD+N
THDNUB=0xF2 # B Voltage THD+N
THDNUC=0xF3 # C Voltage THD+N
########/=0xF4 # Reserved Register
THDNIA=0xF5 # A Current THD+N
THDNIB=0xF6 # B Current THD+N
THDNIC=0xF7 # V Current THD+N
Freq=0xF8 # Frequency
PAngleA=0xF9 # A Mean Phase Angle
PAngleB=0xFA # B Mean Phase Angle
PAngleC=0xFB # C Mean Phase Angle
Temp=0xFC # Measured Temperature
UangleA=0xFD # A Voltage Phase Angle
UangleB=0xFE # B Voltage Phase Angle
UangleC=0xFF # C Voltage Phase Angle
import time
import struct
import binascii
__write__ = False
__read__ = True
class ATM90E36_SPI:
'''
spi - hardware or software SPI implementation
cs - Chip Select pin
'''
def __init__(self, spi):
self.spi = spi
self.init_config()
'''
rw - True - read, False - write
address - register to operate
val - value to write (if any)
'''
def comm_atm90(self, RW, address, val):
# switch MSB and LSB of value
read_buf = bytearray(4)
write_buf = bytearray(4)
# Set read write flag
address |= RW << 15
if(RW): # 1 as MSB marks a read
struct.pack_into('>H',read_buf,0,address)
print(address,binascii.hexlify(read_buf))
time.sleep(10e-6)
# Write address + x2 receive buffer
read_res = self.spi.xfer(read_buf)
''' Must wait 4 us for data to become valid '''
print("Read",''.join('{:02x}'.format(x) for x in read_res))
return 0
else: #0 as MSB and 32 clock cycles marks a write
struct.pack_into('>H',write_buf,0,address)
struct.pack_into('>H',write_buf,2,val)
print(address,binascii.hexlify(write_buf))
self.spi.xfer(write_buf)# write all the bytes
def init_config(self):
self.comm_atm90(__write__, SoftReset, 0x789A); # Perform soft reset
self.comm_atm90(__write__, FuncEn0, 0x0000); # Voltage sag
self.comm_atm90(__write__, FuncEn1, 0x0000); # Voltage sag
self.comm_atm90(__write__, SagTh, 0x0001); # Voltage sag threshold
""" SagTh = Vth * 100 * sqrt(2) / (2 * Ugain / 32768) """
#Set metering config values (CONFIG)
self.comm_atm90(__write__, ConfigStart, 0x5678); # Metering calibration startup
self.comm_atm90(__write__, PLconstH, 0x0861); # PL Constant MSB (default)
self.comm_atm90(__write__, PLconstL, 0xC468); # PL Constant LSB (default)
self.comm_atm90(__write__, MMode0, 0x1087); # Mode Config (60 Hz, 3P4W)
self.comm_atm90(__write__, MMode1, 0x1500); # 0x5555 (x2) # 0x0000 (1x)
self.comm_atm90(__write__, PStartTh, 0x0000); # Active Startup Power Threshold
self.comm_atm90(__write__, QStartTh, 0x0000); # Reactive Startup Power Threshold
self.comm_atm90(__write__, SStartTh, 0x0000); # Apparent Startup Power Threshold
self.comm_atm90(__write__, PPhaseTh, 0x0000); # Active Phase Threshold
self.comm_atm90(__write__, QPhaseTh, 0x0000); # Reactive Phase Threshold
self.comm_atm90(__write__, SPhaseTh, 0x0000); # Apparent Phase Threshold
self.comm_atm90(__write__, CSZero, 0x4741); # Checksum 0
#Set metering calibration values (CALIBRATION)
self.comm_atm90(__write__, CalStart, 0x5678); # Metering calibration startup
self.comm_atm90(__write__, GainA, 0x0000); # Line calibration gain
self.comm_atm90(__write__, PhiA, 0x0000); # Line calibration angle
self.comm_atm90(__write__, GainB, 0x0000); # Line calibration gain
self.comm_atm90(__write__, PhiB, 0x0000); # Line calibration angle
self.comm_atm90(__write__, GainC, 0x0000); # Line calibration gain
self.comm_atm90(__write__, PhiC, 0x0000); # Line calibration angle
self.comm_atm90(__write__, PoffsetA, 0x0000); # A line active power offset
self.comm_atm90(__write__, QoffsetA, 0x0000); # A line reactive power offset
self.comm_atm90(__write__, PoffsetB, 0x0000); # B line active power offset
self.comm_atm90(__write__, QoffsetB, 0x0000); # B line reactive power offset
self.comm_atm90(__write__, PoffsetC, 0x0000); # C line active power offset
self.comm_atm90(__write__, QoffsetC, 0x0000); # C line reactive power offset
self.comm_atm90(__write__, CSOne, 0x0000); # Checksum 1
#Set metering calibration values (HARMONIC)
self.comm_atm90(__write__, HarmStart, 0x5678); # Metering calibration startup
self.comm_atm90(__write__, POffsetAF, 0x0000); # A Fund. active power offset
self.comm_atm90(__write__, POffsetBF, 0x0000); # B Fund. active power offset
self.comm_atm90(__write__, POffsetCF, 0x0000); # C Fund. active power offset
self.comm_atm90(__write__, PGainAF, 0x0000); # A Fund. active power gain
self.comm_atm90(__write__, PGainBF, 0x0000); # B Fund. active power gain
self.comm_atm90(__write__, PGainCF, 0x0000); # C Fund. active power gain
self.comm_atm90(__write__, CSTwo, 0x0000); # Checksum 2
#Set measurement calibration values (ADJUST)
self.comm_atm90(__write__, AdjStart, 0x5678); # Measurement calibration
self.comm_atm90(__write__, UgainA, 0x0002); # A SVoltage rms gain
self.comm_atm90(__write__, IgainA, 0xFD7F); # A line current gain
self.comm_atm90(__write__, UoffsetA, 0x0000); # A Voltage offset
self.comm_atm90(__write__, IoffsetA, 0x0000); # A line current offset
self.comm_atm90(__write__, UgainB, 0x0002); # B Voltage rms gain
self.comm_atm90(__write__, IgainB, 0xFD7F); # B line current gain
self.comm_atm90(__write__, UoffsetB, 0x0000); # B Voltage offset
self.comm_atm90(__write__, IoffsetB, 0x0000); # B line current offset
self.comm_atm90(__write__, UgainC, 0x0002); # C Voltage rms gain
self.comm_atm90(__write__, IgainC, 0xFD7F); # C line current gain
self.comm_atm90(__write__, UoffsetC, 0x0000); # C Voltage offset
self.comm_atm90(__write__, IoffsetC, 0x0000); # C line current offset
self.comm_atm90(__write__, IgainN, 0xFD7F); # C line current gain
self.comm_atm90(__write__, CSThree, 0x02F6); # Checksum 3
# Done with the configuration
self.comm_atm90(__write__, ConfigStart, 0x5678);
self.comm_atm90(__write__, CalStart, 0x5678); # 0x6886 #0x5678 #8765);
self.comm_atm90(__write__, HarmStart, 0x5678); # 0x6886 #0x5678 #8765);
self.comm_atm90(__write__, AdjStart, 0x5678); # 0x6886 #0x5678 #8765);
self.comm_atm90(__write__, SoftReset, 0x789A); # Perform soft reset
if __name__=="__main__":
spi = spidev.SpiDev()
spi.open(32766, 1)
spi.mode = 0b11
spi.max_speed_hz = 200000
eic1 = ATM90E36_SPI(spi)
while True:
Voltage1 = eic1.comm_atm90(__read__,UrmsB,0xFFFF)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment