[WIP] add: MC2512 on ESP32 support

This commit is contained in:
Rob 2022-11-26 20:58:35 +01:00
parent e4411e85af
commit 40310758ea
13 changed files with 1407 additions and 0 deletions

90
ESP32/main.py Normal file
View File

@ -0,0 +1,90 @@
"""
Following SPI drivers are supported, please adjust by your hardware
from .src import SPIESP8286 as SPI
from .src import SPIESP32 as SPI
The CAN driver can be initialized with default baudrate 10MHz
CAN(SPI(cs=YOUR_SPI_CS_PIN)) or
CAN(SPI(cs=YOUR_SPI_CS_PIN, baudrate=YOUR_DESIRED_BAUDRATE))
And here is an example to set filter for extended frame with ID 0x12345678
can.setFilter(RXF.RXF0, True, 0x12345678 | CAN_EFF_FLAG)
can.setFilterMask(MASK.MASK0, True, 0x1FFFFFFF | CAN_EFF_FLAG)
can.setFilterMask(MASK.MASK1, True, 0x1FFFFFFF | CAN_EFF_FLAG)
"""
import time
from src import (
CAN,
CAN_CLOCK,
CAN_EFF_FLAG,
CAN_ERR_FLAG,
CAN_RTR_FLAG,
CAN_SPEED,
ERROR,
)
from src import SPIESP32 as SPI
from src import CANFrame
def main() -> None:
# Initialization
can = CAN(SPI(cs=23))
# Configuration
if can.reset() != ERROR.ERROR_OK:
print("Can not reset for MCP2515")
return
if can.setBitrate(CAN_SPEED.CAN_250KBPS, CAN_CLOCK.MCP_8MHZ) != ERROR.ERROR_OK:
print("Can not set bitrate for MCP2515")
return
if can.setNormalMode() != ERROR.ERROR_OK:
print("Can not set normal mode for MCP2515")
return
# Prepare frames
data = b"\x12\x34\x56\x78\x9A\xBC\xDE\xF0" # type: bytes
sff_frame = CANFrame(can_id=0x7FF, data=data)
sff_none_data_frame = CANFrame(can_id=0x7FF)
err_frame = CANFrame(can_id=0x7FF | CAN_ERR_FLAG, data=data)
eff_frame = CANFrame(can_id=0x12345678 | CAN_EFF_FLAG, data=data)
eff_none_data_frame = CANFrame(can_id=0x12345678 | CAN_EFF_FLAG)
rtr_frame = CANFrame(can_id=0x7FF | CAN_RTR_FLAG)
rtr_with_eid_frame = CANFrame(can_id=0x12345678 | CAN_RTR_FLAG | CAN_EFF_FLAG)
rtr_with_data_frame = CANFrame(can_id=0x7FF | CAN_RTR_FLAG, data=data)
frames = [
sff_frame,
sff_none_data_frame,
err_frame,
eff_frame,
eff_none_data_frame,
rtr_frame,
rtr_with_eid_frame,
rtr_with_data_frame,
]
# Read all the time and send message in each second
end_time, n = time.ticks_add(time.ticks_ms(), 1000), -1 # type: ignore
while True:
error, iframe = can.readMessage()
if error == ERROR.ERROR_OK:
print("RX {}".format(iframe))
if time.ticks_diff(time.ticks_ms(), end_time) >= 0: # type: ignore
end_time = time.ticks_add(time.ticks_ms(), 1000) # type: ignore
n += 1
n %= len(frames)
error = can.sendMessage(frames[n])
if error == ERROR.ERROR_OK:
print("TX {}".format(frames[n]))
else:
print("TX failed with error code {}".format(error))
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
pass

4
ESP32/src/__init__.py Normal file
View File

@ -0,0 +1,4 @@
from .can import CAN_CLOCK, CAN_SPEED, ERROR
from .can.can import CAN_EFF_FLAG, CAN_ERR_FLAG, CAN_RTR_FLAG, CANFrame
from .can.mcp2515 import CAN
from .spi.spi_esp32 import SPIESP32

630
ESP32/src/can/__init__.py Normal file
View File

