357 lines
11 KiB
Python
357 lines
11 KiB
Python
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)
|
|
|