Differences
This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
| rnd:projects:tnt [2024-03-10 04:39] – asdf | rnd:projects:tnt [2024-06-02 00:56] (current) – [Prototyping] added CircuitPython code asdf | ||
|---|---|---|---|
| Line 65: | Line 65: | ||
| The LBO pin **cannot** be directly connected to the Teensy! It is pulled high to Vin(([[https:// | The LBO pin **cannot** be directly connected to the Teensy! It is pulled high to Vin(([[https:// | ||
| - | {{tag> | + | ===== Prototyping ===== |
| + | Initial development began on the Teensy but shortly thereafter moved to the [[: | ||
| + | |||
| + | <code python> | ||
| + | ''' | ||
| + | ''' | ||
| + | import board | ||
| + | from digitalio import DigitalInOut, | ||
| + | import displayio | ||
| + | from i2cdisplaybus import I2CDisplayBus | ||
| + | import math | ||
| + | import terminalio | ||
| + | import time | ||
| + | |||
| + | from adafruit_debouncer import Debouncer | ||
| + | from adafruit_display_text.label import Label | ||
| + | from adafruit_displayio_ssd1306 import SSD1306 | ||
| + | |||
| + | CS_PIN = board.D10 | ||
| + | BTNA_PIN = board.D9 | ||
| + | BTNB_PIN = board.D6 | ||
| + | BTNC_PIN = board.D5 | ||
| + | OLED_ADDR = 0x3c | ||
| + | OLED_HEIGHT = 32 | ||
| + | OLED_WIDTH = 128 | ||
| + | MAC_ADDR = ' | ||
| + | |||
| + | # init oled buttons | ||
| + | btnApin = DigitalInOut(BTNA_PIN) | ||
| + | btnApin.pull = Pull.UP | ||
| + | btnBpin = DigitalInOut(BTNB_PIN) # has built-in pull-up | ||
| + | btnCpin = DigitalInOut(BTNC_PIN) | ||
| + | btnCpin.pull = Pull.UP | ||
| + | |||
| + | btnA = Debouncer(btnApin) | ||
| + | btnB = Debouncer(btnBpin) | ||
| + | btnC = Debouncer(btnCpin) | ||
| + | |||
| + | # display elements | ||
| + | mac = Label(terminalio.FONT, | ||
| + | host = Label(terminalio.FONT, | ||
| + | iface = Label(terminalio.FONT, | ||
| + | |||
| + | def initdisplay(): | ||
| + | # init oled | ||
| + | displayio.release_displays() | ||
| + | i2c = board.I2C() | ||
| + | displaybus = I2CDisplayBus(i2c, | ||
| + | display = SSD1306(displaybus, | ||
| + | root = displayio.Group() | ||
| + | |||
| + | root.append(mac) | ||
| + | root.append(host) | ||
| + | root.append(iface) | ||
| + | display.root_group = root | ||
| + | return display | ||
| + | |||
| + | # | ||
| + | class Wiznet5500: | ||
| + | def __init__(self, | ||
| + | self.spi = board.SPI() | ||
| + | self.cs = DigitalInOut(cs) | ||
| + | self.cs.direction = Direction.OUTPUT | ||
| + | self.cs.value = True | ||
| + | |||
| + | def reset(self): | ||
| + | self.write(0b00000, | ||
| + | return self.read(0b00000, | ||
| + | |||
| + | def select(self): | ||
| + | while not self.spi.try_lock(): | ||
| + | pass | ||
| + | self.cs.value = False | ||
| + | |||
| + | def deselect(self): | ||
| + | self.cs.value = True | ||
| + | self.spi.unlock() | ||
| + | |||
| + | def read(self, block, address, length): | ||
| + | data = [] | ||
| + | # address | ||
| + | data.append((address & 0xff00) >> 8) | ||
| + | data.append((address & 0x00ff)) | ||
| + | # control byte | ||
| + | data.append((block & 0x1f)<< | ||
| + | preamble = bytearray(data) | ||
| + | # transfer | ||
| + | self.select() | ||
| + | result = bytearray(length) | ||
| + | self.spi.write(bytearray(data)) | ||
| + | self.spi.readinto(result) | ||
| + | self.deselect() | ||
| + | return result | ||
| + | |||
| + | def write(self, block, address, buf): | ||
| + | # buf should already be a bytearray | ||
| + | data = [] | ||
| + | # address | ||
| + | data.append((address & 0xff00) >> 8) | ||
| + | data.append((address & 0x00ff)) | ||
| + | # control byte | ||
| + | data.append(((block & 0x1f) << 3) | 0x4) | ||
| + | # transfer | ||
| + | self.select() | ||
| + | self.spi.write(bytearray(data)) | ||
| + | self.spi.write(buf) | ||
| + | self.deselect() | ||
| + | |||
| + | def recv(self, length): | ||
| + | # get Sn_RX_RD | ||
| + | ptr = int(self.read(0b00001, | ||
| + | # read data from RX buffer | ||
| + | print(f' | ||
| + | data = self.read(0b00011, | ||
| + | # update Sn_RX_RD | ||
| + | ptr = (ptr + length) & 0xffff | ||
| + | out = bytearray.fromhex(f' | ||
| + | self.write(0b00001, | ||
| + | return data | ||
| + | |||
| + | def getFrame(self): | ||
| + | # get Sn_RX_RSR | ||
| + | length = int(self.read(0b00001, | ||
| + | if length > 0: | ||
| + | datalen = int(self.recv(2).hex(), | ||
| + | # Sn_CR_RECV | ||
| + | self.write(0b00001, | ||
| + | frame = self.recv(datalen) | ||
| + | # Sn_CR_RECV | ||
| + | self.write(0b00001, | ||
| + | return frame | ||
| + | else: | ||
| + | return None | ||
| + | |||
| + | def processlldp(frame): | ||
| + | mac.text = ' | ||
| + | frame[6], frame[7], frame[8], | ||
| + | frame[9], frame[10], frame[11] | ||
| + | ) | ||
| + | pos = 14 | ||
| + | while pos < len(frame): | ||
| + | t = frame[pos] >> 1 | ||
| + | pos += 1 | ||
| + | l = (frame[pos-1] << 9) | frame[pos] | ||
| + | pos += 1 | ||
| + | l &= 0x1ff | ||
| + | print(f' | ||
| + | if t == 4: | ||
| + | iface.text = frame[pos: | ||
| + | elif t == 5: | ||
| + | host.text = frame[pos: | ||
| + | pos += l | ||
| + | |||
| + | def hexdump(ba): | ||
| + | l = len(ba) | ||
| + | rows = math.ceil(l / 16) | ||
| + | r = l % 16 | ||
| + | for i in range(rows-1): | ||
| + | sl = ba[16*i: | ||
| + | print(f' | ||
| + | lastrow = '' | ||
| + | sl = ba[16*(rows-1): | ||
| + | for i in range(len(sl)): | ||
| + | lastrow += f' | ||
| + | print(lastrow) | ||
| + | |||
| + | def checkButtons(): | ||
| + | btnA.update() | ||
| + | btnB.update() | ||
| + | btnC.update() | ||
| + | a = btnA.fell | ||
| + | b = btnB.fell | ||
| + | c = btnC.fell | ||
| + | return a, b, c | ||
| + | |||
| + | wiznet = Wiznet5500(CS_PIN) | ||
| + | |||
| + | def main(): | ||
| + | wiznet.reset() | ||
| + | # set tx/rx buf sizes to 16k | ||
| + | wiznet.write(0b00001, | ||
| + | wiznet.write(0b00001, | ||
| + | # set mac address | ||
| + | wiznet.write(0b00000, | ||
| + | # open socket 0 in MACRAW | ||
| + | wiznet.write(0b00001, | ||
| + | wiznet.write(0b00001, | ||
| + | # verify that S0 is open as expected | ||
| + | status = int(wiznet.read(0b00001, | ||
| + | if status != 0x42: | ||
| + | mac.text = f'S0 {status=:# | ||
| + | # HCF? | ||
| + | |||
| + | display = initdisplay() | ||
| + | |||
| + | mac.text = ' | ||
| + | |||
| + | found = False | ||
| + | # main loop | ||
| + | while True: | ||
| + | a, b, c = checkButtons() | ||
| + | |||
| + | if found and a: | ||
| + | for line in display.root_group: | ||
| + | line.x -= 5 | ||
| + | if found and b: | ||
| + | for line in display.root_group: | ||
| + | line.x += 6 | ||
| + | |||
| + | frame = wiznet.getFrame() | ||
| + | if not frame: | ||
| + | # | ||
| + | continue | ||
| + | found = True | ||
| + | ethertype = frame[12: | ||
| + | if ethertype.lower() == ' | ||
| + | processlldp(frame) | ||
| + | |||
| + | time.sleep(0.5) | ||
| + | |||
| + | |||
| + | if __name__ == ' | ||
| + | main() | ||
| + | |||
| + | </ | ||
| + | |||
| + | {{tag> | ||