@ -0,0 +1,630 @@
#
# speed 8M
#
MCP_8MHz_1000kBPS_CFG1 = 0x00
MCP_8MHz_1000kBPS_CFG2 = 0x80
MCP_8MHz_1000kBPS_CFG3 = 0x80
MCP_8MHz_500kBPS_CFG1 = 0x00
MCP_8MHz_500kBPS_CFG2 = 0x90
MCP_8MHz_500kBPS_CFG3 = 0x82
MCP_8MHz_250kBPS_CFG1 = 0x00
MCP_8MHz_250kBPS_CFG2 = 0xB1
MCP_8MHz_250kBPS_CFG3 = 0x85
MCP_8MHz_200kBPS_CFG1 = 0x00
MCP_8MHz_200kBPS_CFG2 = 0xB4
MCP_8MHz_200kBPS_CFG3 = 0x86
MCP_8MHz_125kBPS_CFG1 = 0x01
MCP_8MHz_125kBPS_CFG2 = 0xB1
MCP_8MHz_125kBPS_CFG3 = 0x85
MCP_8MHz_100kBPS_CFG1 = 0x01
MCP_8MHz_100kBPS_CFG2 = 0xB4
MCP_8MHz_100kBPS_CFG3 = 0x86
MCP_8MHz_80kBPS_CFG1 = 0x01
MCP_8MHz_80kBPS_CFG2 = 0xBF
MCP_8MHz_80kBPS_CFG3 = 0x87
MCP_8MHz_50kBPS_CFG1 = 0x03
MCP_8MHz_50kBPS_CFG2 = 0xB4
MCP_8MHz_50kBPS_CFG3 = 0x86
MCP_8MHz_40kBPS_CFG1 = 0x03
MCP_8MHz_40kBPS_CFG2 = 0xBF
MCP_8MHz_40kBPS_CFG3 = 0x87
MCP_8MHz_33k3BPS_CFG1 = 0x47
MCP_8MHz_33k3BPS_CFG2 = 0xE2
MCP_8MHz_33k3BPS_CFG3 = 0x85
MCP_8MHz_31k25BPS_CFG1 = 0x07
MCP_8MHz_31k25BPS_CFG2 = 0xA4
MCP_8MHz_31k25BPS_CFG3 = 0x84
MCP_8MHz_20kBPS_CFG1 = 0x07
MCP_8MHz_20kBPS_CFG2 = 0xBF
MCP_8MHz_20kBPS_CFG3 = 0x87
MCP_8MHz_10kBPS_CFG1 = 0x0F
MCP_8MHz_10kBPS_CFG2 = 0xBF
MCP_8MHz_10kBPS_CFG3 = 0x87
MCP_8MHz_5kBPS_CFG1 = 0x1F
MCP_8MHz_5kBPS_CFG2 = 0xBF
MCP_8MHz_5kBPS_CFG3 = 0x87
#
# speed 16M
#
MCP_16MHz_1000kBPS_CFG1 = 0x00
MCP_16MHz_1000kBPS_CFG2 = 0xD0
MCP_16MHz_1000kBPS_CFG3 = 0x82
MCP_16MHz_500kBPS_CFG1 = 0x00
MCP_16MHz_500kBPS_CFG2 = 0xF0
MCP_16MHz_500kBPS_CFG3 = 0x86
MCP_16MHz_250kBPS_CFG1 = 0x41
MCP_16MHz_250kBPS_CFG2 = 0xF1
MCP_16MHz_250kBPS_CFG3 = 0x85
MCP_16MHz_200kBPS_CFG1 = 0x01
MCP_16MHz_200kBPS_CFG2 = 0xFA
MCP_16MHz_200kBPS_CFG3 = 0x87
MCP_16MHz_125kBPS_CFG1 = 0x03
MCP_16MHz_125kBPS_CFG2 = 0xF0
MCP_16MHz_125kBPS_CFG3 = 0x86
MCP_16MHz_100kBPS_CFG1 = 0x03
MCP_16MHz_100kBPS_CFG2 = 0xFA
MCP_16MHz_100kBPS_CFG3 = 0x87
MCP_16MHz_80kBPS_CFG1 = 0x03
MCP_16MHz_80kBPS_CFG2 = 0xFF
MCP_16MHz_80kBPS_CFG3 = 0x87
MCP_16MHz_83k3BPS_CFG1 = 0x03
MCP_16MHz_83k3BPS_CFG2 = 0xBE
MCP_16MHz_83k3BPS_CFG3 = 0x07
MCP_16MHz_50kBPS_CFG1 = 0x07
MCP_16MHz_50kBPS_CFG2 = 0xFA
MCP_16MHz_50kBPS_CFG3 = 0x87
MCP_16MHz_40kBPS_CFG1 = 0x07
MCP_16MHz_40kBPS_CFG2 = 0xFF
MCP_16MHz_40kBPS_CFG3 = 0x87
MCP_16MHz_33k3BPS_CFG1 = 0x4E
MCP_16MHz_33k3BPS_CFG2 = 0xF1
MCP_16MHz_33k3BPS_CFG3 = 0x85
MCP_16MHz_20kBPS_CFG1 = 0x0F
MCP_16MHz_20kBPS_CFG2 = 0xFF
MCP_16MHz_20kBPS_CFG3 = 0x87
MCP_16MHz_10kBPS_CFG1 = 0x1F
MCP_16MHz_10kBPS_CFG2 = 0xFF
MCP_16MHz_10kBPS_CFG3 = 0x87
MCP_16MHz_5kBPS_CFG1 = 0x3F
MCP_16MHz_5kBPS_CFG2 = 0xFF
MCP_16MHz_5kBPS_CFG3 = 0x87
#
# speed 20M
#
MCP_20MHz_1000kBPS_CFG1 = 0x00
MCP_20MHz_1000kBPS_CFG2 = 0xD9
MCP_20MHz_1000kBPS_CFG3 = 0x82
MCP_20MHz_500kBPS_CFG1 = 0x00
MCP_20MHz_500kBPS_CFG2 = 0xFA
MCP_20MHz_500kBPS_CFG3 = 0x87
MCP_20MHz_250kBPS_CFG1 = 0x41
MCP_20MHz_250kBPS_CFG2 = 0xFB
MCP_20MHz_250kBPS_CFG3 = 0x86
MCP_20MHz_200kBPS_CFG1 = 0x01
MCP_20MHz_200kBPS_CFG2 = 0xFF
MCP_20MHz_200kBPS_CFG3 = 0x87
MCP_20MHz_125kBPS_CFG1 = 0x03
MCP_20MHz_125kBPS_CFG2 = 0xFA
MCP_20MHz_125kBPS_CFG3 = 0x87
MCP_20MHz_100kBPS_CFG1 = 0x04
MCP_20MHz_100kBPS_CFG2 = 0xFA
MCP_20MHz_100kBPS_CFG3 = 0x87
MCP_20MHz_83k3BPS_CFG1 = 0x04
MCP_20MHz_83k3BPS_CFG2 = 0xFE
MCP_20MHz_83k3BPS_CFG3 = 0x87
MCP_20MHz_80kBPS_CFG1 = 0x04
MCP_20MHz_80kBPS_CFG2 = 0xFF
MCP_20MHz_80kBPS_CFG3 = 0x87
MCP_20MHz_50kBPS_CFG1 = 0x09
MCP_20MHz_50kBPS_CFG2 = 0xFA
MCP_20MHz_50kBPS_CFG3 = 0x87
MCP_20MHz_40kBPS_CFG1 = 0x09
MCP_20MHz_40kBPS_CFG2 = 0xFF
MCP_20MHz_40kBPS_CFG3 = 0x87
MCP_20MHz_33k3BPS_CFG1 = 0x0B
MCP_20MHz_33k3BPS_CFG2 = 0xFF
MCP_20MHz_33k3BPS_CFG3 = 0x87
class CAN_CLOCK:
MCP_20MHZ = 1
MCP_16MHZ = 2
MCP_8MHZ = 3
class CAN_SPEED:
CAN_5KBPS = 1
CAN_10KBPS = 2
CAN_20KBPS = 3
CAN_31K25BPS = 4
CAN_33KBPS = 5
CAN_40KBPS = 6
CAN_50KBPS = 7
CAN_80KBPS = 8
CAN_83K3BPS = 9
CAN_95KBPS = 10
CAN_100KBPS = 11
CAN_125KBPS = 12
CAN_200KBPS = 13
CAN_250KBPS = 14
CAN_500KBPS = 15
CAN_1000KBPS = 16
class CAN_CLKOUT:
CLKOUT_DISABLE = -1
CLKOUT_DIV1 = 0x0
CLKOUT_DIV2 = 0x1
CLKOUT_DIV4 = 0x2
CLKOUT_DIV8 = 0x3
class ERROR:
ERROR_OK = 0
ERROR_FAIL = 1
ERROR_ALLTXBUSY = 2
ERROR_FAILINIT = 3
ERROR_FAILTX = 4
ERROR_NOMSG = 5
class MASK:
MASK0 = 1
MASK1 = 2
class RXF:
RXF0 = 0
RXF1 = 1
RXF2 = 2
RXF3 = 3
RXF4 = 4
RXF5 = 5
class RXBn:
RXB0 = 0
RXB1 = 1
class TXBn:
TXB0 = 0
TXB1 = 1
TXB2 = 2
class CANINTF:
CANINTF_RX0IF = 0x01
CANINTF_RX1IF = 0x02
CANINTF_TX0IF = 0x04
CANINTF_TX1IF = 0x08
CANINTF_TX2IF = 0x10
CANINTF_ERRIF = 0x20
CANINTF_WAKIF = 0x40
CANINTF_MERRF = 0x80
class EFLG:
EFLG_RX1OVR = 1 << 7
EFLG_RX0OVR = 1 << 6
EFLG_TXBO = 1 << 5
EFLG_TXEP = 1 << 4
EFLG_RXEP = 1 << 3
EFLG_TXWAR = 1 << 2
EFLG_RXWAR = 1 << 1
EFLG_EWARN = 1 << 0
CANCTRL_REQOP = 0xE0
CANCTRL_ABAT = 0x10
CANCTRL_OSM = 0x08
CANCTRL_CLKEN = 0x04
CANCTRL_CLKPRE = 0x03
class CANCTRL_REQOP_MODE:
CANCTRL_REQOP_NORMAL = 0x00
CANCTRL_REQOP_SLEEP = 0x20
CANCTRL_REQOP_LOOPBACK = 0x40
CANCTRL_REQOP_LISTENONLY = 0x60
CANCTRL_REQOP_CONFIG = 0x80
CANCTRL_REQOP_POWERUP = 0xE0
CANSTAT_OPMOD = 0xE0
CANSTAT_ICOD = 0x0E
CNF3_SOF = 0x80
TXB_EXIDE_MASK = 0x08
DLC_MASK = 0x0F
RTR_MASK = 0x40
RXBnCTRL_RXM_STD = 0x20
RXBnCTRL_RXM_EXT = 0x40
RXBnCTRL_RXM_STDEXT = 0x00
RXBnCTRL_RXM_MASK = 0x60
RXBnCTRL_RTR = 0x08
RXB0CTRL_BUKT = 0x04
RXB0CTRL_FILHIT_MASK = 0x03
RXB1CTRL_FILHIT_MASK = 0x07
RXB0CTRL_FILHIT = 0x00
RXB1CTRL_FILHIT = 0x01
MCP_SIDH = 0
MCP_SIDL = 1
MCP_EID8 = 2
MCP_EID0 = 3
MCP_DLC = 4
MCP_DATA = 5
class STAT:
STAT_RX0IF = 1 << 0
STAT_RX1IF = 1 << 1
STAT_RXIF_MASK = STAT.STAT_RX0IF | STAT.STAT_RX1IF
class TXBnCTRL:
TXB_ABTF = 0x40
TXB_MLOA = 0x20
TXB_TXERR = 0x10
TXB_TXREQ = 0x08
TXB_TXIE = 0x04
TXB_TXP = 0x03
EFLG_ERRORMASK = (
EFLG.EFLG_RX1OVR
| EFLG.EFLG_RX0OVR
| EFLG.EFLG_TXBO
| EFLG.EFLG_TXEP
| EFLG.EFLG_RXEP
)
class INSTRUCTION:
INSTRUCTION_WRITE = 0x02
INSTRUCTION_READ = 0x03
INSTRUCTION_BITMOD = 0x05
INSTRUCTION_LOAD_TX0 = 0x40
INSTRUCTION_LOAD_TX1 = 0x42
INSTRUCTION_LOAD_TX2 = 0x44
INSTRUCTION_RTS_TX0 = 0x81
INSTRUCTION_RTS_TX1 = 0x82
INSTRUCTION_RTS_TX2 = 0x84
INSTRUCTION_RTS_ALL = 0x87
INSTRUCTION_READ_RX0 = 0x90
INSTRUCTION_READ_RX1 = 0x94
INSTRUCTION_READ_STATUS = 0xA0
INSTRUCTION_RX_STATUS = 0xB0
INSTRUCTION_RESET = 0xC0
class REGISTER:
MCP_RXF0SIDH = 0x00
MCP_RXF0SIDL = 0x01
MCP_RXF0EID8 = 0x02
MCP_RXF0EID0 = 0x03
MCP_RXF1SIDH = 0x04
MCP_RXF1SIDL = 0x05
MCP_RXF1EID8 = 0x06
MCP_RXF1EID0 = 0x07
MCP_RXF2SIDH = 0x08
MCP_RXF2SIDL = 0x09
MCP_RXF2EID8 = 0x0A
MCP_RXF2EID0 = 0x0B
MCP_CANSTAT = 0x0E
MCP_CANCTRL = 0x0F
MCP_RXF3SIDH = 0x10
MCP_RXF3SIDL = 0x11
MCP_RXF3EID8 = 0x12
MCP_RXF3EID0 = 0x13
MCP_RXF4SIDH = 0x14
MCP_RXF4SIDL = 0x15
MCP_RXF4EID8 = 0x16
MCP_RXF4EID0 = 0x17
MCP_RXF5SIDH = 0x18
MCP_RXF5SIDL = 0x19
MCP_RXF5EID8 = 0x1A
MCP_RXF5EID0 = 0x1B
MCP_TEC = 0x1C
MCP_REC = 0x1D
MCP_RXM0SIDH = 0x20
MCP_RXM0SIDL = 0x21
MCP_RXM0EID8 = 0x22
MCP_RXM0EID0 = 0x23
MCP_RXM1SIDH = 0x24
MCP_RXM1SIDL = 0x25
MCP_RXM1EID8 = 0x26
MCP_RXM1EID0 = 0x27
MCP_CNF3 = 0x28
MCP_CNF2 = 0x29
MCP_CNF1 = 0x2A
MCP_CANINTE = 0x2B
MCP_CANINTF = 0x2C
MCP_EFLG = 0x2D
MCP_TXB0CTRL = 0x30
MCP_TXB0SIDH = 0x31
MCP_TXB0SIDL = 0x32
MCP_TXB0EID8 = 0x33
MCP_TXB0EID0 = 0x34
MCP_TXB0DLC = 0x35
MCP_TXB0DATA = 0x36
MCP_TXB1CTRL = 0x40
MCP_TXB1SIDH = 0x41
MCP_TXB1SIDL = 0x42
MCP_TXB1EID8 = 0x43
MCP_TXB1EID0 = 0x44
MCP_TXB1DLC = 0x45
MCP_TXB1DATA = 0x46
MCP_TXB2CTRL = 0x50
MCP_TXB2SIDH = 0x51
MCP_TXB2SIDL = 0x52
MCP_TXB2EID8 = 0x53
MCP_TXB2EID0 = 0x54
MCP_TXB2DLC = 0x55
MCP_TXB2DATA = 0x56
MCP_RXB0CTRL = 0x60
MCP_RXB0SIDH = 0x61
MCP_RXB0SIDL = 0x62
MCP_RXB0EID8 = 0x63
MCP_RXB0EID0 = 0x64
MCP_RXB0DLC = 0x65
MCP_RXB0DATA = 0x66
MCP_RXB1CTRL = 0x70
MCP_RXB1SIDH = 0x71
MCP_RXB1SIDL = 0x72
MCP_RXB1EID8 = 0x73
MCP_RXB1EID0 = 0x74
MCP_RXB1DLC = 0x75
MCP_RXB1DATA = 0x76
N_TXBUFFERS = 3
N_RXBUFFERS = 2
CAN_CFGS = {
CAN_CLOCK.MCP_8MHZ: {
CAN_SPEED.CAN_5KBPS: [
MCP_8MHz_5kBPS_CFG1,
MCP_8MHz_5kBPS_CFG2,
MCP_8MHz_5kBPS_CFG3,
],
CAN_SPEED.CAN_10KBPS: [
MCP_8MHz_10kBPS_CFG1,
MCP_8MHz_10kBPS_CFG2,
MCP_8MHz_10kBPS_CFG3,
],
CAN_SPEED.CAN_20KBPS: [
MCP_8MHz_20kBPS_CFG1,
MCP_8MHz_20kBPS_CFG2,
MCP_8MHz_20kBPS_CFG3,
],
CAN_SPEED.CAN_31K25BPS: [
MCP_8MHz_31k25BPS_CFG1,
MCP_8MHz_31k25BPS_CFG2,
MCP_8MHz_31k25BPS_CFG3,
],
CAN_SPEED.CAN_33KBPS: [
MCP_8MHz_33k3BPS_CFG1,
MCP_8MHz_33k3BPS_CFG2,
MCP_8MHz_33k3BPS_CFG3,
],
CAN_SPEED.CAN_40KBPS: [
MCP_8MHz_40kBPS_CFG1,
MCP_8MHz_40kBPS_CFG2,
MCP_8MHz_40kBPS_CFG3,
],
CAN_SPEED.CAN_50KBPS: [
MCP_8MHz_50kBPS_CFG1,
MCP_8MHz_50kBPS_CFG2,
MCP_8MHz_50kBPS_CFG3,
],
CAN_SPEED.CAN_80KBPS: [
MCP_8MHz_80kBPS_CFG1,
MCP_8MHz_80kBPS_CFG2,
MCP_8MHz_80kBPS_CFG3,
],
CAN_SPEED.CAN_100KBPS: [
MCP_8MHz_100kBPS_CFG1,
MCP_8MHz_100kBPS_CFG2,
MCP_8MHz_100kBPS_CFG3,
],
CAN_SPEED.CAN_125KBPS: [
MCP_8MHz_125kBPS_CFG1,
MCP_8MHz_125kBPS_CFG2,
MCP_8MHz_125kBPS_CFG3,
],
CAN_SPEED.CAN_200KBPS: [
MCP_8MHz_200kBPS_CFG1,
MCP_8MHz_200kBPS_CFG2,
MCP_8MHz_200kBPS_CFG3,
],
CAN_SPEED.CAN_250KBPS: [
MCP_8MHz_250kBPS_CFG1,
MCP_8MHz_250kBPS_CFG2,
MCP_8MHz_250kBPS_CFG3,
],
CAN_SPEED.CAN_500KBPS: [
MCP_8MHz_500kBPS_CFG1,
MCP_8MHz_500kBPS_CFG2,
MCP_8MHz_500kBPS_CFG3,
],
CAN_SPEED.CAN_1000KBPS: [
MCP_8MHz_1000kBPS_CFG1,
MCP_8MHz_1000kBPS_CFG2,
MCP_8MHz_1000kBPS_CFG3,
],
},
CAN_CLOCK.MCP_16MHZ: {
CAN_SPEED.CAN_5KBPS: [
MCP_16MHz_5kBPS_CFG1,
MCP_16MHz_5kBPS_CFG2,
MCP_16MHz_5kBPS_CFG3,
],
CAN_SPEED.CAN_10KBPS: [
MCP_16MHz_10kBPS_CFG1,
MCP_16MHz_10kBPS_CFG2,
MCP_16MHz_10kBPS_CFG3,
],
CAN_SPEED.CAN_20KBPS: [
MCP_16MHz_20kBPS_CFG1,
MCP_16MHz_20kBPS_CFG2,
MCP_16MHz_20kBPS_CFG3,
],
CAN_SPEED.CAN_33KBPS: [
MCP_16MHz_33k3BPS_CFG1,
MCP_16MHz_33k3BPS_CFG2,
MCP_16MHz_33k3BPS_CFG3,
],
CAN_SPEED.CAN_40KBPS: [
MCP_16MHz_40kBPS_CFG1,
MCP_16MHz_40kBPS_CFG2,
MCP_16MHz_40kBPS_CFG3,
],
CAN_SPEED.CAN_50KBPS: [
MCP_16MHz_50kBPS_CFG1,
MCP_16MHz_50kBPS_CFG2,
MCP_16MHz_50kBPS_CFG3,
],
CAN_SPEED.CAN_80KBPS: [
MCP_16MHz_80kBPS_CFG1,
MCP_16MHz_80kBPS_CFG2,
MCP_16MHz_80kBPS_CFG3,
],
CAN_SPEED.CAN_83K3BPS: [
MCP_16MHz_83k3BPS_CFG1,
MCP_16MHz_83k3BPS_CFG2,
MCP_16MHz_83k3BPS_CFG3,
],
CAN_SPEED.CAN_100KBPS: [
MCP_16MHz_100kBPS_CFG1,
MCP_16MHz_100kBPS_CFG2,
MCP_16MHz_100kBPS_CFG3,
],
CAN_SPEED.CAN_125KBPS: [
MCP_16MHz_125kBPS_CFG1,
MCP_16MHz_125kBPS_CFG2,
MCP_16MHz_125kBPS_CFG3,
],
CAN_SPEED.CAN_200KBPS: [
MCP_16MHz_200kBPS_CFG1,
MCP_16MHz_200kBPS_CFG2,
MCP_16MHz_200kBPS_CFG3,
],
CAN_SPEED.CAN_250KBPS: [
MCP_16MHz_250kBPS_CFG1,
MCP_16MHz_250kBPS_CFG2,
MCP_16MHz_250kBPS_CFG3,
],
CAN_SPEED.CAN_500KBPS: [
MCP_16MHz_500kBPS_CFG1,
MCP_16MHz_500kBPS_CFG2,
MCP_16MHz_500kBPS_CFG3,
],
CAN_SPEED.CAN_1000KBPS: [
MCP_16MHz_1000kBPS_CFG1,
MCP_16MHz_1000kBPS_CFG2,
MCP_16MHz_1000kBPS_CFG3,
],
},
CAN_CLOCK.MCP_20MHZ: {
CAN_SPEED.CAN_33KBPS: [
MCP_20MHz_33k3BPS_CFG1,
MCP_20MHz_33k3BPS_CFG2,
MCP_20MHz_33k3BPS_CFG3,
],
CAN_SPEED.CAN_40KBPS: [
MCP_20MHz_40kBPS_CFG1,
MCP_20MHz_40kBPS_CFG2,
MCP_20MHz_40kBPS_CFG3,
],
CAN_SPEED.CAN_50KBPS: [
MCP_20MHz_50kBPS_CFG1,
MCP_20MHz_50kBPS_CFG2,
MCP_20MHz_50kBPS_CFG3,
],
CAN_SPEED.CAN_80KBPS: [
MCP_20MHz_80kBPS_CFG1,
MCP_20MHz_80kBPS_CFG2,
MCP_20MHz_80kBPS_CFG3,
],
CAN_SPEED.CAN_83K3BPS: [
MCP_20MHz_83k3BPS_CFG1,
MCP_20MHz_83k3BPS_CFG2,
MCP_20MHz_83k3BPS_CFG3,
],
CAN_SPEED.CAN_100KBPS: [
MCP_20MHz_100kBPS_CFG1,
MCP_20MHz_100kBPS_CFG2,
MCP_20MHz_100kBPS_CFG3,
],
CAN_SPEED.CAN_125KBPS: [
MCP_20MHz_125kBPS_CFG1,
MCP_20MHz_125kBPS_CFG2,
MCP_20MHz_125kBPS_CFG3,
],
CAN_SPEED.CAN_200KBPS: [
MCP_20MHz_200kBPS_CFG1,
MCP_20MHz_200kBPS_CFG2,
MCP_20MHz_200kBPS_CFG3,
],
CAN_SPEED.CAN_250KBPS: [
MCP_20MHz_250kBPS_CFG1,
MCP_20MHz_250kBPS_CFG2,
MCP_20MHz_250kBPS_CFG3,
],
CAN_SPEED.CAN_500KBPS: [
MCP_20MHz_500kBPS_CFG1,
MCP_20MHz_500kBPS_CFG2,
MCP_20MHz_500kBPS_CFG3,
],
CAN_SPEED.CAN_1000KBPS: [
MCP_20MHz_1000kBPS_CFG1,
MCP_20MHz_1000kBPS_CFG2,
MCP_20MHz_1000kBPS_CFG3,
],
},
}

90
ESP32/src/can/can.py Normal file
View File

@ -0,0 +1,90 @@
# Special address description flags for the CAN_ID
CAN_EFF_FLAG = 0x80000000 # EFF/SFF is set in the MSB
CAN_RTR_FLAG = 0x40000000 # remote transmission request
CAN_ERR_FLAG = 0x20000000 # error message frame
# Valid bits in CAN ID for frame formats
CAN_SFF_MASK = 0x000007FF # standard frame format (SFF)
CAN_EFF_MASK = 0x1FFFFFFF # extended frame format (EFF)
CAN_ERR_MASK = 0x1FFFFFFF # omit EFF, RTR, ERR flags
CAN_SFF_ID_BITS = 11
CAN_EFF_ID_BITS = 29
# CAN payload length and DLC definitions according to ISO 11898-1
CAN_MAX_DLC = 8
CAN_MAX_DLEN = 8
# CAN ID length
CAN_IDLEN = 4
class CANFrame:
def __init__(self, can_id: int, data: bytes = b"") -> None:
#
# Controller Area Network Identifier structure
#
# bit 0-28 : CAN identifier (11/29 bit)
# bit 29 : error message frame flag (0 = data frame, 1 = error message)
# bit 30 : remote transmission request flag (1 = rtr frame)
# bit 31 : frame format flag (0 = standard 11 bit, 1 = extended 29 bit)
#
# 32 bit CAN ID + EFF/RTR/ERR flags
#
self.can_id = can_id # type: int
self.data = data # type: bytes
@property
def can_id(self) -> int:
return self._can_id
@can_id.setter
def can_id(self, can_id: int) -> None:
self._can_id = can_id
self._arbitration_id = can_id & CAN_EFF_MASK # type: int
@property
def data(self) -> bytes:
return self._data
@data.setter
def data(self, data: bytes) -> None:
self._data = b"" # type: bytes
self._dlc = 0 # frame payload length in byte (0 .. CAN_MAX_DLEN)
if not data:
return
if len(data) > CAN_MAX_DLEN:
raise Exception("The CAN frame data length exceeds the maximum")
self._data = data
self._dlc = len(data)
@property
def arbitration_id(self) -> int:
return self._arbitration_id
@property
def dlc(self) -> int:
return self._dlc
@property
def is_extended_id(self) -> bool:
return bool(self._can_id & CAN_EFF_FLAG)
@property
def is_remote_frame(self) -> bool:
return bool(self._can_id & CAN_RTR_FLAG)
@property
def is_error_frame(self) -> bool:
return bool(self._can_id & CAN_ERR_FLAG)
def __str__(self) -> str:
data = (
"remote request"
if self.is_remote_frame
else " ".join("{:02X}".format(b) for b in self.data)
)
return "{: >8X} [{}] {}".format(self.arbitration_id, self.dlc, data)

491
ESP32/src/can/mcp2515.py Normal file
View File

@ -0,0 +1,491 @@
try:
from typing import Any, Optional, List, Tuple
except ImportError:
pass
import sys
import time
import collections
from ..spi import SPI_HOLD_US
from . import (
CAN_CFGS,
CAN_CLKOUT,
CAN_CLOCK,
CANCTRL_ABAT,
CANCTRL_CLKEN,
CANCTRL_CLKPRE,
CANCTRL_OSM,
CANCTRL_REQOP,
CANCTRL_REQOP_MODE,
CANINTF,
CANSTAT_ICOD,
CANSTAT_OPMOD,
CNF3_SOF,
DLC_MASK,
EFLG,
EFLG_ERRORMASK,
ERROR,
INSTRUCTION,
MASK,
MCP_DATA,
MCP_DLC,
MCP_EID0,
MCP_EID8,
MCP_SIDH,
MCP_SIDL,
N_RXBUFFERS,
N_TXBUFFERS,
REGISTER,
RTR_MASK,
RXB0CTRL_BUKT,
RXB0CTRL_FILHIT,
RXB0CTRL_FILHIT_MASK,
RXB1CTRL_FILHIT,
RXB1CTRL_FILHIT_MASK,
RXF,
STAT,
STAT_RXIF_MASK,
TXB_EXIDE_MASK,
RXBn,
RXBnCTRL_RTR,
RXBnCTRL_RXM_EXT,
RXBnCTRL_RXM_MASK,
RXBnCTRL_RXM_STD,
RXBnCTRL_RXM_STDEXT,
TXBn,
TXBnCTRL,
)
from .can import (
CAN_EFF_FLAG,
CAN_EFF_MASK,
CAN_ERR_FLAG,
CAN_ERR_MASK,
CAN_IDLEN,
CAN_MAX_DLEN,
CAN_RTR_FLAG,
CAN_SFF_MASK,
CANFrame,
)
try:
from pyb import Pin
except ImportError:
from machine import Pin
TXBnREGS = collections.namedtuple("TXBnREGS", "CTRL SIDH DATA")
RXBnREGS = collections.namedtuple("RXBnREGS", "CTRL SIDH DATA CANINTFRXnIF")
TXB = [
TXBnREGS(REGISTER.MCP_TXB0CTRL, REGISTER.MCP_TXB0SIDH, REGISTER.MCP_TXB0DATA),
TXBnREGS(REGISTER.MCP_TXB1CTRL, REGISTER.MCP_TXB1SIDH, REGISTER.MCP_TXB1DATA),
TXBnREGS(REGISTER.MCP_TXB2CTRL, REGISTER.MCP_TXB2SIDH, REGISTER.MCP_TXB2DATA),
]
RXB = [
RXBnREGS(
REGISTER.MCP_RXB0CTRL,
REGISTER.MCP_RXB0SIDH,
REGISTER.MCP_RXB0DATA,
CANINTF.CANINTF_RX0IF,
),
RXBnREGS(
REGISTER.MCP_RXB1CTRL,
REGISTER.MCP_RXB1SIDH,
REGISTER.MCP_RXB1DATA,
CANINTF.CANINTF_RX1IF,
),
]
class CAN:
def __init__(self, SPI: Any) -> None:
self.SPI = SPI # type: Any
self.mcp2515_rx_index = 0
def reset(self) -> int:
self.SPI.start()
self.SPI.transfer(INSTRUCTION.INSTRUCTION_RESET)
self.SPI.end()
time.sleep_ms(10) # type: ignore
zeros = bytearray(14)
self.setRegisters(REGISTER.MCP_TXB0CTRL, zeros)
self.setRegisters(REGISTER.MCP_TXB1CTRL, zeros)
self.setRegisters(REGISTER.MCP_TXB2CTRL, zeros)
self.setRegister(REGISTER.MCP_RXB0CTRL, 0)
self.setRegister(REGISTER.MCP_RXB1CTRL, 0)
self.setRegister(
REGISTER.MCP_CANINTE,
CANINTF.CANINTF_RX0IF
| CANINTF.CANINTF_RX1IF
| CANINTF.CANINTF_ERRIF
| CANINTF.CANINTF_MERRF,
)
# Receives all valid messages with either Standard or Extended Identifiers that
# meet filter criteria. RXF0 is applied for RXB0, RXF1 is applied for RXB1
self.modifyRegister(
REGISTER.MCP_RXB0CTRL,
RXBnCTRL_RXM_MASK | RXB0CTRL_BUKT | RXB0CTRL_FILHIT_MASK,
RXBnCTRL_RXM_STDEXT | RXB0CTRL_BUKT | RXB0CTRL_FILHIT,
)
self.modifyRegister(
REGISTER.MCP_RXB1CTRL,
RXBnCTRL_RXM_MASK | RXB1CTRL_FILHIT_MASK,
RXBnCTRL_RXM_STDEXT | RXB1CTRL_FILHIT,
)
# Clear filters and masks
# Do not filter any standard frames for RXF0 used by RXB0
# Do not filter any extended frames for RXF1 used by RXB1
filters = [RXF.RXF0, RXF.RXF1, RXF.RXF2, RXF.RXF3, RXF.RXF4, RXF.RXF5]
for f in filters:
ext = True if f == RXF.RXF1 else False
result = self.setFilter(f, ext, 0)
if result != ERROR.ERROR_OK:
return result
masks = [MASK.MASK0, MASK.MASK1]
for m in masks:
result = self.setFilterMask(m, True, 0)
if result != ERROR.ERROR_OK:
return result
return ERROR.ERROR_OK
def readRegister(self, reg: int) -> int:
self.SPI.start()
self.SPI.transfer(INSTRUCTION.INSTRUCTION_READ)
self.SPI.transfer(reg)
ret = self.SPI.transfer(read=True)
self.SPI.end()
return ret
def readRegisters(self, reg: int, n: int) -> List[int]:
self.SPI.start()
self.SPI.transfer(INSTRUCTION.INSTRUCTION_READ)
self.SPI.transfer(reg)
# MCP2515 has auto-increment of address-pointer
values = []
for i in range(n):
values.append(self.SPI.transfer(read=True))
self.SPI.end()
return values
def setRegister(self, reg: int, value: int) -> None:
self.SPI.start()
self.SPI.transfer(INSTRUCTION.INSTRUCTION_WRITE)
self.SPI.transfer(reg)
self.SPI.transfer(value)
self.SPI.end()
def setRegisters(self, reg: int, values: bytearray) -> None:
self.SPI.start()
self.SPI.transfer(INSTRUCTION.INSTRUCTION_WRITE)
self.SPI.transfer(reg)
for v in values:
self.SPI.transfer(v)
self.SPI.end()
def modifyRegister(
self, reg: int, mask: int, data: int, spifastend: bool = False
) -> None:
self.SPI.start()
self.SPI.transfer(INSTRUCTION.INSTRUCTION_BITMOD)
self.SPI.transfer(reg)
self.SPI.transfer(mask)
self.SPI.transfer(data)
if not spifastend:
self.SPI.end()
else:
self.SPI._SPICS.value(1)
time.sleep_us(SPI_HOLD_US) # type: ignore
def getStatus(self) -> int:
self.SPI.start()
self.SPI.transfer(INSTRUCTION.INSTRUCTION_READ_STATUS)
i = self.SPI.transfer(read=True)
self.SPI.end()
return i
def setConfigMode(self) -> int:
return self.setMode(CANCTRL_REQOP_MODE.CANCTRL_REQOP_CONFIG)
def setListenOnlyMode(self) -> int:
return self.setMode(CANCTRL_REQOP_MODE.CANCTRL_REQOP_LISTENONLY)
def setSleepMode(self) -> int:
return self.setMode(CANCTRL_REQOP_MODE.CANCTRL_REQOP_SLEEP)
def setLoopbackMode(self) -> int:
return self.setMode(CANCTRL_REQOP_MODE.CANCTRL_REQOP_LOOPBACK)
def setNormalMode(self) -> int:
return self.setMode(CANCTRL_REQOP_MODE.CANCTRL_REQOP_NORMAL)
def setMode(self, mode: int) -> int:
self.modifyRegister(REGISTER.MCP_CANCTRL, CANCTRL_REQOP, mode)
endTime = time.ticks_add(time.ticks_ms(), 10) # type: ignore
modeMatch = False
while time.ticks_diff(time.ticks_ms(), endTime) < 0: # type: ignore
newmode = self.readRegister(REGISTER.MCP_CANSTAT)
newmode &= CANSTAT_OPMOD
modeMatch = newmode == mode
if modeMatch:
break
return ERROR.ERROR_OK if modeMatch else ERROR.ERROR_FAIL
def setBitrate(self, canSpeed: int, canClock: int = CAN_CLOCK.MCP_16MHZ) -> int:
error = self.setConfigMode()
if error != ERROR.ERROR_OK:
return error
set_ = 1
try:
cfg1, cfg2, cfg3 = CAN_CFGS[canClock][canSpeed]
except KeyError:
set_ = 0
if set_:
self.setRegister(REGISTER.MCP_CNF1, cfg1)
self.setRegister(REGISTER.MCP_CNF2, cfg2)
self.setRegister(REGISTER.MCP_CNF3, cfg3)
return ERROR.ERROR_OK
return ERROR.ERROR_FAIL
def setClkOut(self, divisor: int) -> int:
if divisor == CAN_CLKOUT.CLKOUT_DISABLE:
# Turn off CLKEN
self.modifyRegister(REGISTER.MCP_CANCTRL, CANCTRL_CLKEN, 0x00)
# Turn on CLKOUT for SOF
self.modifyRegister(REGISTER.MCP_CNF3, CNF3_SOF, CNF3_SOF)
return ERROR.ERROR_OK
# Set the prescaler (CLKPRE)
self.modifyRegister(REGISTER.MCP_CANCTRL, CANCTRL_CLKPRE, divisor)
# Turn on CLKEN
self.modifyRegister(REGISTER.MCP_CANCTRL, CANCTRL_CLKEN, CANCTRL_CLKEN)
# Turn off CLKOUT for SOF
self.modifyRegister(REGISTER.MCP_CNF3, CNF3_SOF, 0x00)
return ERROR.ERROR_OK
def prepareId(self, ext: int, id_: int) -> bytearray:
canid = id_ & 0xFFFF
buffer = bytearray(CAN_IDLEN)
if ext:
buffer[MCP_EID0] = canid & 0xFF
buffer[MCP_EID8] = canid >> 8
canid = id_ >> 16
buffer[MCP_SIDL] = canid & 0x03
buffer[MCP_SIDL] += (canid & 0x1C) << 3
buffer[MCP_SIDL] |= TXB_EXIDE_MASK
buffer[MCP_SIDH] = canid >> 5
else:
buffer[MCP_SIDH] = canid >> 3
buffer[MCP_SIDL] = (canid & 0x07) << 5
buffer[MCP_EID0] = 0
buffer[MCP_EID8] = 0
return buffer
def setFilterMask(self, mask: int, ext: int, ulData: int) -> int:
res = self.setConfigMode()
if res != ERROR.ERROR_OK:
return res
reg = None
if mask == MASK.MASK0:
reg = REGISTER.MCP_RXM0SIDH
elif mask == MASK.MASK1:
reg = REGISTER.MCP_RXM1SIDH
else:
return ERROR.ERROR_FAIL
tbufdata = self.prepareId(ext, ulData)
self.setRegisters(reg, tbufdata)
return ERROR.ERROR_OK
def setFilter(self, ft: int, ext: int, ulData: int) -> int:
res = self.setConfigMode()
if res != ERROR.ERROR_OK:
return res
reg = None
if ft == RXF.RXF0:
reg = REGISTER.MCP_RXF0SIDH
elif ft == RXF.RXF1:
reg = REGISTER.MCP_RXF1SIDH
elif ft == RXF.RXF2:
reg = REGISTER.MCP_RXF2SIDH
elif ft == RXF.RXF3:
reg = REGISTER.MCP_RXF3SIDH
elif ft == RXF.RXF4:
reg = REGISTER.MCP_RXF4SIDH
elif ft == RXF.RXF5:
reg = REGISTER.MCP_RXF5SIDH
else:
return ERROR.ERROR_FAIL
tbufdata = self.prepareId(ext, ulData)
self.setRegisters(reg, tbufdata)
return ERROR.ERROR_OK
def sendMessage(self, frame: Any, txbn: Optional[int] = None) -> int:
if txbn is None:
return self.sendMessage_(frame)
if frame.dlc > CAN_MAX_DLEN:
return ERROR.ERROR_FAILTX
txbuf = TXB[txbn]
ext = frame.can_id & CAN_EFF_FLAG
rtr = frame.can_id & CAN_RTR_FLAG
id_ = frame.can_id & (CAN_EFF_MASK if ext else CAN_SFF_MASK)
data = self.prepareId(ext, id_)
mcp_dlc = (frame.dlc | RTR_MASK) if rtr else frame.dlc
data.extend(bytearray(1 + frame.dlc))
data[MCP_DLC] = mcp_dlc
data[MCP_DATA : MCP_DATA + frame.dlc] = frame.data
self.setRegisters(txbuf.SIDH, data)
self.modifyRegister(
txbuf.CTRL, TXBnCTRL.TXB_TXREQ, TXBnCTRL.TXB_TXREQ, spifastend=True
)
ctrl = self.readRegister(txbuf.CTRL)
if ctrl & (TXBnCTRL.TXB_ABTF | TXBnCTRL.TXB_MLOA | TXBnCTRL.TXB_TXERR):
return ERROR.ERROR_FAILTX
return ERROR.ERROR_OK
def sendMessage_(self, frame: Any) -> int:
if frame.dlc > CAN_MAX_DLEN:
return ERROR.ERROR_FAILTX
txBuffers = [TXBn.TXB0, TXBn.TXB1, TXBn.TXB2]
for i in range(N_TXBUFFERS):
txbuf = TXB[txBuffers[i]]
ctrlval = self.readRegister(txbuf.CTRL)
if (ctrlval & TXBnCTRL.TXB_TXREQ) == 0:
return self.sendMessage(frame, txBuffers[i])
return ERROR.ERROR_ALLTXBUSY
def readMessage(self, rxbn: int = None) -> Tuple[int, Any]:
if rxbn is None:
return self.readMessage_()
rxb = RXB[rxbn]
tbufdata = self.readRegisters(rxb.SIDH, 1 + CAN_IDLEN)
id_ = (tbufdata[MCP_SIDH] << 3) + (tbufdata[MCP_SIDL] >> 5)
if (tbufdata[MCP_SIDL] & TXB_EXIDE_MASK) == TXB_EXIDE_MASK:
id_ = (id_ << 2) + (tbufdata[MCP_SIDL] & 0x03)
id_ = (id_ << 8) + tbufdata[MCP_EID8]
id_ = (id_ << 8) + tbufdata[MCP_EID0]
id_ |= CAN_EFF_FLAG
dlc = tbufdata[MCP_DLC] & DLC_MASK
if dlc > CAN_MAX_DLEN:
return ERROR.ERROR_FAIL, None
ctrl = self.readRegister(rxb.CTRL)
if ctrl & RXBnCTRL_RTR:
id_ |= CAN_RTR_FLAG
frame = CANFrame(can_id=id_)
frame.data = bytearray(self.readRegisters(rxb.DATA, dlc))
return ERROR.ERROR_OK, frame
def readMessage_(self) -> Tuple[int, Any]:
rc = ERROR.ERROR_NOMSG, None
stat = self.getStatus()
if stat & STAT.STAT_RX0IF and self.mcp2515_rx_index == 0:
rc = self.readMessage(RXBn.RXB0)
if self.getStatus() & STAT.STAT_RX1IF:
self.mcp2515_rx_index = 1
self.modifyRegister(REGISTER.MCP_CANINTF, RXB[RXBn.RXB0].CANINTFRXnIF, 0)
elif stat & STAT.STAT_RX1IF:
rc = self.readMessage(RXBn.RXB1)
self.mcp2515_rx_index = 0
self.modifyRegister(REGISTER.MCP_CANINTF, RXB[RXBn.RXB1].CANINTFRXnIF, 0)
return rc
def checkReceive(self) -> bool:
res = self.getStatus()
if res & STAT_RXIF_MASK:
return True
return False
def checkError(self) -> bool:
eflg = self.getErrorFlags()
if eflg & EFLG_ERRORMASK:
return True
return False
def getErrorFlags(self) -> int:
return self.readRegister(REGISTER.MCP_EFLG)
def clearRXnOVRFlags(self) -> None:
self.modifyRegister(REGISTER.MCP_EFLG, EFLG.EFLG_RX0OVR | EFLG.EFLG_RX1OVR, 0)
def getInterrupts(self) -> int:
return self.readRegister(REGISTER.MCP_CANINTF)
def clearInterrupts(self) -> None:
self.setRegister(REGISTER.MCP_CANINTF, 0)
def getInterruptMask(self) -> int:
return self.readRegister(REGISTER.MCP_CANINTE)
def clearTXInterrupts(self) -> None:
self.modifyRegister(
REGISTER.MCP_CANINTF,
CANINTF.CANINTF_TX0IF | CANINTF.CANINTF_TX1IF | CANINTF.CANINTF_TX2IF,
0,
)
def clearRXnOVR(self) -> None:
eflg = self.getErrorFlags()
if eflg != 0:
self.clearRXnOVRFlags()
self.clearInterrupts()
# modifyRegister(REGISTER.MCP_CANINTF, CANINTF.CANINTF_ERRIF, 0)
def clearMERR(self) -> None:
# self.modifyRegister(REGISTER.MCP_EFLG, EFLG.EFLG_RX0OVR | EFLG.EFLG_RX1OVR, 0)
# self.clearInterrupts()
self.modifyRegister(REGISTER.MCP_CANINTF, CANINTF.CANINTF_MERRF, 0)
def clearERRIF(self) -> None:
# self.modifyRegister(REGISTER.MCP_EFLG, EFLG.EFLG_RX0OVR | EFLG.EFLG_RX1OVR, 0)
# self.clearInterrupts()
self.modifyRegister(REGISTER.MCP_CANINTF, CANINTF.CANINTF_ERRIF, 0)

