class CoreMemDriver(object): def __init__(self): # Instanciate a SPI controller self._spi = SpiController() # Configure the first interface (IF/1) of the FTDI device as a SPI master self._spi.configure('ftdi://ftdi:2232h/2') # Get a SPI port to a SPI slave w/ /CS on A*BUS3 and SPI mode 0 @ 12MHz self._slave = self._spi.get_port(cs=1, freq=500e3, mode=0) def read_miso(self): """Return the current value of the MISO input pin as a bool """ # MISO is on D2 bit of port if self._spi.read_gpio() & (1 << 2): return True else: return False def wait_for_not_busy(self): """Block until the MISO busy signal indicates the chip is ready for a transaction """ # Whenever a SPI transaction is not in progress (i.e. CSn==1), the MISO signal doubles as # a busy inidicator. High indicates busy, and low indicates ready. The only time the # chip will assert busy is after a read/write memory operation, as it cannot take another # command until it completes the current one. MAXWAIT = 0.5 # time to wait in seconds timeout = time.monotonic() + MAXWAIT while time.monotonic() < timeout: time.sleep(0.01) if not self.read_miso(): return raise RuntimeError("Timeout waiting for BUSY signal to go low") def spi_read(self, addr): """Read SPI register and return 8-bit value """ read = self._slave.exchange([addr], 1) return read[0] def spi_write(self, addr, value): """Write SPI register with 8-bit value """ self._slave.exchange([0x80 + addr, value]) def mem_read(self, addr): """Read a byte of memory data """ self.wait_for_not_busy() self.spi_write(ADDR_REG, addr) self.spi_write(CTRL_REG, CTRL_READ_MASK) self.wait_for_not_busy() return self.spi_read(DATA_REG) def mem_write(self, addr, value): """Write a byte of memory data """ self.wait_for_not_busy() self.spi_write(ADDR_REG, addr) self.spi_write(DATA_REG, value) self.spi_write(CTRL_REG, CTRL_WRITE_MASK) def set_vdrive(self, value): """Set the VDRIVE digital pot value value is 16-bit """ self.spi_write(VDRIVE_H_REG, value >> 8) self.spi_write(VDRIVE_L_REG, value & 0xff) def read_vdrive(self): value = 0 value += self.spi_read(VDRIVE_H_REG) << 8 value += self.spi_read(VDRIVE_L_REG) return value def set_vthresh(self, value): """Set the VTHRESH digital pot value value is 16-bit """ self.spi_write(VTHRESH_H_REG, value >> 8) self.spi_write(VTHRESH_L_REG, value & 0xff) def read_vthresh(self): value = 0 value += self.spi_read(VTHRESH_H_REG) << 8 value += self.spi_read(VTHRESH_L_REG) return value def set_sensedelay(self, value): """Set the SENSEDELAY register value value is 8-bit """ self.spi_write(SENSEDELAY_REG, value) def read_sensedelay(self): return self.spi_read(SENSEDELAY_REG) def updatepot(self): """Trigger a write to digital pot This must be called after changing vdrive or vthresh to flush the new value out to the digital pot. """ self.wait_for_not_busy() self.spi_write(CTRL_REG, CTRL_UPDATEPOT_MASK)