Skip to content

Commit 56758f3

Browse files
committed
Reorganization: added the display sources files to this repository
1 parent 6f30c44 commit 56758f3

122 files changed

Lines changed: 31129 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
603 KB
Binary file not shown.
343 KB
Binary file not shown.
59.6 KB
Binary file not shown.
231 KB
Binary file not shown.

display/firmware/buttons.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import digitalio
2+
3+
class Buttons(object):
4+
def __init__(self, power_pin, up_pin, down_pin):
5+
6+
self._power = digitalio.DigitalInOut(power_pin)
7+
self._power.direction = digitalio.Direction.INPUT
8+
self._power.pull = digitalio.Pull.UP
9+
10+
self._up = digitalio.DigitalInOut(up_pin)
11+
self._up.direction = digitalio.Direction.INPUT
12+
self._up.pull = digitalio.Pull.UP
13+
14+
self._down = digitalio.DigitalInOut(down_pin)
15+
self._down.direction = digitalio.Direction.INPUT
16+
self._down.pull = digitalio.Pull.UP
17+
18+
@property
19+
def power(self):
20+
return not self._power.value
21+
22+
@property
23+
def up(self):
24+
return not self._up.value
25+
26+
@property
27+
def down(self):
28+
return not self._down.value

display/firmware/display_sh1106.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import busio
2+
import displayio
3+
import adafruit_displayio_sh1106
4+
5+
class Display(object):
6+
def __init__(self, spi_clk_pin, spi_mosi_pin, chip_select_pin, command_pin, reset_pin, spi_clock_frequency):
7+
8+
displayio.release_displays()
9+
10+
spi = busio.SPI(
11+
spi_clk_pin, # CLK pin
12+
spi_mosi_pin, # MOSI pin
13+
None) # MISO pin, not need to drive this display
14+
15+
display_bus = displayio.FourWire(
16+
spi,
17+
command = command_pin,
18+
reset = reset_pin,
19+
chip_select = chip_select_pin, # not used but for some reason there is an error if chip_select is None
20+
baudrate = spi_clock_frequency)
21+
22+
WIDTH = 132
23+
HEIGHT = 64
24+
BORDER = 0
25+
26+
self._display = adafruit_displayio_sh1106.SH1106(display_bus, width = WIDTH, height = HEIGHT)
27+
28+
# set the display to vertical mode
29+
self._display.rotation = 90
30+
31+
@property
32+
def display(self):
33+
return self._display

display/firmware/ebike_board.py

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
import busio
2+
import struct
3+
4+
class EBikeBoard(object):
5+
"""EBike_board"""
6+
def __init__(self, uart_tx_pin, uart_rx_pin, ebike_data):
7+
"""EBike_board
8+
:param ~microcontroller.Pin uart_tx_pin: UART TX pin that connects to display
9+
:param ~microcontroller.Pin uart_tx_pin: UART RX pin that connects to display
10+
"""
11+
12+
# configure UART for communications with display
13+
self._uart = busio.UART(uart_tx_pin, uart_rx_pin, baudrate=19200, timeout=0.005)
14+
15+
# init variables
16+
self._read_and_unpack__state = 0
17+
self._read_and_unpack__len = 0
18+
self._read_and_unpack__cnt = 0
19+
self._rx_package = RXPackage()
20+
self._process_data__error_cnt = 0
21+
self._ebike_data = ebike_data
22+
23+
# code taken from:
24+
# https://github.com/LacobusVentura/MODBUS-CRC16
25+
def _crc16(self, data):
26+
27+
table = [
28+
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
29+
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
30+
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
31+
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
32+
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
33+
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
34+
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
35+
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
36+
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
37+
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
38+
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
39+
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
40+
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
41+
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
42+
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
43+
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
44+
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
45+
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
46+
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
47+
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
48+
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
49+
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
50+
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
51+
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
52+
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
53+
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
54+
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
55+
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
56+
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
57+
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
58+
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
59+
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
60+
]
61+
62+
xor = 0
63+
crc = 0xFFFF
64+
for byte in data:
65+
xor = (byte ^ crc) & 0xff
66+
crc >>= 8
67+
crc ^= table[xor]
68+
crc &= 0xFFFF # important, crc must stay 16bits all the way through
69+
70+
return crc
71+
72+
def _read_and_unpack(self):
73+
# only read next data bytes after we process the previous package
74+
if self._rx_package.received == False:
75+
rx_array = self._uart.read()
76+
if rx_array is not None:
77+
for data in rx_array:
78+
# find start byte
79+
if self._read_and_unpack__state == 0:
80+
if (data == 0x59):
81+
self._rx_package.data[0] = data
82+
self._read_and_unpack__state = 1
83+
else:
84+
self._read_and_unpack__state = 0
85+
86+
# len byte
87+
elif self._read_and_unpack__state == 1:
88+
self._rx_package.data[1] = data
89+
self._read_and_unpack__len = data
90+
self._read_and_unpack__state = 2
91+
92+
# rest of the package
93+
elif self._read_and_unpack__state == 2:
94+
self._rx_package.data[self._read_and_unpack__cnt + 2] = data
95+
self._read_and_unpack__cnt += 1
96+
97+
# end of the package
98+
if self._read_and_unpack__cnt >= self._read_and_unpack__len:
99+
100+
# print(",".join(["0x{:02X}".format(i) for i in self._rx_package.data[0: self._read_and_unpack__len]]))
101+
102+
# calculate the CRC
103+
crc = self._crc16(self._rx_package.data[0: self._read_and_unpack__len])
104+
# get the original CRC
105+
crc_original = struct.unpack_from('<H', self._rx_package.data, self._read_and_unpack__len)[0]
106+
107+
# check if CRC is ok
108+
self._rx_package.received = True if crc == crc_original else False
109+
110+
self._process_data__error_cnt = 0
111+
self._read_and_unpack__cnt = 0
112+
self._read_and_unpack__state = 0
113+
else:
114+
# keep increasing error counter
115+
self._process_data__error_cnt += 1
116+
117+
def _process_data(self):
118+
if self._rx_package.received == True:
119+
self._ebike_data.battery_voltage = struct.unpack_from('<H', self._rx_package.data, 2)[0] / 100.0
120+
self._ebike_data.battery_current = self._rx_package.data[4] / 5.0
121+
self._ebike_data.motor_power = struct.unpack_from('<H', self._rx_package.data, 5)[0]
122+
self._ebike_data.vesc_temperature_x10 = struct.unpack_from('<H', self._rx_package.data, 7)[0]
123+
self._ebike_data.motor_temperature_sensor_x10 = struct.unpack_from('<H', self._rx_package.data, 9)[0]
124+
self._ebike_data.vesc_fault_code = self._rx_package.data[11]
125+
self._ebike_data.brakes_are_active = self._rx_package.data[12]
126+
127+
self._rx_package.received = False # signal that next package can be processed
128+
129+
def _send_data(self):
130+
# start building the TX package
131+
# start byte + len byte + [package type + xx data bytes] + CRC 2 bytes
132+
# len = count([package type + xx data bytes] + CRC 2 bytes)
133+
tx_array = bytearray(255)
134+
tx_array[0] = 0x59
135+
_len = 2 # start byte + len byte
136+
137+
tx_array[2] = int(self._ebike_data.assist_level)
138+
_len += 1
139+
140+
# final building of the TX package
141+
tx_array[1] = _len
142+
143+
# calculate the CRC
144+
crc = self._crc16(tx_array[0: _len])
145+
struct.pack_into('<H', tx_array, _len, crc) # CRC: 2 bytes
146+
147+
# send packet to UART
148+
self._uart.write(tx_array[0: _len + 2])
149+
150+
# print(",".join(["0x{:02X}".format(i) for i in tx_array[0: _len + 2]]))
151+
152+
# read and process UART data
153+
def process_data(self):
154+
self._read_and_unpack()
155+
self._process_data()
156+
self._send_data()
157+
158+
class RXPackage():
159+
data = bytearray(255)
160+
received = False

display/firmware/ebike_data.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import time
2+
3+
class EBike(object):
4+
5+
def __init__(self):
6+
self.vesc_fault_code = 0
7+
self.battery_voltage = 0
8+
self.battery_current = 0
9+
self.motor_power = 0
10+
self.motor_current = 0
11+
self.motor_speed_erpm = 0
12+
self.previous_motor_current_target = True
13+
self.brakes_are_active = False
14+
self.torque_weight = 0
15+
self.cadence = 0
16+
self.ramp_last_time = time.monotonic_ns()
17+
self.motor_current_target = 0
18+
self.assist_level = 0
19+
self.vesc_temperature_x10 = 0
20+
self.motor_temperature_sensor_x10 = 0
21+

0 commit comments

Comments
 (0)