Last active
October 21, 2024 16:21
-
-
Save ciniml/e39503ad36624fe2a5f37112e5ff3f70 to your computer and use it in GitHub Desktop.
GOWIN SSPI configuration script for M5Stack
This file contains hidden or 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 os | |
import machine | |
import time | |
class GowinConfig(object): | |
def __init__(self, pin_cs:machine.Pin, pin_mode0:machine.Pin, pin_reconfig_n:machine.Pin, pin_ready:machine.Pin, spi:machine.SPI): | |
self.__pin_cs = pin_cs | |
self.__pin_mode0 = pin_mode0 | |
self.__pin_reconfig_n = pin_reconfig_n | |
self.__pin_ready = pin_ready | |
self.__sspi = spi | |
def begin_reconfig(self): | |
self.__pin_cs.on() | |
self.__pin_reconfig_n.on() | |
self.__pin_mode0.on() | |
time.sleep_ms(100) | |
self.__pin_reconfig_n.off() | |
time.sleep_ms(100) | |
self.__pin_reconfig_n.on() | |
time.sleep_ms(100) | |
self.__sspi.write(b'\xff') | |
def is_ready(self) -> bool: | |
return self.__pin_ready.value() != 0 | |
def wait_ready(self) -> None: | |
while not self.is_ready: | |
pass | |
def read_id(self): | |
self.__pin_cs.off() | |
self.__sspi.write(b'\x11\x00\x00\x00') | |
id = self.__sspi.read(4) | |
self.__pin_cs.on() | |
self.__sspi.write(b'\xff') | |
return id | |
def config_enable(self): | |
self.__pin_cs.off() | |
self.__sspi.write(b'\x15xff') | |
self.__pin_cs.on() | |
self.__sspi.write(b'\xff') | |
def config_disable(self): | |
self.__pin_cs.off() | |
self.__sspi.write(b'\x3axff') | |
self.__pin_cs.on() | |
self.__sspi.write(b'\xff') | |
def configure(self, path:str, buffer:Optional[bytearray]=None): | |
buf = memoryview(buffer if buffer is not None else bytearray(8192)) | |
with open(path, 'rb') as f: | |
remaining = f.seek(0, 2) | |
f.seek(0, 0) | |
self.__pin_cs.off() | |
self.__sspi.write(b'\x3b') | |
while remaining > 0: | |
print(remaining) | |
bytes_to_read = len(buf) if remaining > len(buf) else remaining | |
f.readinto(buf[0:bytes_to_read]) | |
self.__sspi.write(buf[0:bytes_to_read]) | |
remaining -= bytes_to_read | |
self.__pin_cs.on() | |
self.__sspi.write(b'\xff') |
This file contains hidden or 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 os | |
import machine | |
import time | |
import gowin | |
i2c = machine.I2C(0, sda=machine.Pin(21), scl=machine.Pin(22)) | |
class IOExpander(object): | |
"I/O Expander on I2C bus" | |
REG_INPUT = const(0) | |
REG_OUTPUT = const(1) | |
REG_INVERSION = const(2) | |
REG_CONFIG = const(3) | |
def __init__(self, i2c: machine.I2C, address: int, output:int=0x00, inversion:int=0xf0, direction:int=0xff): | |
""" | |
Initialize I/O expander driver | |
i2c: machine.I2C object on which the I/O expander is. | |
address: I2C slave address of the I/O expander. | |
""" | |
self.__i2c = i2c | |
self.__address = address | |
self.__regs = memoryview(bytearray([0x00, output, inversion, direction])) | |
self.__apply() | |
def __apply(self) -> None: | |
for i in (3,2,1): | |
self.__i2c.writeto_mem(self.__address, i, self.__regs[i:i+1]) | |
def configure(self, direction:int, inversion:int, output:int) -> None: | |
self.__regs[IOExpander.REG_OUTPUT] = output | |
self.__regs[IOExpander.REG_INVERSION] = inversion | |
self.__regs[IOExpander.REG_CONFIG] = direction | |
self.__apply() | |
def input(self) -> int: | |
self.__i2c.readfrom_mem_into(self.__address, IOExpander.REG_INPUT, self.__regs[IOExpander.REG_INPUT:IOExpander.REG_INPUT+1]) | |
return self.__regs[IOExpander.REG_INPUT] | |
def last_input(self) -> int: | |
return self.__regs[IOExpander.REG_INPUT] | |
def output(self, value:Optional[int,None]=None, mask:int=0xff) -> int: | |
if value is not None: | |
self.__set_masked(IOExpander.REG_OUTPUT, value, mask) | |
return self.__regs[IOExpander.REG_OUTPUT] | |
def direction(self, value:Optional[int,None]=None, mask:int=0xff) -> int: | |
if value is not None: | |
self.__set_masked(IOExpander.REG_CONFIG, value, mask) | |
return self.__regs[IOExpander.REG_CONFIG] | |
def __set_masked(self, reg:int, value:int, mask:int) -> None: | |
self.__regs[reg] = (self.__regs[reg] & ~mask) | value | |
self.__i2c.writeto_mem(self.__address, reg, self.__regs[reg:reg+1]) | |
def pin(self, pin:int) -> IOExpanderPin: | |
return IOExpanderPin(self, pin) | |
class IOExpanderPin(object): | |
def __init__(self, ioe:IOExpander, pin:int, is_open_drain:bool=False): | |
self.__ioe = ioe | |
self.__mask = 1<<pin | |
self.__is_open_drain = is_open_drain | |
def value(self, x:Optional[bool,None]=None) -> bool: | |
if x is not None: | |
value = self.__mask if x else 0 | |
self.__ioe.output(value=value, mask=self.__mask) | |
if not self.__is_open_drain: | |
if (self.__ioe.direction() & self.__mask) == 0: | |
return (self.__ioe.output() & self.__mask) != 0 | |
else: | |
return (self.__ioe.input() & self.__mask) != 0 | |
else: | |
return (self.__ioe.direction() & self.__mask) == 0 | |
def enable_output(self) -> None: | |
self.__ioe.direction(value=0, mask=self.__mask) | |
def disable_output(self) -> None: | |
self.__ioe.direction(value=self.__mask, mask=self.__mask) | |
def on(self) -> None: | |
if self.__is_open_drain: | |
self.disable_output() | |
else: | |
self.value(True) | |
def off(self) -> None: | |
if self.__is_open_drain: | |
self.enable_output() | |
else: | |
self.value(False) | |
ioe = IOExpander(i2c, 24, output=0x00, inversion=0x00, direction=0x7f) | |
pin_mode0 = IOExpanderPin(ioe, 7) | |
pin_reconfig_n = IOExpanderPin(ioe, 6, is_open_drain=True) | |
pin_ready = IOExpanderPin(ioe, 5) | |
#pin_reconfig_n = machine.Pin(5, machine.Pin.OPEN_DRAIN) | |
#pin_ready = machine.Pin(36, machine.Pin.IN) | |
pin_cs = machine.Pin(13, machine.Pin.OUT) | |
pin_sclk = machine.Pin(12, machine.Pin.OUT) | |
pin_miso = machine.Pin(34, machine.Pin.IN) | |
pin_mosi = machine.Pin(15, machine.Pin.OUT) | |
pin_sd_cs = machine.Pin(4, machine.Pin.OUT) | |
pin_sd_sck = machine.Pin(18, machine.Pin.OUT) | |
pin_sd_miso = machine.Pin(19, machine.Pin.IN) | |
pin_sd_mosi = machine.Pin(23, machine.Pin.OUT) | |
sd = machine.SDCard(slot=2, sck=pin_sd_sck, miso=pin_sd_miso, mosi=pin_sd_mosi, cs=pin_sd_cs) | |
sd.info() | |
os.mount(sd, '/sd') | |
pin_reconfig_n.on() | |
pin_cs.on() | |
sspi = machine.SPI(baudrate=1000000, polarity=0, phase=0, sck=pin_sclk, mosi=pin_mosi, miso=pin_miso) | |
sspi.init() | |
sspi.write(b'\xff') | |
gowin = gowin.GowinConfig(pin_cs, pin_mode0, pin_reconfig_n, pin_ready, sspi) | |
def configure_file(path:str = '/sd/blinky.bin'): | |
gowin.begin_reconfig() | |
gowin.wait_ready() | |
time.sleep_ms(100) | |
print('Reading device ID...') | |
while(True): | |
id = gowin.read_id() | |
if id == b'\x01\x00\x38\x1b': | |
break | |
else: | |
print('invalid ID', id) | |
print('Device detected') | |
print('Begin config') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment