from pyb import SPI spi = SPI(1) print(spi) spi = SPI(1, SPI.MASTER) spi = SPI(1, SPI.MASTER, baudrate=500000) spi = SPI(1, SPI.MASTER, 500000, polarity=1, phase=0, bits=8, firstbit=SPI.MSB, ti=False, crc=None) print(spi) spi.init(SPI.SLAVE, phase=1) print(spi) spi.init(SPI.MASTER) spi.send(1, timeout=100) print(spi.recv(1, timeout=100)) print(spi.send_recv(1, timeout=100))
def run(): print('demo spi') spi = SPI(3, SPI.MASTER, baudrate=600000, polarity=1, phase=0, crc=0x7) while 1: tx = ''.join(chr(random.randint(50, 85)) for _ in range(4)) rx = bytearray(4) spi.send_recv(tx, rx) print('tx: ' + str(tx)) print('rx: ' + str(rx)) time.sleep(2)
class LIS302DL: def __init__(self): self.cs_pin = Pin('PE3', Pin.OUT_PP, Pin.PULL_NONE) self.cs_pin.high() self.spi = SPI(1, SPI.MASTER, baudrate=328125, polarity=0, phase=1, bits=8) def rd(self, addr, nbytes): if nbytes > 1: addr |= READWRITE_CMD | MULTIPLEBYTE_CMD else: addr |= READWRITE_CMD self.cs_pin.low() self.spi.send(addr) buf = self.spi.send_recv(bytearray(nbytes * [0])) # read data, MSB first self.cs_pin.high() return buf def wr(self, addr, buf): if len(buf) > 1: addr |= MULTIPLEBYTE_CMD self.cs_pin.low() self.spi.send(addr) for b in buf: self.spi.send(b) self.cs_pin.high() def read_id(self): return self.rd(LIS302DL_WHO_AM_I_ADDR, 1) def init(self, init_param=0x47, filter_param=0x2D): self.wr(LIS302DL_CTRL_REG1_ADDR, bytearray([init_param])) self.wr(LIS302DL_CTRL_REG2_ADDR, bytearray([filter_param])) def getx(self): buf = (self.rd(0x29, 1)[0]) - 1 if buf > 127: return ((256 - buf) * (-1)) / 5.81 else: return buf / 5.81 def gety(self): buf = (self.rd(0x2B, 1)[0]) - 4 if buf > 127: return ((256 - buf) * (-1)) / 5.81 else: return buf / 5.81 def getz(self): buf = (self.rd(0x2D, 1)[0]) + 8 if buf > 127: return ((256 - buf) * (-1)) / 5.81 else: return buf / 5.81
class L3GD20: def __init__(self): self.csPin = Pin('PE3', Pin.OUT_PP, Pin.PULL_NONE) self.csPin.high() self.spi = SPI(1, SPI.MASTER, baudrate=328125, polarity=0, phase=1, bits=8) def read(self, address, nbytes): if nbytes > 1: address |= READWRITE_CMD | MULTIPLEBYTE_CMD else: address |= READWRITE_CMD self.csPin.low() self.spi.send(address) buf = self.spi.send_recv(bytearray(nbytes * [0])) # read data, MSB first self.csPin.high() return buf def write(self, address, buf): if len(buf) > 1: address |= MULTIPLEBYTE_CMD self.csPin.low() self.spi.send(address) for b in buf: self.spi.send(b) self.csPin.high() def readID(self): return (self.read(L3GD20_WHO_AM_I_ADDR, 1)[0]) def initGyro(self, reg1Param = 0x3F, reg2Param = 0x00, reg4Param = 0x10): self.write(L3GD20_CTRL_REG1_ADDR, bytearray([reg1Param])) self.write(L3GD20_CTRL_REG2_ADDR, bytearray([reg2Param])) self.write(L3GD20_CTRL_REG4_ADDR, bytearray([reg4Param])) def getXGyro(self): buf = (self.read(L3GD20_OUT_X_L_ADDR,2)) num = buf[1] << 8 | buf[0] return (s16(num)*17.50*0.001) def getYGyro(self): buf = (self.read(L3GD20_OUT_Y_L_ADDR,2)) num = buf[1] << 8 | buf[0] return (s16(num)*17.50*0.001) def getZGyro(self): buf = (self.read(L3GD20_OUT_Z_L_ADDR,2)) num = buf[1] << 8 | buf[0] return (s16(num)*17.50*0.001) def getTempGyro(self): buf = (self.read(L3GD20_OUT_TEMP_ADDR,1)[0]) return s16(buf)
class STAccel: def __init__(self): self.cs_pin = Pin('PE3', Pin.OUT_PP, Pin.PULL_NONE) self.cs_pin.high() self.spi = SPI(1, SPI.MASTER, baudrate=328125, polarity=0, phase=1, bits=8) self.wr(LIS302DL_CTRL_REG1_ADDR, bytearray([LIS302DL_CONF])) def rd(self, addr, nbytes): if nbytes > 1: addr |= READWRITE_CMD | MULTIPLEBYTE_CMD else: addr |= READWRITE_CMD self.cs_pin.low() self.spi.send(addr) buf = self.spi.send_recv(bytearray(nbytes * [0])) # read data, MSB first self.cs_pin.high() return buf def wr(self, addr, buf): if len(buf) > 1: addr |= MULTIPLEBYTE_CMD self.cs_pin.low() self.spi.send(addr) for b in buf: self.spi.send(b) self.cs_pin.high() def read_id(self): return self.rd(LIS302DL_WHO_AM_I_ADDR, 1) def get_xyz(self): val = self.rd(LIS302DL_OUT_X, 5) x = signed8(val[0]) * 18.0 / 1000 y = signed8(val[2]) * 18.0 / 1000 z = signed8(val[4]) * 18.0 / 1000 return [x, y, z]
print(spi) spi = SPI(1, SPI.CONTROLLER) spi = SPI(1, SPI.CONTROLLER, baudrate=500000) spi = SPI(1, SPI.CONTROLLER, 500000, polarity=1, phase=0, bits=8, firstbit=SPI.MSB, ti=False, crc=None) print(str(spi)[:32], str(spi)[53:]) # don't print baudrate/prescaler spi.init(SPI.PERIPHERAL, phase=1) print(spi) try: # need to flush input before we get an error (error is what we want to test) for i in range(10): spi.recv(1, timeout=100) except OSError: print("OSError") spi.init(SPI.CONTROLLER) spi.send(1, timeout=100) print(spi.recv(1, timeout=100)) print(spi.send_recv(1, timeout=100)) spi.deinit()
adc = ADC(Pin('X19')) adc.read() # read value, 0-4095 from pyb import Pin, DAC dac = DAC(Pin('X5')) dac.write(120) # output between 0 and 255 # SPI from pyb import SPI spi = SPI(1, SPI.MASTER, baudrate=200000, polarity=1, phase=0) spi.send('hello') spi.recv(5) # receive 5 bytes on the bus spi.send_recv('hello') # send a receive 5 bytes # I2C from pyb import I2C i2c = I2C(1, I2C.MASTER, baudrate=100000) i2c.scan() # returns list of slave addresses i2c.send('hello', 0x42) # send 5 bytes to slave with address 0x42 i2c.recv(5, 0x42) # receive 5 bytes from slave i2c.mem_read(2, 0x42, 0x10) # read 2 bytes from slave 0x42, slave memory 0x10 i2c.mem_write('xy', 0x42, 0x10) # write 2 bytes to slave 0x42, slave memory 0x10 ''' To enter safe mode, do the following steps: Connect the pyboard to USB so it powers up.
class MCP23S08(object): ADDRESS = 0b0100000 STRUCT = "BBB" REGISTERS = { "IODIR": (0x00, 0b11111111), "IPOL": (0x01, 0b00000000), "GPINTEN": (0x02, 0b00000000), "DEFVAL": (0x03, 0b00000000), "INTCON": (0x04, 0b00000000), "IOCON": (0x05, 0b00000000), "GPPU": (0x06, 0b00000000), "INTF": (0x07, 0b00000000), "INTCAP": (0x08, 0b00000000), "GPIO": (0x09, 0b00000000), "OLAT": (0x0A, 0b00000000) } def __init__(self, cs=Pin.cpu.A4): self.__cs = Pin(cs, Pin.OUT_PP) self.__cs.high() self.__spi = SPI(1, SPI.MASTER, baudrate=10000, polarity=1, phase=1) self.reset() def reset(self): for reg in MCP23S08.REGISTERS.values(): self.write_register(reg, reg[1]) def read_register(self, register): buf = bytearray( struct.pack(MCP23S08.STRUCT, (MCP23S08.ADDRESS << 1) | 1, register[0], 0)) self.__cs.low() self.__spi.send_recv(buf, buf) self.__cs.high() return buf[2] def write_register(self, register, value): buf = bytearray( struct.pack(MCP23S08.STRUCT, MCP23S08.ADDRESS << 1, register[0], value)) self.__cs.low() self.__spi.send_recv(buf, buf) self.__cs.high() def set_directions(self, directions): self.write_register(MCP23S08.REGISTERS["IODIR"], directions) def get_directions(self): return self.read_register(MCP23S08.REGISTERS["IODIR"]) def set_direction(self, idx, direction): self.set_directions( TMC_helpers.field_set(self.get_directions(), (1 << idx), idx, direction)) def get_direction(self, idx): return TMC_helpers.field_get(self.get_directions(), (1 << idx), idx) def set_pullups(self, pullups): self.write_register(MCP23S08.REGISTERS["GPPU"], pullups) def get_pullups(self): return self.read_register(MCP23S08.REGISTERS["GPPU"]) def set_pullup(self, idx, pullup): self.set_pullups( TMC_helpers.field_set(self.get_pullups(), (1 << idx), idx, pullup)) def get_pullup(self, idx): return TMC_helpers.field_get(self.get_pullups(), (1 << idx), idx) def set_gpios(self, gpios): self.write_register(MCP23S08.REGISTERS["GPIO"], gpios) def get_gpios(self): return self.read_register(MCP23S08.REGISTERS["GPIO"]) def set_gpio(self, idx, gpio): self.set_gpios( TMC_helpers.field_set(self.get_gpios(), (1 << idx), idx, gpio)) def get_gpio(self, idx): return TMC_helpers.field_get(self.get_gpios(), (1 << idx), idx)
pyb.Pin("P3", pyb.Pin.IN, pull=pyb.Pin.PULL_UP) # loop ad infinitum while True: # flash light off to indicate waiting for SPI signal pyb.LED(RED_LED_PIN).off() # prepare/refresh buffer buf = bytearray(5) # for troubleshooting # print(buf) # send/receive message # spi.recv(buf) # for receiving only spi.send_recv(b'heyyy', buf) # for troubleshooting # print(buf) # print received message print(''.join(chr(b) for b in buf)) # flash light on to indicate reception of SPI signal pyb.LED(RED_LED_PIN).on() # pause briefly to indicate end of loop sensor.skip_frames(1)
f.write(img_data) print('Save Checkpoint 3!') ''' # print img_data for troubleshooting (should see bytes, 'JFIF', and weird stuff like P7<F<2PFAFZUP_) # print(img_data) ### Communication # flash light to indicate waiting for SPI signal pyb.LED(RED_LED_PIN).on() # prepare hello_buffer hello_buffer = bytearray(5) spi.send_recv(b'ready', hello_buffer) # print message received from MCU print(''.join(chr(b) for b in hello_buffer)) # determine size of image # image_size = img.size() # if img is being sent to MCU image_size = len(img_data) # if img_data is being sent to MCU # create new size_buffer based on image_size size_buffer = bytearray(len( str(image_size))) # str() converts num 2 str, len() produces numeric input # send that size to the MCU in a robust way # print(str(image_size)) # print for troubleshooting spi.send_recv(bytearray(str(image_size)), size_buffer)
pixels_threshold=1, area_threshold=1, x_stride=1): #st mask.lighten(blob.x(), blob.y(), blob.w(), blob.h()) if (enable_masking and mask.ispersist(blob.cx(), blob.cy())): img.draw_rectangle(blob.rect(), color=(0, 255, 0)) continue else: img.draw_cross(blob.cx(), blob.cy()) str = struct.pack('<HHHHHH', fcount, bcount, blob.cx(), blob.cy(), blob.w(), blob.h()) while hs.value() == 0: pyb.delay(1) cs.low() pyb.udelay(1) spi.send_recv(str, rbuf) pyb.udelay(1) cs.high() pyb.udelay(10) bcount = bcount + 1 # end of frame packet while hs.value() == 0: pyb.delay(1) str = struct.pack('<HHHHHH', 0xa5a5, 0, 0, 0, 0, 0) cs.low() pyb.udelay(1) spi.send_recv(str, rbuf) pyb.udelay(1) cs.high() pyb.udelay(10)
class RFM69: def __init__(self, reset_pin=None, dio0_pin=None, spi_channel=None, config=None): self.reset_pin = reset_pin self.nss = Pin('X5', Pin.OUT_PP) self.reset = self.reset() self.spi_channel = spi_channel self.spi = SPI(1, SPI.MASTER, baudrate=50000, polarity=0, phase=0, firstbit=SPI.MSB, crc=None) self.dio0_pin = 'X3' self.conf = self.configure() self.mode = self.set_mode() self.txBufLen = 0 self.txBuf = bytearray(registers["RFM69_MAX_MESSAGE_LEN"]) self.rxBufLen = 0 self.rxBuf = bytearray(registers["RFM69_MAX_MESSAGE_LEN"]) self.version = self.getVersion() self.lastRssi = -(self.spi_read(registers["RFM69_REG_24_RSSI_VALUE"])/2) self.paLevel = 15 def configure(self): print ("Configuring...") for reg, value in config.items(): self.spi_write(registers.get(reg), value) return True def getVersion(self): self.version = self.spi_read(registers["RFM69_REG_10_VERSION"]) return self.version def set_mode(self, newMode=registers["RFM69_MODE_RX"]): self.spi_write(registers["RFM69_REG_01_OPMODE"], (self.spi_read(registers["RFM69_REG_01_OPMODE"]) & 0xE3) | newMode) while(self.spi_read(registers["RFM69_REG_01_OPMODE"]) != newMode): self.spi_write(registers["RFM69_REG_01_OPMODE"], (self.spi_read(registers["RFM69_REG_01_OPMODE"]) & 0xE3) | newMode) print ("Waiting... Attempted mode: %d" % newMode) sleep(1) pass self.mode = newMode return newMode def get_mode(self): #self.mode = self.spi_read(registers["RFM69_REG_01_OPMODE"]) return self.mode def init_gpio(self): self.dio0_pin = Pin('X3', Pin.IN, Pin.PULL_DOWN) def init_spi(self): self.spi = SPI(1, SPI.MASTER, baudrate=50000, polarity=0, phase=0, firstbit=SPI.MSB, crc=None) def reset(self): """ Reset the module, then check it's working. """ print ("Initialising RFM...") self.nss.high() self.reset_pin = Pin('X4', Pin.OUT_PP) self.reset_pin.low() sleep(0.1) self.reset_pin.high() sleep(0.1) self.reset_pin.low() sleep(0.1) def checkRx(self): print ("MODE: %d" % self.get_mode()) print ("Waiting for Payload") while ((self.spi_read(registers["RFM69_REG_28_IRQ_FLAGS2"]) & registers["RF_IRQFLAGS2_PAYLOADREADY"]) != registers["RF_IRQFLAGS2_PAYLOADREADY"]): pass print ("MODE: %d" % self.spi_read(registers["RFM69_REG_01_OPMODE"])) print ("IRQ Flag: %d" % self.spi_read(registers["RFM69_REG_28_IRQ_FLAGS2"])) self.rxBufLen = self.spi_read(registers["RFM69_REG_00_FIFO"])+1 print ("RX Buffer Length: %d" % self.rxBufLen) self.rxBuf = self.spi_burst_read(registers["RFM69_REG_00_FIFO"], registers["RFM69_FIFO_SIZE"]) self.lastRssi = -(self.spi_read(registers["RFM69_REG_24_RSSI_VALUE"])/2) self.clearFifo() def recv(self): # Store received data for return rxTuple = (self.rxBuf, self.rxBufLen, self.lastRssi) # Clear RX buffer self.rxBufLen = 0 self.rxBuf = bytearray(registers["RFM69_MAX_MESSAGE_LEN"]) # Return received telemetry return rxTuple def send(self, data, length, power): if (power<2 or power > 20): return False #Dangerous power levels oldMode = self.mode # Copy into TX buffer self.txBuf = data self.txBufLen = length # Start Transmitter print ("OLD MODE: %d" % self.mode) self.set_mode(registers["RFM69_MODE_TX"]) print ("NEW MODE: %d" % self.mode) #Setup PA if (power <= 17): # Set PA Level self.paLevel = power + 14 self.spi_write(registers["RFM69_REG_11_PA_LEVEL"], registers["RF_PALEVEL_PA0_OFF"] | registers["RF_PALEVEL_PA1_ON"] | registers["RF_PALEVEL_PA2_ON"] | self.paLevel ) else: # Disable Over Current Protection self.spi_write(registers["RFM69_REG_13_OCP"], registers["RF_OCP_OFF"]) # Enable High Power Registers self.spi_write(registers["RFM69_REG_5A_TEST_PA1"], 0x5D) self.spi_write(registers["RFM69_REG_5C_TEST_PA2"], 0x7C) # Set PA Level self.paLevel = power + 11 self.spi_write(registers["RFM69_REG_11_PA_LEVEL"], registers["RF_PALEVEL_PA0_OFF"] | registers["RF_PALEVEL_PA1_ON"] | registers["RF_PALEVEL_PA2_ON"] | self.paLevel ) # Wait for PA ramp-up print ("Waiting for PA ramp-up") while((self.spi_read(registers["RFM69_REG_27_IRQ_FLAGS1"]) & registers["RF_IRQFLAGS1_TXREADY"]) != registers["RF_IRQFLAGS1_TXREADY"]): pass # Transmit self.write_fifo(self.txBuf) # Wait for packet to be sent print ("Waiting for packet to be sent") while ((self.spi_read(registers["RFM69_REG_28_IRQ_FLAGS2"]) & registers["RF_IRQFLAGS2_PACKETSENT"]) != registers["RF_IRQFLAGS2_PACKETSENT"]): pass # Return Transceiver to original mode print ("OLD MODE: %d" % self.mode) self.set_mode(oldMode) print ("NEW MODE: %d" % self.mode) # If we were in high power, switch off High Power Registers if (power > 17): self.spi_write(registers["RFM69_REG_5A_TEST_PA1"], 0x55) self.spi_write(registers["RFM69_REG_5C_TEST_PA2"], 0x70) self.spi_write(registers["RFM69_REG_13_OCP"], (registers["RF_OCP_ON"] | registers["RF_OCP_TRIM_95"])) # Clear TX buffer self.txBufLen = 0 self.txBuf = bytearray(registers["RFM69_MAX_MESSAGE_LEN"]) print ("Transmission complete!") def setLnaMode(self, lnaMode): self.spi_write(registers["RFM69_REG_58_TEST_LNA"], lnaMode) def clearFifo(self): self.set_mode(registers["RFM69_MODE_STDBY"]) self.set_mode(registers["RFM69_MODE_RX"]) def readTemp(self): oldMode = self.mode self.set_mode(registers["RFM69_MODE_STDBY"]) self.spi_write(registers["RFM69_REG_4E_TEMP1"], registers["RF_TEMP1_MEAS_START"]) print ("Temp Measurement Running") while (self.spi_read(registers["RFM69_REG_4E_TEMP1"]) == registers["RF_TEMP1_MEAS_RUNNING"]): pass rawTemp = self.spi_read(registers["RFM69_REG_4F_TEMP2"]) self.set_mode(oldMode) return (168 - rawTemp) - 5 # Offset and compensate for self-heating def lastRssi(self): return self.lastRssi def sampleRssi(self): # Must only be called in RX mode if (self.mode != registers["RFM69_MODE_RX"]): # Not sure what happens otherwise, so check this return 0 # Trigger RSSI Measurement self.spi_write(registers["RFM69_REG_23_RSSI_CONFIG"], registers["RF_RSSI_START"]) # Wait for Measurement to complete print ("Wait for RSSI") while((self.spi_read(registers["RFM69_REG_23_RSSI_CONFIG"]) & registers["RF_RSSI_DONE"]) != registers["RF_RSSI_DONE"]): pass # Read, store in _lastRssi and return RSSI Value self.lastRssi = -(self.spi_read(registers["RFM69_REG_24_RSSI_VALUE"])/2) return self.lastRssi # Read/Write Functions def spi_read(self, register): data = bytearray(2) data[0] = register & ~0x80 data[1] = 0 resp = bytearray(2) self.nss.low() self.spi.send_recv(data, resp, timeout=5000) self.nss.high() return resp[1] def spi_burst_read(self, register, length): data = bytearray(length+1) data[0] = register & ~0x80 for i in range(1,length+1): data[i] = 0 # We get the length again as the first character of the buffer buf = bytearray(length+1) self.nss.low() self.spi.send_recv(data, buf, timeout=5000) self.nss.high() return buf[1:] def spi_write(self, register, value): data = bytearray(2) data[0] = register | 0x80 data[1] = value self.nss.low() self.spi.send(data, timeout=5000) self.nss.high() def write_fifo(self, data): fifo_data = bytearray(len(data)+2) fifo_data[0] = registers["RFM69_REG_00_FIFO"] | 0x80 fifo_data[1] = len(data) for i in range(2,len(data)+2): fifo_data[i] = data[i-2] self.nss.low() self.spi.send(fifo_data, timeout=5000) self.nss.high()
class SPIFlash: """ MicroPython for SPI Flash. Parameters ---------- nss : (str) CS pin. bus : (int) 1 -> The physical pins of the SPI busses 1 : (NSS, SCK, MISO, MOSI) = (X5, X6, X7, X8) = (PA4, PA5, PA6, PA7) 2 : (NSS, SCK, MISO, MOSI) = (Y5, Y6, Y7, Y8) = (PB12, PB13, PB14, PB15) mode : SPI.MASTER or SPI.SLAVE. baudrate : (int) default=42000000 Returns ------- None Examples -------- >>> import spiflash >>> flash = spiflash.SPIFlash() """ def __init__(self, nss='A4', bus=1, mode=SPI.MASTER, baudrate=42000000): self.__nss = pyb.Pin(nss) self.__nss.init(pyb.Pin.OUT_PP) self.__nss.high() self.spi = SPI(bus, mode, baudrate=baudrate, polarity=0, phase=0) self.__device_id = self.read_id() def __generic_command(self, cmd): self.__nss.low() self.spi.send(cmd) self.__nss.high() def __write_enable(self): self.__generic_command(__SFLASH_WRITE_ENABLE) self.__read_status_register() def __read_status_register(self): """ Status Register bit definitions STATUS_REGISTER_BUSY 0x01 STATUS_REGISTER_WRITE_ENABLED 0x02 STATUS_REGISTER_BLOCK_PROTECTED_0 0x04 STATUS_REGISTER_BLOCK_PROTECTED_1 0x08 STATUS_REGISTER_BLOCK_PROTECTED_2 0x10 [SST & Macronix Only] STATUS_REGISTER_BLOCK_PROTECTED_3 0x20 [SST & Macronix Only] STATUS_REGISTER_AUTO_ADDRESS_INCREMENT 0x40 [SST Only] STATUS_REGISTER_BLOCK_PROTECT_BITS_READ_ONLY 0x80 [SST Only] STATUS_REGISTER_QUAD_ENABLE 0x40 [Macronix Only] STATUS_REGISTER_WRITE_PROTECT_PIN_ENABLE 0x80 [Macronix Only] """ buf = bytearray(1) self.__nss.low() self.spi.send_recv(__SFLASH_READ_STATUS_REGISTER, buf) self.__nss.high() # print('__read_status_register: %s'%ubinascii.hexlify(buf).decode('UTF-8').upper()) return buf[0] def read_id(self): """ Read SPI Flash ID. """ self.wait() self.__nss.low() self.spi.send(__SFLASH_READ_JEDEC_ID) ret = self.spi.recv(3) self.__nss.high() return ubinascii.hexlify(ret).decode('UTF-8').upper() def wait(self, timeout=0): """ Wait. """ while timeout < 1000: if self.__read_status_register() == 0: return True else: timeout += 1 return False def sector_erase(self, addr): """ Sector Erase. """ self.__write_enable() self.__nss.low() self.spi.send(__SFLASH_SECTOR_ERASE) self.spi.send(bytearray([(addr&0x00FF0000)>>16, (addr&0x0000FF00)>>8, addr&0x000000FF])) self.__nss.high() return self.__read_status_register() def chip_erase(self): """ Chip Erase. """ self.__write_enable() self.__generic_command(__SFLASH_CHIP_ERASE2) return self.__read_status_register() def write(self, addr, buf): """ Write data to flash. """ pos = 0 write_size = len(buf) max_write_size = self.page_size() while pos < write_size: size = min(write_size-pos, max_write_size) self.__write_enable() self.__nss.low() self.spi.send(__SFLASH_WRITE) self.spi.send(bytearray([(addr&0x00FF0000)>>16, (addr&0x0000FF00)>>8, addr&0x000000FF])) self.spi.send(buf[pos:pos+size]) self.__nss.high() self.wait() addr += size pos += size return True def read(self, addr, size): """ Read data from flash. """ self.__nss.low() self.spi.send(__SFLASH_READ) self.spi.send(bytearray([(addr&0x00FF0000)>>16, (addr&0x0000FF00)>>8, addr&0x000000FF])) ret = self.spi.recv(size) self.__nss.high() return ret def chip_size(self): """ Get flash size. """ try: return SFLASH_ID_SIZE[self.__device_id] except KeyError: return 0 def page_size(self): """ Read Page Size. Parameters ---------- Returns ------- Flash page size. Examples -------- >>> spi.page_size() 128 """ # Some manufacturers support programming an entire page in one command. try: return SFLASH_PAGE_SIZE[self.__device_id[:2]] except KeyError: return 1
class SerialFlash25: """Class to communicate Serial Flash Memory 25xxxx series with.""" def __init__(self, name: str, size: int, page_size: int, addr_bytes_num: int, spi: int, cs: str, wp: str, block_size=None, sector_size=None, is_chip_erase=False, conn_chk: bool = False) -> None: self.name = name self.size = size self.sector_size = sector_size self.block_size = block_size self.page_size = page_size self.addr_bytes_num = addr_bytes_num self.cs = Pin(cs, Pin.OUT_PP) self.wp = Pin(wp, Pin.OUT_PP) self.spi = SPI(spi, SPI.MASTER, prescaler=128, polarity=0, phase=0) self.conn_chk = conn_chk self.is_chip_erase = is_chip_erase self._pages_count = size // page_size self._sectors_count = size // sector_size if sector_size is not None else None self._blocks_count = size // block_size if block_size is not None else None @_is_available() def read_id(self) -> str: """Read device JEDEC Id.""" self.cs.value(False) result = bytearray(4) self.spi.send_recv(bytearray([CMD_RDID] + [DUMMY_BYTE] * 3), result) # Id always contains 3 bytes self.cs.value(True) res_id = " ".join(["0x%02X" % x for x in result[1:]]) if res_id == "0x00 0x00 0x00": raise RuntimeError( "Either IC is connected incorrectly " "or it doesn't support Read ID (0x%02X) command." % CMD_RDID) return res_id def dump(self, path: str) -> None: """Dump all device contents to binary file.""" if self.conn_chk: self.read_id() if self.sector_size is not None: read_cnt, read_item_size = self._sectors_count, self.sector_size else: read_cnt, read_item_size = self._pages_count, self.page_size makedirs(dirname(path)) with open(path, 'wb') as f: for i in range(0, read_cnt): # dumping is implemented by sectors/pages # because it may be impossible to allocate buffer size of full flash buf = self.read(i * read_item_size, read_item_size) f.write(buf) del buf log.info("Dump finished. %s image -> %s" % (self.name, path)) def program(self, path: str): """Flash binary to device.""" if self.conn_chk: self.read_id() if not isfile(path): raise FileNotFoundError("File not found: '%s'" % path) filesize = getsize(path) if filesize != self.size: raise ValueError( "File size (0x%02X bytes) doesn't equal IC size (0x%02X bytes)" % (filesize, self.size)) self.chip_erase() with open(path, 'rb') as f: for i in range(0, self._pages_count): buf = bytearray(f.read(self.page_size)) self.page_program(i, buf) log.info("Program finished. %s image -> %s" % (path, self.name)) def chip_erase(self) -> None: """Erase chip.""" if self.is_chip_erase: self._wait_wip_reset() self._write_enable() self.cs.value(False) self.spi.send(bytearray([CMD_CE])) self.cs.value(True) self._write_disable() self._wait_wip_reset() else: for i in range(0, self._pages_count): self.page_program(i, bytearray([0xFF] * self.page_size)) log.info("Chip erase finished.") @_is_available("sector_size") def sector_program(self, sector_num: int, bytebuffer: bytearray) -> None: """Program sector with bytes in bytebuffer.""" bytebuffer_len = len(bytebuffer) if sector_num > self._sectors_count: raise ValueError( "Sector number (%d) is more than total sectors number (%d)." % (sector_num, self._sectors_count)) if bytebuffer_len > self.page_size: raise ValueError( "Bytebuffer length (%d) is more than sector size (%d)." % (len(bytebuffer), self.page_size)) self.sector_erase(sector_num) pages_count = bytebuffer_len // self.page_size remain_bytes = bytebuffer_len % self.page_size if remain_bytes != 0: log.warning("sector_program: Bytebuffer is not sector aligned.") start_page = sector_num * self.sector_size // self.page_size for i in range(0, pages_count): self.page_program( start_page + i, bytebuffer[self.page_size * i:self.page_size * (i + 1) + 1]) if remain_bytes != 0: self.page_program(start_page + pages_count, bytebuffer[self.page_size * pages_count:]) log.info('Sector %d program finished.' % sector_num) @_is_available("sector_size") def sector_erase(self, sector_num: int) -> None: """Erase specified sector.""" if sector_num > self._sectors_count: raise ValueError( "Sector number (%d) is more than total sectors number (%d)." % (sector_num, self._sectors_count)) addr = sector_num * self.sector_size self._wait_wip_reset() self._write_enable() self.cs.value(False) self.spi.send( bytearray([CMD_SE]) + addr.to_bytes(self.addr_bytes_num, "big")) self.cs.value(True) self._write_disable() self._wait_wip_reset() log.info("Sector %d erase finished." % sector_num) @_is_available("block_size") def block_erase(self, block_num: int) -> None: """Erase specified block.""" if block_num > self._blocks_count: raise ValueError( "Block number (%d) is more than total block number (%d)." % (block_num, self._blocks_count)) addr = block_num * self.sector_size self._wait_wip_reset() self._write_enable() self.cs.value(False) self.spi.send( bytearray([CMD_BE]) + addr.to_bytes(self.addr_bytes_num, "big")) self.cs.value(True) self._write_disable() self._wait_wip_reset() log.info("Block %d erase finished." % block_num) def read(self, offset: int, size: int) -> bytearray: """Read data from specified offset using specified size.""" if (offset > self.size) or (offset + size > self.size): raise ValueError( "Read data from 0x%02X-0x%02X is out of range. Max address is 0x%02X." % (offset, offset + size, self.size)) self.cs.value(False) self.spi.send( bytearray([CMD_READ]) + offset.to_bytes(self.addr_bytes_num, "big")) result = bytearray(size) self.spi.send_recv(bytearray([DUMMY_BYTE] * size), result) self.cs.value(True) log.info("Data read 0x%02X-0x%02X finished." % (offset, offset + size)) return result def page_program(self, page_num: int, bytebuffer: bytearray) -> None: """Program page with bytes in bytebuffer""" if page_num > self._pages_count: raise ValueError( "Page number (%d) is more than total pages number (%d)." % (page_num, self._pages_count)) if len(bytebuffer) > self.page_size: raise ValueError( "Bytebuffer length (%d) is more than page size (%d)." % (len(bytebuffer), self.page_size)) addr = page_num * self.page_size self._wait_wip_reset() self._write_enable() self.cs.value(False) self.spi.send( bytearray([CMD_PP]) + addr.to_bytes(self.addr_bytes_num, "big")) self.spi.send(bytebuffer) self.cs.value(True) self._write_disable() self._wait_wip_reset() log.info('Page %d program finished.' % page_num) def _wait_wip_reset(self) -> None: """Wait for WIP=0. WIP is bit0 in Status Register.""" sr = self.read_sr() while sr & SR_WIP: sr = self.read_sr() def _write_enable(self) -> None: """Enable Write operation via command.""" self.cs.value(False) self.spi.send(bytearray([CMD_WREN])) self.cs.value(True) def _write_disable(self) -> None: """Disable Write operation via command.""" self.cs.value(False) self.spi.send(bytearray([CMD_WRDI])) self.cs.value(True) def read_sr(self): """Read status register.""" result = bytearray(2) self.cs.value(False) self.spi.send_recv(bytearray([CMD_RDSR, DUMMY_BYTE]), result) self.cs.value(True) return result[1] def write_sr(self, sr_val: int) -> None: """Write status register.""" self._write_enable() self.cs.value(False) self.spi.send(bytearray([CMD_WRSR, sr_val & 0xFF])) self.cs.value(True) self._write_disable()
# See pyb.UART. from pyb import UART uart = UART(1, 9600) uart.write("hello") uart.read(5) # read up to 5 bytes # SPI bus from pyb import SPI spi = SPI(1, SPI.CONTROLLER, baudrate=200000, polarity=1, phase=0) spi.send("hello") spi.recv(5) # receive 5 bytes on the bus spi.send_recv("hello") # send and receive 5 bytes # I2C bus from machine import I2C i2c = I2C("X", freq=400000) # create hardware I2c object i2c = I2C(scl="X1", sda="X2", freq=100000) # create software I2C object i2c.scan() # returns list of peripheral addresses i2c.writeto(0x42, "hello") # write 5 bytes to peripheral with address 0x42 i2c.readfrom(0x42, 5) # read 5 bytes from peripheral i2c.readfrom_mem( 0x42, 0x10, 2) # read 2 bytes from peripheral 0x42, peripheral memory 0x10 i2c.writeto_mem(