Skip to content
Snippets Groups Projects
Commit 40e43b2f authored by Václav Jelínek's avatar Václav Jelínek
Browse files

Add basic i2c master library, replace magic numbers with constants

parent cd5e396e
No related branches found
No related tags found
1 merge request!12Major update of menu visuals and example programs
Pipeline #107454 canceled
from .buzzer import Buzzer from .buzzer import Buzzer
from .i2c_guard import I2CGuard from .i2c_guard import I2CGuard
from .sh1106 import SH1106_I2C from .sh1106 import SH1106_I2C
from .esp_config import Esp from .esp_config import Esp
\ No newline at end of file from .i2c_master import I2C_master
\ No newline at end of file
...@@ -3,7 +3,7 @@ from machine import UART, Timer, Pin ...@@ -3,7 +3,7 @@ from machine import UART, Timer, Pin
import utime import utime
import struct 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: class Esp:
MAX_PAYLOAD = const(255) MAX_PAYLOAD = const(255)
...@@ -298,7 +298,7 @@ class Esp: ...@@ -298,7 +298,7 @@ class Esp:
self.esp_mode_prev = self.esp_mode self.esp_mode_prev = self.esp_mode
self.esp_mode_prev = self.esp_mode self.esp_mode_prev = self.esp_mode
self.esp_mode = Esp.MODE_CMD 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) utime.sleep(0.01)
self.flush() self.flush()
...@@ -307,7 +307,7 @@ class Esp: ...@@ -307,7 +307,7 @@ class Esp:
utime.sleep(0.01) utime.sleep(0.01)
self.flush() self.flush()
self.esp_mode = self.esp_mode_prev 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) utime.sleep(0.01)
def timeout(self): def timeout(self):
......
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
...@@ -403,6 +403,29 @@ class SH1106(framebuf.FrameBuffer): ...@@ -403,6 +403,29 @@ class SH1106(framebuf.FrameBuffer):
y += 1 y += 1
self.show() 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): def centered_text(self, s: str, y: int, c: int = 1):
x = max((self.width - 8 * len(s)) // 2, 0) x = max((self.width - 8 * len(s)) // 2, 0)
self.text(s, x, y, c) self.text(s, x, y, c)
......
...@@ -4,7 +4,7 @@ from lib.robot_consts import BAT_VOLTAGE_MAX, BAT_VOLTAGE_MIN ...@@ -4,7 +4,7 @@ from lib.robot_consts import BAT_VOLTAGE_MAX, BAT_VOLTAGE_MIN
DISPLAY_TITLE_POS = 18 DISPLAY_TITLE_POS = 18
DISPLAY_PROG_POS = 42 DISPLAY_PROG_POS = 42
DISPLAY_ARROW_GAP = 10 DISPLAY_ARROW_GAP = 9
ESP_MAX_RESET_FAILED = 5 ESP_MAX_RESET_FAILED = 5
class Menu: class Menu:
...@@ -93,8 +93,11 @@ def display_fill_cube_test(robot, current_cube_test, cube_test_menu_name): ...@@ -93,8 +93,11 @@ def display_fill_cube_test(robot, current_cube_test, cube_test_menu_name):
display_fill_arrows(robot) display_fill_arrows(robot)
def display_fill_arrows(robot): def display_fill_arrows(robot):
robot.display.centered_text('^', DISPLAY_PROG_POS - DISPLAY_ARROW_GAP, 1) y_pos = DISPLAY_PROG_POS - DISPLAY_ARROW_GAP
robot.display.centered_text('v', DISPLAY_PROG_POS + DISPLAY_ARROW_GAP, 1) 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): def display_fill_fw_version(robot, fw_version):
robot.display.fill(0) robot.display.fill(0)
......
...@@ -2,6 +2,8 @@ from machine import Timer, I2C, Pin ...@@ -2,6 +2,8 @@ from machine import Timer, I2C, Pin
import utime import utime
import rp2 import rp2
from lib.hw_defs.pins import UTZ_I2C_SCK_PIN, UTZ_I2C_SDA_PIN
# I2C Nonblocking via PIO # 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) @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(): def I2C_ReadSensor():
...@@ -70,8 +72,8 @@ class UltrasonicSensor: ...@@ -70,8 +72,8 @@ class UltrasonicSensor:
# Inicialization of I2C, recommended baud rate is 9600, capable of 30000 # Inicialization of I2C, recommended baud rate is 9600, capable of 30000
if(self.use_nonblocking == True): if(self.use_nonblocking == True):
SDA = Pin(16,mode=Pin.OPEN_DRAIN, pull=Pin.PULL_UP) SDA = Pin(UTZ_I2C_SDA_PIN,mode=Pin.OPEN_DRAIN, pull=Pin.PULL_UP)
SCL = Pin(17,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.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) 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: ...@@ -80,7 +82,7 @@ class UltrasonicSensor:
self.sm0.irq(self.handler) self.sm0.irq(self.handler)
self.sm0.active(1) self.sm0.active(1)
else: 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 # Initialize return buffer
if only_first_target == True: if only_first_target == True:
self.read_buffer = [255] self.read_buffer = [255]
......
from machine import Pin, I2C, Timer from machine import Pin, I2C, Timer
from time import sleep, ticks_ms 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 import nxt, ev3, OC
from lib.hw_defs.ports import SENSOR_PORT_PINS, MOTOR_PORT_PINS from lib.hw_defs.ports import SENSOR_PORT_PINS, MOTOR_PORT_PINS
...@@ -30,6 +30,8 @@ class Robot: ...@@ -30,6 +30,8 @@ class Robot:
self.sensors = Sensors() self.sensors = Sensors()
self.motors = [EmptyObject() for i in range(len(MOTOR_PORT_PINS))] self.motors = [EmptyObject() for i in range(len(MOTOR_PORT_PINS))]
self.i2c_master = EmptyObject()
# Initialize brick components # Initialize brick components
self.battery = brick_ll.Battery() self.battery = brick_ll.Battery()
self.buzzer = Buzzer() self.buzzer = Buzzer()
...@@ -117,11 +119,21 @@ class Robot: ...@@ -117,11 +119,21 @@ class Robot:
gyro_irq_pin = Pin(ICM_IRQ_PIN) gyro_irq_pin = Pin(ICM_IRQ_PIN)
gyro_irq_pin.irq(handler=None) 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 # Deinitialize all hardware components initialized by the user program
def deinit_all(self): def deinit_all(self):
self.led.off() self.led.off()
self.buzzer.off() self.buzzer.off()
self.deinit_irq() self.deinit_irq()
self.deinit_i2c_master()
self.deinit_motors() self.deinit_motors()
self.deinit_sensors() self.deinit_sensors()
self.delete_mutex() self.delete_mutex()
......
...@@ -81,6 +81,9 @@ BAT_VOLTAGE_TURNOFF = (BAT_VOLTAGE_MIN+0.1) # Volts ...@@ -81,6 +81,9 @@ BAT_VOLTAGE_TURNOFF = (BAT_VOLTAGE_MIN+0.1) # Volts
PCF_CHECK_PERIOD = const(50) # ms PCF_CHECK_PERIOD = const(50) # ms
I2C_FREQ = const(400000) # Hz I2C_FREQ = const(400000) # Hz
I2C_MULTICUBE_FREQ = const(100000)
ESP_BAUDRATE = const(115200) # bps ESP_BAUDRATE = const(115200) # bps
ESP32_COMMAND_PIN = const(8)
FW_VERSION = "17.10.2024" # Firmware version FW_VERSION = "17.10.2024" # Firmware version
\ No newline at end of file
...@@ -39,7 +39,7 @@ def main(): ...@@ -39,7 +39,7 @@ def main():
MENU_PROGRAM_NXT_UTZ_IDX = 3 MENU_PROGRAM_NXT_UTZ_IDX = 3
menu_programs_functions_size = len(menu_programs_functions) 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), ('Wifi webserver', menu_programs.esp_wifi_run), ('I2C Master', menu_programs.i2c_master_run),
('I2C Slave', menu_programs.i2c_slave_run)) ('I2C Slave', menu_programs.i2c_slave_run))
menu_cube_programs_functions_size = len(menu_cube_programs_functions) menu_cube_programs_functions_size = len(menu_cube_programs_functions)
......
...@@ -24,7 +24,7 @@ def cube_utility_run(robot): ...@@ -24,7 +24,7 @@ def cube_utility_run(robot):
# Show info on the display # Show info on the display
robot.display.fill(0) 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('Bat: {:.2f}V'.format(bat_voltage), 0, 16, 1)
robot.display.text('Counter: {}'.format(counter), 0, 24, 1) robot.display.text('Counter: {}'.format(counter), 0, 24, 1)
robot.display.text('LED state: {}'.format(counter % 2 == 0), 0, 32, 1) robot.display.text('LED state: {}'.format(counter % 2 == 0), 0, 32, 1)
......
...@@ -7,7 +7,7 @@ ASCII_a = 97 ...@@ -7,7 +7,7 @@ ASCII_a = 97
def i2c_master_run(robot): 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_received = 0x5F
data_sending = 0 data_sending = 0
debounce = False debounce = False
...@@ -27,8 +27,9 @@ def i2c_master_run(robot): ...@@ -27,8 +27,9 @@ def i2c_master_run(robot):
robot.display.text('<', 0, 54, 1) robot.display.text('<', 0, 54, 1)
robot.display.show() robot.display.show()
i2c.writeto(0x41, (data_sending + ASCII_a).to_bytes(1, 'big')) print(robot.i2c_master.i2c.scan())
data_received = int.from_bytes(i2c.readfrom(0x41, 1), 'big') 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() buttons = robot.buttons.pressed()
if buttons[Button.LEFT]: if buttons[Button.LEFT]:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment