Created
November 10, 2022 13:30
-
-
Save piratecarrot/ce9490abada84c0696d2f68c1eb55288 to your computer and use it in GitHub Desktop.
Python SPIDEV controlling Maxim MAX14915 on STM32MP1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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