from abc import abstractmethod from time import sleep class I2CInterface: @abstractmethod def read(self, addr: int, length: int) -> bytes: pass @abstractmethod def write(self, addr: int, data: bytes) -> None: pass @abstractmethod def write_read(self, addr: int, data: bytes, length: int) -> bytes: pass @abstractmethod def open(self) -> None: pass @abstractmethod def close(self) -> None: pass class I2CException(Exception): pass class DevI2CInterface(I2CInterface): def __init__(self, bus) -> None: super().__init__() from smbus2 import SMBus, i2c_msg self.bus = SMBus(bus) self.msg = i2c_msg def read(self, addr: int, length: int) -> bytes: m = self.msg.read(addr, length) self.bus.i2c_rdwr(m) return bytes(m.buf[0:length]) def write(self, addr: int, data: bytes) -> None: m = self.msg.write(addr, data) self.bus.i2c_rdwr(m) def write_read(self, addr: int, data: bytes, length: int) -> bytes: mw = self.msg.write(addr, data) mr = self.msg.read(addr, length) self.bus.i2c_rdwr(mw, mr) return bytes(mr.buf[0:length]) def open(self) -> None: pass def close(self) -> None: pass class JLinkSwdI2CInterface(I2CInterface): GPIO_BASE = { 'PA': 0x40010800, 'PB': 0x40010C00, 'PC': 0x40011000, 'PD': 0x40011400, 'PE': 0x40011800, } GPIO_REGS = { 'CRL': 0x00, 'CRH': 0x04, 'IDR': 0x08, 'ODR': 0x0C, 'BSRR': 0x10, 'BRR': 0x14, 'LCKR': 0x18 } BIT_TIME = (1/100000) / 2 def __init__(self, jlink_serial=None, chip_id='STM32F105RB', sda='PB7', scl='PB6') -> None: super().__init__() from pylink import JLink self.jlink = JLink() if not self.jlink.connected(): self.jlink.open(serial_no=jlink_serial) self.chip_id = chip_id self.sda = (JLinkSwdI2CInterface.GPIO_BASE[sda.upper()[0:2]], int(sda[2])) self.scl = (JLinkSwdI2CInterface.GPIO_BASE[scl.upper()[0:2]], int(scl[2])) def open(self) -> None: from pylink.enums import JLinkInterfaces super().open() if not self.jlink.target_connected(): self.jlink.set_tif(JLinkInterfaces.SWD) self.jlink.connect(self.chip_id) assert self.jlink.halt(), 'STM32 could not be halted' self._set_pin_od(self.scl) self._set_pin_od(self.sda) def close(self) -> None: if self.jlink.target_connected(): if not self.jlink.halted(): self.jlink.halt() self.jlink.reset(halt=False) self.jlink.close() return super().close() def read(self, addr: int, length: int) -> bytes: self._send_start() JLinkSwdI2CInterface._bit_sleep() ack = self._send_byte((addr << 1) | 1) JLinkSwdI2CInterface._bit_sleep() if not ack: raise I2CInterface.I2CException('addr not acked') data = [] for _ in range(length-1): data.append(self._recv_byte()) JLinkSwdI2CInterface._bit_sleep() data.append(self._recv_byte(ack=False)) JLinkSwdI2CInterface._bit_sleep() self._send_stop() return bytes(data) def write(self, addr: int, data: bytes) -> None: self._send_start() JLinkSwdI2CInterface._bit_sleep() ack = self._send_byte(addr << 1) JLinkSwdI2CInterface._bit_sleep() if not ack: raise I2CInterface.I2CException('addr not acked') for b in data: ack = self._send_byte(b) if not ack: raise I2CInterface.I2CException('data not acked') JLinkSwdI2CInterface._bit_sleep() self._send_stop() def write_read(self, addr: int, data: bytes, length: int) -> bytes: self._send_start() ack = self._send_byte(addr << 1) if not ack: raise I2CInterface.I2CException('W addr not acked') for b in data: ack = self._send_byte(b) if not ack: raise I2CInterface.I2CException('data not acked') self._send_start() ack = self._send_byte((addr << 1) | 1) if not ack: raise I2CInterface.I2CException('R addr not acked') data = [] for _ in range(length): data.append(self._recv_byte()) self._send_stop() @classmethod def _bit_sleep(cls): # pass sleep(cls.BIT_TIME) def _rmw(self, addr, offset, size, val) -> None: mask = ((2**size)-1) << offset nmask = 0xFFFFFFFF ^ mask reg_val = self.jlink.memory_read32(addr, 1)[0] reg_val &= nmask reg_val |= (val << offset) & mask self.jlink.memory_write32(addr, [reg_val]) def _set_pin_od(self, pin) -> None: cr = JLinkSwdI2CInterface.GPIO_REGS['CRH'] if pin[1] >= 8 else JLinkSwdI2CInterface.GPIO_REGS['CRL'] pin_off = 4 * (pin[1]-8 if pin[1] >= 8 else pin[1]) self._rmw(pin[0] + cr, pin_off, 4, 0b1000) self._set_pin(pin, True) self._rmw(pin[0] + cr, pin_off, 4, 0b0110) def _set_pin(self, pin, state: bool): reg = JLinkSwdI2CInterface.GPIO_REGS['BSRR'] if state else JLinkSwdI2CInterface.GPIO_REGS['BRR'] mask = 1 << pin[1] self.jlink.memory_write16(pin[0] + reg, [mask]) def _get_pin(self, pin) -> bool: mask = 1 << pin[1] reg_val = self.jlink.memory_read16(pin[0] + JLinkSwdI2CInterface.GPIO_REGS['IDR'], 1)[0] return bool(reg_val & mask) def _send_start(self) -> None: self._set_pin(self.sda, True) JLinkSwdI2CInterface._bit_sleep() self._set_pin(self.scl, True) JLinkSwdI2CInterface._bit_sleep() self._set_pin(self.sda, False) JLinkSwdI2CInterface._bit_sleep() self._set_pin(self.scl, False) JLinkSwdI2CInterface._bit_sleep() def _send_byte(self, val) -> bool: self._set_pin(self.scl, False) JLinkSwdI2CInterface._bit_sleep() for i in range(8): bit = bool(val & (0x80 >> i)) self._set_pin(self.sda, bit) JLinkSwdI2CInterface._bit_sleep() self._set_pin(self.scl, True) JLinkSwdI2CInterface._bit_sleep() self._set_pin(self.scl, False) JLinkSwdI2CInterface._bit_sleep() self._set_pin(self.sda, True) JLinkSwdI2CInterface._bit_sleep() self._set_pin(self.scl, True) JLinkSwdI2CInterface._bit_sleep() ack = not self._get_pin(self.sda) self._set_pin(self.scl, False) JLinkSwdI2CInterface._bit_sleep() return ack def _recv_byte(self, ack=True) -> int: val = 0 self._set_pin(self.scl, False) JLinkSwdI2CInterface._bit_sleep() self._set_pin(self.sda, True) JLinkSwdI2CInterface._bit_sleep() for i in range(8): self._set_pin(self.scl, True) JLinkSwdI2CInterface._bit_sleep() bit = self._get_pin(self.sda) if bit: val |= (0x80 >> i) self._set_pin(self.scl, False) JLinkSwdI2CInterface._bit_sleep() self._set_pin(self.sda, not ack) JLinkSwdI2CInterface._bit_sleep() self._set_pin(self.scl, True) JLinkSwdI2CInterface._bit_sleep() self._set_pin(self.scl, False) JLinkSwdI2CInterface._bit_sleep() return val def _send_stop(self): self._set_pin(self.scl, False) JLinkSwdI2CInterface._bit_sleep() self._set_pin(self.sda, False) JLinkSwdI2CInterface._bit_sleep() self._set_pin(self.scl, True) JLinkSwdI2CInterface._bit_sleep() self._set_pin(self.sda, True) JLinkSwdI2CInterface._bit_sleep() # class JLinkSwdI2CInterface_I2C(I2CInterface): # def __init__(self, jlink_serial=None) -> None: # super().__init__() # from pylink import JLink # self.jlink = JLink() # if not self.jlink.connected(): # self.jlink.open(serial_no=jlink_serial) # self.chip_id = 'STM32F105RB' # def open(self) -> None: # from pylink.enums import JLinkInterfaces # super().open() # if not self.jlink.target_connected(): # self.jlink.set_tif(JLinkInterfaces.SWD) # self.jlink.connect(self.chip_id) # assert self.jlink.halt(), 'STM32 could not be halted' # self._rmw(0x40010C00,24,8,0b10001000) # self. # self._rmw(0x40010C00,24,8,0b11101110) # def close(self) -> None: # if self.jlink.target_connected(): # if not self.jlink.halted(): # self.jlink.halt() # self.jlink.reset(halt=False) # self.jlink.close() # return super().close() # def read(self, addr: int, length: int) -> bytes: # self._send_start() # JLinkSwdI2CInterface._bit_sleep() # ack = self._send_byte((addr << 1) | 1) # JLinkSwdI2CInterface._bit_sleep() # if not ack: # raise I2CInterface.I2CException('addr not acked') # data = [] # for _ in range(length-1): # data.append(self._recv_byte()) # JLinkSwdI2CInterface._bit_sleep() # data.append(self._recv_byte(ack=False)) # JLinkSwdI2CInterface._bit_sleep() # self._send_stop() # return bytes(data) # def write(self, addr: int, data: bytes) -> None: # self._send_start() # JLinkSwdI2CInterface._bit_sleep() # ack = self._send_byte(addr << 1) # JLinkSwdI2CInterface._bit_sleep() # if not ack: # raise I2CInterface.I2CException('addr not acked') # for b in data: # ack = self._send_byte(b) # if not ack: # raise I2CInterface.I2CException('data not acked') # JLinkSwdI2CInterface._bit_sleep() # self._send_stop() # def write_read(self, addr: int, data: bytes, length: int) -> bytes: # self._send_start() # ack = self._send_byte(addr << 1) # if not ack: # raise I2CInterface.I2CException('W addr not acked') # for b in data: # ack = self._send_byte(b) # if not ack: # raise I2CInterface.I2CException('data not acked') # self._send_start() # ack = self._send_byte((addr << 1) | 1) # if not ack: # raise I2CInterface.I2CException('R addr not acked') # data = [] # for _ in range(length): # data.append(self._recv_byte()) # self._send_stop() # def _rmw(self, addr, offset, size, val) -> None: # mask = ((2**size)-1) << offset # nmask = 0xFFFFFFFF ^ mask # reg_val = self.jlink.memory_read32(addr, 1)[0] # reg_val &= nmask # reg_val |= (val << offset) & mask # self.jlink.memory_write32(addr, [reg_val]) # def _set_pin_af_od(self, pin) -> None: # cr = 4 if pin[1] >= 8 else 0 # pin_off = 4 * (pin[1]-8 if pin[1] >= 8 else pin[1]) # self._rmw(pin[0] + cr, pin_off, 4, 0b1000) # self._set_pin(pin, True) # self._rmw(pin[0] + cr, pin_off, 4, 0b1110)