20
ESP32/src/spi/__init__.py Normal file
View File

@ -0,0 +1,20 @@
try:
from pyb import SPI
except ImportError:
from machine import SPI
SPI_DUMMY_INT = 0x00
SPI_TRANSFER_LEN = 1
SPI_HOLD_US = 50
SPI_DEFAULT_BAUDRATE = 10000000 # 10MHz
SPI_DEFAULT_FIRSTBIT = SPI.MSB
SPI_DEFAULT_POLARITY = 0
SPI_DEFAULT_PHASE = 0
SPI_ESP32_HARDWARE_CHANNEL = 1
SPI_ESP32_SCK_PIN = 14
SPI_ESP32_MOSI_PIN = 13
SPI_ESP32_MISO_PIN = 12
SPI_ESP32_CS_PIN = 23

47
ESP32/src/spi/spi.py Normal file
View File

@ -0,0 +1,47 @@
try:
from typing import Any, Optional
except ImportError:
pass
import sys
import time
try:
from pyb import Pin
except ImportError:
from machine import Pin
from . import SPI_DEFAULT_BAUDRATE, SPI_DUMMY_INT, SPI_TRANSFER_LEN, SPI_HOLD_US
class SPI:
def __init__(self, cs: int, baudrate: int = SPI_DEFAULT_BAUDRATE) -> None:
self._SPICS = Pin(cs, Pin.OUT)
self._SPI = self.init(baudrate=baudrate) # type: Any
self.end()
def init(self, baudrate: int) -> Any:
raise NotImplementedError
def start(self) -> None:
self._SPICS.value(0)
time.sleep_us(SPI_HOLD_US) # type: ignore
def end(self) -> None:
self._SPICS.value(1)
time.sleep_us(SPI_HOLD_US) # type: ignore
def transfer(self, value: int = SPI_DUMMY_INT, read: bool = False) -> Optional[int]:
"""Write int value to SPI and read SPI as int value simultaneously.
This method supports transfer single byte only,
and the system byte order doesn't matter because of that. The input and
output int value are unsigned.
"""
value_as_byte = value.to_bytes(SPI_TRANSFER_LEN, sys.byteorder)
if read:
output = bytearray(SPI_TRANSFER_LEN)
self._SPI.write_readinto(value_as_byte, output)
return int.from_bytes(output, sys.byteorder)
self._SPI.write(value_as_byte)
return None

View File

@ -0,0 +1,35 @@
try:
from typing import Any, Optional
except ImportError:
pass
try:
from pyb import Pin, SPI as MICROPYTHON_SPI
except ImportError:
from machine import Pin, SPI as MICROPYTHON_SPI
from . import (
SPI_DEFAULT_BAUDRATE,
SPI_DEFAULT_FIRSTBIT,
SPI_DEFAULT_PHASE,
SPI_DEFAULT_POLARITY,
SPI_ESP32_HARDWARE_CHANNEL,
SPI_ESP32_MISO_PIN,
SPI_ESP32_MOSI_PIN,
SPI_ESP32_SCK_PIN,
)
from .spi import SPI
class SPIESP32(SPI):
def init(self, baudrate: int) -> Any:
return MICROPYTHON_SPI(
SPI_ESP32_HARDWARE_CHANNEL,
sck=Pin(SPI_ESP32_SCK_PIN),
mosi=Pin(SPI_ESP32_MOSI_PIN),
miso=Pin(SPI_ESP32_MISO_PIN),
baudrate=baudrate,
firstbit=SPI_DEFAULT_FIRSTBIT,
polarity=SPI_DEFAULT_POLARITY,
phase=SPI_DEFAULT_POLARITY,
)

View File