Skip to content

Instantly share code, notes, and snippets.

@piratecarrot
Created November 10, 2022 13:30
Show Gist options
  • Save piratecarrot/ce9490abada84c0696d2f68c1eb55288 to your computer and use it in GitHub Desktop.
Save piratecarrot/ce9490abada84c0696d2f68c1eb55288 to your computer and use it in GitHub Desktop.
Python SPIDEV controlling Maxim MAX14915 on STM32MP1
import gpiod
import spidev
from maxim import Type, Output, RegisterAddress, FastStatus, GlobalError, Config1, Config2, Mask, Interrupt, cmd
import time
#if __name__ == '__main__':
chip_b = gpiod.chip(1)
chip_c = gpiod.chip(2)
chip_h = gpiod.chip(7)
chip_i = gpiod.chip(8)
LATCH_OFFSET = 10
SYNC_OFFSET = 9
CS1_OFFSET = 3
CS2_OFFSET = 12
CS3_OFFSET = 12
CS4_OFFSET = 11
PTT_OFFSET = 11
latch = chip_c.get_line(LATCH_OFFSET)
sync = chip_c.get_line(SYNC_OFFSET)
cs1 = chip_i.get_line(CS1_OFFSET)
cs2 = chip_c.get_line(CS2_OFFSET)
cs3 = chip_h.get_line(CS3_OFFSET)
cs4 = chip_c.get_line(CS4_OFFSET)
ptt = chip_i.get_line(PTT_OFFSET)
out_config = gpiod.line_request()
out_config.request_type = gpiod.line_request.DIRECTION_OUTPUT
out_config.consumer = "Input Latch"
latch.request(out_config)
out_config.consumer = "Output Sync"
sync.request(out_config)
out_config.consumer = "CS1"
cs1.request(out_config)
out_config.consumer = "CS2"
cs2.request(out_config)
out_config.consumer = "CS3"
cs3.request(out_config)
out_config.consumer = "CS4"
cs4.request(out_config)
out_config.consumer = "PTT"
ptt.request(out_config)
cs1.set_value(1)
cs2.set_value(1)
cs3.set_value(1)
cs4.set_value(1)
sync.set_value(1)
spi = spidev.SpiDev()
spi.open(0, 0)
# Settings (for example)
spi.max_speed_hz = 1000000
spi.mode = 0
setup_config1 = list(cmd(0, RegisterAddress.CONFIG1, Type.WRITE, 80).to_bytes(3, 'big'))
setup_config2 = list(cmd(0, RegisterAddress.CONFIG2, Type.WRITE, 0).to_bytes(3, 'big'))
setup_mask = list(cmd(0, RegisterAddress.MASK, Type.WRITE, Mask.OWOnM | Mask.OWOffM).to_bytes(3, 'big'))
setup_owonen = list(cmd(0, RegisterAddress.OwOnEn, Type.WRITE, 0).to_bytes(3, 'big'))
setup_owoffen = list(cmd(0, RegisterAddress.OwOffEn, Type.WRITE, 0).to_bytes(3, 'big'))
setup_shtvdden = list(cmd(0, RegisterAddress.ShtVddEn, Type.WRITE, 0).to_bytes(3, 'big'))
read_global_fault = list(cmd(0, RegisterAddress.GLOBAL_ERROR, Type.READ, 0).to_bytes(3, 'big'))
read_interrupt = list(cmd(0, RegisterAddress.INTERRUPT, Type.READ, 0).to_bytes(3, 'big'))
read_owonchf = list(cmd(0, RegisterAddress.OwOnChF, Type.READ, 0).to_bytes(3, 'big'))
read_owoffchf = list(cmd(0, RegisterAddress.OwOffChF, Type.READ, 0).to_bytes(3, 'big'))
read_shtvddchf = list(cmd(0, RegisterAddress.ShtVddChF, Type.READ, 0).to_bytes(3, 'big'))
read_ovlchf = list(cmd(0, RegisterAddress.OvlChF, Type.READ, 0).to_bytes(3, 'big'))
read_currlimf = list(cmd(0, RegisterAddress.CurrLim, Type.READ, 0).to_bytes(3, 'big'))
read_output = list(cmd(0, RegisterAddress.SET_OUT, Type.READ, 0).to_bytes(3, 'big'))
read_led_fault = list(cmd(0, RegisterAddress.SET_FAULT_LED, Type.READ, 0).to_bytes(3, 'big'))
read_led_status = list(cmd(0, RegisterAddress.SET_STATUS_LED, Type.READ, 0).to_bytes(3, 'big'))
turn10n2Off = list(cmd(0, RegisterAddress.SET_OUT, Type.WRITE, Output.On1 & ~Output.On2).to_bytes(3, 'big'))
turn10ff2On = list(cmd(0, RegisterAddress.SET_OUT, Type.WRITE, Output.On2 & ~Output.On1).to_bytes(3, 'big'))
curr_cmd_idx = False
cs4.set_value(0)
spi.writebytes(setup_config1)
cs4.set_value(1)
cs4.set_value(0)
spi.writebytes(setup_config2)
cs4.set_value(1)
cs4.set_value(0)
spi.writebytes(setup_mask)
cs4.set_value(1)
cs4.set_value(0)
spi.writebytes(setup_owonen)
cs4.set_value(1)
cs4.set_value(0)
spi.writebytes(setup_owoffen)
cs4.set_value(1)
cs4.set_value(0)
spi.writebytes(setup_shtvdden)
cs4.set_value(1)
def do_output():
cs4.set_value(0)
data = spi.xfer(read_output)
d = Output(data[1])
cs4.set_value(1)
print("Output Status: {}".format(d.__repr__()))
def do_led_fault():
cs4.set_value(0)
data = spi.xfer(read_led_fault)
d = Output(data[1])
cs4.set_value(1)
print("Fault LED: {}".format(d.__repr__()))
def do_led_status():
cs4.set_value(0)
data = spi.xfer(read_led_status)
d = Output(data[1])
cs4.set_value(1)
print("Status LED: {}".format(d.__repr__()))
def do_interrupt():
cs4.set_value(0)
data = spi.xfer(read_interrupt)
d = Interrupt(data[1])
cs4.set_value(1)
print("Interrupt: {}".format(d.__repr__()))
def do_owonchf():
cs4.set_value(0)
data = spi.xfer(read_owonchf)
d = Output(data[1])
cs4.set_value(1)
print("OwOnChF: {}".format(d.__repr__()))
def do_owoffchf():
cs4.set_value(0)
data = spi.xfer(read_owoffchf)
d = Output(data[1])
cs4.set_value(1)
print("OwOffChF: {}".format(d.__repr__()))
def do_shtvddchf():
cs4.set_value(0)
data = spi.xfer(read_shtvddchf)
d = Output(data[1])
cs4.set_value(1)
print("ShtVddChF: {}".format(d.__repr__()))
def do_ovlchf():
cs4.set_value(0)
data = spi.xfer(read_ovlchf)
d = Output(data[1])
cs4.set_value(1)
print("OvlChF: {}".format(d.__repr__()))
def do_currlimf():
cs4.set_value(0)
data = spi.xfer(read_currlimf)
d = Output(data[1])
cs4.set_value(1)
print("CurrLimF: {}".format(d.__repr__()))
def global_fault():
cs4.set_value(0)
data = spi.xfer(read_global_fault)
error = GlobalError(data[1])
cs4.set_value(1)
print("Global Error: {}".format(error.__repr__()))
while True:
if curr_cmd_idx:
curr_cmd = turn10ff2On
else:
curr_cmd = turn10n2Off
curr_cmd_idx = not curr_cmd_idx
cs4.set_value(0)
data = spi.xfer(curr_cmd)
status = FastStatus(data[0])
fault = Output(data[1])
cs4.set_value(1)
print("Status: {}".format(status.__repr__()))
do_output()
do_led_fault()
do_led_status()
# if fault > 0:
# print("Fault: {}".format(fault.__repr__()))
# do_interrupt()
# do_owonchf()
# do_owoffchf()
# do_shtvddchf()
# do_ovlchf()
# do_currlimf()
zzz = 1 if zzz == 0 else 0
if FastStatus.GloblF in status: global_fault()
time.sleep(0.5)
from enum import IntEnum, IntFlag, auto
__CRC_INIT = 0x07 # 5-bit init word, constant, 00111
__CRC_POLY = 0x35 # 6-bit polynomial, constant, 110101
__CRC_LEN = 19 # 19-bit data
def crc(datainput: int) -> int :
crc_step: int = 0
tmp: int = 0
# append 5-bit init word to first 19-bit data
datainput = (datainput & 0xffffe0) + __CRC_INIT
# first step, get crc_step 0
tmp = ((datainput & 0xfc0000) >> 18) # crc_step 0= data[18:13]
# next crc_step = crc_step[5] = 0 ? (crc_step[5:0] ^ crc_poly) : crc_step[5:0]
if ((tmp & 0x20) == 0x20):
crc_step = tmp ^ __CRC_POLY
else:
crc_step = tmp
# step 1-18
for i in range(__CRC_LEN - 1):
# append next data bit to previous crc_step[4:0], {crc_step[4:0], next data bit}
tmp = (((crc_step & 0x1f) << 1) + ((datainput >> (__CRC_LEN - 2 - i)) & 0x01))
# next crc_step = crc_step[5] = 0 ? (crc_step[5:0] ^ crc_poly) : crc_step[5:0]
if ((tmp & 0x20) == 0x20):
crc_step = (tmp ^ __CRC_POLY)
else:
crc_step = tmp
return crc_step & 0x1f # crc result = crc_step[4:0]
class RegisterAddress(IntEnum):
SET_OUT = 0x00
SET_FAULT_LED = 0x01
SET_STATUS_LED = 0x02
INTERRUPT = 0x03
OvlChF = 0x04
CurrLim = 0x05
OwOffChF = 0x06
OwOnChF = 0x07
ShtVddChF = 0x08
GLOBAL_ERROR = 0x09
OwOffEn = 0x0a
OwOnEn = 0x0b
ShtVddEn = 0x0c
CONFIG1 = 0x0d
CONFIG2 = 0x0e
MASK = 0x0f
class Type(IntEnum):
READ = 0x00
WRITE = 0x01
class Output(IntFlag):
On1 = auto()
On2 = auto()
On3 = auto()
On4 = auto()
On5 = auto()
On6 = auto()
On7 = auto()
On8 = auto()
class Config1(IntFlag):
FLEDSet = auto()
SLEDSet = auto()
FLEDStrech0 = auto()
FLEDStrech1 = auto()
FFilterEn = auto()
FiltrLong = auto()
FLatchEn = auto()
LEDCurrLim = auto()
class Config2(IntFlag):
VDDOnThr = auto()
SynchWDEn = auto()
ShrtVddThr0 = auto()
ShrtVddThr1 = auto()
OWOffCs0 = auto()
OWOffCs1 = auto()
WDTo0 = auto()
WDTo1 = auto()
class Mask(IntFlag):
OverLdM = auto()
CurrLimM = auto()
OWOffM = auto()
OWOnM = auto()
ShtVddM = auto()
VddOKM = auto()
SupplyErrM = auto()
ComErrM = auto()
class Interrupt(IntFlag):
OverLdFault = auto()
CurrLimFault = auto()
OWOffFault = auto()
OWOnFault = auto()
ShrtVddFault = auto()
ThermErr = auto()
SupplyErr = auto()
ComErr = auto()
class GlobalError(IntFlag):
Vint_UV = auto()
VA_UVLO = auto()
VddNotGood = auto()
VddWarn = auto()
VddUvlo = auto()
ThrmShutd = auto()
SynchErr = auto()
WDErr = auto()
class FastStatus(IntFlag):
GloblF = auto()
OverLdF = auto()
CurrLim = auto()
OWOffF = auto()
OWOnF = auto()
ShrtVDD = auto()
def cmd(address: int, register: RegisterAddress, type: Type, data: int, burst: bool=False) -> int:
cmd = (address & 0x03) << 6
cmd = (cmd | (1<<5)) if burst else cmd
cmd = cmd | (register << 1)
cmd = cmd | type
cmd = cmd << 8
cmd = cmd | (data & 0xff)
cmd = cmd << 8
cmd = cmd | crc(cmd)
return cmd
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment