From 40e43b2f90290319343acf85811f0f27fa254686 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20Jel=C3=ADnek?= <jelinva4@fel.cvut.cz> Date: Thu, 17 Oct 2024 19:01:32 +0200 Subject: [PATCH] Add basic i2c master library, replace magic numbers with constants --- lib/cube/__init__.py | 3 ++- lib/cube/esp_config.py | 6 +++--- lib/cube/i2c_master.py | 35 +++++++++++++++++++++++++++++++++++ lib/cube/sh1106.py | 23 +++++++++++++++++++++++ lib/menu_display.py | 9 ++++++--- lib/nxt/ultra.py | 8 +++++--- lib/robot.py | 14 +++++++++++++- lib/robot_consts.py | 3 +++ main/main.py | 2 +- menu_programs/cube_utility.py | 2 +- menu_programs/i2c_master.py | 7 ++++--- 11 files changed, 96 insertions(+), 16 deletions(-) create mode 100644 lib/cube/i2c_master.py diff --git a/lib/cube/__init__.py b/lib/cube/__init__.py index 852e982..8d6a70a 100644 --- a/lib/cube/__init__.py +++ b/lib/cube/__init__.py @@ -1,4 +1,5 @@ from .buzzer import Buzzer from .i2c_guard import I2CGuard from .sh1106 import SH1106_I2C -from .esp_config import Esp \ No newline at end of file +from .esp_config import Esp +from .i2c_master import I2C_master \ No newline at end of file diff --git a/lib/cube/esp_config.py b/lib/cube/esp_config.py index 790b0ce..c87cafd 100644 --- a/lib/cube/esp_config.py +++ b/lib/cube/esp_config.py @@ -3,7 +3,7 @@ from machine import UART, Timer, Pin import utime import struct -from lib.hw_defs.pins import INTERNAL_UART_HW_ID, INTERNAL_UART_TX_PIN, INTERNAL_UART_RX_PIN +from lib.hw_defs.pins import INTERNAL_UART_HW_ID, INTERNAL_UART_TX_PIN, INTERNAL_UART_RX_PIN, BUTTON_POWER_RPIN_BIT class Esp: MAX_PAYLOAD = const(255) @@ -298,7 +298,7 @@ class Esp: self.esp_mode_prev = self.esp_mode self.esp_mode_prev = self.esp_mode self.esp_mode = Esp.MODE_CMD - self.pcf_buttons.set_pin(8, False) + self.pcf_buttons.set_pin(BUTTON_POWER_RPIN_BIT, False) utime.sleep(0.01) self.flush() @@ -307,7 +307,7 @@ class Esp: utime.sleep(0.01) self.flush() self.esp_mode = self.esp_mode_prev - self.pcf_buttons.set_pin(8, True) + self.pcf_buttons.set_pin(BUTTON_POWER_RPIN_BIT, True) utime.sleep(0.01) def timeout(self): diff --git a/lib/cube/i2c_master.py b/lib/cube/i2c_master.py new file mode 100644 index 0000000..10cafa1 --- /dev/null +++ b/lib/cube/i2c_master.py @@ -0,0 +1,35 @@ +from machine import I2C, Pin + +from lib.hw_defs.pins import UTZ_I2C_SDA_PIN, UTZ_I2C_SCK_PIN, I2C_STRONG_PULL_RPIN +from lib.robot_consts import I2C_MULTICUBE_FREQ + +class I2C_master: + def __init__(self, pcf_buttons, general_add=0x41): + self.general_add = general_add + self.pcf_buttons = pcf_buttons + self.data_received = None + self.data_sending = None + self.start() + + def start(self): + self.pcf_buttons.set_pin(I2C_STRONG_PULL_RPIN, False) + self.i2c = I2C(id=0,scl=Pin(UTZ_I2C_SCK_PIN), + sda=Pin(UTZ_I2C_SDA_PIN), freq=I2C_MULTICUBE_FREQ) + + def read(self, add, len=10): + self.data_received = self.i2c.readfrom(add, len) + return self.data_received + + def write(self, add, message): + self.data_sending = message + self.i2c.writeto(add, message) + + def write_general(self, message): + self.i2c.writeto(self.general_add, message) + + def get_general_add(self): + return self.general_add + + def deinit(self): + self.i2c = None + self.pcf_buttons.set_pin(I2C_STRONG_PULL_RPIN, True) \ No newline at end of file diff --git a/lib/cube/sh1106.py b/lib/cube/sh1106.py index 65ab805..12c6ca4 100644 --- a/lib/cube/sh1106.py +++ b/lib/cube/sh1106.py @@ -403,6 +403,29 @@ class SH1106(framebuf.FrameBuffer): y += 1 self.show() + def draw_arrow(self, x: int, y: int, dir: int, c: int = 1): + if dir == 0: #left + for i in range(4): + for j in range(2): + self.pixel(x+i+j, y+i, c) + self.pixel(x+i+j, y-i, c) + elif dir == 1: #up + for i in range(4): + for j in range(2): + self.pixel(x+i, y+i+j, c) + self.pixel(x-i, y+i+j, c) + elif dir == 2: #right + for i in range(4): + for j in range(2): + self.pixel(x-i-j, y+i, c) + self.pixel(x-i-j, y-i, c) + elif dir == 3: #down + for i in range(4): + for j in range(2): + self.pixel(x+i, y-i-j, c) + self.pixel(x-i, y-i-j, c) + + def centered_text(self, s: str, y: int, c: int = 1): x = max((self.width - 8 * len(s)) // 2, 0) self.text(s, x, y, c) diff --git a/lib/menu_display.py b/lib/menu_display.py index b302f05..b97187c 100644 --- a/lib/menu_display.py +++ b/lib/menu_display.py @@ -4,7 +4,7 @@ from lib.robot_consts import BAT_VOLTAGE_MAX, BAT_VOLTAGE_MIN DISPLAY_TITLE_POS = 18 DISPLAY_PROG_POS = 42 -DISPLAY_ARROW_GAP = 10 +DISPLAY_ARROW_GAP = 9 ESP_MAX_RESET_FAILED = 5 class Menu: @@ -93,8 +93,11 @@ def display_fill_cube_test(robot, current_cube_test, cube_test_menu_name): display_fill_arrows(robot) def display_fill_arrows(robot): - robot.display.centered_text('^', DISPLAY_PROG_POS - DISPLAY_ARROW_GAP, 1) - robot.display.centered_text('v', DISPLAY_PROG_POS + DISPLAY_ARROW_GAP, 1) + y_pos = DISPLAY_PROG_POS - DISPLAY_ARROW_GAP + x_pos = 64 + robot.display.draw_arrow(x_pos, y_pos, 1, 1) + y_pos = DISPLAY_PROG_POS + DISPLAY_ARROW_GAP + 7 + robot.display.draw_arrow(x_pos, y_pos, 3, 1) def display_fill_fw_version(robot, fw_version): robot.display.fill(0) diff --git a/lib/nxt/ultra.py b/lib/nxt/ultra.py index 27aef9a..70be3e1 100644 --- a/lib/nxt/ultra.py +++ b/lib/nxt/ultra.py @@ -2,6 +2,8 @@ from machine import Timer, I2C, Pin import utime import rp2 +from lib.hw_defs.pins import UTZ_I2C_SCK_PIN, UTZ_I2C_SDA_PIN + # I2C Nonblocking via PIO @rp2.asm_pio(autopush=False, autopull=False, out_shiftdir=rp2.PIO.SHIFT_RIGHT, sideset_init=rp2.PIO.OUT_HIGH, out_init=rp2.PIO.OUT_HIGH) def I2C_ReadSensor(): @@ -70,8 +72,8 @@ class UltrasonicSensor: # Inicialization of I2C, recommended baud rate is 9600, capable of 30000 if(self.use_nonblocking == True): - SDA = Pin(16,mode=Pin.OPEN_DRAIN, pull=Pin.PULL_UP) - SCL = Pin(17,mode=Pin.OPEN_DRAIN, pull=Pin.PULL_UP) + SDA = Pin(UTZ_I2C_SDA_PIN,mode=Pin.OPEN_DRAIN, pull=Pin.PULL_UP) + SCL = Pin(UTZ_I2C_SCK_PIN,mode=Pin.OPEN_DRAIN, pull=Pin.PULL_UP) self.sm0 = rp2.StateMachine(0, I2C_ReadSensor, out_base=SDA, sideset_base=SCL, freq=30000*8) self.sm1 = rp2.StateMachine(1, I2C_ReadSensor2, in_base=SDA, out_base=SDA, sideset_base=SCL, freq=30000*8) @@ -80,7 +82,7 @@ class UltrasonicSensor: self.sm0.irq(self.handler) self.sm0.active(1) else: - self.i2c = I2C(id=0,scl=Pin(17), sda=Pin(16), freq=(30000)) + self.i2c = I2C(id=0,scl=Pin(UTZ_I2C_SCK_PIN), sda=Pin(UTZ_I2C_SDA_PIN), freq=(30000)) # Initialize return buffer if only_first_target == True: self.read_buffer = [255] diff --git a/lib/robot.py b/lib/robot.py index d4aebaf..200c395 100644 --- a/lib/robot.py +++ b/lib/robot.py @@ -1,7 +1,7 @@ from machine import Pin, I2C, Timer from time import sleep, ticks_ms -from lib.cube import Buzzer, I2CGuard, SH1106_I2C, Esp +from lib.cube import Buzzer, I2CGuard, SH1106_I2C, Esp, I2C_master from lib import nxt, ev3, OC from lib.hw_defs.ports import SENSOR_PORT_PINS, MOTOR_PORT_PINS @@ -30,6 +30,8 @@ class Robot: self.sensors = Sensors() self.motors = [EmptyObject() for i in range(len(MOTOR_PORT_PINS))] + self.i2c_master = EmptyObject() + # Initialize brick components self.battery = brick_ll.Battery() self.buzzer = Buzzer() @@ -117,11 +119,21 @@ class Robot: gyro_irq_pin = Pin(ICM_IRQ_PIN) gyro_irq_pin.irq(handler=None) + def init_i2c_master(self): + if isinstance(self.i2c_master, EmptyObject): + self.i2c_master = I2C_master(self.buttons) + + def deinit_i2c_master(self): + if not isinstance(self.i2c_master, EmptyObject): + self.i2c_master.deinit() + self.i2c_master = EmptyObject() + # Deinitialize all hardware components initialized by the user program def deinit_all(self): self.led.off() self.buzzer.off() self.deinit_irq() + self.deinit_i2c_master() self.deinit_motors() self.deinit_sensors() self.delete_mutex() diff --git a/lib/robot_consts.py b/lib/robot_consts.py index ae4fdea..27e439c 100644 --- a/lib/robot_consts.py +++ b/lib/robot_consts.py @@ -81,6 +81,9 @@ BAT_VOLTAGE_TURNOFF = (BAT_VOLTAGE_MIN+0.1) # Volts PCF_CHECK_PERIOD = const(50) # ms I2C_FREQ = const(400000) # Hz +I2C_MULTICUBE_FREQ = const(100000) + ESP_BAUDRATE = const(115200) # bps +ESP32_COMMAND_PIN = const(8) FW_VERSION = "17.10.2024" # Firmware version \ No newline at end of file diff --git a/main/main.py b/main/main.py index c0aadea..580948d 100644 --- a/main/main.py +++ b/main/main.py @@ -39,7 +39,7 @@ def main(): MENU_PROGRAM_NXT_UTZ_IDX = 3 menu_programs_functions_size = len(menu_programs_functions) - menu_cube_programs_functions = (('Gyro Acc', menu_programs.cube_gyro_acc_run), ('Utility', menu_programs.cube_utility_run), + menu_cube_programs_functions = (('Gyro Acc', menu_programs.cube_gyro_acc_run), ('LED & buzzer', menu_programs.cube_utility_run), ('Wifi webserver', menu_programs.esp_wifi_run), ('I2C Master', menu_programs.i2c_master_run), ('I2C Slave', menu_programs.i2c_slave_run)) menu_cube_programs_functions_size = len(menu_cube_programs_functions) diff --git a/menu_programs/cube_utility.py b/menu_programs/cube_utility.py index f8eadb9..9f09c9d 100644 --- a/menu_programs/cube_utility.py +++ b/menu_programs/cube_utility.py @@ -24,7 +24,7 @@ def cube_utility_run(robot): # Show info on the display robot.display.fill(0) - robot.display.centered_text("Utility", 0, 1) + robot.display.centered_text("LED & buzzer", 0, 1) robot.display.text('Bat: {:.2f}V'.format(bat_voltage), 0, 16, 1) robot.display.text('Counter: {}'.format(counter), 0, 24, 1) robot.display.text('LED state: {}'.format(counter % 2 == 0), 0, 32, 1) diff --git a/menu_programs/i2c_master.py b/menu_programs/i2c_master.py index c23412a..5197fd4 100644 --- a/menu_programs/i2c_master.py +++ b/menu_programs/i2c_master.py @@ -7,7 +7,7 @@ ASCII_a = 97 def i2c_master_run(robot): - i2c = I2C(id=0,scl=Pin(17), sda=Pin(16), freq=100000) + robot.init_i2c_master() data_received = 0x5F data_sending = 0 debounce = False @@ -27,8 +27,9 @@ def i2c_master_run(robot): robot.display.text('<', 0, 54, 1) robot.display.show() - i2c.writeto(0x41, (data_sending + ASCII_a).to_bytes(1, 'big')) - data_received = int.from_bytes(i2c.readfrom(0x41, 1), 'big') + print(robot.i2c_master.i2c.scan()) + robot.i2c_master.write(0x41, (data_sending + ASCII_a).to_bytes(1, 'big')) + data_received = int.from_bytes(robot.i2c_master.read(0x41, 1), 'big') buttons = robot.buttons.pressed() if buttons[Button.LEFT]: -- GitLab