class MAX6675Temperature: def __init__(self): from machine import SPI, Pin self.spi = SPI(1, baudrate=2000000, polarity=1, phase=0, bits=8, firstbit=SPI.MSB, sck=Pin(14), mosi=Pin(13), miso=Pin(12)) self.cs = Pin(27, Pin.OUT) self.cs.on() self.tempC = 0 def getTemperature(self): self.cs.off() result = self.spi.read(2) result = result[0] << 8 | result[1] result >>= 4 self.tempC = result & 0b0000111111111111 # 12 LSB after we have shifted it return self.tempC def startConversion(self): # self.cs.off() #Not using this as we can call startConversion many times for the same comversion self.cs.on()
class MAX6675: def __init__(self, sck, mosi, miso, cs): ''' self.spi = SPI(1, baudrate=200000, polarity=0, phase=0) self.spi.init(baudrate=200000) # set the baudrate # (SPI(0) 仅用于内部的 FlashROM。) ''' self.cs = cs self.cs.on() # 使能引脚拉高self.cs = cs self.spi = SPI(1, baudrate=100000, polarity=1, phase=0) # self.spi = SPI(-1, baudrate=1000000, polarity=1, # phase=0, sck=sck, mosi=mosi, miso=miso) self.connect = False def read_temperature(self, ): """ 读取一次温度(摄氏度),读取错误或者热电偶异常均返回4095 """ self.cs.off() # CS引脚检测到下降沿后停止转换。随后在sck时钟控制下输出16位数据 value = self.spi.read(2) # 读取两个字节 self.cs.on() temp = value[0] << 8 | value[1] self.connect = True if (temp & MAX6675_CONNECT) == 0 else False gc.collect() if self.connect == True: # 没检测到电热偶 return ((temp & 0x7FFF) >> 3) >> 2 # 测得的温度单位是0.25,所以要乘以0.25(即除以4) else: return 4095 def __del__(self, ): self.spi.deinit() # 关闭spi
class osd: def __init__(self): self.screen_x = const(64) self.screen_y = const(20) self.cwd = "/" self.init_fb() self.exp_names = " KMGTE" self.mark = bytearray([32, 16, 42]) # space, right triangle, asterisk self.diskfile = [open("main.py", "rb"), open("main.py", "rb")] # any dummy file that can open self.imgtype = bytearray( 2) # [0]=0:.mac/.bin 1638400 bytes, [0]=1:.dsk 819200 bytes self.drive = bytearray(1) # [0]=0:1st drive, [0]=1:2nd drive self.conv_dataIn12K = bytearray(12 * 1024) # memoryview for each track//16 datainmv = memoryview(self.conv_dataIn12K) self.conv_dataIn = [] for i in range(5): self.conv_dataIn.append(memoryview(datainmv[0:(12 - i) * 1024])) self.conv_nibsOut = bytearray(1024) dsk2mac.init_nibsOut(self.conv_nibsOut) self.track2sector = bytearray(81 * 2) self.init_track2sector() self.read_dir() self.spi_read_irq = bytearray([1, 0xF1, 0, 0, 0, 0, 0]) self.spi_read_btn = bytearray([1, 0xFB, 0, 0, 0, 0, 0]) self.spi_read_trackno = bytearray([1, 0xD0, 0, 0, 0, 0, 0]) self.spi_result = bytearray(7) self.spi_enable_osd = bytearray([0, 0xFE, 0, 0, 0, 1]) self.spi_write_osd = bytearray([0, 0xFD, 0, 0, 0]) self.spi_write_track = [ bytearray([0, 0xD1, 0, 0, 0]), bytearray([0, 0xD1, 0, 0x60, 0]) ] self.spi_channel = const(2) self.spi_freq = const(3000000) self.init_pinout_sd() self.init_spi() alloc_emergency_exception_buf(100) self.enable = bytearray(1) self.timer = Timer(3) self.irq_handler(0) self.irq_handler_ref = self.irq_handler # allocation happens here self.spi_request = Pin(0, Pin.IN, Pin.PULL_UP) self.spi_request.irq(trigger=Pin.IRQ_FALLING, handler=self.irq_handler_ref) def init_spi(self): self.spi = SPI(self.spi_channel, baudrate=self.spi_freq, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, sck=Pin(self.gpio_sck), mosi=Pin(self.gpio_mosi), miso=Pin(self.gpio_miso)) self.cs = Pin(self.gpio_cs, Pin.OUT) self.cs.off() self.led = Pin(self.gpio_led, Pin.OUT) self.led.off() # init file browser def init_fb(self): self.fb_topitem = 0 self.fb_cursor = 0 self.fb_selected = -1 @micropython.viper def init_track2sector(self): p16t2s = ptr16(addressof(self.track2sector)) offset = 0 for i in range(0, 81): p16t2s[i] = offset offset += 12 - i // 16 @micropython.viper def init_pinout_sd(self): self.gpio_cs = const(17) self.gpio_sck = const(16) #self.gpio_mosi = const(4) #self.gpio_miso = const(12) self.gpio_mosi = const(25) self.gpio_miso = const(26) self.gpio_led = const(5) @micropython.viper def update_track(self): p8result = ptr8(addressof(self.spi_result)) p16t2s = ptr16(addressof(self.track2sector)) p8it = ptr8(addressof(self.imgtype)) # ask FPGA for current track number self.ctrl(4) # stop cpu self.cs.on() self.spi.write_readinto(self.spi_read_trackno, self.spi_result) self.cs.off() drive = 0 if p8result[6] & 0x80: drive = 1 track = p8result[6] & 0x7F if track > 79: track = 79 trackdiv16 = track // 16 #print("Fetching drive " + str(drive) + " track " + str(track)) sectors = 12 - trackdiv16 self.diskfile[drive].seek((2 - p8it[drive]) * p16t2s[track] * 1024) # upload data self.cs.on() self.spi.write(self.spi_write_track[drive]) if p8it[drive]: # .dsk self.diskfile[drive].readinto(self.conv_dataIn[trackdiv16]) offset = 0 for side in range(2): for sector in range(sectors): dsk2mac.convert_sector(self.conv_dataIn12K, offset, self.conv_nibsOut, track, side, sector) offset += 512 self.spi.write(self.conv_nibsOut) else: # .mac for side in range(2): self.diskfile[drive].readinto(self.conv_dataIn[trackdiv16]) self.spi.write(self.conv_dataIn[trackdiv16]) self.cs.off() self.ctrl(0) # resume cpu @micropython.viper def irq_handler(self, pin): p8result = ptr8(addressof(self.spi_result)) p8drive = ptr8(addressof(self.drive)) self.cs.on() self.spi.write_readinto(self.spi_read_irq, self.spi_result) self.cs.off() btn_irq = p8result[6] if btn_irq & 1: # drive 1 request self.update_track() if btn_irq & 0x80: # btn event IRQ flag self.cs.on() self.spi.write_readinto(self.spi_read_btn, self.spi_result) self.cs.off() btn = p8result[6] p8enable = ptr8(addressof(self.enable)) if p8enable[0] & 2: # wait to release all BTNs if btn == 1: p8enable[ 0] &= 1 # clear bit that waits for all BTNs released else: # all BTNs released if (btn & 0x78 ) == 0x78: # all cursor BTNs pressed at the same time self.show_dir() # refresh directory p8enable[0] = (p8enable[0] ^ 1) | 2 self.osd_enable(p8enable[0] & 1) if p8enable[0] == 1: if btn == 9: # btn3 cursor up self.start_autorepeat(-1) if btn == 17: # btn4 cursor down self.start_autorepeat(1) if btn == 1: self.timer.deinit() # stop autorepeat if btn == 33: # btn5 cursor left self.updir() if btn == 65: # btn6 cursor right 1st drive p8drive[0] = 0 self.select_entry() if btn == 3: # btn1 2nd drive p8drive[0] = 1 self.select_entry() def start_autorepeat(self, i: int): self.autorepeat_direction = i self.move_dir_cursor(i) self.timer_slow = 1 self.timer.init(mode=Timer.PERIODIC, period=500, callback=self.autorepeat) def autorepeat(self, timer): if self.timer_slow: self.timer_slow = 0 self.timer.init(mode=Timer.PERIODIC, period=30, callback=self.autorepeat) self.move_dir_cursor(self.autorepeat_direction) self.irq_handler(0) # catch stale IRQ def select_entry(self): if self.direntries[self.fb_cursor][1]: # is it directory oldselected = self.fb_selected - self.fb_topitem self.fb_selected = self.fb_cursor try: self.cwd = self.fullpath(self.direntries[self.fb_cursor][0]) except: self.fb_selected = -1 self.show_dir_line(oldselected) self.show_dir_line(self.fb_cursor - self.fb_topitem) self.init_fb() self.read_dir() self.show_dir() else: self.change_file() def updir(self): if len(self.cwd) < 2: self.cwd = "/" else: s = self.cwd.split("/")[:-1] self.cwd = "" for name in s: if len(name) > 0: self.cwd += "/" + name self.init_fb() self.read_dir() self.show_dir() def fullpath(self, fname): if self.cwd.endswith("/"): return self.cwd + fname else: return self.cwd + "/" + fname def change_file(self): oldselected = self.fb_selected - self.fb_topitem self.fb_selected = self.fb_cursor try: filename = self.fullpath(self.direntries[self.fb_cursor][0]) except: filename = False self.fb_selected = -1 self.show_dir_line(oldselected) self.show_dir_line(self.fb_cursor - self.fb_topitem) if filename: if filename.endswith(".mac") or filename.endswith( ".MAC") or filename.endswith(".dsk") or filename.endswith( ".DSK"): self.diskfile[self.drive[0]] = open(filename, "rb") self.imgtype[self.drive[0]] = 0 if filename.endswith(".dsk") or filename.endswith(".DSK"): self.imgtype[self.drive[0]] = 1 #self.update_track() self.ctrl(16 << self.drive[0]) # set insert_disk self.enable[0] = 0 self.osd_enable(0) if filename.endswith(".bit"): self.spi_request.irq(handler=None) self.timer.deinit() self.enable[0] = 0 self.osd_enable(0) self.spi.deinit() import ecp5 ecp5.prog_stream(open(filename, "rb"), blocksize=1024) if filename.endswith("_sd.bit"): os.umount("/sd") for i in bytearray([2, 4, 12, 13, 14, 15]): p = Pin(i, Pin.IN) a = p.value() del p, a result = ecp5.prog_close() del tap gc.collect() #os.mount(SDCard(slot=3),"/sd") # BUG, won't work self.init_spi() # because of ecp5.prog() spi.deinit() self.spi_request.irq(trigger=Pin.IRQ_FALLING, handler=self.irq_handler_ref) self.irq_handler(0) # handle stuck IRQ if filename.endswith(".nes") \ or filename.endswith(".snes") \ or filename.endswith(".smc") \ or filename.endswith(".sfc"): import ld_nes s = ld_nes.ld_nes(self.spi, self.cs) s.ctrl(1) s.ctrl(0) s.load_stream(open(filename, "rb")) del s gc.collect() self.enable[0] = 0 self.osd_enable(0) if filename.startswith("/sd/ti99_4a/") and filename.endswith( ".bin"): import ld_ti99_4a s = ld_ti99_4a.ld_ti99_4a(self.spi, self.cs) s.load_rom_auto(open(filename, "rb"), filename) del s gc.collect() self.enable[0] = 0 self.osd_enable(0) if (filename.startswith("/sd/msx") and filename.endswith(".rom")) \ or filename.endswith(".mx1"): import ld_msx s = ld_msx.ld_msx(self.spi, self.cs) s.load_msx_rom(open(filename, "rb")) del s gc.collect() self.enable[0] = 0 self.osd_enable(0) if filename.endswith(".z80"): self.enable[0] = 0 self.osd_enable(0) import ld_zxspectrum s = ld_zxspectrum.ld_zxspectrum(self.spi, self.cs) s.loadz80(filename) del s gc.collect() if filename.endswith(".ora") or filename.endswith(".orao"): self.enable[0] = 0 self.osd_enable(0) import ld_orao s = ld_orao.ld_orao(self.spi, self.cs) s.loadorao(filename) del s gc.collect() if filename.endswith(".vsf"): self.enable[0] = 0 self.osd_enable(0) import ld_vic20 s = ld_vic20.ld_vic20(self.spi, self.cs) s.loadvsf(filename) del s gc.collect() if filename.endswith(".prg"): self.enable[0] = 0 self.osd_enable(0) import ld_vic20 s = ld_vic20.ld_vic20(self.spi, self.cs) s.loadprg(filename) del s gc.collect() if filename.endswith(".cas"): self.enable[0] = 0 self.osd_enable(0) import ld_trs80 s = ld_trs80.ld_trs80(self.spi, self.cs) s.loadcas(filename) del s gc.collect() if filename.endswith(".cmd"): self.enable[0] = 0 self.osd_enable(0) import ld_trs80 s = ld_trs80.ld_trs80(self.spi, self.cs) s.loadcmd(filename) del s gc.collect() @micropython.viper def osd_enable(self, en: int): pena = ptr8(addressof(self.spi_enable_osd)) pena[5] = en & 1 self.cs.on() self.spi.write(self.spi_enable_osd) self.cs.off() @micropython.viper def osd_print(self, x: int, y: int, i: int, text): p8msg = ptr8(addressof(self.spi_write_osd)) a = 0xF000 + (x & 63) + ((y & 31) << 6) p8msg[2] = i p8msg[3] = a >> 8 p8msg[4] = a self.cs.on() self.spi.write(self.spi_write_osd) self.spi.write(text) self.cs.off() @micropython.viper def osd_cls(self): p8msg = ptr8(addressof(self.spi_write_osd)) p8msg[3] = 0xF0 p8msg[4] = 0 self.cs.on() self.spi.write(self.spi_write_osd) self.spi.read(1280, 32) self.cs.off() # y is actual line on the screen def show_dir_line(self, y): if y < 0 or y >= self.screen_y: return mark = 0 invert = 0 if y == self.fb_cursor - self.fb_topitem: mark = 1 invert = 1 if y == self.fb_selected - self.fb_topitem: mark = 2 i = y + self.fb_topitem if i >= len(self.direntries): self.osd_print(0, y, 0, "%64s" % "") return if self.direntries[i][1]: # directory self.osd_print( 0, y, invert, "%c%-57s D" % (self.mark[mark], self.direntries[i][0])) else: # file mantissa = self.direntries[i][2] exponent = 0 while mantissa >= 1024: mantissa >>= 10 exponent += 1 self.osd_print( 0, y, invert, "%c%-57s %4d%c" % (self.mark[mark], self.direntries[i][0], mantissa, self.exp_names[exponent])) def show_dir(self): for i in range(self.screen_y): self.show_dir_line(i) def move_dir_cursor(self, step): oldcursor = self.fb_cursor if step == 1: if self.fb_cursor < len(self.direntries) - 1: self.fb_cursor += 1 if step == -1: if self.fb_cursor > 0: self.fb_cursor -= 1 if oldcursor != self.fb_cursor: screen_line = self.fb_cursor - self.fb_topitem if screen_line >= 0 and screen_line < self.screen_y: # move cursor inside screen, no scroll self.show_dir_line(oldcursor - self.fb_topitem) # no highlight self.show_dir_line(screen_line) # highlight else: # scroll if screen_line < 0: # cursor going up screen_line = 0 if self.fb_topitem > 0: self.fb_topitem -= 1 self.show_dir() else: # cursor going down screen_line = self.screen_y - 1 if self.fb_topitem + self.screen_y < len(self.direntries): self.fb_topitem += 1 self.show_dir() def read_dir(self): self.direntries = [] ls = sorted(os.listdir(self.cwd)) for fname in ls: stat = os.stat(self.fullpath(fname)) if stat[0] & 0o170000 == 0o040000: self.direntries.append([fname, 1, 0]) # directory for fname in ls: stat = os.stat(self.fullpath(fname)) if stat[0] & 0o170000 != 0o040000: self.direntries.append([fname, 0, stat[6]]) # file # NOTE: this can be used for debugging #def osd(self, a): # if len(a) > 0: # enable = 1 # else: # enable = 0 # self.cs.on() # self.spi.write(bytearray([0,0xFE,0,0,0,enable])) # enable OSD # self.cs.off() # if enable: # self.cs.on() # self.spi.write(bytearray([0,0xFD,0,0,0])) # write content # self.spi.write(bytearray(a)) # write content # self.cs.off() def ctrl(self, i): self.cs.on() self.spi.write(bytearray([0, 0xFF, 0xFF, 0xFF, 0xFF, i])) self.cs.off() def peek(self, addr, length): self.ctrl(4) self.ctrl(6) self.cs.on() self.spi.write( bytearray([ 1, (addr >> 24) & 0xFF, (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, addr & 0xFF, 0 ])) b = bytearray(length) self.spi.readinto(b) self.cs.off() self.ctrl(4) self.ctrl(0) return b def poke(self, addr, data): self.ctrl(4) self.ctrl(6) self.cs.on() self.spi.write( bytearray([ 0, (addr >> 24) & 0xFF, (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, addr & 0xFF ])) self.spi.write(data) self.cs.off() self.ctrl(4) self.ctrl(0)
class MFRC522: OK = 0 NOTAGERR = 1 ERR = 2 REQIDL = 0x26 REQALL = 0x52 AUTHENT1A = 0x60 AUTHENT1B = 0x61 def __init__(self, sck, mosi, miso, rst, cs): self.sck = Pin(sck, Pin.OUT) self.mosi = Pin(mosi, Pin.OUT) self.miso = Pin(miso) self.rst = Pin(rst, Pin.OUT) self.cs = Pin(cs, Pin.OUT) self.rst.value(0) self.cs.value(1) board = uname()[0] if board == 'WiPy' or board == 'LoPy' or board == 'FiPy': self.spi = SPI(0) self.spi.init(SPI.MASTER, baudrate=1000000, pins=(self.sck, self.mosi, self.miso)) elif board == 'esp8266' or board == 'esp32': self.spi = SPI(baudrate=100000, polarity=0, phase=0, sck=self.sck, mosi=self.mosi, miso=self.miso) self.spi.init() else: raise RuntimeError("Unsupported platform") self.rst.value(1) self.init() def _wreg(self, reg, val): self.cs.value(0) self.spi.write(b'%c' % int(0xff & ((reg << 1) & 0x7e))) self.spi.write(b'%c' % int(0xff & val)) self.cs.value(1) def _rreg(self, reg): self.cs.value(0) self.spi.write(b'%c' % int(0xff & (((reg << 1) & 0x7e) | 0x80))) val = self.spi.read(1) self.cs.value(1) return val[0] def _sflags(self, reg, mask): self._wreg(reg, self._rreg(reg) | mask) def _cflags(self, reg, mask): self._wreg(reg, self._rreg(reg) & (~mask)) def _tocard(self, cmd, send): recv = [] bits = irq_en = wait_irq = n = 0 stat = self.ERR if cmd == 0x0E: irq_en = 0x12 wait_irq = 0x10 elif cmd == 0x0C: irq_en = 0x77 wait_irq = 0x30 self._wreg(0x02, irq_en | 0x80) self._cflags(0x04, 0x80) self._sflags(0x0A, 0x80) self._wreg(0x01, 0x00) for c in send: self._wreg(0x09, c) self._wreg(0x01, cmd) if cmd == 0x0C: self._sflags(0x0D, 0x80) i = 2000 while True: n = self._rreg(0x04) i -= 1 if ~((i != 0) and ~(n & 0x01) and ~(n & wait_irq)): break self._cflags(0x0D, 0x80) if i: if (self._rreg(0x06) & 0x1B) == 0x00: stat = self.OK if n & irq_en & 0x01: stat = self.NOTAGERR elif cmd == 0x0C: n = self._rreg(0x0A) lbits = self._rreg(0x0C) & 0x07 if lbits != 0: bits = (n - 1) * 8 + lbits else: bits = n * 8 if n == 0: n = 1 elif n > 16: n = 16 for _ in range(n): recv.append(self._rreg(0x09)) else: stat = self.ERR return stat, recv, bits def _crc(self, data): self._cflags(0x05, 0x04) self._sflags(0x0A, 0x80) for c in data: self._wreg(0x09, c) self._wreg(0x01, 0x03) i = 0xFF while True: n = self._rreg(0x05) i -= 1 if not ((i != 0) and not (n & 0x04)): break return [self._rreg(0x22), self._rreg(0x21)] def init(self): self.reset() self._wreg(0x2A, 0x8D) self._wreg(0x2B, 0x3E) self._wreg(0x2D, 30) self._wreg(0x2C, 0) self._wreg(0x15, 0x40) self._wreg(0x11, 0x3D) self.antenna_on() def reset(self): self._wreg(0x01, 0x0F) def antenna_on(self, on=True): if on and ~(self._rreg(0x14) & 0x03): self._sflags(0x14, 0x03) else: self._cflags(0x14, 0x03) def request(self, mode): self._wreg(0x0D, 0x07) (stat, recv, bits) = self._tocard(0x0C, [mode]) if (stat != self.OK) | (bits != 0x10): stat = self.ERR return stat, bits def anticoll(self): ser_chk = 0 ser = [0x93, 0x20] self._wreg(0x0D, 0x00) (stat, recv, bits) = self._tocard(0x0C, ser) if stat == self.OK: if len(recv) == 5: for i in range(4): ser_chk = ser_chk ^ recv[i] if ser_chk != recv[4]: stat = self.ERR else: stat = self.ERR return stat, recv def select_tag(self, ser): buf = [0x93, 0x70] + ser[:5] buf += self._crc(buf) (stat, recv, bits) = self._tocard(0x0C, buf) return self.OK if (stat == self.OK) and (bits == 0x18) else self.ERR def auth(self, mode, addr, sect, ser): return self._tocard(0x0E, [mode, addr] + sect + ser[:4])[0] def stop_crypto1(self): self._cflags(0x08, 0x08) def read(self, addr): data = [0x30, addr] data += self._crc(data) (stat, recv, _) = self._tocard(0x0C, data) return recv if stat == self.OK else None def write(self, addr, data): buf = [0xA0, addr] buf += self._crc(buf) (stat, recv, bits) = self._tocard(0x0C, buf) if not (stat == self.OK) or not (bits == 4) or not ((recv[0] & 0x0F) == 0x0A): stat = self.ERR else: buf = [] for i in range(16): buf.append(data[i]) buf += self._crc(buf) (stat, recv, bits) = self._tocard(0x0C, buf) if not (stat == self.OK) or not (bits == 4) or not ((recv[0] & 0x0F) == 0x0A): stat = self.ERR return stat
print(spi) spi.init(baudrate=20000000, polarity=0, phase=0) print(spi) spi=SPI() print(spi) SPI(mode=SPI.MASTER) SPI(mode=SPI.MASTER, pins=spi_pins) SPI(id=0, mode=SPI.MASTER, polarity=0, phase=0, pins=('GP14', 'GP16', 'GP15')) SPI(0, SPI.MASTER, polarity=0, phase=0, pins=('GP31', 'GP16', 'GP15')) spi = SPI(0, SPI.MASTER, baudrate=10000000, polarity=0, phase=0, pins=spi_pins) print(spi.write('123456') == 6) buffer_r = bytearray(10) print(spi.readinto(buffer_r) == 10) print(spi.readinto(buffer_r, write=0x55) == 10) read = spi.read(10) print(len(read) == 10) read = spi.read(10, write=0xFF) print(len(read) == 10) buffer_w = bytearray([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]) print(spi.write_readinto(buffer_w, buffer_r) == 10) print(buffer_w == buffer_r) # test all polaritiy and phase combinations spi.init(polarity=1, phase=0, pins=None) buffer_r = bytearray(10) spi.write_readinto(buffer_w, buffer_r) print(buffer_w == buffer_r) spi.init(polarity=1, phase=1, pins=None) buffer_r = bytearray(10)
#importing machine and spi from machine import Pin, SPI #SPI functions# #Constructing the SPI bus using the following pins # polarity is the idle state of SCK # phase=0 means sample on the first edge of SCK, phase=1 means the second spi = SPI(baudrate=100000, polarity=1, phase=0, sck=Pin(0), mosi=Pin(2), miso=Pin(4)) spi.init(baudrate=200000) #Setting the baudrate spi.read(10) #Reading 10 bytes from the baudrate spi.read(10, 0xff) #read 10 bytes while outputting 0xff on MOSI buf = bytearray(50) # create a buffer spi.readinto(buf) # read into the given buffer (reads 50 bytes in this case) spi.readinto(buf, 0xff) # read into the given buffer and output 0xff on MOSI spi.write(b'12345') # write 5 bytes on MOSI buf = bytearray(4) # create a buffer spi.write_readinto(b'1234', buf) # write to MOSI and read from MISO into the buffer spi.write_readinto(buf, buf) # write buf to MOSI and read MISO back into buf while True: #Input your code that runs continually
class machx02_spi(object): # bit12:busy, bit13:failed, bit9:enabled status = {"busy": 4096, "failed": 8192, "enabled": 512, "done": 256} mask = 0x00000000FFFFFFFF def __init__(self, baudrate, deviceid): self.cs = Pin(15, Pin.OUT) self.cs.on() self.hspi = SPI(1, baudrate=400000, sck=Pin(14), mosi=Pin(13), miso=Pin(12)) self.deviceid = deviceid # transfert spi def spiTrans(self, cmd, size): resp_machx02_spi = bytearray(size) self.hspi.init(baudrate=400000, sck=Pin(14), mosi=Pin(13), miso=Pin(12), firstbit=SPI.MSB) # set the baudrate* self.cs.off() self.hspi.write_readinto(cmd, resp_machx02_spi) self.cs.on() return resp_machx02_spi # check idcode def check_idcode(self): cmd = bytearray([ MACHXO2_CMD_READ_DEVICEID, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]) resp_machx02_spi = self.spiTrans(cmd, 8) resp_machx02_spi_int = self.from_bytes_big(bytes(resp_machx02_spi)) result = resp_machx02_spi_int & self.mask return (self.deviceid == result) # disable def disable(self): #disable configuration cmd = bytearray([MACHXO2_CMD_DISABLE, 0x00, 0x00]) resp_machx02_spi = self.spiTrans(cmd, 3) # nop cmd = bytearray([MACHXO2_CMD_NOP, 0xFF, 0xFF, 0xFF]) resp_machx02_spi = self.spiTrans(cmd, 4) # refresh cmd = bytearray([MACHXO2_CMD_REFRESH, 0x00, 0x00]) resp_machx02_spi = self.spiTrans(cmd, 3) utime.sleep_ms(10000) def wakeup_device(self): # refresh cmd = bytearray([MACHXO2_CMD_REFRESH, 0x00, 0x00]) resp_machx02_spi = self.spiTrans(cmd, 3) utime.sleep_ms(10000) # enable offline configuration def enable(self): cmd = bytearray([MACHXO2_CMD_ENABLE_OFFLINE, 0x08, 0x00, 0x00]) resp_machx02_spi = self.spiTrans(cmd, 4) self.waitidle() # erase SRAM cmd = bytearray([MACHXO2_CMD_ERASE, 0x01, 0x00, 0x00]) resp_machx02_spi = self.spiTrans(cmd, 4) self.waitidle() # bit 13 = fail # bit 9 = enabled resp = self.readstatus() print("status enable", resp) status_failed = self.from_bytes_big(resp) & self.status["failed"] status_enabled = self.from_bytes_big(resp) & self.status["enabled"] #print(status_failed,status_enabled) return (status_failed != self.status["failed"]) and ( status_enabled == self.status["enabled"]) # busy = bit12 def waitidle(self): while True: resp = self.readstatus() # print("status=",resp) status_busy = self.from_bytes_big(resp) & self.status["busy"] #print("busy ",status_busy,type(status_busy)) if status_busy == self.status["busy"]: #print("busy") utime.sleep_ms(1) # datasheet = 200 us else: break def waitdone(self): while True: resp = self.readstatus() status_done = self.from_bytes_big(resp) & self.status["done"] print("wait done status=", status_done) if status_done != self.status["done"]: print("wait done") utime.sleep_ms(1) # datasheet = 200 us else: break def waitrefresh(self): while True: resp = self.readstatus() print("wait refresh=", resp) status_done = self.from_bytes_big(resp) & self.status["done"] print("status_done=", status_done) status_busy = self.from_bytes_big(resp) & self.status["busy"] print("status_busy=", status_busy) if status_busy == self.status["busy"]: cmd = bytearray([MACHXO2_CMD_REFRESH, 0x00, 0x00]) resp_machx02_spi = self.spiTrans(cmd, 3) print("wait refresh") utime.sleep_ms(1) # datasheet = 200 us else: break # read status def readstatus(self): cmd = bytearray([ MACHXO2_CMD_READ_STATUS, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]) resp_machx02_spi = self.spiTrans(cmd, 8) return resp_machx02_spi # read features def readfeatures(self): cmd = bytearray([ MACHXO2_CMD_READ_FEATURE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]) feature_row = self.spiTrans(cmd, 12) # read FEABITS cmd = bytearray( [MACHXO2_CMD_READ_FEABITS, 0x00, 0x00, 0x00, 0x00, 0x00]) feabits = self.spiTrans(cmd, 6) return self.from_bytes_big(feature_row), self.from_bytes_big(feabits) # programm jedec file def program(self, fusetable): # erase flash cmd = bytearray([MACHXO2_CMD_ERASE, 0x04, 0x00, 0x00]) resp_machx02_spi = self.spiTrans(cmd, 4) print("erase flash ...") self.waitidle() resp = self.readstatus() status_failed = self.from_bytes_big(resp) & self.status["failed"] if status_failed == self.status["failed"]: return False # set address to zero cmd = bytearray([MACHXO2_CMD_INIT_ADDRESS, 0x00, 0x00, 0x00]) resp_machx02_spi = self.spiTrans(cmd, 4) #print("set adress to 0") self.waitidle() # program pages sizefile = len(fusetable) nb_bit = sizefile * 128 # not implemented, because ufm not programmed # if nb_bit != int(MACHXO2_SIZE_FUSETABLE_7000): # print("error size fusetable",nb_bit) # sys.exit() # else: # print("size fusetable",nb_bit) #lines = [i.strip() for i in fusetable] numbit = 0 crc = 0 nbdata = 16 countline = 0 req = bytearray(20) for line in fusetable: #before = gc.mem_free() line_strip = line.strip() size_line = len(line_strip) # print("count",countline,size_line) countline = countline + 1 for countbit_128 in range(size_line): valbit = line_strip[countbit_128] if valbit == "1": val = 1 else: val = 0 crc += val << (numbit % 8) numbit = numbit + 1 line_bytes = [line_strip[i:i + 8] for i in range(0, size_line, 8)] # transmit data with format : cmd,0,0,1 <16* 8 bytes data> req[0] = MACHXO2_CMD_PROG_INCR_NV req[1] = 0x00 req[2] = 0x00 req[3] = 0x01 # transmit Y*16 bytes for i in range(nbdata): req[4 + i] = self.str_to_byte(line_bytes[i]) resp_machx02_spi = self.spiTrans(req, nbdata + 4) #after = gc.mem_free() #print("mem =",before - after ,"bytes") self.waitidle() print("numbit programmed = ", numbit) # program DONE bit cmd = bytearray([MACHXO2_CMD_PROGRAM_DONE, 0x00, 0x00, 0x00]) resp_machx02_spi = self.spiTrans(cmd, 4) self.waitdone() status = self.readstatus() status_failed = self.from_bytes_big(status) & self.status["failed"] error = (status_failed != self.status["failed"]) return error, crc # read flash def checkflash(self): countpage = 0x0100 # 14 bits counter page cmd = bytearray([MACHXO2_CMD_READ_INCR_NV, 0x01, 0x01, 0x00]) self.cs.off() self.hspi.write(cmd) self.cs.on() utime.sleep_us(500) self.cs.off() resp_machx02_spi = self.hspi.read(int(countpage)) self.cs.on() return resp_machx02_spi # read ufm def readufm(self): cmd = bytearray([MACHXO2_CMD_READ_UFM, 0x01, 0x00, 0x00]) resp_machx02_spi = self.spiTrans(cmd, 4) return resp_machx02_spi def from_bytes_big(self, b): n = 0 for x in b: n <<= 8 n |= x return n def str_to_byte(self, s): b = 0 for i in range(len(s)): b |= int(s[i]) << 7 - i return b
class MFRC522: OK = 0 NOTAGERR = 1 ERR = 2 REQIDL = 0x26 REQALL = 0x52 AUTHENT1A = 0x60 AUTHENT1B = 0x61 def __init__(self, sck, mosi, miso, rst, cs): self.sck = Pin(sck, Pin.OUT) self.mosi = Pin(mosi, Pin.OUT) self.miso = Pin(miso) self.rst = Pin(rst, Pin.OUT) self.cs = Pin(cs, Pin.OUT) self.rst.value(0) self.cs.value(1) board = uname()[0] if board == 'esp32' or board == 'LoPy' or board == 'FiPy': self.spi = SPI(1, 10000000, sck=self.sck, mosi=self.mosi, miso=self.miso) self.spi.init() elif board == 'esp8266': self.spi = SPI(baudrate=100000, polarity=0, phase=0, sck=self.sck, mosi=self.mosi, miso=self.miso) self.spi.init() else: raise RuntimeError("Unsupported platform") self.rst.value(1) self.init() def _wreg(self, reg, val): self.cs.value(0) self.spi.write(b'%c' % int(0xff & ((reg << 1) & 0x7e))) self.spi.write(b'%c' % int(0xff & val)) self.cs.value(1) def _rreg(self, reg): self.cs.value(0) self.spi.write(b'%c' % int(0xff & (((reg << 1) & 0x7e) | 0x80))) val = self.spi.read(1) self.cs.value(1) return val[0] def _sflags(self, reg, mask): self._wreg(reg, self._rreg(reg) | mask) def _cflags(self, reg, mask): self._wreg(reg, self._rreg(reg) & (~mask)) def _tocard(self, cmd, send): recv = [] bits = irq_en = wait_irq = n = 0 stat = self.ERR if cmd == 0x0E: irq_en = 0x12 wait_irq = 0x10 elif cmd == 0x0C: irq_en = 0x77 wait_irq = 0x30 self._wreg(0x02, irq_en | 0x80) self._cflags(0x04, 0x80) self._sflags(0x0A, 0x80) self._wreg(0x01, 0x00) #print("send:") #print([hex(x) for x in send]) for c in send: self._wreg(0x09, c) self._wreg(0x01, cmd) if cmd == 0x0C: self._sflags(0x0D, 0x80) i = 500 #2000 while True: n = self._rreg(0x04) i -= 1 if ~((i != 0) and ~(n & 0x01) and ~(n & wait_irq)): break self._cflags(0x0D, 0x80) if i: if (self._rreg(0x06) & 0x1B) == 0x00: stat = self.OK if n & irq_en & 0x01: stat = self.NOTAGERR elif cmd == 0x0C: n = self._rreg(0x0A) lbits = self._rreg(0x0C) & 0x07 if lbits != 0: bits = (n - 1) * 8 + lbits else: bits = n * 8 if n == 0: n = 1 elif n > 16: n = 16 for _ in range(n): recv.append(self._rreg(0x09)) else: stat = self.ERR #print("recv:") #print(stat,[hex(x) for x in recv],bits) return stat, recv, bits def _crc(self, data): self._cflags(0x05, 0x04) self._sflags(0x0A, 0x80) for c in data: self._wreg(0x09, c) self._wreg(0x01, 0x03) i = 0xFF while True: n = self._rreg(0x05) i -= 1 if not ((i != 0) and not (n & 0x04)): break return [self._rreg(0x22), self._rreg(0x21)] def init(self): self.reset() self._wreg(0x2A, 0x8D) self._wreg(0x2B, 0x3E) self._wreg(0x2D, 30) self._wreg(0x2C, 0) self._wreg(0x15, 0x40) self._wreg(0x11, 0x3D) self.antenna_on() def reset(self): self._wreg(0x01, 0x0F) def antenna_on(self, on=True): if on and ~(self._rreg(0x14) & 0x03): self._sflags(0x14, 0x03) else: self._cflags(0x14, 0x03) def request(self, mode): self._wreg(0x0D, 0x07) (stat, recv, bits) = self._tocard(0x0C, [mode]) if (stat != self.OK) | (bits != 0x10): stat = self.ERR return stat, bits def requestRawAnswer(self, mode): self._wreg(0x0D, 0x07) (stat, recv, bits) = self._tocard(0x0C, [mode]) if (stat != self.OK): stat = self.ERR return stat, recv, bits def anticoll(self): ser_chk = 0 ser = [0x93, 0x20] self._wreg(0x0D, 0x00) (stat, recv, bits) = self._tocard(0x0C, ser) if stat == self.OK: if len(recv) == 5: for i in range(4): ser_chk = ser_chk ^ recv[i] if ser_chk != recv[4]: stat = self.ERR else: stat = self.ERR return stat, recv #PICC_HALT https://www.rubydoc.info/gems/mfrc522/0.0.1/Mfrc522#picc_halt-instance_method: def halt(self): PICC_HALT = 0x50 buf = [PICC_HALT, 0x00] buf += self._crc(buf) (stat, recv, bits) = self._tocard(0x0C, buf) return self.OK if (stat == self.OK) and (bits == 0x18) else self.ERR #PICC_WUPA =0x52 #REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame. def wake(self): PICC_WUPA = 0x52 (stat, recv, bits) = self._tocard(0x0C, [PICC_WUPA]) return self.OK if (stat == self.OK) and (bits == 0x18) else self.ERR def select_tag(self, ser): buf = [0x93, 0x70] + ser[:5] buf += self._crc(buf) (stat, recv, bits) = self._tocard(0x0C, buf) return self.OK if (stat == self.OK) and (bits == 0x18) else self.ERR def auth(self, mode, addr, sect, ser): return self._tocard(0x0E, [mode, addr] + sect + ser[:4])[0] def stop_crypto1(self): self._cflags(0x08, 0x08) def read(self, addr): data = [0x30, addr] data += self._crc(data) (stat, recv, _) = self._tocard(0x0C, data) return recv if stat == self.OK else None def write(self, addr, data): buf = [0xA0, addr] buf += self._crc(buf) (stat, recv, bits) = self._tocard(0x0C, buf) if not (stat == self.OK) or not (bits == 4) or not ((recv[0] & 0x0F) == 0x0A): stat = self.ERR else: buf = [] for i in range(16): buf.append(data[i]) buf += self._crc(buf) (stat, recv, bits) = self._tocard(0x0C, buf) if not (stat == self.OK) or not (bits == 4) or not ((recv[0] & 0x0F) == 0x0A): stat = self.ERR return stat def checkChinaUID(self): answer = False #try to send magic command to the sector 0 self.halt() (stat, data, bits) = self.requestRawAnswer(0x40) # request is 7 bits #print(stat, data, bits) if stat == self.OK and data[0] == 0xA: #if answer is 0xA, we check further... maybe this is a china changeable UID card answer=True #-------------- #if the next command didn't work, we're pretty sure that is a china card #disabled this as the above is enough to detect a china card #-------------- #self._wreg(0x0D, 0x08) #send 8 bytes #(stat, data, bytes) = self._tocard(0x0C,[0x43]) #if stat == self.OK and data[0] == 0xA: #sector unlocked. this is a china card #from here we can write sector 0 without authentication # answer=True #-------------- self.wake() return answer #https://learn.adafruit.com/adafruit-pn532-rfid-nfc/ndef def setKey(self,sector,keya,keyb): #https://www.az-delivery.de/blogs/azdelivery-blog-fur-arduino-und-raspberry-pi/zugangsbeschrankung-zu-geraten-per-contactless-card-mit-der-nodemcu-und-dem-rc522-modul-vierter-teil-down-the-rabbit-hole?ls=de&cache=false sectorkeytable = [3,7,11,15,19,23,27,31,35,39,43,47,51,55,59,63] key = [] key.extend(keya[:6]) key.append(0x78) #Data Block 0-3 Access Conditions: Key B write / Key A Read key.append(0x77) #KEY A & KEY B & Acces Bits Write:Key B / Key A Read Access Bits key.append(0x88) #Calculator: http://calc.gmss.ru/Mifare1k/ key.append(0x69) #Fixer Wert - > default hex 69 key.extend(keyb[:6]) #print(key) self.write(sectorkeytable[sector], key) def reSetKeyOpen(self,sector,keya,keyb): #https://www.az-delivery.de/blogs/azdelivery-blog-fur-arduino-und-raspberry-pi/zugangsbeschrankung-zu-geraten-per-contactless-card-mit-der-nodemcu-und-dem-rc522-modul-vierter-teil-down-the-rabbit-hole?ls=de&cache=false sectorkeytable = [3,7,11,15,19,23,27,31,35,39,43,47,51,55,59,63] key = [] key.extend(keya[:6]) key.append(0xFF) #Data Block 0-3 Access Conditions: Key B write / Key A Read key.append(0x07) #KEY A & KEY B & Acces Bits Write:Key B / Key A Read Access Bits key.append(0x80) #Calculator: http://calc.gmss.ru/Mifare1k/ key.append(0x69) #Fixer Wert - > default hex 69 key.extend(keyb[:6]) #print(key) self.write(sectorkeytable[sector], key)
class MFRC522: RESET = 'GP22' CLK = 'GP14' MISO = 'GP15' MOSI = 'GP16' CS = 'GP17' MAX_LEN = 16 PCD_IDLE = 0x00 PCD_AUTHENT = 0x0E PCD_TRANSCEIVE = 0x0C PCD_RESETPHASE = 0x0F PCD_CALCCRC = 0x03 PICC_REQIDL = 0x26 PICC_REQALL = 0x52 PICC_ANTICOLL = 0x93 PICC_SElECTTAG = 0x93 PICC_AUTHENT1A = 0x60 PICC_READ = 0x30 PICC_WRITE = 0xA0 MI_OK = 0 MI_NOTAGERR = 1 MI_ERR = 2 MI_AUTH_ERROR_STATUS2REG = 3 CommandReg = 0x01 CommIEnReg = 0x02 CommIrqReg = 0x04 DivIrqReg = 0x05 ErrorReg = 0x06 Status2Reg = 0x08 FIFODataReg = 0x09 FIFOLevelReg = 0x0A WaterLevelReg = 0x0B ControlReg = 0x0C BitFramingReg = 0x0D ModeReg = 0x11 TxControlReg = 0x14 TxAutoReg = 0x15 CRCResultRegM = 0x21 CRCResultRegL = 0x22 TModeReg = 0x2A TPrescalerReg = 0x2B TReloadRegH = 0x2C TReloadRegL = 0x2D serNum = [] def __init__(self, spd=1000000): # first assign CLK, MISO, MOSI, CS to the correct pins self.pin_clk = Pin(self.CLK, mode=Pin.OUT) # CLK self.pin_miso = Pin(self.MISO) # MISO self.pin_mosi = Pin(self.MOSI, mode=Pin.OUT) # MOSI self.pin_cs = Pin(self.CS, mode=Pin.OUT) # NSS/CS self.pin_reset = Pin(self.RESET, mode=Pin.OUT) self.pin_reset.value(0) self.pin_cs.value(1) self.spi = SPI(0) self.spi.init(mode=SPI.MASTER, baudrate=spd, pins=(self.CLK, self.MOSI, self.MISO)) self.pin_reset.value(1) self.MFRC522_Init() def MFRC522_Reset(self): self.Write_MFRC522(self.CommandReg, self.PCD_RESETPHASE) def Write_MFRC522(self, addr, val): self.pin_cs.value(0) # 0(MSB = Write) ADDR1 ADDR2 ADDR3 ADDR4 ADDR5 ADDR6 0(LSB = 0) DATA spiBytes = bytearray(2) spiBytes[0] = ((addr<<1)&0x7E) spiBytes[1] = val self.spi.write(spiBytes) self.pin_cs.value(1) def Read_MFRC522(self, addr): self.pin_cs.value(0) # 1(MSB = Read) ADDR1 ADDR2 ADDR3 ADDR4 ADDR5 ADDR6 0(LSB = 0) self.spi.write((addr<<1)&0x7E|0x80) data = self.spi.read(1) self.pin_cs.value(1) return data[0] def SetBitMask(self, reg, mask): tmp = self.Read_MFRC522(reg) self.Write_MFRC522(reg, tmp | mask) def ClearBitMask(self, reg, mask): tmp = self.Read_MFRC522(reg); self.Write_MFRC522(reg, tmp & (~mask)) def AntennaOn(self): temp = self.Read_MFRC522(self.TxControlReg) if(~(temp & 0x03)): self.SetBitMask(self.TxControlReg, 0x03) def AntennaOff(self): self.ClearBitMask(self.TxControlReg, 0x03) def MFRC522_ToCard(self,command,sendData): backData = [] backLen = 0 status = self.MI_ERR irqEn = 0x00 waitIRq = 0x00 lastBits = None n = 0 i = 0 if command == self.PCD_AUTHENT: irqEn = 0x12 waitIRq = 0x10 if command == self.PCD_TRANSCEIVE: irqEn = 0x77 waitIRq = 0x30 self.Write_MFRC522(self.CommIEnReg, irqEn|0x80) self.ClearBitMask(self.CommIrqReg, 0x80) self.SetBitMask(self.FIFOLevelReg, 0x80) self.Write_MFRC522(self.CommandReg, self.PCD_IDLE); while(i<len(sendData)): self.Write_MFRC522(self.FIFODataReg, sendData[i]) i = i+1 self.Write_MFRC522(self.CommandReg, command) if command == self.PCD_TRANSCEIVE: self.SetBitMask(self.BitFramingReg, 0x80) i = 2000 while True: n = self.Read_MFRC522(self.CommIrqReg) i = i - 1 if ~((i!=0) and ~(n&0x01) and ~(n&waitIRq)): break self.ClearBitMask(self.BitFramingReg, 0x80) if i != 0: st = self.Read_MFRC522(self.ErrorReg) if (st & 0x1B)==0x00: status = self.MI_OK if n & irqEn & 0x01: status = self.MI_NOTAGERR elif command == self.PCD_TRANSCEIVE: n = self.Read_MFRC522(self.FIFOLevelReg) lastBits = self.Read_MFRC522(self.ControlReg) & 0x07 if lastBits != 0: backLen = (n-1)*8 + lastBits else: backLen = n*8 if n == 0: n = 1 if n > self.MAX_LEN: n = self.MAX_LEN i = 0 while i<n: backData.append(self.Read_MFRC522(self.FIFODataReg)) i = i + 1; else: status = self.MI_ERR return (status,backData,backLen) def MFRC522_Request(self, reqMode): status = None backBits = None TagType = [reqMode] self.Write_MFRC522(self.BitFramingReg, 0x07) (status,backData,backBits) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, TagType) if ((status != self.MI_OK) | (backBits != 0x10)): status = self.MI_ERR return (status,backBits) def MFRC522_Anticoll(self): backData = [] serNumCheck = 0 serNum = [self.PICC_ANTICOLL, 0x20] self.Write_MFRC522(self.BitFramingReg, 0x00) (status,backData,backBits) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE,serNum) if(status == self.MI_OK): i = 0 if len(backData)==5: while i<4: serNumCheck = serNumCheck ^ backData[i] i = i + 1 if serNumCheck != backData[i]: status = self.MI_ERR else: status = self.MI_ERR return (status,backData) def CalulateCRC(self, pIndata): self.ClearBitMask(self.DivIrqReg, 0x04) self.SetBitMask(self.FIFOLevelReg, 0x80); i = 0 while i<len(pIndata): self.Write_MFRC522(self.FIFODataReg, pIndata[i]) i = i + 1 self.Write_MFRC522(self.CommandReg, self.PCD_CALCCRC) i = 0xFF while True: n = self.Read_MFRC522(self.DivIrqReg) i = i - 1 if not ((i != 0) and not (n&0x04)): break pOutData = [] pOutData.append(self.Read_MFRC522(self.CRCResultRegL)) pOutData.append(self.Read_MFRC522(self.CRCResultRegM)) return pOutData def MFRC522_SelectTag(self, serNum): backData = [] buf = [self.PICC_SElECTTAG, 0x70] + serNum[:5] buf += self.CalulateCRC(buf) (status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, buf) if (status == self.MI_OK) and (backLen == 0x18): return self.MI_OK else: return self.MI_ERR def MFRC522_Auth(self, authMode, BlockAddr, Sectorkey, serNum): #First byte should be the authMode (A or B) #Second byte is the trailerBlock (usually 7) #Now we need to append the authKey which usually is 6 bytes of 0xFF #Next we append the first 4 bytes of the UID buff = [authMode, BlockAddr] + Sectorkey + serNum[:4] # Now we start the authentication itself (status, backData, backLen) = self.MFRC522_ToCard(self.PCD_AUTHENT,buff) # Check if an error occurred # Return the status return status def MFRC522_StopCrypto1(self): self.ClearBitMask(self.Status2Reg, 0x08) def MFRC522_Read(self, blockAddr): recvData = [self.PICC_READ, blockAddr] recvData += self.CalulateCRC(recvData) (status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, recvData) return (status, backData) def MFRC522_Write(self, blockAddr, writeData): buff = [self.PICC_WRITE, blockAddr] buff += self.CalulateCRC(buff) (status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, buff) if not(status == self.MI_OK) or not(backLen == 4) or not((backData[0] & 0x0F) == 0x0A): status = self.MI_ERR if status == self.MI_OK: i = 0 buf = [] while i < 16: buf.append(writeData[i]) i = i + 1 buf += self.CalulateCRC(buf) (status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE,buf) if not(status == self.MI_OK) or not(backLen == 4) or not((backData[0] & 0x0F) == 0x0A): status = self.MI_ERR return status def MFRC522_Init(self): self.MFRC522_Reset(); self.Write_MFRC522(self.TModeReg, 0x8D) self.Write_MFRC522(self.TPrescalerReg, 0x3E) self.Write_MFRC522(self.TReloadRegL, 30) self.Write_MFRC522(self.TReloadRegH, 0) self.Write_MFRC522(self.TxAutoReg, 0x40) self.Write_MFRC522(self.ModeReg, 0x3D) self.AntennaOn()
from machine import SPI,SoftSPI,Pin # configure the SPI master @ 2MHz # this uses the SPI non-default pins for CLK, MOSI and MISO (``P19``, ``P20`` and ``P21``) spi = SPI(2, baudrate=80000000, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, sck=Pin(18), mosi=Pin(23), miso=Pin(19)) spi.write(bytes([0x01, 0x02, 0x03, 0x04, 0x05])) # send 5 bytes on the bus spi.read(5) # receive 5 bytes on the bus rbuf = bytearray(5) spi.write_readinto(bytes([0x01, 0x02, 0x03, 0x04, 0x05]), rbuf) # send a receive 5 bytes int_val = int.from_bytes(spi.read(5), "big") print(int_val) print(spi.read(5))
class RFM69(RFM69_CONST_VARS): def __init__(self, cspin, ISRPin, nodeID, networkID, freqBand=868, isRFM69HW=False): RFM69_CONST_VARS.__init__(self) self._isRFM69HW = isRFM69HW tREG_FRFMSB = self.RF_FRFMSB_868 tREG_FRFMID = self.RF_FRFMID_868 tREG_FRFLSB = self.RF_FRFLSB_868 if freqBand==433: tREG_FRFMSB = self.RF_FRFMSB_433 tREG_FRFMID = self.RF_FRFMID_433 tREG_FRFLSB = self.RF_FRFLSB_433 if freqBand==315: tREG_FRFMSB = self.RF_FRFMSB_315 tREG_FRFMID = self.RF_FRFMID_315 tREG_FRFLSB = self.RF_FRFLSB_315 if freqBand==915: tREG_FRFMSB = self.RF_FRFMSB_915 tREG_FRFMID = self.RF_FRFMID_915 tREG_FRFLSB = self.RF_FRFLSB_915 self.CONFIG = [[self.REG_OPMODE, self.RF_OPMODE_SEQUENCER_ON | self.RF_OPMODE_LISTEN_OFF | self.RF_OPMODE_STANDBY], [self.REG_DATAMODUL, self.RF_DATAMODUL_DATAMODE_PACKET | self.RF_DATAMODUL_MODULATIONTYPE_FSK | self.RF_DATAMODUL_MODULATIONSHAPING_00], [self.REG_BITRATEMSB, self.RF_BITRATEMSB_55555], [self.REG_BITRATELSB, self.RF_BITRATELSB_55555], [self.REG_FDEVMSB, self.RF_FDEVMSB_50000], [self.REG_FDEVLSB, self.RF_FDEVLSB_50000], [self.REG_FRFMSB, tREG_FRFMSB ], [self.REG_FRFMID, tREG_FRFMID], [self.REG_FRFLSB, tREG_FRFLSB], [self.REG_RXBW, self.RF_RXBW_DCCFREQ_010 | self.RF_RXBW_MANT_16 | self.RF_RXBW_EXP_2 ], [self.REG_DIOMAPPING1, self.RF_DIOMAPPING1_DIO0_01], [self.REG_DIOMAPPING2, self.RF_DIOMAPPING2_CLKOUT_OFF], [self.REG_IRQFLAGS2, self.RF_IRQFLAGS2_FIFOOVERRUN], [self.REG_RSSITHRESH, 220], [self.REG_SYNCCONFIG, self.RF_SYNC_ON | self.RF_SYNC_FIFOFILL_AUTO | self.RF_SYNC_SIZE_2 | self.RF_SYNC_TOL_0], [self.REG_SYNCVALUE1, 0x2D], [self.REG_SYNCVALUE2, networkID ], [self.REG_PACKETCONFIG1, self.RF_PACKET1_FORMAT_VARIABLE | self.RF_PACKET1_DCFREE_OFF | self.RF_PACKET1_CRC_ON | self.RF_PACKET1_CRCAUTOCLEAR_ON | self.RF_PACKET1_ADRSFILTERING_OFF], [self.REG_FIFOTHRESH, self.RF_FIFOTHRESH_TXSTART_FIFONOTEMPTY | self.RF_FIFOTHRESH_VALUE], [self.REG_PACKETCONFIG2, self.RF_PACKET2_RXRESTARTDELAY_2BITS | self.RF_PACKET2_AUTORXRESTART_ON | self.RF_PACKET2_AES_OFF], [self.REG_TESTDAGC, self.RF_DAGC_IMPROVED_LOWBETA0]] self.cspin = Pin(cspin, mode=Pin.OUT) self.cspin.value(1) self.isrpin = Pin(ISRPin, mode=Pin.IN) self.isrpin.callback(trigger=Pin.IRQ_RISING, handler=self.isr0) self.spi = SPI(0, mode=SPI.MASTER, baudrate=1000000, polarity=0, phase=0, firstbit=SPI.MSB) start = millis() timeout = 50 while millis()-start < timeout: self.writeReg(self.REG_SYNCVALUE1, 0xAA) if self.readReg(self.REG_SYNCVALUE1) == 0xaa: break start = utime.ticks_ms() while utime.ticks_ms()-start < timeout: self.writeReg(self.REG_SYNCVALUE1, 0x55) if self.readReg(self.REG_SYNCVALUE1) == 0x55: break for item in self.CONFIG: self.writeReg(item[0], item[1]) self.encrypt(0) def getFrequency(self): return self.RF69_FSTEP * (self.readReg(self.REG_FRFMSB) << 16) + self.readReg(self.REG_FRFMID) + self.readReg(self.REG_FRFLSB) def setFrequency(self, freqHz): oldMode = self._mode if oldMode == self.RF69_MODE_TX: self.setMode(self.RF69_MODE_RX) freqHz /= self.RF69_FSTEP self.writeReg(self.REG_FRFMSB, freqHz >> 16) self.writeReg(self.REG_FRFMID, freqHz >> 8) self.writeReg(self.REG_FRFLSB, freqHz) if oldMode == self.RF69_MODE_RX: self.setMode(self.RF69_MODE_SYNTH) self.setMode(oldMode) def setMode(self, new_mode): if self._mode == new_mode: return if new_mode == self.RF69_MODE_TX: self.writeReg(self.REG_OPMODE, (self.readReg(self.REG_OPMODE) & 0xE3) | self.RF_OPMODE_TRANSMITTER) if self._isRFM69HW: self.setHighPowerRegs(True) if new_mode == self.RF69_MODE_RX: self.writeReg(self.REG_OPMODE, (self.readReg(self.REG_OPMODE) & 0xE3) | self.RF_OPMODE_RECEIVER) if self._isRFM69HW: self.setHighPowerRegs(False) if new_mode == self.RF69_MODE_SYNTH: self.writeReg(self.REG_OPMODE, (self.readReg(self.REG_OPMODE) & 0xE3) | self.RF_OPMODE_SYNTHESIZER) if new_mode == self.RF69_MODE_STANDBY: self.writeReg(self.REG_OPMODE, (self.readReg(self.REG_OPMODE) & 0xE3) | self.RF_OPMODE_STANDBY) if new_mode == self.RF69_MODE_SLEEP: self.writeReg(self.REG_OPMODE, (self.readReg(self.REG_OPMODE) & 0xE3) | self.RF_OPMODE_SLEEP) while self._mode == self.RF69_MODE_SLEEP and (self.readReg(self.REG_IRQFLAGS1) & self.RF_IRQFLAGS1_MODEREADY) == 0x00: pass self._mode = new_mode def sleep(self): self.setMode(self.RF69_MODE_SLEEP) def setAddress(self, addr): self._address = addr; self.writeReg(self.REG_NODEADRS, self._address) def setNetwork(self, networkID): self.writeReg(self.REG_SYNCVALUE2, networkID) def setPowerLevel(self, powerLevel): self._powerLevel = powerLevel if self._powerLevel > 31: self._powerLevel = 31 self.writeReg(self.REG_PALEVEL, (self.readReg(self.REG_PALEVEL) & 0xE0) | self._powerLevel); def canSend(self): if self._mode == self.RF69_MODE_RX and self.PAYLOADLEN == 0 and self.readRSSI() < self.CSMA_LIMIT: self.setMode(self.RF69_MODE_STANDBY) return True return False def send(self, toAddress, buffer, bufferSize, requestACK): self.writeReg(self.REG_PACKETCONFIG2, (self.readReg(self.REG_PACKETCONFIG2) & 0xFB) | self.RF_PACKET2_RXRESTART) now = millis() while self.canSend()==False and millis() - now < self.RF69_CSMA_LIMIT_MS: self.receiveDone() self.sendFrame(toAddress, buffer, bufferSize, requestACK, False) def sendWithRetry(self, toAddress, buffer, bufferSize, retries, retryWaitTime): for i in range(retries+1): self.send(toAddress, buffer, bufferSize, False) sentTime = millis() while millis() - sentTime < retryWaitTime: if self.ACKReceived(toAddress): return True return False def ACKReceived(self, fromNodeID): if self.receiveDone(): return (self.SENDERID == fromNodeID or fromNodeID == self.RF69_BROADCAST_ADDR) and self.ACK_RECEIVED return False def ACKRequested(self): return self.ACK_REQUESTED and (self.TARGETID != self.RF69_BROADCAST_ADDR) def sendACK(self, buffer, bufferSize): self.ACK_REQUESTED = 0 sender = self.SENDERID _RSSI = self.RSSI self.writeReg(self.REG_PACKETCONFIG2, (self.readReg(self.REG_PACKETCONFIG2) & 0xFB) | self.RF_PACKET2_RXRESTART) now = millis() while not self.canSend() and millis() - now < self.RF69_CSMA_LIMIT_MS: self.receiveDone() self.SENDERID = sender self.sendFrame(sender, buffer, bufferSize, False, True) self.RSSI = _RSSI def sendFrame(self, toAddress, buffer, bufferSize, requestACK, sendACK): self.setMode(self.RF69_MODE_STANDBY) while self.readReg(self.REG_IRQFLAGS1) & self.RF_IRQFLAGS1_MODEREADY == 0x00: pass self.writeReg(self.REG_DIOMAPPING1, self.RF_DIOMAPPING1_DIO0_00) if bufferSize > self.RF69_MAX_DATA_LEN: bufferSize = self.RF69_MAX_DATA_LEN CTLbyte = 0x00; if sendACK: CTLbyte = self.RFM69_CTL_SENDACK else: if requestACK: CTLbyte = self.RFM69_CTL_REQACK self.select(); self.spi.write(self.REG_FIFO | 0x80) self.spi.write(bufferSize + 3) self.spi.write(toAddress) self.spi.write(self._address) self.spi.write(CTLbyte) for i in range(bufferSize): self.spi.write(buffer[i]) self.unselect() self.setMode(self.RF69_MODE_TX) txStart = millis(); while (self.isrpin.value() == 0 and millis() - txStart < self.RF69_TX_LIMIT_MS): pass self.setMode(self.RF69_MODE_STANDBY); def interruptHandler(self, id): if self._mode == self.RF69_MODE_RX and (self.readReg(self.REG_IRQFLAGS2) & self.RF_IRQFLAGS2_PAYLOADREADY): self.setMode(self.RF69_MODE_STANDBY) self.select() self.spi.write(self.REG_FIFO & 0x7F) self.PAYLOADLEN = self.spi.read(1) self.PAYLOADLEN = self.PAYLOADLEN if self.PAYLOADLEN > 66: self.PAYLOADLEN = 66 self.TARGETID = self.spi.read(1) if not (self._promiscuousMode or self.TARGETID == self._address or self.TARGETID == self.RF69_BROADCAST_ADDR) or self.PAYLOADLEN < 3: self.PAYLOADLEN = 0 self.unselect() self.receiveBegin() return self.DATALEN = self.PAYLOADLEN - 3 self.SENDERID = self.spi.read(1) CTLbyte = self.spi.read(1) self.ACK_RECEIVED = CTLbyte & self.RFM69_CTL_SENDACK self.ACK_REQUESTED = CTLbyte & self.RFM69_CTL_REQACK self.interruptHook(CTLbyte) for i in range(self.DATALEN): self.DATA[i] = self.spi.read(1) if self.DATALEN < self.RF69_MAX_DATA_LEN: self.DATA[self.DATALEN] = 0 self.unselect() self.setMode(self.RF69_MODE_RX) self.RSSI = self.readRSSI() def isr0(self, id): self._inISR=True self.interruptHandler(id) self._inISR=False def receiveBegin(self): self.DATALEN = 0 self.SENDERID = 0 self.TARGETID = 0 self.PAYLOADLEN = 0 self.ACK_REQUESTED = 0 self.ACK_RECEIVED = 0 self.RSSI = 0 if self.readReg(self.REG_IRQFLAGS2) & self.RF_IRQFLAGS2_PAYLOADREADY: self.writeReg(self.REG_PACKETCONFIG2, (self.readReg(self.REG_PACKETCONFIG2) & 0xFB) |self.RF_PACKET2_RXRESTART) self.writeReg(self.REG_DIOMAPPING1, self.RF_DIOMAPPING1_DIO0_01) self.setMode(self.RF69_MODE_RX) def receiveDone(self): noInterrupts() if self._mode == self.RF69_MODE_RX and self.PAYLOADLEN > 0: self.setMode(self.RF69_MODE_STANDBY) return True else: if self._mode==self.RF69_MODE_RX: interrupts() return False self.receiveBegin() return False def encrypt(self, key): self.setMode(self.RF69_MODE_STANDBY) if key != 0: self.select() self.spi.write(self.REG_AESKEY1 | 0x80) for i in range(16): self.spi.write(key[i]) self.unselect() val = 1 if key==None: val = 0 self.writeReg(self.REG_PACKETCONFIG2, (self.readReg(self.REG_PACKETCONFIG2) & 0xFE) | val) def readRSSI(self, forceTrigger): rssi = 0 if forceTrigger: self.writeReg(self.REG_RSSICONFIG, self.RF_RSSI_START) while (self.readReg(self.REG_RSSICONFIG) & self.RF_RSSI_DONE) == 0x00: pass rssi = -self.readReg(self.REG_RSSIVALUE) rssi = rssi >> 1 return rssi def readReg(self, addr): self.select() self.spi.write(addr & 0x7F) regValue = self.spi.read(1) self.unselect() return regValue def writeReg(self, addr, value): self.select() self.spi.write(addr | 0x80) self.spi.write(value) self.unselect() def select(self): self.cspin.value(0) def unselect(self): self.cspin.value(1) def promiscuous(self, onOff): self._promiscuousMode = onOff def setHighPower(self, onOff): self._isRFM69HW = onOff if self._isRFM69HW: self.writeReg(self.REG_OCP, self.RF_OCP_OFF) self.writeReg(self.REG_PALEVEL, (self.readReg(self.REG_PALEVEL) & 0x1F) | self.RF_PALEVEL_PA1_ON | self.RF_PALEVEL_PA2_ON) else: self.writeReg(self.REG_OCP, self.RF_OCP_ON) self.writeReg(self.REG_PALEVEL, self.RF_PALEVEL_PA0_ON | self.RF_PALEVEL_PA1_OFF | self.RF_PALEVEL_PA2_OFF | self._powerLevel) def setHighPowerRegs(self, onOff): if onOff: self.writeReg(self.REG_TESTPA1, 0x5D) self.writeReg(self.REG_TESTPA2, 0x7C) else: self.writeReg(self.REG_TESTPA1, 0x55) self.writeReg(self.REG_TESTPA2, 0x70) def setCS(self, newSPISlaveSelect): self._slaveSelectPin = newSPISlaveSelect self.cspin = Pin(self._slaveSelectPin, mode=Pin.OUT) self.cspin.value(1) def readAllRegs(self): regVal = 0 print("Address - HEX - BIN") for regAddr in range(1, 0x4F): self.select() self.spi.write(regAddr & 0x7F) regVal = self.spi.read(1) self.unselect() print(regAddr, " - ", regVal) def readTemperature(self, calFactor): self.setMode(self.RF69_MODE_STANDBY); self.writeReg(self.REG_TEMP1, self.RF_TEMP1_MEAS_START) while self.readReg(self.REG_TEMP1) & self.RF_TEMP1_MEAS_RUNNING: pass return ~self.readReg(self.REG_TEMP2) + self.COURSE_TEMP_COEF + calFactor def rcCalibration(self): self.writeReg(self.REG_OSC1, self.RF_OSC1_RCCAL_START) while (self.readReg(self.REG_OSC1) & self.RF_OSC1_RCCAL_DONE) == 0x00: pass def maybeInterrupts(self): if not self._inISR: interrupts() def initialize(self): pass
class spiram: def __init__(self): self.led = Pin(5, Pin.OUT) self.led.off() self.rom="48.rom" #self.rom="opense.rom" #self.rom="/sd/zxspectrum/48.rom" self.spi_channel = const(2) self.init_pinout_sd() self.spi_freq = const(4000000) self.hwspi=SPI(self.spi_channel, baudrate=self.spi_freq, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, sck=Pin(self.gpio_sck), mosi=Pin(self.gpio_mosi), miso=Pin(self.gpio_miso)) @micropython.viper def init_pinout_sd(self): self.gpio_sck = const(16) self.gpio_mosi = const(4) self.gpio_miso = const(12) # read from file -> write to SPI RAM def load_stream(self, filedata, addr=0, maxlen=0x10000, blocksize=1024): block = bytearray(blocksize) # Request load self.led.on() self.hwspi.write(bytearray([0,(addr >> 24) & 0xFF, (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, addr & 0xFF])) bytes_loaded = 0 while bytes_loaded < maxlen: if filedata.readinto(block): self.hwspi.write(block) bytes_loaded += blocksize else: break self.led.off() # read from SPI RAM -> write to file def save_stream(self, filedata, addr=0, length=1024, blocksize=1024): bytes_saved = 0 block = bytearray(blocksize) # Request save self.led.on() self.hwspi.write(bytearray([1,(addr >> 24) & 0xFF, (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, addr & 0xFF, 0])) while bytes_saved < length: self.hwspi.readinto(block) filedata.write(block) bytes_saved += len(block) self.led.off() def ctrl(self,i): self.led.on() self.hwspi.write(bytearray([0, 0xFF, 0xFF, 0xFF, 0xFF, i])) self.led.off() def cpu_halt(self): self.ctrl(2) def cpu_continue(self): self.ctrl(0) def load_z80_compressed_stream(self, filedata, length=0xFFFF): b=bytearray(1) escbyte=bytearray([0xED]) s=0 repeat=0 bytes_loaded=0 while bytes_loaded < length: if filedata.readinto(b): nexts=s if s==0: if b[0]==escbyte[0]: nexts=1 else: self.hwspi.write(b) if s==1: if b[0]==escbyte[0]: nexts=2 else: self.hwspi.write(escbyte) self.hwspi.write(b) nexts=0 if s==2: repeat=b[0] if repeat==0: print("end") break nexts=3 if s==3: self.hwspi.read(repeat,b[0]) nexts=0 s=nexts bytes_loaded += 1 else: break print("bytes loaded %d" % bytes_loaded) def load_z80_v1_compressed_block(self, filedata): self.led.on() self.hwspi.write(bytearray([0,0,0,0x40,0])) # from 0x4000 self.load_z80_compressed_stream(filedata) self.led.off() def load_z80_v23_block(self, filedata): header = bytearray(3) if filedata.readinto(header): length,page = unpack("<HB",header) print("load z80 block: length=%d, page=%d" % (length,page)) else: return False addr = -1 if page==4: addr=0x8000 if page==5: addr=0xC000 if page==8: addr=0x4000 if addr < 0: print("unsupported page ignored") filedata.seek(length,1) return True if length==0xFFFF: compress=0 length=0x4000 else: compress=1 #print("addr=%04X compress=%d" % (addr,compress)) if compress: # Request load self.led.on() self.hwspi.write(bytearray([0,(addr >> 24) & 0xFF, (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, addr & 0xFF])) self.load_z80_compressed_stream(filedata,length) self.led.off() else: print("uncompressed v2/v3 may need FIXME") self.load_stream(filedata,addr,16384) return True def patch_rom(self,pc,header): # overwrite tape saving code in original ROM # with restore code and data from header code_addr = 0x4C2 header_addr = 0x500 self.led.on() self.hwspi.write(bytearray([0, 0,0,0,0, 0xF3, 0xAF, 0x11, 0xFF, 0xFF, 0xC3, code_addr&0xFF, (code_addr>>8)&0xFF])) # overwrite start of ROM to JP 0x04C2 self.led.off() self.led.on() self.hwspi.write(bytearray([0, 0,0,(code_addr>>8)&0xFF,code_addr&0xFF])) # overwrite 0x04C2 # Z80 code that POPs REGs from header as stack data at 0x500 # z80asm restore.z80asm; hexdump -v -e '/1 "0x%02X,"' a.bin # restores border color, registers I, AFBCDEHL' and AFBCDEHL self.hwspi.write(bytearray([0x31,(header_addr+9)&0xFF,((header_addr+9)>>8)&0xFF,0xF1,0xED,0x47,0xF1,0x1F,0xD3,0xFE,0xD1,0xD9,0xC1,0xD1,0xE1,0xD9,0xF1,0x08,0xFD,0xE1,0xDD,0xE1,0x21,0xE5,0xFF,0x39,0xF9,0xF1,0xC1,0xE1])); self.hwspi.write(bytearray([0x31])) # LD SP, ... self.hwspi.write(header[8:10]) self.hwspi.write(bytearray([0xED])) # IM ... imarg = bytearray([0x46,0x56,0x5E,0x5E]) self.hwspi.write(bytearray([imarg[header[29]&3]])) # IM mode if header[27]: self.hwspi.write(bytearray([0xFB])) # EI header[6]=pc&0xFF header[7]=(pc>>8)&0xFF self.hwspi.write(bytearray([0xC3])) # JP ... self.hwspi.write(header[6:8]) # PC address of final JP self.led.off() self.led.on() self.hwspi.write(bytearray([0, 0,0,(header_addr>>8)&0xFF,header_addr&0xFF])) # overwrite 0x0500 with header # header fix: exchange A and F, A' and F' to become POPable x=header[0] header[0]=header[1] header[1]=x x=header[21] header[21]=header[22] header[22]=x if header[12]==255: header[12]=1 #header[12] ^= 7<<1 # FIXME border color self.hwspi.write(header) # AF and AF' now POPable self.led.off() def loadz80(self,filename): z=open(filename,"rb") header1 = bytearray(30) z.readinto(header1) pc=unpack("<H",header1[6:8])[0] self.cpu_halt() self.load_stream(open(self.rom, "rb"), addr=0) if pc: # V1 format print("Z80 v1") self.patch_rom(pc,header1) if header1[12] & 32: self.load_z80_v1_compressed_block(z) else: self.load_stream(z,0x4000) else: # V2 or V3 format word = bytearray(2) z.readinto(word) length2 = unpack("<H", word)[0] if length2 == 23: print("Z80 v2") else: if length2 == 54 or length2 == 55: print("Z80 v3") else: print("unsupported header2 length %d" % length2) return header2 = bytearray(length2) z.readinto(header2) pc=unpack("<H",header2[0:2])[0] self.patch_rom(pc,header1) while self.load_z80_v23_block(z): pass self.ctrl(3) # reset and halt self.ctrl(1) # only reset self.cpu_continue() # restore original ROM after image starts self.cpu_halt() self.load_stream(open(self.rom, "rb"), addr=0) self.cpu_continue() # release reset
# _________________________________________________________ # Software SPI bus # There are two SPI drivers. One is implemented in software (bit-banging) and works on all pins: from machine import Pin, SPI # construct an SPI bus on the given pins # polarity is the idle state of SCK # phase=0 means sample on the first edge of SCK, phase=1 means the second spi = SPI(-1, baudrate=100000, polarity=1, phase=0, sck=Pin(0), mosi=Pin(2), miso=Pin(4)) spi.init(baudrate=200000) # set the baudrate spi.read(10) # read 10 bytes on MISO spi.read(10, 0xff) # read 10 bytes while outputing 0xff on MOSI buf = bytearray(50) # create a buffer spi.readinto(buf) # read into the given buffer (reads 50 bytes in this case) spi.readinto(buf, 0xff) # read into the given buffer and output 0xff on MOSI spi.write(b'12345') # write 5 bytes on MOSI buf = bytearray(4) # create a buffer spi.write_readinto(b'1234', buf) # write to MOSI and read from MISO into the buffer spi.write_readinto(buf, buf) # write buf to MOSI and read MISO back into buf # _________________________________________________________
class EPD(object): MAX_READ = 45 SW_NORMAL_PROCESSING = 0x9000 EP_FRAMEBUFFER_SLOT_OVERRUN = 0x6a84 # too much data fed in EP_SW_INVALID_LE = 0x6c00 # Wrong expected length EP_SW_INSTRUCTION_NOT_SUPPORTED = 0x6d00 # bad instr EP_SW_WRONG_PARAMETERS_P1P2 = 0x6a00 EP_SW_WRONG_LENGTH = 0x6700 DEFAULT_SLOT=0 # always the *oldest*, should wear-level then I think def __init__(self, debug=False, baud=100000): # From datasheet # Bit rate – up to 12 MHz1 # ▪ Polarity – CPOL = 1; clock transition high-to-low on the leading edge and low-to-high on the # trailing edge # ▪ Phase – CPHA = 1; setup on the leading edge and sample on the trailing edge # ▪ Bit order – MSB first # ▪ Chip select polarity – active low self.spi = SPI(0) try: self.spi.init(mode=SPI.MASTER, baudrate=baud, bits=8, polarity=1, phase=1, firstbit=SPI.MSB, pins=('GP31', 'GP16', 'GP30')) # CLK, MOSI, MISO except AttributeError: self.spi.init(baudrate=baud, bits=8, polarity=1, phase=1, firstbit=SPI.MSB, pins=('GP31', 'GP16', 'GP30')) # CLK, MOSI, MISO # These are all active low! self.tc_en_bar = Pin('GP4', mode=Pin.OUT) self.disable() self.tc_busy_bar = Pin('GP5', mode=Pin.IN) self.tc_busy_bar.irq(trigger=Pin.IRQ_RISING) # Wake up when it changes self.tc_cs_bar = Pin('GP17', mode=Pin.ALT, alt=7) self.debug = debug def enable(self): self.tc_en_bar.value(0) # Power up time.sleep_ms(5) while self.tc_busy_bar() == 0: machine.idle() # will it wake up here? # /tc_busy goes high during startup, low during init, then high when not busy def disable(self): self.tc_en_bar.value(1) # Off def send_command(self, ins, p1, p2, data=None, expected=None): # These command variables are always sent cmd = struct.pack('3B', ins, p1, p2) # Looks like data is only sent with the length (Lc) if data: assert len(data) <= 251 # Thus speaks the datasheet cmd += struct.pack('B', len(data)) cmd += data # Expected data is either not present at all, 0 for null-terminated, or a number for fixed if expected is not None: cmd += struct.pack('B', expected) if self.debug: print("Sending: " + hexlify(cmd).decode()) self.spi.write(cmd) # Wait for a little while time.sleep_us(15) # This should take at most 14.5us while self.tc_busy_bar() == 0: machine.idle() # Request a response if expected is not None: if expected > 0: result_bytes = self.spi.read(2 + expected) else: result_bytes = self.spi.read(EPD.MAX_READ) strlen = result_bytes.find(b'\x00') result_bytes = result_bytes[:strlen] + result_bytes[strlen+1:strlen+3] else: result_bytes = self.spi.read(2) if self.debug: print("Received: " + hexlify(result_bytes).decode()) (result,) = struct.unpack_from('>H', result_bytes[-2:]) if result != EPD.SW_NORMAL_PROCESSING: raise ValueError("Bad result code: 0x%x" % result) return result_bytes[:-2] @staticmethod def calculate_checksum(data, skip=16): """ Initial checksum value is 0x6363 :param data: :param skip: Skip some data as slices are expensive :return: """ acc = 0x6363 for byte in data: if skip > 0: skip -= 1 else: acc ^= byte acc = ((acc >> 8) | (acc << 8)) & 0xffff acc ^= ((acc & 0xff00) << 4) & 0xffff acc ^= (acc >> 8) >> 4 acc ^= (acc & 0xff00) >> 5 return acc def get_sensor_data(self): # GetSensorData val = self.send_command(0xe5, 1, 0, expected=2) (temp,) = struct.unpack(">H", val) return temp def get_device_id(self): return self.send_command(0x30, 2, 1, expected=0x14) def get_system_info(self): return self.send_command(0x31, 1, 1, expected=0) def get_system_version_code(self): return self.send_command(0x31, 2, 1, expected=0x10) def display_update(self, slot=0, flash=True): cmd = 0x86 if flash: cmd = 0x24 self.send_command(cmd, 1, slot) def reset_data_pointer(self): self.send_command(0x20, 0xd, 0) def image_erase_frame_buffer(self, slot=0): self.send_command(0x20, 0xe, slot) def get_checksum(self, slot): cksum_val = self.send_command(0x2e, 1, slot, expected=2) (cksum,) = struct.unpack(">H", cksum_val) return cksum def upload_image_data(self, data, slot=0, delay_us=1000): self.send_command(0x20, 1, slot, data) time.sleep_us(delay_us) def upload_whole_image(self, img, slot=0): """ Chop up chunks and send it :param img: Image to send in EPD format :param slot: Slot framebuffer number to use :param delay_us: Delay between packets? 450us and the Tbusy line never comes back :return: """ total = len(img) idx = 0 try: while idx < total - 250: chunk = img[idx:idx+250] self.upload_image_data(chunk, slot) del chunk idx += 250 self.upload_image_data(img[idx:], slot) except KeyboardInterrupt: print("Stopped at user request at position: %d (%d)" % (idx, (idx // 250))) except ValueError as e: print("Stopped at position: %d (%d) - %s" % (idx, (idx // 250), e))
class RFM69(object): def __init__(self, freqBand, nodeID, networkID, isRFM69HW=False, intPin='P9', rstPin='P22', spiBus=0, spiDevice=0, wakeup=False): if wakeup == False: self.freqBand = freqBand self.address = nodeID self.networkID = networkID self.isRFM69HW = isRFM69HW self.intPin = intPin self.rstPin = rstPin self.spiBus = spiBus self.spiDevice = spiDevice self.intLock = False self.mode = "" self.promiscuousMode = False self.DATASENT = False self.DATALEN = 0 self.SENDERID = 0 self.TARGETID = 0 self.PAYLOADLEN = 0 self.ACK_REQUESTED = 0 self.ACK_RECEIVED = 0 self.RSSI = 0 self.DATA = [] self.sendSleepTime = 0.05 pinInt = Pin(self.intPin, mode=Pin.IN) pinRst = Pin(self.rstPin, mode=Pin.OUT) frfMSB = { RF69_315MHZ: RF_FRFMSB_315, RF69_433MHZ: RF_FRFMSB_433, RF69_868MHZ: RF_FRFMSB_868, RF69_915MHZ: RF_FRFMSB_915 } frfMID = { RF69_315MHZ: RF_FRFMID_315, RF69_433MHZ: RF_FRFMID_433, RF69_868MHZ: RF_FRFMID_868, RF69_915MHZ: RF_FRFMID_915 } frfLSB = { RF69_315MHZ: RF_FRFLSB_315, RF69_433MHZ: RF_FRFLSB_433, RF69_868MHZ: RF_FRFLSB_868, RF69_915MHZ: RF_FRFLSB_915 } self.CONFIG = { 0x01: [ REG_OPMODE, RF_OPMODE_SEQUENCER_ON | RF_OPMODE_LISTEN_OFF | RF_OPMODE_STANDBY ], #no shaping 0x02: [ REG_DATAMODUL, RF_DATAMODUL_DATAMODE_PACKET | RF_DATAMODUL_MODULATIONTYPE_FSK | RF_DATAMODUL_MODULATIONSHAPING_00 ], #default:4.8 KBPS 0x03: [REG_BITRATEMSB, RF_BITRATEMSB_55555], 0x04: [REG_BITRATELSB, RF_BITRATELSB_55555], #default:5khz, (FDEV + BitRate/2 <= 500Khz) 0x05: [REG_FDEVMSB, RF_FDEVMSB_50000], 0x06: [REG_FDEVLSB, RF_FDEVLSB_50000], 0x07: [REG_FRFMSB, frfMSB[freqBand]], 0x08: [REG_FRFMID, frfMID[freqBand]], 0x09: [REG_FRFLSB, frfLSB[freqBand]], # looks like PA1 and PA2 are not implemented on RFM69W, hence the max output power is 13dBm # +17dBm and +20dBm are possible on RFM69HW # +13dBm formula: Pout=-18+OutputPower (with PA0 or PA1**) # +17dBm formula: Pout=-14+OutputPower (with PA1 and PA2)** # +20dBm formula: Pout=-11+OutputPower (with PA1 and PA2)** and high power PA settings (section 3.3.7 in datasheet) #0x11: [REG_PALEVEL, RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | RF_PALEVEL_OUTPUTPOWER_11111], #over current protection (default is 95mA) #0x13: [REG_OCP, RF_OCP_ON | RF_OCP_TRIM_95], # RXBW defaults are { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_5} (RxBw: 10.4khz) #//(BitRate < 2 * RxBw) 0x19: [ REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_16 | RF_RXBW_EXP_2 ], #for BR-19200: //* 0x19 */ { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_3 }, #DIO0 is the only IRQ we're using 0x25: [REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_01], #must be set to dBm = (-Sensitivity / 2) - default is 0xE4=228 so -114dBm 0x29: [REG_RSSITHRESH, 220], #/* 0x2d */ { REG_PREAMBLELSB, RF_PREAMBLESIZE_LSB_VALUE } // default 3 preamble bytes 0xAAAAAA 0x2e: [ REG_SYNCCONFIG, RF_SYNC_ON | RF_SYNC_FIFOFILL_AUTO | RF_SYNC_SIZE_2 | RF_SYNC_TOL_0 ], #attempt to make this compatible with sync1 byte of RFM12B lib 0x2f: [REG_SYNCVALUE1, 0x2D], #NETWORK ID 0x30: [REG_SYNCVALUE2, networkID], 0x37: [ REG_PACKETCONFIG1, RF_PACKET1_FORMAT_VARIABLE | RF_PACKET1_DCFREE_OFF | RF_PACKET1_CRC_ON | RF_PACKET1_CRCAUTOCLEAR_ON | RF_PACKET1_ADRSFILTERING_OFF ], #in variable length mode: the max frame size, not used in TX 0x38: [REG_PAYLOADLENGTH, 66], #* 0x39 */ { REG_NODEADRS, nodeID }, //turned off because we're not using address filtering #TX on FIFO not empty 0x3C: [ REG_FIFOTHRESH, RF_FIFOTHRESH_TXSTART_FIFONOTEMPTY | RF_FIFOTHRESH_VALUE ], #RXRESTARTDELAY must match transmitter PA ramp-down time (bitrate dependent) 0x3d: [ REG_PACKETCONFIG2, RF_PACKET2_RXRESTARTDELAY_2BITS | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF ], #for BR-19200: //* 0x3d */ { REG_PACKETCONFIG2, RF_PACKET2_RXRESTARTDELAY_NONE | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF }, //RXRESTARTDELAY must match transmitter PA ramp-down time (bitrate dependent) #* 0x6F */ { REG_TESTDAGC, RF_DAGC_CONTINUOUS }, // run DAGC continuously in RX mode # run DAGC continuously in RX mode, recommended default for AfcLowBetaOn=0 0x6F: [REG_TESTDAGC, RF_DAGC_IMPROVED_LOWBETA0], 0x00: [255, 0] } #initialize SPI # this uses the SPI default pins for CLK, MOSI and MISO (``P10``, ``P11`` and ``P14``) self.spi = SPI(0, mode=SPI.MASTER, baudrate=400000, polarity=0, phase=0, firstbit=SPI.MSB) self.p_out = Pin('P21', mode=Pin.OUT) # Hard reset the RFM module pinRst.value(1) time.sleep(0.1) pinRst.value(0) self.p_out.value(1) #verify chip is syncing? while self.readReg(REG_SYNCVALUE1) != 0xAA: self.writeReg(REG_SYNCVALUE1, 0xAA) while self.readReg(REG_SYNCVALUE1) != 0x55: self.writeReg(REG_SYNCVALUE1, 0x55) #write config for value in self.CONFIG.values(): self.writeReg(value[0], value[1]) self.encrypt(0) self.setHighPower(self.isRFM69HW) # Wait for ModeReady while (self.readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00: pass #interrupt if a message arrives pinInt.callback(Pin.IRQ_RISING, self.interruptHandler) else: self.freqBand = freqBand self.address = nodeID self.networkID = networkID self.isRFM69HW = isRFM69HW self.intPin = intPin self.rstPin = rstPin self.spiBus = spiBus self.spiDevice = spiDevice self.intLock = False self.mode = RF69_MODE_RX self.promiscuousMode = False self.DATASENT = False self.DATALEN = 0 self.SENDERID = 0 self.TARGETID = 0 self.PAYLOADLEN = 0 self.ACK_REQUESTED = 0 self.ACK_RECEIVED = 0 self.RSSI = 0 self.DATA = [] self.sendSleepTime = 0.05 pinInt = Pin(self.intPin, mode=Pin.IN) pinRst = Pin(self.rstPin, mode=Pin.OUT) frfMSB = { RF69_315MHZ: RF_FRFMSB_315, RF69_433MHZ: RF_FRFMSB_433, RF69_868MHZ: RF_FRFMSB_868, RF69_915MHZ: RF_FRFMSB_915 } frfMID = { RF69_315MHZ: RF_FRFMID_315, RF69_433MHZ: RF_FRFMID_433, RF69_868MHZ: RF_FRFMID_868, RF69_915MHZ: RF_FRFMID_915 } frfLSB = { RF69_315MHZ: RF_FRFLSB_315, RF69_433MHZ: RF_FRFLSB_433, RF69_868MHZ: RF_FRFLSB_868, RF69_915MHZ: RF_FRFLSB_915 } #initialize SPI # this uses the SPI default pins for CLK, MOSI and MISO (``P10``, ``P11`` and ``P14``) self.spi = SPI(0, mode=SPI.MASTER, baudrate=400000, polarity=0, phase=0, firstbit=SPI.MSB) self.p_out = Pin('P21', mode=Pin.OUT) #interrupt if a message arrives pinInt.callback(Pin.IRQ_RISING, self.interruptHandler) def setFreqeuncy(self, FRF): self.writeReg(REG_FRFMSB, FRF >> 16) self.writeReg(REG_FRFMID, FRF >> 8) self.writeReg(REG_FRFLSB, FRF) def setMode(self, newMode): if newMode == self.mode: return if newMode == RF69_MODE_TX: self.writeReg(REG_OPMODE, (self.readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_TRANSMITTER) if self.isRFM69HW: self.setHighPowerRegs(True) elif newMode == RF69_MODE_RX: self.writeReg(REG_OPMODE, (self.readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_RECEIVER) if self.isRFM69HW: self.setHighPowerRegs(False) elif newMode == RF69_MODE_SYNTH: self.writeReg(REG_OPMODE, (self.readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_SYNTHESIZER) elif newMode == RF69_MODE_STANDBY: self.writeReg(REG_OPMODE, (self.readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_STANDBY) elif newMode == RF69_MODE_SLEEP: self.writeReg(REG_OPMODE, (self.readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_SLEEP) else: return # we are using packet mode, so this check is not really needed # but waiting for mode ready is necessary when going from sleep because the FIFO may not be immediately available from previous mode while self.mode == RF69_MODE_SLEEP and self.readReg( REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY == 0x00: pass self.mode = newMode def sleep(self): self.setMode(RF69_MODE_SLEEP) def setAddress(self, addr): self.address = addr self.writeReg(REG_NODEADRS, self.address) def setNetwork(self, networkID): self.networkID = networkID self.writeReg(REG_SYNCVALUE2, networkID) def setPowerLevel(self, powerLevel): if powerLevel > 31: powerLevel = 31 self.powerLevel = powerLevel self.writeReg(REG_PALEVEL, (self.readReg(REG_PALEVEL) & 0xE0) | self.powerLevel) def canSend(self): if self.mode == RF69_MODE_STANDBY: self.receiveBegin() return True #if signal stronger than -100dBm is detected assume channel activity elif self.mode == RF69_MODE_RX and self.PAYLOADLEN == 0 and self.readRSSI( ) < CSMA_LIMIT: self.setMode(RF69_MODE_STANDBY) return True return False def send(self, toAddress, buff="", requestACK=False): self.writeReg(REG_PACKETCONFIG2, (self.readReg(REG_PACKETCONFIG2) & 0xFB) | RF_PACKET2_RXRESTART) now = time.time() while (not self.canSend()) and time.time() - now < RF69_CSMA_LIMIT_S: self.receiveDone() self.sendFrame(toAddress, buff, requestACK, False) # to increase the chance of getting a packet across, call this function instead of send # and it handles all the ACK requesting/retrying for you :) # The only twist is that you have to manually listen to ACK requests on the other side and send back the ACKs # The reason for the semi-automaton is that the lib is ingterrupt driven and # requires user action to read the received data and decide what to do with it # replies usually take only 5-8ms at 50kbps@915Mhz def sendWithRetry(self, toAddress, buff="", retries=3, retryWaitTime=10): for i in range(0, retries): self.send(toAddress, buff, True) sentTime = time.time() while (time.time() - sentTime) < retryWaitTime: if self.ACKReceived(toAddress): return True return False def ACKReceived(self, fromNodeID): if self.receiveDone(): return (self.SENDERID == fromNodeID or fromNodeID == RF69_BROADCAST_ADDR) and self.ACK_RECEIVED return False def ACKRequested(self): return self.ACK_REQUESTED and self.TARGETID != RF69_BROADCAST_ADDR def sendACK(self, toAddress=0, buff=""): toAddress = toAddress if toAddress > 0 else self.SENDERID while not self.canSend(): self.receiveDone() self.sendFrame(toAddress, buff, False, True) def sendFrame(self, toAddress, buff, requestACK, sendACK): #turn off receiver to prevent reception while filling fifo self.setMode(RF69_MODE_STANDBY) #wait for modeReady while (self.readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00: pass # DIO0 is "Packet Sent" self.writeReg(REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_00) if (len(buff) > RF69_MAX_DATA_LEN): buff = buff[0:RF69_MAX_DATA_LEN] ack = 0 if sendACK: ack = 0x80 elif requestACK: ack = 0x40 if isinstance(buff, str): #original basestr self.spiWriteMultipleBytes( [REG_FIFO | 0x80, len(buff) + 3, toAddress, self.address, ack] + [int(ord(i)) for i in list(buff)]) else: self.spiWriteMultipleBytes( [REG_FIFO | 0x80, len(buff) + 3, toAddress, self.address, ack] + buff) self.DATASENT = False self.setMode(RF69_MODE_TX) slept = 0 while not self.DATASENT: time.sleep(self.sendSleepTime) slept += self.sendSleepTime if slept > 1.0: break self.setMode(RF69_MODE_RX) def interruptHandler(self, pin): self.intLock = True self.DATASENT = True if self.mode == RF69_MODE_RX and self.readReg( REG_IRQFLAGS2) & RF_IRQFLAGS2_PAYLOADREADY: self.setMode(RF69_MODE_STANDBY) self.PAYLOADLEN, self.TARGETID, self.SENDERID, CTLbyte = self.readFifo( [REG_FIFO & 0x7f, 0, 0, 0, 0])[1:] if self.PAYLOADLEN > 66: self.PAYLOADLEN = 66 if not (self.promiscuousMode or self.TARGETID == self.address or self.TARGETID == RF69_BROADCAST_ADDR): self.PAYLOADLEN = 0 self.intLock = False return self.DATALEN = self.PAYLOADLEN - 3 self.ACK_RECEIVED = CTLbyte & 0x80 self.ACK_REQUESTED = CTLbyte & 0x40 self.DATA = self.readFifo([REG_FIFO & 0x7f] + [0 for i in range(0, self.DATALEN)])[1:] self.RSSI = self.readRSSI() self.intLock = False def receiveBegin(self): while self.intLock: time.sleep(.1) self.DATALEN = 0 self.SENDERID = 0 self.TARGETID = 0 self.PAYLOADLEN = 0 self.ACK_REQUESTED = 0 self.ACK_RECEIVED = 0 self.RSSI = 0 if (self.readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PAYLOADREADY): # avoid RX deadlocks self.writeReg(REG_PACKETCONFIG2, (self.readReg(REG_PACKETCONFIG2) & 0xFB) | RF_PACKET2_RXRESTART) #set DIO0 to "PAYLOADREADY" in receive mode self.writeReg(REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_01) self.setMode(RF69_MODE_RX) def receiveDone(self): if (self.mode == RF69_MODE_RX or self.mode == RF69_MODE_STANDBY) and self.PAYLOADLEN > 0: self.setMode(RF69_MODE_STANDBY) return True if self.readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_TIMEOUT: # https://github.com/russss/rfm69-python/blob/master/rfm69/rfm69.py#L112 # Russss figured out that if you leave alone long enough it times out # tell it to stop being silly and listen for more packets self.writeReg(REG_PACKETCONFIG2, (self.readReg(REG_PACKETCONFIG2) & 0xFB) | RF_PACKET2_RXRESTART) elif self.mode == RF69_MODE_RX: # already in RX no payload yet return False self.receiveBegin() return False def readRSSI(self, forceTrigger=False): rssi = 0 if forceTrigger: self.writeReg(REG_RSSICONFIG, RF_RSSI_START) while self.readReg(REG_RSSICONFIG) & RF_RSSI_DONE == 0x00: pass rssi = self.readReg(REG_RSSIVALUE) * -1 rssi = rssi >> 1 return rssi def encrypt(self, key): self.setMode(RF69_MODE_STANDBY) if key != 0 and len(key) == 16: self.writeReg(REG_AESKEY1, int(ord(key[0]))) self.writeReg(REG_AESKEY2, int(ord(key[1]))) self.writeReg(REG_AESKEY3, int(ord(key[2]))) self.writeReg(REG_AESKEY4, int(ord(key[3]))) self.writeReg(REG_AESKEY5, int(ord(key[4]))) self.writeReg(REG_AESKEY6, int(ord(key[5]))) self.writeReg(REG_AESKEY7, int(ord(key[6]))) self.writeReg(REG_AESKEY8, int(ord(key[7]))) self.writeReg(REG_AESKEY9, int(ord(key[8]))) self.writeReg(REG_AESKEY10, int(ord(key[9]))) self.writeReg(REG_AESKEY11, int(ord(key[10]))) self.writeReg(REG_AESKEY12, int(ord(key[11]))) self.writeReg(REG_AESKEY13, int(ord(key[12]))) self.writeReg(REG_AESKEY14, int(ord(key[13]))) self.writeReg(REG_AESKEY15, int(ord(key[14]))) self.writeReg(REG_AESKEY16, int(ord(key[15]))) self.writeReg(REG_PACKETCONFIG2, (self.readReg(REG_PACKETCONFIG2) & 0xFE) | RF_PACKET2_AES_ON) else: self.writeReg(REG_PACKETCONFIG2, (self.readReg(REG_PACKETCONFIG2) & 0xFE) | RF_PACKET2_AES_OFF) def readReg(self, addr): addrbytes = bytes([addr & 0x7F]) self.p_out.value(0) self.spi.write(addrbytes) temp = self.spi.read(1) self.p_out.value(1) return ord(temp) def writeReg(self, addr, value): addrbytes = bytes([addr | 0x80, value]) self.p_out.value(0) self.spi.write(addrbytes) self.p_out.value(1) def spiWriteMultipleBytes(self, values): valuebytes = bytes(values) self.p_out.value(0) self.spi.write(valuebytes) self.p_out.value(1) def readFifo(self, values): addr = values[0] addrbytes = bytes(addr) self.p_out.value(0) self.spi.write(addrbytes) recstring = self.spi.read(len(values)) self.p_out.value(1) returnval = [] for i in recstring: returnval.append(i) return returnval def promiscuous(self, onOff): self.promiscuousMode = onOff def setHighPower(self, onOff): if onOff: self.writeReg(REG_OCP, RF_OCP_OFF) #enable P1 & P2 amplifier stages self.writeReg(REG_PALEVEL, (self.readReg(REG_PALEVEL) & 0x1F) | RF_PALEVEL_PA1_ON | RF_PALEVEL_PA2_ON) else: self.writeReg(REG_OCP, RF_OCP_ON) #enable P0 only self.writeReg( REG_PALEVEL, RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | powerLevel) def setHighPowerRegs(self, onOff): if onOff: self.writeReg(REG_TESTPA1, 0x5D) self.writeReg(REG_TESTPA2, 0x7C) else: self.writeReg(REG_TESTPA1, 0x55) self.writeReg(REG_TESTPA2, 0x70) def readAllRegs(self): results = [] for address in range(1, 0x50): results.append( [str(hex(address)), str(bin(self.readReg(address)))]) return results def readTemperature(self, calFactor): self.setMode(RF69_MODE_STANDBY) self.writeReg(REG_TEMP1, RF_TEMP1_MEAS_START) while self.readReg(REG_TEMP1) & RF_TEMP1_MEAS_RUNNING: pass # COURSE_TEMP_COEF puts reading in the ballpark, user can add additional correction #'complement'corrects the slope, rising temp = rising val return (int(~self.readReg(REG_TEMP2)) * -1) + COURSE_TEMP_COEF + calFactor def rcCalibration(self): self.writeReg(REG_OSC1, RF_OSC1_RCCAL_START) while self.readReg(REG_OSC1) & RF_OSC1_RCCAL_DONE == 0x00: pass def shutdown(self): self.setHighPower(False) self.sleep() def receiveMessage(self): self.intLock = True self.DATASENT = True if self.mode == RF69_MODE_RX and self.readReg( REG_IRQFLAGS2) & RF_IRQFLAGS2_PAYLOADREADY: self.setMode(RF69_MODE_STANDBY) self.PAYLOADLEN, self.TARGETID, self.SENDERID, CTLbyte = self.readFifo( [REG_FIFO & 0x7f, 0, 0, 0, 0])[1:] if self.PAYLOADLEN > 66: self.PAYLOADLEN = 66 if not (self.promiscuousMode or self.TARGETID == self.address or self.TARGETID == RF69_BROADCAST_ADDR): self.PAYLOADLEN = 0 self.intLock = False return self.DATALEN = self.PAYLOADLEN - 3 self.ACK_RECEIVED = CTLbyte & 0x80 self.ACK_REQUESTED = CTLbyte & 0x40 self.DATA = self.readFifo([REG_FIFO & 0x7f] + [0 for i in range(0, self.DATALEN)])[1:] self.RSSI = self.readRSSI() self.intLock = False
class MFRC522: OK = 0 NOTAGERR = 1 ERR = 2 REQIDL = 0x26 REQALL = 0x52 AUTHENT1A = 0x60 AUTHENT1B = 0x61 def __init__(self, sck, mosi, miso, rst, cs): self.sck = Pin(sck, Pin.OUT) self.mosi = Pin(mosi, Pin.OUT) self.miso = Pin(miso) self.rst = Pin(rst, Pin.OUT) self.cs = Pin(cs, Pin.OUT) self.rst.value(0) self.cs.value(1) if uname()[0] == 'WiPy': self.spi = SPI(0) self.spi.init(SPI.MASTER, baudrate=1000000, pins=(self.sck, self.mosi, self.miso)) elif uname()[0] == 'esp8266': self.spi = SPI(baudrate=100000, polarity=0, phase=0, sck=self.sck, mosi=self.mosi, miso=self.miso) self.spi.init() else: raise RuntimeError("Unsupported platform") self.rst.value(1) self.init() def _wreg(self, reg, val): self.cs.value(0) self.spi.write(b'%c' % int(0xff & ((reg << 1) & 0x7e))) self.spi.write(b'%c' % int(0xff & val)) self.cs.value(1) def _rreg(self, reg): self.cs.value(0) self.spi.write(b'%c' % int(0xff & (((reg << 1) & 0x7e) | 0x80))) val = self.spi.read(1) self.cs.value(1) return val[0] def _sflags(self, reg, mask): self._wreg(reg, self._rreg(reg) | mask) def _cflags(self, reg, mask): self._wreg(reg, self._rreg(reg) & (~mask)) def _tocard(self, cmd, send): recv = [] bits = irq_en = wait_irq = n = 0 stat = self.ERR if cmd == 0x0E: irq_en = 0x12 wait_irq = 0x10 elif cmd == 0x0C: irq_en = 0x77 wait_irq = 0x30 self._wreg(0x02, irq_en | 0x80) self._cflags(0x04, 0x80) self._sflags(0x0A, 0x80) self._wreg(0x01, 0x00) for c in send: self._wreg(0x09, c) self._wreg(0x01, cmd) if cmd == 0x0C: self._sflags(0x0D, 0x80) i = 2000 while True: n = self._rreg(0x04) i -= 1 if ~((i != 0) and ~(n & 0x01) and ~(n & wait_irq)): break self._cflags(0x0D, 0x80) if i: if (self._rreg(0x06) & 0x1B) == 0x00: stat = self.OK if n & irq_en & 0x01: stat = self.NOTAGERR elif cmd == 0x0C: n = self._rreg(0x0A) lbits = self._rreg(0x0C) & 0x07 if lbits != 0: bits = (n - 1) * 8 + lbits else: bits = n * 8 if n == 0: n = 1 elif n > 16: n = 16 for _ in range(n): recv.append(self._rreg(0x09)) else: stat = self.ERR return stat, recv, bits def _crc(self, data): self._cflags(0x05, 0x04) self._sflags(0x0A, 0x80) for c in data: self._wreg(0x09, c) self._wreg(0x01, 0x03) i = 0xFF while True: n = self._rreg(0x05) i -= 1 if not ((i != 0) and not (n & 0x04)): break return [self._rreg(0x22), self._rreg(0x21)] def init(self): self.reset() self._wreg(0x2A, 0x8D) self._wreg(0x2B, 0x3E) self._wreg(0x2D, 30) self._wreg(0x2C, 0) self._wreg(0x15, 0x40) self._wreg(0x11, 0x3D) self.antenna_on() def reset(self): self._wreg(0x01, 0x0F) def antenna_on(self, on=True): if on and ~(self._rreg(0x14) & 0x03): self._sflags(0x14, 0x03) else: self._cflags(0x14, 0x03) def request(self, mode): self._wreg(0x0D, 0x07) (stat, recv, bits) = self._tocard(0x0C, [mode]) if (stat != self.OK) | (bits != 0x10): stat = self.ERR return stat, bits def anticoll(self): ser_chk = 0 ser = [0x93, 0x20] self._wreg(0x0D, 0x00) (stat, recv, bits) = self._tocard(0x0C, ser) if stat == self.OK: if len(recv) == 5: for i in range(4): ser_chk = ser_chk ^ recv[i] if ser_chk != recv[4]: stat = self.ERR else: stat = self.ERR return stat, recv def select_tag(self, ser): buf = [0x93, 0x70] + ser[:5] buf += self._crc(buf) (stat, recv, bits) = self._tocard(0x0C, buf) return self.OK if (stat == self.OK) and (bits == 0x18) else self.ERR def auth(self, mode, addr, sect, ser): return self._tocard(0x0E, [mode, addr] + sect + ser[:4])[0] def stop_crypto1(self): self._cflags(0x08, 0x08) def read(self, addr): data = [0x30, addr] data += self._crc(data) (stat, recv, _) = self._tocard(0x0C, data) return recv if stat == self.OK else None def write(self, addr, data): buf = [0xA0, addr] buf += self._crc(buf) (stat, recv, bits) = self._tocard(0x0C, buf) if not (stat == self.OK) or not (bits == 4) or not ((recv[0] & 0x0F) == 0x0A): stat = self.ERR else: buf = [] for i in range(16): buf.append(data[i]) buf += self._crc(buf) (stat, recv, bits) = self._tocard(0x0C, buf) if not (stat == self.OK) or not (bits == 4) or not ((recv[0] & 0x0F) == 0x0A): stat = self.ERR return stat
class ADXL362: def _init__(self, cspin): self.cspin = Pin(cspin, mode=Pin.OUT) self.cspin.value(1) self.x = 0 self.y = 0 self.z = 0 self.t = 0 self.spi = SPI(0, mode=SPI.MASTER, baudrate=1000000, polarity=0, phase=0, firstbit=SPI.MSB) time.sleep_ms(1000) self.SPIwriteOneRegister(0x1F, 0x52) #RESET time.sleep_ms(10) self.DEVICEID = self.SPIreadOneRegister(0x00) self.DEVID_MST = self.SPIreadOneRegister(0x01) self.PART_ID = self.SPIreadOneRegister(0x02) self.REV_ID = self.SPIreadOneRegister(0x03) self.STATUS = self.getStatus() def getStatus(self): return self.SPIreadOneRegister(0x0B) def beginMeasure(self): temp = self.SPIreadOneRegister(0x2D) tempwrite = temp | 0x02 self.SPIwriteOneRegister(0x2D, tempwrite) time.sleep_ms(10) def readXData(self): XDATA = self.SPIreadTwoRegisters(0x0E) return XDATA def readYData(self): YDATA = self.SPIreadTwoRegisters(0x10) return YDATA def readZData(self): ZDATA = self.SPIreadTwoRegisters(0x12) return ZDATA def readTemp(self): TEMP = self.SPIreadTwoRegisters(0x14) return TEMP def readXYZTData(self): ret = {} self.select() self.spi.write(0x0B) self.spi.write(0x0E) ret['x'] = self.spi.read(1) ret['x'] += self.spi.read(1) << 8 ret['y'] = self.spi.read(1) ret['y'] += self.spi.read(1) << 8 ret['z'] = self.spi.read(1) ret['z'] += self.spi.read(1) << 8 ret['t'] = self.spi.read(1) ret['t'] += self.spi.read(1) << 8 self.deselect() self.x = ret['x'] self.y = ret['y'] self.z = ret['z'] self.t = ret['t'] return ret def setupACActivityInterrupt(self, threshold, time): self.SPIwriteTwoRegisters(0x20, threshold) self.SPIwriteOneRegister(0x22, time) ACT_INACT_CTL_Reg = self.SPIreadOneRegister(0x27) ACT_INACT_CTL_Reg = ACT_INACT_CTL_Reg | (0x03) self.SPIwriteOneRegister(0x27, ACT_INACT_CTL_Reg) ACT_INACT_CTL_Reg = self.SPIreadOneRegister(0x27) def setupACInactivityInterrupt(self, threshold, time): self.SPIwriteTwoRegisters(0x23, threshold) self.SPIwriteTwoRegisters(0x25, time) ACT_INACT_CTL_Reg = self.SPIreadOneRegister(0x27) ACT_INACT_CTL_Reg = ACT_INACT_CTL_Reg | (0x0C) self.SPIwriteOneRegister(0x27, ACT_INACT_CTL_Reg) ACT_INACT_CTL_Reg = self.SPIreadOneRegister(0x27) def setupDCActivityInterrupt(self, threshold, time): self.SPIwriteTwoRegisters(0x20, threshold) self.SPIwriteOneRegister(0x22, time) ACT_INACT_CTL_Reg = self.SPIreadOneRegister(0x27) ACT_INACT_CTL_Reg = ACT_INACT_CTL_Reg | (0x01) self.SPIwriteOneRegister(0x27, ACT_INACT_CTL_Reg) ACT_INACT_CTL_Reg = self.SPIreadOneRegister(0x27) def setupDCInactivityInterrupt(self, threshold, time): self.SPIwriteTwoRegisters(0x23, threshold) self.SPIwriteTwoRegisters(0x25, time) ACT_INACT_CTL_Reg = self.SPIreadOneRegister(0x27) ACT_INACT_CTL_Reg = ACT_INACT_CTL_Reg | (0x04) self.SPIwriteOneRegister(0x27, ACT_INACT_CTL_Reg) ACT_INACT_CTL_Reg = self.SPIreadOneRegister(0x27) def SPIreadOneRegister(self, regAddress): self.select() self.spi.write(0x0B) self.spi.write(regAddress) regValue = self.spi.read(1) self.deselect() return regValue def SPIwriteOneRegister(self, regAddress, regValue): self.select() self.spi.write(0x0A) self.spi.write(regAddress) self.spi.write(regValue) self.deselect() def SPIwriteTwoRegisters(self, regAddress, twoRegValue): twoRegValueH = twoRegValue >> 8 twoRegValueL = twoRegValue self.select() self.spi.write(0x0A) self.spi.write(regAddress) self.spi.write(twoRegValueL) self.spi.write(twoRegValueH) self.deselect() def SPIreadTwoRegisters(self, regAddress): self.select() self.spi.write(0x0B) self.spi.write(regAddress) twoRegValue = self.read(1) twoRegValue += self.read(1) << 8 self.deselect() return twoRegValue def select(self): self.cspin.value(0) def deselect(self): self.cspin.value(1)
class ATM90e32: ############################################################################## def __init__(self, linefreq, pgagain, ugain, igainA, igainB, igainC): self._linefreq = linefreq self._pgagain = pgagain self._ugain = ugain self._igainA = igainA self._igainB = igainB self._igainC = igainC # Chip select pin self.cs = Pin(15, Pin.OUT) self.cs.on() # Doc on esp8266 SPI hw init: http://bit.ly/2ZhqeRB self.spi = SPI(1, baudrate=200000, polarity=1, phase=1) self._init_config() def _init_config(self): # CurrentGainCT2 = 25498 #25498 - SCT-013-000 100A/50mA if (self._linefreq == 4485 or self._linefreq == 5231): # North America power frequency FreqHiThresh = 61 * 100 FreqLoThresh = 59 * 100 sagV = 90 else: FreqHiThresh = 51 * 100 FreqLoThresh = 49 * 100 sagV = 190 # calculation for voltage sag threshold - assumes we do not want to go under 90v for split phase and 190v otherwise # sqrt(2) = 1.41421356 fvSagTh = (sagV * 100 * 1.41421356) / (2 * self._ugain / 32768) # convert to int for sending to the atm90e32. vSagTh = self._round_number(fvSagTh) self._spi_rw(SPI_WRITE, SoftReset, 0x789A) # Perform soft reset # enable register config access self._spi_rw(SPI_WRITE, CfgRegAccEn, 0x55AA) self._spi_rw(SPI_WRITE, MeterEn, 0x0001) # Enable Metering self._spi_rw(SPI_WRITE, SagTh, vSagTh) # Voltage sag threshold # High frequency threshold - 61.00Hz self._spi_rw(SPI_WRITE, FreqHiTh, FreqHiThresh) # Lo frequency threshold - 59.00Hz self._spi_rw(SPI_WRITE, FreqLoTh, FreqLoThresh) self._spi_rw(SPI_WRITE, EMMIntEn0, 0xB76F) # Enable interrupts self._spi_rw(SPI_WRITE, EMMIntEn1, 0xDDFD) # Enable interrupts self._spi_rw(SPI_WRITE, EMMIntState0, 0x0001) # Clear interrupt flags self._spi_rw(SPI_WRITE, EMMIntState1, 0x0001) # Clear interrupt flags # ZX2, ZX1, ZX0 pin config self._spi_rw(SPI_WRITE, ZXConfig, 0x0A55) # Set metering config values (CONFIG) # PL Constant MSB (default) - Meter Constant = 3200 - PL Constant = 140625000 self._spi_rw(SPI_WRITE, PLconstH, 0x0861) # PL Constant LSB (default) - this is 4C68 in the application note, which is incorrect self._spi_rw(SPI_WRITE, PLconstL, 0xC468) # Mode Config (frequency set in main program) self._spi_rw(SPI_WRITE, MMode0, self._linefreq) # PGA Gain Configuration for Current Channels - 0x002A (x4) # 0x0015 (x2) # 0x0000 (1x) self._spi_rw(SPI_WRITE, MMode1, self._pgagain) # Active Startup Power Threshold - 50% of startup current = 0.9/0.00032 = 2812.5 self._spi_rw(SPI_WRITE, PStartTh, 0x0AFC) # Reactive Startup Power Threshold self._spi_rw(SPI_WRITE, QStartTh, 0x0AEC) # Apparent Startup Power Threshold self._spi_rw(SPI_WRITE, SStartTh, 0x0000) # Active Phase Threshold = 10% of startup current = 0.06/0.00032 = 187.5 self._spi_rw(SPI_WRITE, PPhaseTh, 0x00BC) self._spi_rw(SPI_WRITE, QPhaseTh, 0x0000) # Reactive Phase Threshold # Apparent Phase Threshold self._spi_rw(SPI_WRITE, SPhaseTh, 0x0000) # Set metering calibration values (CALIBRATION) self._spi_rw(SPI_WRITE, PQGainA, 0x0000) # Line calibration gain self._spi_rw(SPI_WRITE, PhiA, 0x0000) # Line calibration angle self._spi_rw(SPI_WRITE, PQGainB, 0x0000) # Line calibration gain self._spi_rw(SPI_WRITE, PhiB, 0x0000) # Line calibration angle self._spi_rw(SPI_WRITE, PQGainC, 0x0000) # Line calibration gain self._spi_rw(SPI_WRITE, PhiC, 0x0000) # Line calibration angle # A line active power offset self._spi_rw(SPI_WRITE, PoffsetA, 0x0000) # A line reactive power offset self._spi_rw(SPI_WRITE, QoffsetA, 0x0000) # B line active power offset self._spi_rw(SPI_WRITE, PoffsetB, 0x0000) # B line reactive power offset self._spi_rw(SPI_WRITE, QoffsetB, 0x0000) # C line active power offset self._spi_rw(SPI_WRITE, PoffsetC, 0x0000) # C line reactive power offset self._spi_rw(SPI_WRITE, QoffsetC, 0x0000) # Set metering calibration values (HARMONIC) # A Fund. active power offset self._spi_rw(SPI_WRITE, POffsetAF, 0x0000) # B Fund. active power offset self._spi_rw(SPI_WRITE, POffsetBF, 0x0000) # C Fund. active power offset self._spi_rw(SPI_WRITE, POffsetCF, 0x0000) # A Fund. active power gain self._spi_rw(SPI_WRITE, PGainAF, 0x0000) # B Fund. active power gain self._spi_rw(SPI_WRITE, PGainBF, 0x0000) # C Fund. active power gain self._spi_rw(SPI_WRITE, PGainCF, 0x0000) # Set measurement calibration values (ADJUST) self._spi_rw(SPI_WRITE, UgainA, self._ugain) # A Voltage rms gain # A line current gain self._spi_rw(SPI_WRITE, IgainA, self._igainA) self._spi_rw(SPI_WRITE, UoffsetA, 0x0000) # A Voltage offset self._spi_rw(SPI_WRITE, IoffsetA, 0x0000) # A line current offset self._spi_rw(SPI_WRITE, UgainB, self._ugain) # B Voltage rms gain # B line current gain self._spi_rw(SPI_WRITE, IgainB, self._igainB) self._spi_rw(SPI_WRITE, UoffsetB, 0x0000) # B Voltage offset self._spi_rw(SPI_WRITE, IoffsetB, 0x0000) # B line current offset self._spi_rw(SPI_WRITE, UgainC, self._ugain) # C Voltage rms gain # C line current gain self._spi_rw(SPI_WRITE, IgainC, self._igainC) self._spi_rw(SPI_WRITE, UoffsetC, 0x0000) # C Voltage offset self._spi_rw(SPI_WRITE, IoffsetC, 0x0000) # C line current offset self._spi_rw(SPI_WRITE, CfgRegAccEn, 0x0000) # end configuration ##################################################################################### @property def lastSpiData(self): reading = self._spi_rw(SPI_READ, LastSPIData, 0xFFFF) return reading ##################################################################################### @property def sys_status0(self): reading = self._spi_rw(SPI_READ, EMMIntState0, 0xFFFF) return reading ##################################################################################### @property def sys_status1(self): reading = self._spi_rw(SPI_READ, EMMIntState1, 0xFFFF) return reading ##################################################################################### @property def meter_status0(self): reading = self._spi_rw(SPI_READ, EMMState0, 0xFFFF) return reading ##################################################################################### @property def meter_status1(self): reading = self._spi_rw(SPI_READ, EMMState1, 0xFFFF) return reading ##################################################################################### @property def line_voltageA(self): reading = self._spi_rw(SPI_READ, UrmsA, 0xFFFF) return reading / 100.0 ##################################################################################### @property def line_voltageB(self): reading = self._spi_rw(SPI_READ, UrmsB, 0xFFFF) return reading / 100.0 ##################################################################################### @property def line_voltageC(self): reading = self._spi_rw(SPI_READ, UrmsC, 0xFFFF) return reading / 100.0 ##################################################################################### @property def line_currentA(self): reading = self._spi_rw(SPI_READ, IrmsA, 0xFFFF) return reading / 1000.0 ##################################################################################### @property def line_currentC(self): reading = self._spi_rw(SPI_READ, IrmsC, 0xFFFF) return reading / 1000.0 ##################################################################################### @property def frequency(self): reading = self._spi_rw(SPI_READ, Freq, 0xFFFF) return reading / 100.0 ##################################################################################### @property def active_power(self): reading = self._read32Register(PmeanT, PmeanTLSB) return reading * 0.00032 ##################################################################################### # do the SPI read or write request. ##################################################################################### def _spi_rw(self, rw, address, val): # Set read/write flag address |= rw << 15 # Enable SPI and wait for SPI to activate self.cs.off() time.sleep_us(10) # pack the address into a the bytearray. It is an unsigned short(H) that needs to be in MSB(>) two_byte_buf = struct.pack('>H', address) # send address self.spi.write(two_byte_buf) # wait for data to become valid (4uS) - see http://bit.ly/2Zh6VI9 time.sleep_us(4) if (rw): # read # Get the unsigned short register values sent from the atm90e32 results_buf = self.spi.read(2) result = struct.unpack('>H', results_buf)[0] else: # pack the address into a the bytearray. It is an unsigned short(H) that needs to be in MSB(>) two_byte_buf = struct.pack('>H', val) self.spi.write(two_byte_buf) result = 0 # Put cs back to HIGH - SPI bytes have been written/read. self.cs.on() return result ################################################################################### def _round_number(self, f_num): if f_num - math.floor(f_num) < 0.5: return math.floor(f_num) return math.ceil(f_num) ################################################################################### def _read32Register(self, regh_addr, regl_addr): val_h = self._spi_rw(SPI_READ, regh_addr, 0xFFFF) val_l = self._spi_rw(SPI_READ, regl_addr, 0xFFFF) val = val_h << 16 val |= val_l # concatenate the 2 registers to make 1 32 bit number # flip the bits...different than Arduino... val = val ^ 0xffffffff return (val)
from machine import SPI spi1 = SPI(SPI.SPI1, mode=SPI.MODE_MASTER, baudrate=10000000, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, sck=28, mosi=29, miso=30, cs0=27) w = b'1234' r = bytearray(4) spi1.write(w) spi1.write(w, cs=SPI.CS0) spi1.write_readinto(w, r) spi1.read(5, write=0x00) spi1.readinto(r, write=0x00)
class ch376: def __init__(self): self.led = Pin(5, Pin.OUT) self.led.off() self.spi_channel = const(1) self.hwspi=SPI(self.spi_channel, baudrate=6000000, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, sck=Pin(16), mosi=Pin(4), miso=Pin(12)) self.busy=Pin(0, Pin.IN) self.exist=0 self.reset_data01() def reset_data01(self): self.data01in=bytearray(16) # track DATA0/DATA1 tokens for each endpoint self.data01out=bytearray(16) # track DATA0/DATA1 tokens for each endpoint def wait(self): while self.busy.value(): pass def reset(self): self.reset_data01() self.led.on() self.hwspi.write(bytearray([0x05])) self.led.off() self.wait() def get_ic_ver(self) -> int: self.led.on() self.hwspi.write(bytearray([0x01])) response = self.hwspi.read(1)[0] self.led.off() return response & 0x3F def check_exist(self,value:int) -> int: self.led.on() self.hwspi.write(bytearray([0x06,value])) response = self.hwspi.read(1)[0] self.led.off() if response == value ^ 0xFF: return 1 else: return 0 def set_usb_mode(self,mode:int) -> int: self.led.on() self.hwspi.write(bytearray([0x15,mode])) sleep_us(10) response = self.hwspi.read(1)[0] self.led.off() return response # works only during set_usb_mode(5) # 0x44: no device # 0x10: low-speed # 0x20: full-speed def get_dev_rate(self) -> int: self.led.on() self.hwspi.write(bytearray([0x0A,0x07])) response = self.hwspi.read(1)[0] self.led.off() return response # 0:full-speed 12Mbps, 2:low-speed 1.5 Mbps def set_usb_speed(self,speed:int): self.led.on() self.hwspi.write(bytearray([0x04,speed])) self.led.off() def set_usb_low_speed(self): self.led.on() self.hwspi.write(bytearray([0x0B,0x17,0xD8])) self.led.off() def auto_setup(self): self.led.on() self.hwspi.write(bytearray([0x4D])) self.led.off() # sets remote address def set_address(self,addr:int) -> int: self.led.on() self.hwspi.write(bytearray([0x45,addr])) response = self.hwspi.read(1)[0] self.led.off() return response # sets our address def set_our_address(self,addr:int): self.led.on() self.hwspi.write(bytearray([0x13,addr])) self.led.off() def set_config(self,config:int): self.led.on() self.hwspi.write(bytearray([0x49,config])) self.led.off() def get_status(self) -> int: self.led.on() self.hwspi.write(bytearray([0x22])) status = self.hwspi.read(1)[0] self.led.off() return status def rd_usb_data0(self): self.led.on() self.hwspi.write(bytearray([0x27])) len = self.hwspi.read(1)[0] if len: data = self.hwspi.read(len) else: data = bytearray() self.led.off() return data def rd_usb_data(self): self.led.on() self.hwspi.write(bytearray([0x28])) len = self.hwspi.read(1)[0] if len: data = self.hwspi.read(len) else: data = bytearray() self.led.off() return data def wr_usb_data(self,buffer): self.led.on() self.hwspi.write(bytearray([0x2C,len(buffer)])) if len(buffer): self.hwspi.write(buffer) self.led.off() # token alternate 0x00/0x80 # x: high 4 bits: endpoint, low 4 bits: operation 9=read def issue_token_x(self,token:int,x:int): self.led.on() self.hwspi.write(bytearray([0x4E,token,x])) self.led.off() def clr_stall(self,ep:int): self.led.on() self.hwspi.write(bytearray([0x41,ep])) self.led.off() def test_connect(self) -> int: self.led.on() self.hwspi.write(bytearray([0x16])) response = self.hwspi.read(1)[0] self.led.off() return response # enumerates but has some problem with reading def start(self): self.reset() self.wait() while True: sleep_ms(100) self.exist+=1 if self.check_exist(self.exist): break print("CH376 v%d waits for hotplug of USB HID device" % self.get_ic_ver()) # my module is v3, albiero is v4 self.set_usb_mode(5) # host mode: CH376 turns module LED ON hotplug = 0x44 while hotplug == 0x44: self.wait() hotplug = self.get_dev_rate() self.set_usb_mode(7) # reset and host mode, mouse turns bottom LED ON sleep_ms(20) self.set_usb_mode(6) # release from reset self.wait() if hotplug == 0x10: # low-speed device self.set_usb_speed(2) # 2:low-speed 1.5 Mbps print("hot-plugged USB low-speed 1.5 Mbps device") if hotplug == 0x20: # full-speed device self.set_usb_speed(0) # 0:full-speed 12Mbps print("hot-plugged USB full-speed 12 Mbps device") self.wait() self.auto_setup() self.wait() self.set_config(1) # turns ON USB mouse LED self.wait() #self.set_config(0) # verify that this turns OFF USB mouse LED #sleep_ms(200) #self.set_config(1) # turns ON USB mouse LED #sleep_ms(200) #self.wait() #self.wr_usb_data(bytearray([0x21,0x0B,0,0,0,0,0,0])) # BOOTP compatible mouse, no wheel #self.issue_token_x(0,0x0D) #self.wait # HID request for device not to send reports if IDLE # only when user presses something the report will be send # some HID devices ignore this command and send idle reports anyway #self.wr_usb_data(bytearray([0x21,0x0A,0,0,0,0,0,0])) # SET IDLE 0 #self.issue_token_x(0,0x0D) # 0x0D -> 0:EP0 D:WRITE #self.wait def prhex(self,d): if d: if len(d) > 0: print(len(d), end=":") for i in range(len(d)): print(" %02X" % d[i], end="") print("") def ctrl(self,type,request,value,index): self.wr_usb_data(bytearray([type,request,value&0xFF,(value>>8)&0xFF,index&0xFF,(index>>8)&0xFF,0,0])) self.issue_token_x(0,0xD) # 0x0D -> 0:EP0 D:WRITE self.wait() self.wr_usb_data(bytearray()) self.issue_token_x(0x80,1) # 0:EP0 1:OUT status self.wait() # data phase host to device def ctrlout(self,type,request,value,index,data): self.wr_usb_data(bytearray([type,request,value&0xFF,(value>>8)&0xFF,index&0xFF,(index>>8)&0xFF,len(data)&0xFF,(len(data)>>8)&0xFF])) #print("data phase") #sleep_ms(5000) self.issue_token_x(0,0xD) # 0x0D -> 0:EP0 D:SETUP self.wait() token = 0x80 i = 0 while i < len(data): self.wr_usb_data(data[i:i+8]) #self.prhex(data[i:i+8]) self.issue_token_x(token,1) # 0x01 -> 0:EP0 1:OUT token ^= 0x80 i += 8 self.wait() self.issue_token_x(0x80,9) # 0:EP0 9:IN read status self.wait() return self.rd_usb_data0() # data phase device to host def ctrlin(self,type,request,value,index,rdlen): self.wr_usb_data(bytearray([type,request,value&0xFF,(value>>8)&0xFF,index&0xFF,(index>>8)&0xFF,rdlen&0xFF,(rdlen>>8)&0xFF])) self.issue_token_x(0,0xD) # 0x0D -> 0:EP0 D:WRITE self.wait() data = bytearray() token = 0x80 while rdlen > 0: self.issue_token_x(token,9) # 0x09 -> 0:EP0 9:IN token ^= 0x80 self.wait() d = self.rd_usb_data0() # 8 bytes max if len(d): data += d rdlen -= len(d) else: rdlen = 0 self.wr_usb_data(bytearray()) self.issue_token_x(0x80,1) # 0:EP0 1:OUT status self.wait() return data def epin(self,ep=1): self.issue_token_x(self.data01in[ep],(ep<<4)|9) # 0x19 -> 1:EP1 9:READ self.data01in[ep]^=0x80 self.wait() return self.rd_usb_data0() def epout(self,data,ep=2): self.wr_usb_data(data) self.issue_token_x(self.data01out[ep],(ep<<4)|1) # 0x11 -> 1:EP1 1:OUT self.data01out[ep]^=0x80 self.wait() def reading(self,ep=1): token = 0 while self.get_status() == 0x14: sleep_ms(10) self.prhex(self.epin(ep)) collect()
from machine import Pin, SPI import time import ubinascii vref = 3.3 cs = Pin(15, Pin.OUT) cs.high() hspi = SPI(1, baudrate=1600000, polarity=0, phase=0) value = bytearray(2) while True: data = bytearray(2) wget = b'\xA0\x00' cs.low() hspi.write(b'\x01') hspi.write(b'\xA0') data = hspi.read(1) # data = hspi.write_readinto(wget, data) cs.high() print(str(int(ubinascii.hexlify(data & b'\x0fff'))*vref/4096)) time.sleep(1) # data = data*vref/4096 # time.sleep(1) # print(str(data & b'\x0fff'))
class osd: def __init__(self): self.screen_x = const(64) self.screen_y = const(20) self.cwd = "/" self.init_fb() self.exp_names = " KMGTE" self.mark = bytearray([32,16,42]) # space, right triangle, asterisk self.diskfile=False self.data_buf=bytearray(554) self.mdv_byte=bytearray(1) self.mdv_phase=bytearray([1]) self.read_dir() self.spi_read_irq = bytearray([1,0xF1,0,0,0,0,0]) self.spi_read_btn = bytearray([1,0xFB,0,0,0,0,0]) self.spi_read_blktyp = bytearray([1,0xD0,0,0,0,0,0]) self.spi_result = bytearray(7) self.spi_enable_osd = bytearray([0,0xFE,0,0,0,1]) self.spi_write_osd = bytearray([0,0xFD,0,0,0]) self.spi_send_mdv_bram = bytearray([0,0xD1,0,0,0]) self.spi_channel = const(2) self.spi_freq = const(3000000) self.init_pinout_sd() self.init_spi() alloc_emergency_exception_buf(100) self.enable = bytearray(1) self.timer = Timer(3) self.irq_handler(0) self.irq_handler_ref = self.irq_handler # allocation happens here self.spi_request = Pin(0, Pin.IN, Pin.PULL_UP) self.spi_request.irq(trigger=Pin.IRQ_FALLING, handler=self.irq_handler_ref) def init_spi(self): self.spi=SPI(self.spi_channel, baudrate=self.spi_freq, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, sck=Pin(self.gpio_sck), mosi=Pin(self.gpio_mosi), miso=Pin(self.gpio_miso)) self.cs=Pin(self.gpio_cs,Pin.OUT) self.cs.off() self.led=Pin(self.gpio_led,Pin.OUT) self.led.off() # init file browser def init_fb(self): self.fb_topitem = 0 self.fb_cursor = 0 self.fb_selected = -1 @micropython.viper def init_pinout_sd(self): self.gpio_cs = const(17) self.gpio_sck = const(16) self.gpio_mosi = const(4) self.gpio_miso = const(12) self.gpio_led = const(5) @micropython.viper def irq_handler(self, pin): p8result = ptr8(addressof(self.spi_result)) self.cs.on() self.spi.write_readinto(self.spi_read_irq, self.spi_result) self.cs.off() btn_irq = p8result[6] if btn_irq&1: # microdrive 1 request #self.cs.on() #self.spi.write_readinto(self.spi_read_blktyp,self.spi_result) #self.cs.off() #blktyp=p8result[6] if self.diskfile: self.mdv_read() if btn_irq&0x80: # btn event IRQ flag self.cs.on() self.spi.write_readinto(self.spi_read_btn, self.spi_result) self.cs.off() btn = p8result[6] p8enable = ptr8(addressof(self.enable)) if p8enable[0]&2: # wait to release all BTNs if btn==1: p8enable[0]&=1 # clear bit that waits for all BTNs released else: # all BTNs released if (btn&0x78)==0x78: # all cursor BTNs pressed at the same time self.show_dir() # refresh directory p8enable[0]=(p8enable[0]^1)|2; self.osd_enable(p8enable[0]&1) if p8enable[0]==1: if btn==9: # btn3 cursor up self.start_autorepeat(-1) if btn==17: # btn4 cursor down self.start_autorepeat(1) if btn==1: self.timer.deinit() # stop autorepeat if btn==33: # btn5 cursor left self.updir() if btn==65: # btn6 cursor right self.select_entry() def start_autorepeat(self, i:int): self.autorepeat_direction=i self.move_dir_cursor(i) self.timer_slow=1 self.timer.init(mode=Timer.PERIODIC, period=500, callback=self.autorepeat) def autorepeat(self, timer): if self.timer_slow: self.timer_slow=0 self.timer.init(mode=Timer.PERIODIC, period=30, callback=self.autorepeat) self.move_dir_cursor(self.autorepeat_direction) self.irq_handler(0) # catch stale IRQ def select_entry(self): if self.direntries[self.fb_cursor][1]: # is it directory oldselected = self.fb_selected - self.fb_topitem self.fb_selected = self.fb_cursor try: self.cwd = self.fullpath(self.direntries[self.fb_cursor][0]) except: self.fb_selected = -1 self.show_dir_line(oldselected) self.show_dir_line(self.fb_cursor - self.fb_topitem) self.init_fb() self.read_dir() self.show_dir() else: self.change_file() def updir(self): if len(self.cwd) < 2: self.cwd = "/" else: s = self.cwd.split("/")[:-1] self.cwd = "" for name in s: if len(name) > 0: self.cwd += "/"+name self.init_fb() self.read_dir() self.show_dir() def fullpath(self,fname): if self.cwd.endswith("/"): return self.cwd+fname else: return self.cwd+"/"+fname def change_file(self): oldselected = self.fb_selected - self.fb_topitem self.fb_selected = self.fb_cursor try: filename = self.fullpath(self.direntries[self.fb_cursor][0]) except: filename = False self.fb_selected = -1 self.show_dir_line(oldselected) self.show_dir_line(self.fb_cursor - self.fb_topitem) if filename: if filename.endswith(".mdv") or filename.endswith(".MDV"): self.diskfile = open(filename,"rb") self.mdv_refill_buf() self.enable[0]=0 self.osd_enable(0) if filename.endswith(".bit"): self.spi_request.irq(handler=None) self.timer.deinit() self.enable[0]=0 self.osd_enable(0) self.spi.deinit() tap=ecp5.ecp5() tap.prog_stream(open(filename,"rb"),blocksize=1024) if filename.endswith("_sd.bit"): os.umount("/sd") for i in bytearray([2,4,12,13,14,15]): p=Pin(i,Pin.IN) a=p.value() del p,a result=tap.prog_close() del tap gc.collect() #os.mount(SDCard(slot=3),"/sd") # BUG, won't work self.init_spi() # because of ecp5.prog() spi.deinit() self.spi_request.irq(trigger=Pin.IRQ_FALLING, handler=self.irq_handler_ref) self.irq_handler(0) # handle stuck IRQ if filename.endswith(".nes") \ or filename.endswith(".snes") \ or filename.endswith(".smc") \ or filename.endswith(".sfc"): import ld_nes s=ld_nes.ld_nes(self.spi,self.cs) s.ctrl(1) s.ctrl(0) s.load_stream(open(filename,"rb")) del s gc.collect() self.enable[0]=0 self.osd_enable(0) if filename.startswith("/sd/ti99_4a/") and filename.endswith(".bin"): import ld_ti99_4a s=ld_ti99_4a.ld_ti99_4a(self.spi,self.cs) s.load_rom_auto(open(filename,"rb"),filename) del s gc.collect() self.enable[0]=0 self.osd_enable(0) if (filename.startswith("/sd/msx") and filename.endswith(".rom")) \ or filename.endswith(".mx1"): import ld_msx s=ld_msx.ld_msx(self.spi,self.cs) s.load_msx_rom(open(filename,"rb")) del s gc.collect() self.enable[0]=0 self.osd_enable(0) if filename.endswith(".z80"): self.enable[0]=0 self.osd_enable(0) import ld_zxspectrum s=ld_zxspectrum.ld_zxspectrum(self.spi,self.cs) s.loadz80(filename) del s gc.collect() if filename.endswith(".ora") or filename.endswith(".orao"): self.enable[0]=0 self.osd_enable(0) import ld_orao s=ld_orao.ld_orao(self.spi,self.cs) s.loadorao(filename) del s gc.collect() if filename.endswith(".vsf"): self.enable[0]=0 self.osd_enable(0) import ld_vic20 s=ld_vic20.ld_vic20(self.spi,self.cs) s.loadvsf(filename) del s gc.collect() if filename.endswith(".prg"): self.enable[0]=0 self.osd_enable(0) import ld_vic20 s=ld_vic20.ld_vic20(self.spi,self.cs) s.loadprg(filename) del s gc.collect() if filename.endswith(".cas"): self.enable[0]=0 self.osd_enable(0) import ld_trs80 s=ld_trs80.ld_trs80(self.spi,self.cs) s.loadcas(filename) del s gc.collect() if filename.endswith(".cmd"): self.enable[0]=0 self.osd_enable(0) import ld_trs80 s=ld_trs80.ld_trs80(self.spi,self.cs) s.loadcmd(filename) del s gc.collect() @micropython.viper def osd_enable(self, en:int): pena = ptr8(addressof(self.spi_enable_osd)) pena[5] = en&1 self.cs.on() self.spi.write(self.spi_enable_osd) self.cs.off() @micropython.viper def osd_print(self, x:int, y:int, i:int, text): p8msg=ptr8(addressof(self.spi_write_osd)) a=0xF000+(x&63)+((y&31)<<6) p8msg[2]=i p8msg[3]=a>>8 p8msg[4]=a self.cs.on() self.spi.write(self.spi_write_osd) self.spi.write(text) self.cs.off() @micropython.viper def osd_cls(self): p8msg=ptr8(addressof(self.spi_write_osd)) p8msg[3]=0xF0 p8msg[4]=0 self.cs.on() self.spi.write(self.spi_write_osd) self.spi.read(1280,32) self.cs.off() # y is actual line on the screen def show_dir_line(self, y): if y < 0 or y >= self.screen_y: return mark = 0 invert = 0 if y == self.fb_cursor - self.fb_topitem: mark = 1 invert = 1 if y == self.fb_selected - self.fb_topitem: mark = 2 i = y+self.fb_topitem if i >= len(self.direntries): self.osd_print(0,y,0,"%64s" % "") return if self.direntries[i][1]: # directory self.osd_print(0,y,invert,"%c%-57s D" % (self.mark[mark],self.direntries[i][0])) else: # file mantissa = self.direntries[i][2] exponent = 0 while mantissa >= 1024: mantissa >>= 10 exponent += 1 self.osd_print(0,y,invert,"%c%-57s %4d%c" % (self.mark[mark],self.direntries[i][0], mantissa, self.exp_names[exponent])) def show_dir(self): for i in range(self.screen_y): self.show_dir_line(i) def move_dir_cursor(self, step): oldcursor = self.fb_cursor if step == 1: if self.fb_cursor < len(self.direntries)-1: self.fb_cursor += 1 if step == -1: if self.fb_cursor > 0: self.fb_cursor -= 1 if oldcursor != self.fb_cursor: screen_line = self.fb_cursor - self.fb_topitem if screen_line >= 0 and screen_line < self.screen_y: # move cursor inside screen, no scroll self.show_dir_line(oldcursor - self.fb_topitem) # no highlight self.show_dir_line(screen_line) # highlight else: # scroll if screen_line < 0: # cursor going up screen_line = 0 if self.fb_topitem > 0: self.fb_topitem -= 1 self.show_dir() else: # cursor going down screen_line = self.screen_y-1 if self.fb_topitem+self.screen_y < len(self.direntries): self.fb_topitem += 1 self.show_dir() def read_dir(self): self.direntries = [] ls = sorted(os.listdir(self.cwd)) for fname in ls: stat = os.stat(self.fullpath(fname)) if stat[0] & 0o170000 == 0o040000: self.direntries.append([fname,1,0]) # directory for fname in ls: stat = os.stat(self.fullpath(fname)) if stat[0] & 0o170000 != 0o040000: self.direntries.append([fname,0,stat[6]]) # file def mdv_skip_preamble(self,n:int)->int: i=0 j=0 found=0 while j<n: if self.diskfile.readinto(self.mdv_byte): if self.mdv_byte[0]==0xFF: self.diskfile.readinto(self.mdv_byte) if self.mdv_byte[0]==0xFF and i>=10: found=1 i+=2 break else: i=0 else: if self.mdv_byte[0]==0: i+=1 else: i=0 j+=1 else: # EOF, make it circular self.diskfile.seek(0) print("MDV: wraparound",self.data_buf[2:12].decode("utf-8")) if found: return i return 0 def mdv_refill_buf(self): if self.mdv_skip_preamble(1000): self.diskfile.readinto(self.data_buf) # skip block if header doesn't start with 0xFF #i=0 #while self.data_buf[0]!=0xFF and i<254: # self.mdv_skip_preamble(1000) # self.diskfile.readinto(self.data_buf) # i+=1 #print(self.data_buf[1],self.data_buf[2:12]) # block number, volume name #print(self.data_buf[0:16],self.data_buf[28:32],self.data_buf[40:44]) # block number, volume name else: print("MDV: preamble not found") @micropython.viper def mdv_checksum(self,a:int,b:int)->int: p8b=ptr8(addressof(self.data_buf)) c=0xF0F i=a while i<b: c+=p8b[i] i+=1 return c&0xFFFF def mdv_read(self): if self.mdv_phase[0]: self.ctrl(8) # R_cpu_control[3]=1 self.cs.on() self.spi.write(self.spi_send_mdv_bram) self.spi.write(self.data_buf[0:16]) self.cs.off() self.ctrl(0) else: self.ctrl(8) self.cs.on() self.spi.write(self.spi_send_mdv_bram) self.spi.write(self.data_buf[28:32]) self.spi.write(self.data_buf[40:554]) self.cs.off() self.ctrl(0) self.led.on() self.mdv_refill_buf() # fix checksum in broken MDV images #c=self.mdv_checksum(0,14) #self.data_buf[14]=c #self.data_buf[15]=c>>8 c=self.mdv_checksum(28,30) self.data_buf[30]=c self.data_buf[31]=c>>8 #c=self.mdv_checksum(40,552) #self.data_buf[552]=c #self.data_buf[553]=c>>8 self.led.off() self.mdv_phase[0]^=1 # NOTE: this can be used for debugging #def osd(self, a): # if len(a) > 0: # enable = 1 # else: # enable = 0 # self.cs.on() # self.spi.write(bytearray([0,0xFE,0,0,0,enable])) # enable OSD # self.cs.off() # if enable: # self.cs.on() # self.spi.write(bytearray([0,0xFD,0,0,0])) # write content # self.spi.write(bytearray(a)) # write content # self.cs.off() def ctrl(self,i): self.cs.on() self.spi.write(bytearray([0, 0xFF, 0xFF, 0xFF, 0xFF, i])) self.cs.off() def peek(self,addr,length): self.ctrl(4) self.ctrl(6) self.cs.on() self.spi.write(bytearray([1,(addr >> 24) & 0xFF, (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, addr & 0xFF, 0])) b=bytearray(length) self.spi.readinto(b) self.cs.off() self.ctrl(4) self.ctrl(0) return b def poke(self,addr,data): self.ctrl(4) self.ctrl(6) self.cs.on() self.spi.write(bytearray([0,(addr >> 24) & 0xFF, (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, addr & 0xFF])) self.spi.write(data) self.cs.off() self.ctrl(4) self.ctrl(0)
# # Copyright (c) 2006-2019, RT-Thread Development Team # # SPDX-License-Identifier: MIT License # # Change Logs: # Date Author Notes # 2019-06-13 SummerGift first version # from machine import Pin, SPI clk = Pin(("clk", 43), Pin.OUT_PP) mosi = Pin(("mosi", 44), Pin.OUT_PP) miso = Pin(("miso", 45), Pin.IN) spi = SPI(-1, 500000, polarity=0, phase=0, bits=8, firstbit=0, sck=clk, mosi=mosi, miso=miso) print(spi) spi.write("hello rt-thread!") spi.read(10)
class MAX31865(): def __init__(self, clk=14, mosi=13, miso=12, cs=27): self.SCK = Pin(clk, Pin.OUT) self.MOSI = Pin(mosi, Pin.OUT) self.MISO = Pin(miso, Pin.IN) self.CS = Pin(cs, Pin.OUT) # HSPI is MOSI=GPIO13, MISO=GPIO12 and SCK=GPIO14 # HSPI(1) self.spi = SPI(1) self.spi.init(baudrate=100000, sck=self.SCK, miso=self.MISO, mosi=self.MOSI, polarity=0, phase=1) """ Configuration bits: Vbias 1=on Conversion mode 1=auto,0=normally off 1-shot 1=1-shot (auto-clear) 3-wire 1=3-wire,0=2/4 wire Fault detection Fault detection Fault Status 1=clear Filter 1=50Hz,2=60Hz """ config = 0xb2 buf = bytearray(2) buf[0] = 0x80 # configuration write addr buf[1] = config self.CS.value(0) self.spi.write(buf) self.CS.value(1) time.sleep(.2) # Re-implementing: # https://github.com/frogshead/MAX31865/blob/master/max31865.py def read_temperature(self): print("Entering read_temp function") time.sleep(.2) buf = bytearray(1) buf[0] = 0x00 self.CS.value(0) self.spi.write(buf) register_values = self.spi.read(8) self.CS.value(1) print("Configuration Register Value: {:02x}".format( register_values[0])) print("RTD MSB Register Value: {:02x}".format(register_values[1])) print("RTD LSB Register Value: {:02x}".format(register_values[2])) print("High Fault MSB Treshold Register Value: {:02x}".format( register_values[3])) print("High Fault LSB Treshold Register Value: {:02x}".format( register_values[4])) print("Low Fault MSB Register Value: {:02x}".format( register_values[5])) print("Low Fault LSB Register Value: {:02x}".format( register_values[6])) print("Fault Status Register Value: {:02x}".format(register_values[0])) adc = ((register_values[1] << 8) | register_values[2]) >> 1 print("ADC value: ", adc) print("Linear Temperature: {}".format((adc / 32) - 256))
class LIGHT_Sensor: ''' Represents a light sensor ''' def __init__(self, freq, port, csbpin, sckpin=18, mosipin=23, misopin=19): print("CSB pin = %d" % csbpin) self.csb = machine.Pin(csbpin, machine.Pin.OUT) self.csb.value(1) # disable # construct an SPI bus on the given pins # polarity is the idle state of SCK # phase=0 means sample on the first edge of SCK, phase=1 means the second # 1M, 10M, 20M ok (1M is more stable) if (port == 1): print("Use hardware spi port 1: sck 14, mosi 13, miso 12") self.spi = SPI(1, baudrate=freq, polarity=1, phase=1, bits=8, firstbit=0, sck=Pin(14), mosi=Pin(13), miso=Pin(12)) elif (port == 2): print("Use hardware spi port 2: sck 18, mosi 23, miso 19") self.spi = SPI(2, baudrate=freq, polarity=1, phase=1, bits=8, firstbit=0, sck=Pin(18), mosi=Pin(23), miso=Pin(19)) else: print("Use software spi port : sck %d, mosi %d, miso %d" % (sckpin, mosipin, misopin)) self.spi = SPI(baudrate=freq, polarity=1, phase=1, sck=Pin(sckpin), mosi=Pin(mosipin), miso=Pin(misopin)) # software spi def get_light_sensor_data(self): #print ("Read 2 bytes from SPI light sensor.") self.csb.value(0) # enable buf = self.spi.read(2) # read 2 bytes on MISO self.csb.value(1) # disable print("Raw Data from the sensor:") for x in buf: print("%x" % x) #print ("MSB data") data_msb = (buf[0] & 0x1f) << 3 #print ("%x" % data_msb) #print ("LSB data") data_lsb = (buf[1] & 0xe0) >> 5 #print ("%x" % data_lsb) #print ("8 bit sensor data:") data = data_msb | data_lsb #print ("%x" % data) return data
class MAX31865(): ### Register constants, see data sheet for info. # Read Addresses MAX31865_REG_READ_CONFIG = 0x00 MAX31865_REG_READ_RTD_MSB = 0x01 MAX31865_REG_READ_RTD_LSB = 0x02 MAX31865_REG_READ_HFT_MSB = 0x03 MAX31865_REG_READ_HFT_LSB = 0x04 MAX31865_REG_READ_LFT_MSB = 0x05 MAX31865_REG_READ_LFT_LSB = 0x06 MAX31865_REG_READ_FAULT = 0x07 # Write Addresses MAX31865_REG_WRITE_CONFIG = 0x80 MAX31865_REG_WRITE_HFT_MSB = 0x83 MAX31865_REG_WRITE_HFT_LSB = 0x84 MAX31865_REG_WRITE_LFT_MSB = 0x85 MAX31865_REG_WRITE_LFT_LSB = 0x86 # Configuration Register MAX31865_CONFIG_50HZ_FILTER = 0x01 MAX31865_CONFIG_CLEAR_FAULT = 0x02 MAX31865_CONFIG_3WIRE = 0x10 MAX31865_CONFIG_ONE_SHOT = 0x20 MAX31865_CONFIG_AUTO = 0x40 MAX31865_CONFIG_BIAS_ON = 0x80 def __init__(self, wires=2, cs_pin='P9'): # initialize ``P9`` in gpio mode and make it an CS output self.CS = Pin(cs_pin, mode=Pin.OUT) self.CS(True) # init chip select self.spi = SPI(0, mode=SPI.MASTER, baudrate=100000, polarity=0, phase=1, firstbit=SPI.MSB) # set configuration register config = self.MAX31865_CONFIG_BIAS_ON + self.MAX31865_CONFIG_AUTO + self.MAX31865_CONFIG_CLEAR_FAULT + self.MAX31865_CONFIG_50HZ_FILTER if (wires == 3): config = config + MAX31865_CONFIG_3WIRE buf = bytearray(2) buf[0] = self.MAX31865_REG_WRITE_CONFIG # config write address buf[1] = config self.CS(False) # Select chip nw=self.spi.write(buf) # write config self.CS(True) self.RefR = 430.0 self.R0 = 100.0 def _RawToTemp(self, raw): RTD = (raw * self.RefR) / (32768) A = 3.908e-3 B = -5.775e-7 return (-A + math.sqrt(A*A - 4*B*(1-RTD/self.R0))) / (2*B), RTD def read(self): temp = self._read() return temp def _read(self): self.CS(False) nw=self.spi.write(bytes([0x01])) # first read address MSB = self.spi.read(1) # multi-byte transfer LSB = self.spi.read(1) self.CS(True) raw = (MSB[0] << 8) + LSB[0] raw = raw >> 1 # print( 'raw: ', raw) temp, RTD = self._RawToTemp(raw) return temp
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ from machine import Pin, SPI from time import sleep_ms # UEXT wiring on the Pyboard. # https://github.com/mchobby/pyboard-driver/tree/master/UEXT spi = SPI(2) # MOSI=Y8, MISO=Y7, SCK=Y6, SS=Y5 spi.init(baudrate=5000000, phase=0, polarity=0) # We must manage the SS signal ourself ss = Pin(Pin.board.Y5, Pin.OUT) ss.value(1) sleep_ms(10) # Wait 10ms before new transaction! # Start a new SPI transaction ss.value(0) print("Read IDCode from GameDuino (0x6d expected)") spi.write(bytes([0x28, 0x00])) buf = spi.read(1) # read 1 byte print("Response:") print(buf) # bytes print("0x%02x" % buf[0]) # print as Hexa
class MFRC522_Custom: def __init__(self, rst, cs): self.OK = 0 self.NOTAGERR = 1 self.ERR = 2 self.REQIDL = 0x26 self.REQALL = 0x52 self.AUTHENT1A = 0x60 self.AUTHENT1B = 0x61 self.rst = Pin(rst, Pin.OUT) self.cs = Pin(cs, Pin.OUT) self.rst.value(0) self.cs.value(1) self.spi = SPI(1, baudrate=100000, polarity=0, phase=0) self.spi.init() self.rst.value(1) self.init() def _wreg(self, reg, val): self.cs.value(0) self.spi.write(b'%c' % int(0xff & ((reg << 1) & 0x7e))) self.spi.write(b'%c' % int(0xff & val)) self.cs.value(1) def _rreg(self, reg): self.cs.value(0) self.spi.write(b'%c' % int(0xff & (((reg << 1) & 0x7e) | 0x80))) val = self.spi.read(1) self.cs.value(1) return val[0] def _sflags(self, reg, mask): self._wreg(reg, self._rreg(reg) | mask) def _cflags(self, reg, mask): self._wreg(reg, self._rreg(reg) & (~mask)) def _tocard(self, cmd, send): recv = [] bits = irq_en = wait_irq = n = 0 stat = self.ERR if cmd == 0x0E: irq_en = 0x12 wait_irq = 0x10 elif cmd == 0x0C: irq_en = 0x77 wait_irq = 0x30 self._wreg(0x02, irq_en | 0x80) self._cflags(0x04, 0x80) self._sflags(0x0A, 0x80) self._wreg(0x01, 0x00) for c in send: self._wreg(0x09, c) self._wreg(0x01, cmd) if cmd == 0x0C: self._sflags(0x0D, 0x80) #MUDANDO AQUI! i = 100 while True: n = self._rreg(0x04) i -= 1 if ~((i != 0) and ~(n & 0x01) and ~(n & wait_irq)): break self._cflags(0x0D, 0x80) if i: if (self._rreg(0x06) & 0x1B) == 0x00: stat = self.OK if n & irq_en & 0x01: stat = self.NOTAGERR elif cmd == 0x0C: n = self._rreg(0x0A) lbits = self._rreg(0x0C) & 0x07 if lbits != 0: bits = (n - 1) * 8 + lbits else: bits = n * 8 if n == 0: n = 1 elif n > 16: n = 16 for _ in range(n): recv.append(self._rreg(0x09)) else: stat = self.ERR return stat, recv, bits def _crc(self, data): self._cflags(0x05, 0x04) self._sflags(0x0A, 0x80) for c in data: self._wreg(0x09, c) self._wreg(0x01, 0x03) i = 0xFF while True: n = self._rreg(0x05) i -= 1 if not ((i != 0) and not (n & 0x04)): break return [self._rreg(0x22), self._rreg(0x21)] def init(self): self.reset() self._wreg(0x2A, 0x8D) self._wreg(0x2B, 0x3E) self._wreg(0x2D, 30) self._wreg(0x2C, 0) self._wreg(0x15, 0x40) self._wreg(0x11, 0x3D) self.antenna_on() def reset(self): self._wreg(0x01, 0x0F) def antenna_on(self, on=True): if on and ~(self._rreg(0x14) & 0x03): self._sflags(0x14, 0x03) else: self._cflags(0x14, 0x03) def request(self, mode): self._wreg(0x0D, 0x07) (stat, recv, bits) = self._tocard(0x0C, [mode]) if (stat != self.OK) | (bits != 0x10): stat = self.ERR return stat, bits def anticoll(self): ser_chk = 0 ser = [0x93, 0x20] self._wreg(0x0D, 0x00) (stat, recv, bits) = self._tocard(0x0C, ser) if stat == self.OK: if len(recv) == 5: for i in range(4): ser_chk = ser_chk ^ recv[i] if ser_chk != recv[4]: stat = self.ERR else: stat = self.ERR return stat, recv def select_tag(self, ser): buf = [0x93, 0x70] + ser[:5] buf += self._crc(buf) (stat, recv, bits) = self._tocard(0x0C, buf) return self.OK if (stat == self.OK) and (bits == 0x18) else self.ERR def auth(self, mode, addr, sect, ser): return self._tocard(0x0E, [mode, addr] + sect + ser[:4])[0] def stop_crypto1(self): self._cflags(0x08, 0x08) def read(self, addr): data = [0x30, addr] data += self._crc(data) (stat, recv, _) = self._tocard(0x0C, data) return recv if stat == self.OK else None def write(self, addr, data): buf = [0xA0, addr] buf += self._crc(buf) (stat, recv, bits) = self._tocard(0x0C, buf) if not (stat == self.OK) or not (bits == 4) or not ( (recv[0] & 0x0F) == 0x0A): stat = self.ERR else: buf = [] for i in range(16): buf.append(data[i]) buf += self._crc(buf) (stat, recv, bits) = self._tocard(0x0C, buf) if not (stat == self.OK) or not (bits == 4) or not ( (recv[0] & 0x0F) == 0x0A): stat = self.ERR return stat def lerCartao(self): (stat, tag_type) = self.request(self.REQIDL) saida = "" if stat == self.OK: (stat, raw_uid) = self.anticoll() if stat == self.OK: saida = "0x%02x%02x%02x%02x" % (raw_uid[0], raw_uid[1], raw_uid[2], raw_uid[3]) return saida
class NRF: def __init__(self, port=1, miso=12, mosi=11, sck=10, csn=9, ce = 8): self.csn = Pin(csn, 1) self.ce = Pin(ce,1) self.spi = SPI(port, 1000000, miso=Pin(miso), mosi=Pin(mosi), sck=Pin(sck)) self.csnHigh() self.ceLow() utime.sleep_ms(11) def csnHigh(self): self.csn(1) def csnLow(self): self.csn(0) def ceHigh(self): self.ce(1) def ceLow(self): self.ce(0) def readReg(self, reg, size=1): reg = [0b00011111 & reg] self.csnLow() self.spi.write(bytearray(reg)) result = self.spi.read(size) self.csnHigh() return result def writeReg(self, reg, data): reg = [0b00100000 | (0b00011111 & reg)] self.csnLow() self.spi.write(bytearray(reg)) data = [data] if type(data) == type(1) else data self.spi.write(bytearray(data)) self.csnHigh() def config(self, channel=60, channelName ="gyroc", packetSize = 32): self.csnHigh() self.ceLow() utime.sleep_ms(11) self.writeReg(0,0b00001010) # config utime.sleep_us(1500) self.writeReg(1,0b00000011) #no ack self.writeReg(5, channel) self.writeReg(0x0a, channelName) self.writeReg(0x10, channelName) self.writeReg(0x11, packetSize) # def modeTX(self): reg = self.readReg(0)[0] reg &= ~(1<<0) self.writeReg(0,reg) self.ceLow() utime.sleep_us(130) def modeRX(self): reg = self.readReg(0)[0] reg |= (1<<0) self.writeReg(0,reg) self.ceHigh() utime.sleep_us(130) def sendMessage(self, data,size = 32): reg = [0b10100000] self.csnLow() self.spi.write(bytearray([0b11100001])) self.csnHigh() self.csnLow() self.spi.write(bytearray(reg)) localData = bytearray(data) localData.extend(bytearray(size - len(localData))) self.spi.write(bytearray(localData)) self.csnHigh() self.ceHigh() utime.sleep_us(10) for i in range(0,10000): reg = self.readReg(7)[0] if reg & 0b00110000: break self.ceLow() self.writeReg(7,0b00110000) # Clear status flags. def readMessage(self,size=32): reg = [0b01100001] self.csnLow() self.spi.write(bytearray(reg)) result = self.spi.read(size) self.csnHigh() self.writeReg(0x07,0b01000000) # clear status flags return result def newMessage(self): regfs = self.readReg(0x17)[0] regs = self.readReg(7)[0] return (not (0b00000001 & regfs)) or (0b01000000 & regs)
class osd: def __init__(self): alloc_emergency_exception_buf(100) self.screen_x = const(64) self.screen_y = const(20) self.cwd = "/sd/slides" # shown on startup self.init_fb() self.exp_names = " KMGTE" self.mark = bytearray([32, 16, 42]) # space, right triangle, asterisk self.read_dir() self.spi_read_irq = bytearray([1, 0xF1, 0, 0, 0, 0, 0]) self.spi_read_btn = bytearray([1, 0xFB, 0, 0, 0, 0, 0]) self.spi_result = bytearray(7) self.spi_enable_osd = bytearray([0, 0xFE, 0, 0, 0, 1]) self.spi_write_osd = bytearray([0, 0xFD, 0, 0, 0]) self.spi_channel = const(2) self.spi_freq = const(3000000) self.init_pinout_sd() #self.spi=SPI(self.spi_channel, baudrate=self.spi_freq, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, sck=Pin(self.gpio_sck), mosi=Pin(self.gpio_mosi), miso=Pin(self.gpio_miso)) self.init_spi() self.enable = bytearray(1) self.timer = Timer(3) self.init_slides() self.files2slides() self.start_bgreader() self.irq_handler(0) self.irq_handler_ref = self.irq_handler # allocation happens here self.spi_request = Pin(0, Pin.IN, Pin.PULL_UP) self.spi_request.irq(trigger=Pin.IRQ_FALLING, handler=self.irq_handler_ref) def init_spi(self): self.spi = SPI(self.spi_channel, baudrate=self.spi_freq, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, sck=Pin(self.gpio_sck), mosi=Pin(self.gpio_mosi), miso=Pin(self.gpio_miso)) self.cs = Pin(self.gpio_cs, Pin.OUT) self.cs.off() # init file browser def init_fb(self): self.fb_topitem = 0 self.fb_cursor = 0 self.fb_selected = -1 @micropython.viper def init_pinout_sd(self): self.gpio_cs = const(5) self.gpio_sck = const(16) self.gpio_mosi = const(4) self.gpio_miso = const(12) @micropython.viper def irq_handler(self, pin): p8result = ptr8(addressof(self.spi_result)) self.cs.on() self.spi.write_readinto(self.spi_read_irq, self.spi_result) self.cs.off() btn_irq = p8result[6] if btn_irq & 0x80: # btn event IRQ flag self.cs.on() self.spi.write_readinto(self.spi_read_btn, self.spi_result) self.cs.off() btn = p8result[6] p8enable = ptr8(addressof(self.enable)) if p8enable[0] & 2: # wait to release all BTNs if btn == 1: p8enable[ 0] &= 1 # clear bit that waits for all BTNs released else: # all BTNs released if (btn & 0x78 ) == 0x78: # all cursor BTNs pressed at the same time self.show_dir() # refresh directory p8enable[0] = (p8enable[0] ^ 1) | 2 self.osd_enable(p8enable[0] & 1) if p8enable[0] == 1: if btn == 9: # btn3 cursor up self.start_autorepeat(-1) if btn == 17: # btn4 cursor down self.start_autorepeat(1) if btn == 1: self.timer.deinit() # stop autorepeat if btn == 33: # btn5 cursor left self.updir() if btn == 65: # btn6 cursor right self.select_entry() else: if btn == 33: # btn5 cursor left self.change_slide(-1) if btn == 65: # btn6 cursor right self.change_slide(1) self.show_slide() @micropython.viper def show_slide(self): addr = int(self.xres) * int( self.yres) * (int(self.vi) % int(self.ncache)) self.cs.on() self.rgtr(0x19, self.i24(addr)) self.cs.off() def start_autorepeat(self, i: int): self.autorepeat_direction = i self.move_dir_cursor(i) self.timer_slow = 1 self.timer.init(mode=Timer.PERIODIC, period=500, callback=self.autorepeat) def autorepeat(self, timer): if self.timer_slow: self.timer_slow = 0 self.timer.init(mode=Timer.PERIODIC, period=30, callback=self.autorepeat) self.move_dir_cursor(self.autorepeat_direction) self.irq_handler(0) # catch stale IRQ def select_entry(self): if self.direntries[self.fb_cursor][1]: # is it directory oldselected = self.fb_selected - self.fb_topitem self.fb_selected = self.fb_cursor try: self.cwd = self.fullpath(self.direntries[self.fb_cursor][0]) except: self.fb_selected = -1 self.show_dir_line(oldselected) self.show_dir_line(self.fb_cursor - self.fb_topitem) self.init_fb() self.read_dir() self.show_dir() else: self.change_file() def updir(self): if len(self.cwd) < 2: self.cwd = "/" else: s = self.cwd.split("/")[:-1] self.cwd = "" for name in s: if len(name) > 0: self.cwd += "/" + name self.init_fb() self.read_dir() self.show_dir() def fullpath(self, fname): if self.cwd.endswith("/"): return self.cwd + fname else: return self.cwd + "/" + fname def change_file(self): oldselected = self.fb_selected - self.fb_topitem self.fb_selected = self.fb_cursor try: filename = self.fullpath(self.direntries[self.fb_cursor][0]) except: filename = False self.fb_selected = -1 self.show_dir_line(oldselected) self.show_dir_line(self.fb_cursor - self.fb_topitem) if filename: if filename.endswith(".bit"): self.spi_request.irq(handler=None) self.timer.deinit() self.enable[0] = 0 self.osd_enable(0) self.spi.deinit() tap = ecp5.ecp5() tap.prog_stream(open(filename, "rb"), blocksize=1024) if filename.endswith("_sd.bit"): os.umount("/sd") for i in bytearray([2, 4, 12, 13, 14, 15]): p = Pin(i, Pin.IN) a = p.value() del p, a result = tap.prog_close() del tap gc.collect() #os.mount(SDCard(slot=3),"/sd") # BUG, won't work self.init_spi() # because of ecp5.prog() spi.deinit() self.spi_request.irq(trigger=Pin.IRQ_FALLING, handler=self.irq_handler_ref) self.irq_handler(0) # handle stuck IRQ if filename.endswith(".ppm"): self.files2slides() self.start_bgreader() self.enable[0] = 0 self.osd_enable(0) @micropython.viper def osd_enable(self, en: int): pena = ptr8(addressof(self.spi_enable_osd)) pena[5] = en & 1 self.cs.on() self.spi.write(self.spi_enable_osd) self.cs.off() @micropython.viper def osd_print(self, x: int, y: int, i: int, text): p8msg = ptr8(addressof(self.spi_write_osd)) a = 0xF000 + (x & 63) + ((y & 31) << 6) p8msg[2] = i p8msg[3] = a >> 8 p8msg[4] = a self.cs.on() self.spi.write(self.spi_write_osd) self.spi.write(text) self.cs.off() @micropython.viper def osd_cls(self): p8msg = ptr8(addressof(self.spi_write_osd)) p8msg[3] = 0xF0 p8msg[4] = 0 self.cs.on() self.spi.write(self.spi_write_osd) self.spi.read(1280, 32) self.cs.off() # y is actual line on the screen def show_dir_line(self, y): if y < 0 or y >= self.screen_y: return mark = 0 invert = 0 if y == self.fb_cursor - self.fb_topitem: mark = 1 invert = 1 if y == self.fb_selected - self.fb_topitem: mark = 2 i = y + self.fb_topitem if i >= len(self.direntries): self.osd_print(0, y, 0, "%64s" % "") return if self.direntries[i][1]: # directory self.osd_print( 0, y, invert, "%c%-57s D" % (self.mark[mark], self.direntries[i][0])) else: # file mantissa = self.direntries[i][2] exponent = 0 while mantissa >= 1024: mantissa >>= 10 exponent += 1 self.osd_print( 0, y, invert, "%c%-57s %4d%c" % (self.mark[mark], self.direntries[i][0], mantissa, self.exp_names[exponent])) def show_dir(self): for i in range(self.screen_y): self.show_dir_line(i) def move_dir_cursor(self, step): oldcursor = self.fb_cursor if step == 1: if self.fb_cursor < len(self.direntries) - 1: self.fb_cursor += 1 if step == -1: if self.fb_cursor > 0: self.fb_cursor -= 1 if oldcursor != self.fb_cursor: screen_line = self.fb_cursor - self.fb_topitem if screen_line >= 0 and screen_line < self.screen_y: # move cursor inside screen, no scroll self.show_dir_line(oldcursor - self.fb_topitem) # no highlight self.show_dir_line(screen_line) # highlight else: # scroll if screen_line < 0: # cursor going up screen_line = 0 if self.fb_topitem > 0: self.fb_topitem -= 1 self.show_dir() else: # cursor going down screen_line = self.screen_y - 1 if self.fb_topitem + self.screen_y < len(self.direntries): self.fb_topitem += 1 self.show_dir() def read_dir(self): self.direntries = [] ls = sorted(os.listdir(self.cwd)) for fname in ls: stat = os.stat(self.fullpath(fname)) if stat[0] & 0o170000 == 0o040000: self.direntries.append([fname, 1, 0]) # directory self.file0 = len(self.direntries) for fname in ls: stat = os.stat(self.fullpath(fname)) if stat[0] & 0o170000 != 0o040000: self.direntries.append([fname, 0, stat[6]]) # file self.nfiles = len(self.direntries) - self.file0 gc.collect() # *** SLIDESHOW *** # self.direntries, self.file0 def init_slides(self): self.xres = 800 self.yres = 600 self.bpp = 16 membytes = 32 * 1024 * 1024 self.slide_pixels = self.xres * self.yres self.ncache = membytes // (self.slide_pixels * self.bpp // 8) #self.ncache=7 # NOTE debug self.priority_forward = 2 self.priority_backward = 1 self.nbackward = self.ncache * self.priority_backward // ( self.priority_forward + self.priority_backward) self.nforward = self.ncache - self.nbackward #print(self.nforward, self.nbackward, self.nbackward+self.nforward) self.rdi = 0 # currently reading image self.prev_rdi = -1 self.vi = 0 # currently viewed image self.cache_li = [] # image to be loaded self.cache_ti = [] # top image self.cache_ty = [] # top good lines 0..(y-1) self.cache_tyend = [] # top y load max self.cache_bi = [] # bot image self.cache_by = [] # bot good lines y..yres for i in range(self.ncache): self.cache_li.append(i) self.cache_ti.append(-1) self.cache_ty.append(0) self.cache_tyend.append(self.yres) self.cache_bi.append(-1) self.cache_by.append(0) self.bg_file = None self.PPM_line_buf = bytearray(3 * self.xres) self.rb = bytearray(256) # reverse bits self.init_reverse_bits() self.finished = 1 def files2slides(self): self.finished = 1 self.bg_file = None self.rdi = 0 self.prev_rdi = -1 self.vi = 0 self.show_slide() self.nslides = 0 self.slide_fi = [] # file index in direntries self.slide_xres = [] self.slide_yres = [] self.slide_pos = [] for i in range(self.nfiles): filename = self.fullpath(self.direntries[self.file0 + i][0]) f = open(filename, "rb") line = f.readline(1000) if line[0:2] == b"P6": # PPM header line = b"#" while line[0] == 35: # skip commented lines line = f.readline(1000) xystr = line.split(b" ") xres = int(xystr[0]) yres = int(xystr[1]) line = f.readline(1000) if int(line) == 255: # 255 levels supported only self.slide_fi.append(self.file0 + i) self.slide_xres.append(xres) self.slide_yres.append(yres) self.slide_pos.append(f.tell()) self.nslides += 1 #if self.nslides>=256: # break # discard cache for i in range(self.ncache): ci = i % self.nslides if i < self.nslides: self.cache_li[ci] = i else: self.cache_li[ci] = -1 self.cache_ti[ci] = -1 self.cache_ty[ci] = 0 self.cache_tyend[ci] = self.yres self.cache_bi[ci] = -1 self.cache_by[ci] = 0 # choose next, ordered by priority def next_to_read(self): before_first = self.nbackward - self.vi if before_first < 0: before_first = 0 after_last = self.vi + self.nforward - self.nslides if after_last < 0: after_last = 0 #print("before_first=%d after_last=%d" % (before_first,after_last)) next_forward_slide = -1 i = self.vi n = i + self.nforward + before_first - after_last if n < 0: n = 0 if n > self.nslides: n = self.nslides while i < n: ic = i % self.ncache if self.cache_ti[ic]!=self.cache_li[ic] \ or self.cache_ty[ic]<self.yres: next_forward_slide = i break i += 1 next_backward_slide = -1 i = self.vi - 1 n = i - self.nbackward - after_last + before_first if n < 0: n = 0 if n > self.nslides: n = self.nslides while i >= n: ic = i % self.ncache if self.cache_ti[ic]!=self.cache_li[ic] \ or self.cache_ty[ic]<self.yres: next_backward_slide = i break i -= 1 next_reading_slide = -1 if next_forward_slide >= 0 and next_backward_slide >= 0: if (next_forward_slide-self.vi)*self.priority_backward < \ (self.vi-next_backward_slide)*self.priority_forward: next_reading_slide = next_forward_slide else: next_reading_slide = next_backward_slide else: if next_forward_slide >= 0: next_reading_slide = next_forward_slide else: if next_backward_slide >= 0: next_reading_slide = next_backward_slide return next_reading_slide # image to be discarded at changed view def next_to_discard(self) -> int: return (self.vi + self.nforward - 1) % self.ncache # which image to replace after changing slide def replace(self, mv): dc_replace = -1 if mv > 0: dc_replace = self.vi + self.nforward - 1 if dc_replace >= self.nslides: dc_replace -= self.ncache if mv < 0: dc_replace = (self.vi - self.nbackward - 1) if dc_replace < 0: dc_replace += self.ncache return dc_replace # change currently viewed slide # discard images in cache def change_slide(self, mv): vi = self.vi + mv if vi < 0 or vi >= self.nslides or mv == 0: return self.cache_li[self.next_to_discard()] = self.replace(mv) self.vi = vi self.cache_li[self.next_to_discard()] = self.replace(mv) self.rdi = self.next_to_read() if self.rdi >= 0: self.start_bgreader() @micropython.viper def init_reverse_bits(self): p8rb = ptr8(addressof(self.rb)) for i in range(256): v = i r = 0 for j in range(8): r <<= 1 r |= v & 1 v >>= 1 p8rb[i] = r # convert PPM line RGB888 to RGB565, bits reversed @micropython.viper def ppm2pixel(self): p8 = ptr8(addressof(self.PPM_line_buf)) p8rb = ptr8(addressof(self.rb)) xi = 0 yi = 0 yn = 2 * int(self.xres) while yi < yn: r = p8[xi] g = p8[xi + 1] b = p8[xi + 2] p8[yi] = p8rb[(r & 0xF8) | ((g & 0xE0) >> 5)] p8[yi + 1] = p8rb[((g & 0x1C) << 3) | ((b & 0xF8) >> 3)] xi += 3 yi += 2 def read_scanline(self): bytpp = self.bpp // 8 # on screen rdi = self.rdi % self.ncache self.bg_file.readinto(self.PPM_line_buf) if self.slide_xres[self.rdi] != self.xres: self.bg_file.seek(self.slide_pos[self.rdi] + 3 * self.slide_xres[self.rdi] * (self.cache_ty[rdi] + 1)) self.ppm2pixel() # write PPM_line_buf to screen addr = self.xres * (rdi * self.yres + self.cache_ty[rdi]) # DMA transfer <= 2048 bytes each # DMA transfer must be divided in N buffer uploads # buffer upload <= 256 bytes each nbuf = 8 astep = 200 abuf = 0 self.cs.on() self.rgtr(0x16, self.i24(addr)) for j in range(nbuf): self.rgtr(0x18, self.PPM_line_buf[abuf:abuf + astep]) abuf += astep self.rgtr(0x17, self.i24(nbuf * astep // bytpp - 1)) self.cs.off() # file should be already closed when calling this def next_file(self): #print("next_file") filename = self.fullpath(self.direntries[self.slide_fi[self.rdi]][0]) self.bg_file = open(filename, "rb") rdi = self.rdi % self.ncache # Y->seek to first position to read from self.bg_file.seek(self.slide_pos[self.rdi] + 3 * self.slide_xres[self.rdi] * self.cache_ty[rdi]) print("%d RD %s" % (self.rdi, filename)) # background read, call it periodically def bgreader(self, timer): if self.rdi < 0: self.finished = 1 self.timer.deinit() return rdi = self.rdi % self.ncache if self.cache_ti[rdi] != self.cache_li[rdi]: # cache contains different image than the one to be loaded # y begin from top self.cache_ti[rdi] = self.cache_li[rdi] self.cache_ty[rdi] = 0 # y end depends on cache content # if bottom part is already in cache, reduce tyend if self.cache_bi[rdi] == self.cache_ti[rdi]: self.cache_tyend[rdi] = self.cache_by[rdi] else: self.cache_tyend[rdi] = self.yres # update self.rdi after cache_ti[rdi] has changed self.rdi = self.cache_ti[rdi] rdi = self.rdi % self.ncache # after self.rdi and cache_ty has been updated # call next file if self.prev_rdi != self.rdi or self.bg_file == None: # file changed, close and reopen if self.bg_file: # maybe not needed, python will auto-close? self.bg_file.close() self.bg_file = None self.next_file() self.prev_rdi = self.rdi if self.cache_ty[rdi] < self.cache_tyend[rdi]: # file read self.read_scanline() self.cache_ty[rdi] += 1 if self.cache_ty[rdi] > self.cache_by[rdi]: self.cache_by[rdi] = self.cache_ty[rdi] if self.cache_ty[rdi] >= self.cache_tyend[rdi]: # slide complete, close file, find next self.cache_ty[rdi] = self.yres self.cache_bi[rdi] = self.cache_li[rdi] self.cache_by[rdi] = 0 self.bg_file = None self.rdi = self.next_to_read() if self.rdi < 0: self.finished = 1 return self.timer.init(mode=Timer.ONE_SHOT, period=0, callback=self.bgreader) def start_bgreader(self): if self.finished: self.finished = 0 self.timer.init(mode=Timer.ONE_SHOT, period=1, callback=self.bgreader) # convert integer to 24-bit RGTR parameter def i24(self, i: int): return bytearray([ self.rb[(i >> 16) & 0xFF], self.rb[(i >> 8) & 0xFF], self.rb[i & 0xFF] ]) # x is bytearray, length 1-256 def rgtr(self, cmd, x): self.spi.write(bytearray([self.rb[cmd], self.rb[len(x) - 1]])) self.spi.write(x) def ctrl(self, i): self.cs.on() self.spi.write(bytearray([0, 0xFF, 0xFF, 0xFF, 0xFF, i])) self.cs.off() def peek(self, addr, length): self.ctrl(2) self.cs.on() self.spi.write( bytearray([ 1, (addr >> 24) & 0xFF, (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, addr & 0xFF, 0 ])) b = bytearray(length) self.spi.readinto(b) self.cs.off() self.ctrl(0) return b def poke(self, addr, data): self.ctrl(2) self.cs.on() self.spi.write( bytearray([ 0, (addr >> 24) & 0xFF, (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, addr & 0xFF ])) self.spi.write(data) self.cs.off() self.ctrl(0)
class osd: def __init__(self): self.screen_x = const(64) self.screen_y = const(20) self.cwd = "/" self.init_fb() self.exp_names = " KMGTE" self.mark = bytearray([32, 16, 42]) # space, right triangle, asterisk self.read_dir() self.spi_read_irq = bytearray([1, 0xF1, 0, 0, 0, 0, 0]) self.spi_read_btn = bytearray([1, 0xFB, 0, 0, 0, 0, 0]) self.spi_result = bytearray(7) self.spi_enable_osd = bytearray([0, 0xFE, 0, 0, 0, 1]) self.spi_write_osd = bytearray([0, 0xFD, 0, 0, 0]) self.spi_channel = const(2) self.spi_freq = const(3000000) self.init_pinout_sd() #self.spi=SPI(self.spi_channel, baudrate=self.spi_freq, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, sck=Pin(self.gpio_sck), mosi=Pin(self.gpio_mosi), miso=Pin(self.gpio_miso)) self.init_spi() alloc_emergency_exception_buf(100) self.enable = bytearray(1) self.timer = Timer(3) self.irq_handler(0) self.irq_handler_ref = self.irq_handler # allocation happens here self.spi_request = Pin(0, Pin.IN, Pin.PULL_UP) self.spi_request.irq(trigger=Pin.IRQ_FALLING, handler=self.irq_handler_ref) def init_spi(self): self.spi = SPI(self.spi_channel, baudrate=self.spi_freq, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, sck=Pin(self.gpio_sck), mosi=Pin(self.gpio_mosi), miso=Pin(self.gpio_miso)) self.cs = Pin(self.gpio_cs, Pin.OUT) self.cs.off() def get_spi_result(self): return self.spi_result def get_spi_result2(self): self.cs.on() self.spi.write_readinto(self.spi_read_btn, self.spi_result) self.cs.off() return self.spi_result # A couple of shortcut functions to change directories, useful for TI-99/4A core development. # After running "import osd", these can be accessed with osd.run.ti_cart() for example. def change_dir(self, dir): os.chdir(dir) print("Current directory changed to {}".format(dir)) def ti_cart(self): self.change_dir("/sd/ti99_4a/cart") def ti_grom(self): self.change_dir("/sd/ti99_4a/grom") def ti_bit(self): self.change_dir("/sd/ti99_4a/bitstreams") # init file browser def init_fb(self): self.fb_topitem = 0 self.fb_cursor = 0 self.fb_selected = -1 @micropython.viper def init_pinout_sd(self): self.gpio_cs = const(5) self.gpio_sck = const(16) self.gpio_mosi = const(4) self.gpio_miso = const(12) @micropython.viper def irq_handler(self, pin): p8result = ptr8(addressof(self.spi_result)) self.cs.on() self.spi.write_readinto(self.spi_read_irq, self.spi_result) self.cs.off() btn_irq = p8result[6] if btn_irq & 0x80: # btn event IRQ flag self.cs.on() self.spi.write_readinto(self.spi_read_btn, self.spi_result) self.cs.off() btn = p8result[6] p8enable = ptr8(addressof(self.enable)) if p8enable[0] & 2: # wait to release all BTNs if btn == 1: p8enable[ 0] &= 1 # clear bit that waits for all BTNs released else: # all BTNs released if (btn & 0x78 ) == 0x78: # all cursor BTNs pressed at the same time self.show_dir() # refresh directory p8enable[0] = (p8enable[0] ^ 1) | 2 self.osd_enable(p8enable[0] & 1) if p8enable[0] == 1: if btn == 9: # btn3 cursor up self.start_autorepeat(-1) if btn == 17: # btn4 cursor down self.start_autorepeat(1) if btn == 1: self.timer.deinit() # stop autorepeat if btn == 33: # btn6 cursor left self.updir() if btn == 65: # btn6 cursor right self.select_entry() def start_autorepeat(self, i: int): self.autorepeat_direction = i self.move_dir_cursor(i) self.timer_slow = 1 self.timer.init(mode=Timer.PERIODIC, period=500, callback=self.autorepeat) def autorepeat(self, timer): if self.timer_slow: self.timer_slow = 0 self.timer.init(mode=Timer.PERIODIC, period=30, callback=self.autorepeat) self.move_dir_cursor(self.autorepeat_direction) self.irq_handler(0) # catch stale IRQ def select_entry(self): if self.direntries[self.fb_cursor][1]: # is it directory oldselected = self.fb_selected - self.fb_topitem self.fb_selected = self.fb_cursor try: self.cwd = self.fullpath(self.direntries[self.fb_cursor][0]) except: self.fb_selected = -1 self.show_dir_line(oldselected) self.show_dir_line(self.fb_cursor - self.fb_topitem) self.init_fb() self.read_dir() self.show_dir() else: self.change_file() def updir(self): if len(self.cwd) < 2: self.cwd = "/" else: s = self.cwd.split("/")[:-1] self.cwd = "" for name in s: if len(name) > 0: self.cwd += "/" + name self.init_fb() self.read_dir() self.show_dir() def fullpath(self, fname): if self.cwd.endswith("/"): return self.cwd + fname else: return self.cwd + "/" + fname def change_file(self): oldselected = self.fb_selected - self.fb_topitem self.fb_selected = self.fb_cursor try: filename = self.fullpath(self.direntries[self.fb_cursor][0]) except: filename = False self.fb_selected = -1 self.show_dir_line(oldselected) self.show_dir_line(self.fb_cursor - self.fb_topitem) if filename: if filename.endswith(".bit"): self.spi_request.irq(handler=None) self.timer.deinit() self.enable[0] = 0 self.osd_enable(0) self.spi.deinit() tap = ecp5.ecp5() tap.prog_stream(open(filename, "rb"), blocksize=1024) if filename.endswith("_sd.bit"): os.umount("/sd") for i in bytearray([2, 4, 12, 13, 14, 15]): p = Pin(i, Pin.IN) a = p.value() del p, a result = tap.prog_close() del tap gc.collect() #os.mount(SDCard(slot=3),"/sd") # BUG, won't work self.init_spi() # because of ecp5.prog() spi.deinit() self.spi_request.irq(trigger=Pin.IRQ_FALLING, handler=self.irq_handler_ref) self.irq_handler(0) # handle stuck IRQ if filename.endswith(".nes") \ or filename.endswith(".snes") \ or filename.endswith(".smc") \ or filename.endswith(".sfc"): import ld_nes s = ld_nes.ld_nes(self.spi, self.cs) s.ctrl(1) s.ctrl(0) s.load_stream(open(filename, "rb"), addr=0, maxlen=0x101000) del s gc.collect() self.enable[0] = 0 self.osd_enable(0) if filename.startswith( "/sd/ti99_4a/") and filename.lower().endswith(".bin"): import ld_ti99_4a s = ld_ti99_4a.ld_ti99_4a(self.spi, self.cs) s.load_rom_auto(open(filename, "rb"), filename) del s gc.collect() self.enable[0] = 0 self.osd_enable(0) if (filename.startswith("/sd/msx") and filename.endswith(".rom")) \ or filename.endswith(".mx1"): import ld_msx s = ld_msx.ld_msx(self.spi, self.cs) s.load_msx_rom(open(filename, "rb")) del s gc.collect() self.enable[0] = 0 self.osd_enable(0) if filename.endswith(".z80"): self.enable[0] = 0 self.osd_enable(0) import ld_zxspectrum s = ld_zxspectrum.ld_zxspectrum(self.spi, self.cs) s.loadz80(filename) del s gc.collect() if filename.endswith(".ora") or filename.endswith(".orao"): self.enable[0] = 0 self.osd_enable(0) import ld_orao s = ld_orao.ld_orao(self.spi, self.cs) s.loadorao(filename) del s gc.collect() if filename.endswith(".vsf"): self.enable[0] = 0 self.osd_enable(0) import ld_vic20 s = ld_vic20.ld_vic20(self.spi, self.cs) s.loadvsf(filename) del s gc.collect() if filename.endswith(".prg"): self.enable[0] = 0 self.osd_enable(0) import ld_vic20 s = ld_vic20.ld_vic20(self.spi, self.cs) s.loadprg(filename) del s gc.collect() if filename.endswith(".cas"): self.enable[0] = 0 self.osd_enable(0) import ld_trs80 s = ld_trs80.ld_trs80(self.spi, self.cs) s.loadcas(filename) del s gc.collect() if filename.endswith(".cmd"): self.enable[0] = 0 self.osd_enable(0) import ld_trs80 s = ld_trs80.ld_trs80(self.spi, self.cs) s.loadcmd(filename) del s gc.collect() @micropython.viper def osd_enable(self, en: int): pena = ptr8(addressof(self.spi_enable_osd)) pena[5] = en & 1 self.cs.on() self.spi.write(self.spi_enable_osd) self.cs.off() @micropython.viper def osd_print(self, x: int, y: int, i: int, text): p8msg = ptr8(addressof(self.spi_write_osd)) a = 0xF000 + (x & 63) + ((y & 31) << 6) p8msg[2] = i p8msg[3] = a >> 8 p8msg[4] = a self.cs.on() self.spi.write(self.spi_write_osd) self.spi.write(text) self.cs.off() @micropython.viper def osd_cls(self): p8msg = ptr8(addressof(self.spi_write_osd)) p8msg[3] = 0xF0 p8msg[4] = 0 self.cs.on() self.spi.write(self.spi_write_osd) self.spi.read(1280, 32) self.cs.off() # y is actual line on the screen def show_dir_line(self, y): if y < 0 or y >= self.screen_y: return mark = 0 invert = 0 if y == self.fb_cursor - self.fb_topitem: mark = 1 invert = 1 if y == self.fb_selected - self.fb_topitem: mark = 2 i = y + self.fb_topitem if i >= len(self.direntries): self.osd_print(0, y, 0, "%64s" % "") return if self.direntries[i][1]: # directory self.osd_print( 0, y, invert, "%c%-57s D" % (self.mark[mark], self.direntries[i][0])) else: # file mantissa = self.direntries[i][2] exponent = 0 while mantissa >= 1024: mantissa >>= 10 exponent += 1 self.osd_print( 0, y, invert, "%c%-57s %4d%c" % (self.mark[mark], self.direntries[i][0], mantissa, self.exp_names[exponent])) def show_dir(self): for i in range(self.screen_y): self.show_dir_line(i) def move_dir_cursor(self, step): oldcursor = self.fb_cursor if step == 1: if self.fb_cursor < len(self.direntries) - 1: self.fb_cursor += 1 if step == -1: if self.fb_cursor > 0: self.fb_cursor -= 1 if oldcursor != self.fb_cursor: screen_line = self.fb_cursor - self.fb_topitem if screen_line >= 0 and screen_line < self.screen_y: # move cursor inside screen, no scroll self.show_dir_line(oldcursor - self.fb_topitem) # no highlight self.show_dir_line(screen_line) # highlight else: # scroll if screen_line < 0: # cursor going up screen_line = 0 if self.fb_topitem > 0: self.fb_topitem -= 1 self.show_dir() else: # cursor going down screen_line = self.screen_y - 1 if self.fb_topitem + self.screen_y < len(self.direntries): self.fb_topitem += 1 self.show_dir() def read_dir(self): self.direntries = [] ls = sorted(os.listdir(self.cwd)) for fname in ls: stat = os.stat(self.fullpath(fname)) if stat[0] & 0o170000 == 0o040000: self.direntries.append([fname, 1, 0]) # directory else: self.direntries.append([fname, 0, stat[6]]) # file gc.collect() # NOTE: this can be used for debugging #def osd(self, a): # if len(a) > 0: # enable = 1 # else: # enable = 0 # self.cs.on() # self.spi.write(bytearray([0,0xFE,0,0,0,enable])) # enable OSD # self.cs.off() # if enable: # self.cs.on() # self.spi.write(bytearray([0,0xFD,0,0,0])) # write content # self.spi.write(bytearray(a)) # write content # self.cs.off() def load_console_grom(self): gromfile = "/sd/ti99_4a/grom/994AGROM.Bin" import ld_ti99_4a s = ld_ti99_4a.ld_ti99_4a(self.spi, self.cs) s.reset_on() print("GROM file: {}".format(gromfile)) bytes = s.load_stream(open(gromfile, "rb"), 0x10000) print("Loaded {} bytes".format(bytes)) s.reset_off() del s gc.collect() def load_console_rom(self): romfile = "/sd/ti99_4a/rom/994AROM.Bin" import ld_ti99_4a s = ld_ti99_4a.ld_ti99_4a(self.spi, self.cs) s.reset_on() print("System ROM file: {}".format(romfile)) bytes = s.load_stream(open(romfile, "rb"), 0) print("Loaded {} bytes".format(bytes)) s.reset_off() del s gc.collect() def load_roms(self): romfile = "/sd/ti99_4a/rom/994AROM.Bin" gromfile = "/sd/ti99_4a/grom/994AGROM.Bin" import ld_ti99_4a s = ld_ti99_4a.ld_ti99_4a(self.spi, self.cs) s.reset_on() # Load ROM print("System ROM file: {}".format(romfile)) bytes = s.load_stream(open(romfile, "rb"), 0) print("Loaded {} bytes".format(bytes)) # Load GROM print("GROM file: {}".format(gromfile)) bytes = s.load_stream(open(gromfile, "rb"), 0x10000) print("Loaded {} bytes".format(bytes)) # remove reset s.reset_off() del s gc.collect() def save_mem(self, filename, addr, length): import ld_ti99_4a old_freq = self.spi_freq self.spi_freq = const(100000) self.init_spi() s = ld_ti99_4a.ld_ti99_4a(self.spi, self.cs) print("Saving memory from {} length {} file: {}".format( addr, length, filename)) s.save_stream(open(filename, "wb"), addr, length) del s self.spi_freq = old_freq self.init_spi() gc.collect()
class Display: def __init__(self): self.en_5V = Pin(5, Pin.OUT) self.pin_hrdy = Pin(21, mode=Pin.IN) self.pin_reset = Pin(22, mode=Pin.OUT) self.pin_cs = Pin(15, mode=Pin.OUT) self.spi = SPI(baudrate=2400000, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, sck=Pin(14), mosi=Pin(13), miso=Pin(12)) def On(self): self.en_5V.on() self.en_5V.value(1) self.pin_cs.on() self.pin_reset.on() print("Display enabled") def Off(self): self.en_5V.off() self.pin_cs.off() self.pin_reset.off() print("Display disabled") def WaitforReady(self): while self.pin_hrdy.value() == 0: machine.idle() def WriteCmd(self, Cmd1, Cmd2): self.WaitforReady() self.pin_cs.value(0) self.WaitforReady() self.spi.write(bytearray([0x60, 0x00])) #Praeamble Cmd self.WaitforReady() self.spi.write(bytearray([Cmd1, Cmd2])) self.pin_cs.value(1) def WriteData(self, Data, AnzData): self.WaitforReady() self.pin_cs.value(0) self.WaitforReady() self.spi.write(bytes([0x00, 0x00])) #Praeamble Write self.WaitforReady() a = 0 while a < AnzData: self.spi.write(bytearray([Data[a], Data[a + 1]])) self.WaitforReady() a += 2 #Immer 2 Schritte pro Runde self.pin_cs.value(1) self.WaitforReady() def WriteReg(self, Addr, Data, AnzData): self.WaitforReady() self.pin_cs.value(0) self.WaitforReady() self.spi.write(bytes([0x60, 0x00])) #Praeamble Write self.WaitforReady() self.spi.write(bytes([0x00, 0x11])) #CMD Write Reg self.pin_cs.value(1) self.WaitforReady() self.pin_cs.value(0) self.WaitforReady() self.spi.write(bytes([0x00, 0x00])) #Praeamble Write self.WaitforReady() self.spi.write(Addr) #write address of register self.WaitforReady() a = 0 while a < AnzData: self.spi.write(bytearray([Data[a], Data[a + 1]])) self.WaitforReady() a += 2 #Immer 2 Schritte pro Runde self.pin_cs.value(1) self.WaitforReady() def ReadReg(self, Addr, AnzData, Data): self.WriteCmd(0x00, 0x10) #Read Register Command self.WriteData(Addr, 2) #read Address Packet self.ReadData(Data, AnzData) def ReadData(self, Data, AnzData): self.WaitforReady() self.pin_cs.value(0) self.WaitforReady() self.spi.write(bytes([0x10, 0x00])) #Praeamble Read self.WaitforReady() print('Start Read') self.spi.read(1) self.WaitforReady() for a in range(AnzData): self.WaitforReady() Data.append(self.spi.read(1)) #print(Data) self.pin_cs.value(1) self.WaitforReady() def send_data_over_spi(self, picture_data_spi): #Auflösung PixB = 1200 PixBx = [0x04, 0xB0] PixH = 825 PixHx = [0x03, 0x39] BpP = 4 # Bit per Pixel self.pin_cs.value(1) #Display Initialisation #-------------------------------------------------- #Reset print('ResetSPI') self.pin_reset.value(0) time.sleep(0.5) self.pin_reset.value(1) self.WaitforReady() print('reset') #Cmd SYS_RUN print('System_Run') self.WriteCmd(0x00, 0x01) #-Load Picture----------------------------------------- print('Load Picture') #Write Image Buffer Adress in Register Command print('Load Picture -Buffer Adress') LISAR = bytes([0x02, 0x0A]) WordH = [0x00, 0x11] self.WriteReg(LISAR, WordH, 2) LISAR = bytes([0x02, 0x08]) WordL = [0xA1, 0xE0] self.WriteReg(LISAR, WordL, 2) #Write Area Image Info print('Load Picture -Area Info') #AreaImgInfo=[0+EndianType, BpP+Rotate, X, X, Y, Y, PixB, PixB, PixH, PixH,] BitperPix = {2: 0x00, 4: 0x20, 8: 0x30} AreaImgInfo = [ 0x01, BitperPix.get(4), 0x00, 0x00, 0x00, 0x00, 0x04, 0xB0, 0x03, 0x39 ] self.WriteCmd(0x00, 0x21) #LD_IMAGE_AREA self.WriteData(AreaImgInfo, 10) #Write Picture Data print('Load Picture -Data') self.pin_cs.value(0) #Praeamble Data self.spi.write(bytes([0x00, 0x00])) self.WaitforReady() #print(len(picture_data_spi)) pix = int(PixB * BpP / 8) foo = bytes(1200) # for i in range(PixH): # line = picture_data_spi[(i*pix):((i+1)*pix)] # print(str((i*(pix+1)+1))+ ":" + str((i+1)*(pix+1))) # self.spi.write(line) #eine Zeile=1200 pixel # #if(i%10==0): # #print(str(i/PixH*100) + " %") #Send the data self.spi.write(picture_data_spi) self.pin_cs.value(1) #Send Load Image End print('Load Picture -End') print('picture end') self.WriteCmd(0x00, 0x22) #Display Area Command print('Disp Area Cmd') #AreaImgInfo = [X, X, Y, Y, PixB, PixB, PixH, PixH, Mode, Mode] AreaCmd = [ 0x00, 0x00, 0x00, 0x00, PixBx[0], PixBx[1], PixHx[0], PixHx[1], 0x00, 0x02 ] self.WriteCmd(0x00, 0x34) #Disp Area Cmd self.WriteData(AreaCmd, 10)
class MFRC522: OK = 0 NOTAGERR = 1 ERR = 2 REQIDL = 0x26 REQALL = 0x52 AUTHENT1A = 0x60 AUTHENT1B = 0x61 def __init__(self, sck, mosi, miso, rst, cs): self.sck = Pin(sck, Pin.OUT) self.mosi = Pin(mosi, Pin.OUT) self.miso = Pin(miso) self.rst = Pin(rst, Pin.OUT) self.cs = Pin(cs, Pin.OUT) self.rst.value(0) self.cs.value(1) self.spi = SPI(baudrate=100000, polarity=0, phase=0, sck=self.sck, mosi=self.mosi, miso=self.miso) self.spi.init() self.rst.value(1) self.init() def _wreg(self, reg, val): self.cs.value(0) self.spi.write(b'%c' % int(0xff & ((reg << 1) & 0x7e))) self.spi.write(b'%c' % int(0xff & val)) self.cs.value(1) def _rreg(self, reg): self.cs.value(0) self.spi.write(b'%c' % int(0xff & (((reg << 1) & 0x7e) | 0x80))) val = self.spi.read(1) self.cs.value(1) return val[0] def _sflags(self, reg, mask): self._wreg(reg, self._rreg(reg) | mask) def _cflags(self, reg, mask): self._wreg(reg, self._rreg(reg) & (~mask)) def _tocard(self, cmd, send): recv = [] bits = irq_en = wait_irq = n = 0 stat = self.ERR if cmd == 0x0E: irq_en = 0x12 wait_irq = 0x10 elif cmd == 0x0C: irq_en = 0x77 wait_irq = 0x30 self._wreg(0x02, irq_en | 0x80) self._cflags(0x04, 0x80) self._sflags(0x0A, 0x80) self._wreg(0x01, 0x00) for c in send: self._wreg(0x09, c) self._wreg(0x01, cmd) if cmd == 0x0C: self._sflags(0x0D, 0x80) i = 200 while True: n = self._rreg(0x04) i -= 1 if ~((i != 0) and ~(n & 0x01) and ~(n & wait_irq)): break self._cflags(0x0D, 0x80) if i: if (self._rreg(0x06) & 0x1B) == 0x00: stat = self.OK if n & irq_en & 0x01: stat = self.NOTAGERR elif cmd == 0x0C: n = self._rreg(0x0A) lbits = self._rreg(0x0C) & 0x07 if lbits != 0: bits = (n - 1) * 8 + lbits else: bits = n * 8 if n == 0: n = 1 elif n > 16: n = 16 for _ in range(n): recv.append(self._rreg(0x09)) else: stat = self.ERR return stat, recv, bits def _crc(self, data): self._cflags(0x05, 0x04) self._sflags(0x0A, 0x80) for c in data: self._wreg(0x09, c) self._wreg(0x01, 0x03) i = 0xFF while True: n = self._rreg(0x05) i -= 1 if not ((i != 0) and not (n & 0x04)): break return [self._rreg(0x22), self._rreg(0x21)] def init(self): self.reset() self._wreg(0x2A, 0x8D) self._wreg(0x2B, 0x3E) self._wreg(0x2D, 30) self._wreg(0x2C, 0) self._wreg(0x15, 0x40) self._wreg(0x11, 0x3D) self.antenna_on() def reset(self): self._wreg(0x01, 0x0F) def antenna_on(self, on=True): if on and ~(self._rreg(0x14) & 0x03): self._sflags(0x14, 0x03) else: self._cflags(0x14, 0x03) def request(self, mode): self._wreg(0x0D, 0x07) (stat, recv, bits) = self._tocard(0x0C, [mode]) if (stat != self.OK) | (bits != 0x10): stat = self.ERR return stat, bits def anticoll(self): ser_chk = 0 ser = [0x93, 0x20] self._wreg(0x0D, 0x00) (stat, recv, bits) = self._tocard(0x0C, ser) if stat == self.OK: if len(recv) == 5: for i in range(4): ser_chk = ser_chk ^ recv[i] if ser_chk != recv[4]: stat = self.ERR else: stat = self.ERR return stat, recv def select_tag(self, ser): buf = [0x93, 0x70] + ser[:5] buf += self._crc(buf) (stat, recv, bits) = self._tocard(0x0C, buf) return self.OK if (stat == self.OK) and (bits == 0x18) else self.ERR def auth(self, mode, addr, sect, ser): return self._tocard(0x0E, [mode, addr] + sect + ser[:4])[0] def stop_crypto1(self): self._cflags(0x08, 0x08) def read(self, addr): data = [0x30, addr] data += self._crc(data) (stat, recv, _) = self._tocard(0x0C, data) return recv if stat == self.OK else None def write(self, addr, data): buf = [0xA0, addr] buf += self._crc(buf) (stat, recv, bits) = self._tocard(0x0C, buf) if not (stat == self.OK) or not (bits == 4) or not ((recv[0] & 0x0F) == 0x0A): stat = self.ERR else: buf = [] for i in range(16): buf.append(data[i]) buf += self._crc(buf) (stat, recv, bits) = self._tocard(0x0C, buf) if not (stat == self.OK) or not (bits == 4) or not ((recv[0] & 0x0F) == 0x0A): stat = self.ERR return stat def read_data(self, addresses=None): """ Wait for card and read data from 'addresses' :param addresses: list of addresses to read from (if you specify empty list, card data will contain only UID) :return: CardData instance with card data """ print("Place card before reader to read from addresses {}".format(addresses)) card = None while True: (stat, tag_type) = self.request(self.REQIDL) if stat != self.OK: continue (stat, raw_uid) = self.anticoll() if stat == self.OK: card = CardData(raw_uid, tag_type) if self.select_tag(card.uid) == self.OK: key = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF] addresses = addresses if addresses is not None else range(64) for i in addresses: if self.auth(self.AUTHENT1A, i, key, card.uid) == self.OK: data = bytes(self.read(i)) card.set_data(i, data) self.stop_crypto1() else: print("Authentication error for address {}".format(i)) else: print("Failed to select tag") return None return card def write_data(self, data): """ Writes specified "data" to card :param data: dict with key - address, value - 16 bytes of data in binary string (hex) :return: CardData instance """ print("Place card before reader to write to addresses {}".format(data.keys())) while True: (stat, tag_type) = self.request(self.REQIDL) if stat != self.OK: continue (stat, raw_uid) = self.anticoll() if stat == self.OK: print("Card detected") card = CardData(raw_uid, tag_type) if self.select_tag(card.uid) == self.OK: key = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF] for addr, value in data.items(): if self.auth(self.AUTHENT1A, addr, key, card.uid) == self.OK: card.set_data(addr, value) stat = self.write(addr, value) self.stop_crypto1() if stat == self.OK: print("Data written to card for address {}".format(addr)) else: print("Failed to write data to card for address {}".format(addr)) else: print("Authentication error for address {}".format(addr)) else: print("Failed to select tag")
class MFRC522: GAIN_REG = 0x26 MAX_GAIN = 0x07 OK = 0 NOTAGERR = 1 ERR = 2 REQIDL = 0x26 REQALL = 0x52 AUTHENT1A = 0x60 AUTHENT1B = 0x61 def __init__(self, spi=None, gpioRst=None, gpioCs=None): if gpioRst is not None: self.rst = Pin(gpioRst, Pin.OUT) else: self.rst = None assert(gpioCs is not None, "Needs gpioCs") # TODO fails without cableSelect if gpioCs is not None: self.cs = Pin(gpioCs, Pin.OUT) else: self.cs = None # TODO CH rationalise which of these are referenced, which can be identical self.regBuf = bytearray(4) self.blockWriteBuf = bytearray(18) self.authBuf = bytearray(12) self.wregBuf = bytearray(2) self.rregBuf = bytearray(1) self.recvBuf = bytearray(16) self.recvMv = memoryview(self.recvBuf) if self.rst is not None: self.rst.value(0) if self.cs is not None: self.cs.value(1) if spi is not None: self.spi = spi else: sck = Pin(14, Pin.OUT) mosi = Pin(13, Pin.OUT) miso = Pin(12, Pin.IN) if uname()[0] == 'WiPy': self.spi = SPI(0) self.spi.init(SPI.MASTER, baudrate=1000000, pins=(sck, mosi, miso)) elif uname()[0] == 'esp8266': # TODO update to match https://github.com/cefn/avatap/blob/master/python/host/cockle.py #prepareHost() self.spi = SPI(baudrate=100000, polarity=0, phase=0, sck=sck, mosi=mosi, miso=miso) self.spi.init() else: raise RuntimeError("Unsupported platform") if self.rst is not None: self.rst.value(1) self.init() def _wreg(self, reg, val): if self.cs is not None: self.cs.value(0) buf = self.wregBuf buf[0]=0xff & ((reg << 1) & 0x7e) buf[1]=0xff & val self.spi.write(buf) if self.cs is not None: self.cs.value(1) def _rreg(self, reg): if self.cs is not None: self.cs.value(0) buf = self.rregBuf buf[0]=0xff & (((reg << 1) & 0x7e) | 0x80) self.spi.write(buf) val = self.spi.read(1) if self.cs is not None: self.cs.value(1) return val[0] def _sflags(self, reg, mask): self._wreg(reg, self._rreg(reg) | mask) def _cflags(self, reg, mask): self._wreg(reg, self._rreg(reg) & (~mask)) def _tocard(self, cmd, send, into=None): recv = emptyRecv bits = irq_en = wait_irq = n = 0 stat = self.ERR if cmd == 0x0E: irq_en = 0x12 wait_irq = 0x10 elif cmd == 0x0C: irq_en = 0x77 wait_irq = 0x30 self._wreg(0x02, irq_en | 0x80) self._cflags(0x04, 0x80) self._sflags(0x0A, 0x80) self._wreg(0x01, 0x00) for c in send: self._wreg(0x09, c) self._wreg(0x01, cmd) if cmd == 0x0C: self._sflags(0x0D, 0x80) i = 2000 while True: n = self._rreg(0x04) i -= 1 if ~((i != 0) and ~(n & 0x01) and ~(n & wait_irq)): break self._cflags(0x0D, 0x80) if i: if (self._rreg(0x06) & 0x1B) == 0x00: stat = self.OK if n & irq_en & 0x01: stat = self.NOTAGERR elif cmd == 0x0C: n = self._rreg(0x0A) lbits = self._rreg(0x0C) & 0x07 if lbits != 0: bits = (n - 1) * 8 + lbits else: bits = n * 8 if n == 0: n = 1 elif n > 16: n = 16 if into is None: recv = self.recvBuf else: recv = into pos = 0 while pos < n: recv[pos] = self._rreg(0x09) pos += 1 if into is None: recv = self.recvMv[:n] else: recv = into else: stat = self.ERR return stat, recv, bits def _assign_crc(self, data, count): self._cflags(0x05, 0x04) self._sflags(0x0A, 0x80) dataPos = 0 while dataPos < count: self._wreg(0x09, data[dataPos]) dataPos += 1 self._wreg(0x01, 0x03) i = 0xFF while True: n = self._rreg(0x05) i -= 1 if not ((i != 0) and not (n & 0x04)): break data[count] = self._rreg(0x22) data[count + 1] = self._rreg(0x21) def init(self): self.reset() self._wreg(0x2A, 0x8D) self._wreg(0x2B, 0x3E) self._wreg(0x2D, 30) self._wreg(0x2C, 0) self._wreg(0x15, 0x40) self._wreg(0x11, 0x3D) self.set_gain(self.MAX_GAIN) self.antenna_on() def reset(self): self._wreg(0x01, 0x0F) def antenna_on(self, on=True): if on and ~(self._rreg(0x14) & 0x03): self._sflags(0x14, 0x03) else: self._cflags(0x14, 0x03) def request(self, mode): self._wreg(0x0D, 0x07) (stat, recv, bits) = self._tocard(0x0C, [mode]) if (stat != self.OK) | (bits != 0x10): stat = self.ERR return stat, bits def anticoll(self): ser_chk = 0 ser = [0x93, 0x20] self._wreg(0x0D, 0x00) (stat, recv, bits) = self._tocard(0x0C, ser) if stat == self.OK: if len(recv) == 5: for i in range(4): ser_chk = ser_chk ^ recv[i] if ser_chk != recv[4]: stat = self.ERR else: stat = self.ERR # CH Note bytearray allocation here return stat, bytearray(recv) def select_tag(self, ser): # TODO CH normalise all list manipulation to bytearray, avoid below allocation buf = bytearray(9) buf[0] = 0x93 buf[1] = 0x70 buf[2:7] = ser self._assign_crc(buf, 7) (stat, recv, bits) = self._tocard(0x0C, buf) return self.OK if (stat == self.OK) and (bits == 0x18) else self.ERR def auth(self, mode, addr, sect, ser): # TODO CH void ser[:4] implicit list allocation buf = self.authBuf buf[0]=mode # A or B buf[1]=addr # block buf[2:8]=sect # key bytes buf[8:12]=ser[:4] # 4 bytes of id return self._tocard(0x0E, buf)[0] # TODO this may well need to be implemented for vault to properly back out from a card session # TODO how, why, when is 'HaltA' needed? see https://github.com/cefn/micropython-mfrc522/issues/1 def halt_a(self): pass def stop_crypto1(self): self._cflags(0x08, 0x08) def set_gain(self, gain): assert gain <= self.MAX_GAIN # clear bits self._cflags(self.GAIN_REG, 0x07<< 4) # set bits according to gain self._sflags(self.GAIN_REG, gain << 4) def read(self, addr, into = None): buf = self.regBuf buf[0]=0x30 buf[1]=addr self._assign_crc(buf, 2) (stat, recv, _) = self._tocard(0x0C, buf, into=into) # TODO this logic probably wrong (should be 'into is None'?) if into is None: # superstitiously avoid returning read buffer memoryview # CH Note bytearray allocation here recv = bytearray(recv) return recv if stat == self.OK else None def write(self, addr, data): buf = self.regBuf buf[0] = 0xA0 buf[1] = addr self._assign_crc(buf, 2) (stat, recv, bits) = self._tocard(0x0C, buf) if not (stat == self.OK) or not (bits == 4) or not ((recv[0] & 0x0F) == 0x0A): stat = self.ERR else: buf = self.blockWriteBuf i = 0 while i < 16: buf[i] = data[i] # TODO CH eliminate this, accelerate it? i += 1 self._assign_crc(buf, 16) (stat, recv, bits) = self._tocard(0x0C, buf) if not (stat == self.OK) or not (bits == 4) or not ((recv[0] & 0x0F) == 0x0A): stat = self.ERR return stat