diff --git a/menu_programs/i2c_master.py b/menu_programs/i2c_master.py index 65629d66a4709610ab42bffd2788bf73d87a039a..1df93a4c7d9b149693aa97e0e7658b4159131a06 100644 --- a/menu_programs/i2c_master.py +++ b/menu_programs/i2c_master.py @@ -6,60 +6,82 @@ from lib.hw_defs.pins import UTZ_I2C_SDA_PIN, UTZ_I2C_SCK_PIN, I2C_STRONG_PULL_R ASCII_a = 97 ADDRESS = 0x44 +W_ADDRESS = 0x0b +W_ADDRESS_MAX = 0x1b +R_ADDRESS = 0x0a + + +TIMEOUT = 3 def i2c_master_run(robot): robot.init_i2c_master() - data_received_parsed = 0x5F - data_received = None + write_mem_add = W_ADDRESS data_sending = 0 - debounce = False - connected = False - robot.display.fill(0) - robot.display.centered_text(f"I2C master", 0, 1) - robot.display.text('< exit', 0, 54, 1) - robot.display.show() - utime.sleep(0.2) - while ADDRESS not in robot.i2c_master.i2c.scan(): + while True: + data_received_parsed = 0x5F + data_received = None + debounce = False + timeout = 0 + + robot.display.fill(0) robot.display.centered_text(f"I2C master", 0, 1) + robot.display.text('< exit', 0, 54, 1) robot.display.centered_text(f"Slave", 18, 1) robot.display.centered_text(f"not found", 28, 1) - robot.display.text('< exit', 0, 54, 1) - robot.display.show() - buttons = robot.buttons.pressed_since() - if buttons[Button.LEFT]: - return + + robot.buttons.pressed_since() + utime.sleep(0.3) + all_add = robot.i2c_master.i2c.scan() + while not all_add: + robot.display.show() + all_add = robot.i2c_master.i2c.scan() + buttons = robot.buttons.pressed_since() + if buttons[Button.LEFT]: + return + slave_add = all_add[0] - while True: - robot.display.fill(0) - robot.display.centered_text(f"I2C master", 0, 1) - robot.display.text(f"Sending: {chr(data_sending+ASCII_a)}", 0, 16, 1) - robot.display.text(f"Received: {chr(data_received_parsed)}", 0, 26, 1) - robot.display.text('< exit char', 0, 54, 1) - robot.display.draw_arrow(74, 56, robot.display.UP, 1) - robot.display.draw_arrow(84, 61, robot.display.DOWN, 1) - robot.display.show() + while timeout < TIMEOUT: + robot.display.fill(0) + robot.display.centered_text(f"I2C master", 0, 1) + robot.display.text(f"Slave add {slave_add}", 0, 16, 1) + robot.display.text(f"Send to {write_mem_add}: {chr(data_sending+ASCII_a)}", 0, 26, 1) + robot.display.text(f"Read from {R_ADDRESS}: {chr(data_received_parsed)}", 0, 36, 1) + robot.display.text('< exit char', 0, 54, 1) + robot.display.draw_arrow(74, 56, robot.display.UP, 1) + robot.display.draw_arrow(84, 61, robot.display.DOWN, 1) + robot.display.show() - robot.i2c_master.write(ADDRESS, (data_sending + ASCII_a).to_bytes(1, 'big'), mem_add=1) - data_received = robot.i2c_master.read(ADDRESS, 1, mem_add=2) - if data_received and data_received != b'\x00': - data_received_parsed = int.from_bytes(data_received, 'big') + data_written = robot.i2c_master.write(slave_add, (data_sending + ASCII_a).to_bytes(1, 'big'), mem_add=write_mem_add) + data_received = robot.i2c_master.read(slave_add, 1, mem_add=R_ADDRESS) + if data_received and data_received != b'\x00': + print("Received: ", data_received) + data_received_parsed = int.from_bytes(data_received, 'big') + elif not data_written: + timeout += 1 + print(data_written, data_received) - buttons = robot.buttons.pressed_since() - if buttons[Button.LEFT]: - break - if not debounce: - if buttons[Button.UP]: - robot.buttons.set_pin(I2C_STRONG_PULL_RPIN_BIT, True) - data_sending -= 1 - data_sending = data_sending % 26 - debounce = True - if buttons[Button.DOWN]: - robot.buttons.set_pin(I2C_STRONG_PULL_RPIN_BIT, False) - data_sending += 1 - data_sending = data_sending % 26 - debounce = True - - if not buttons[Button.UP] and not buttons[Button.DOWN]: - debounce = False - utime.sleep(0.1) \ No newline at end of file + buttons = robot.buttons.pressed_since() + if buttons[Button.LEFT]: + return + if not debounce: + if buttons[Button.UP]: + #robot.buttons.set_pin(I2C_STRONG_PULL_RPIN_BIT, False) + data_sending -= 1 + data_sending = data_sending % 26 + debounce = True + if buttons[Button.DOWN]: + data_sending += 1 + data_sending = data_sending % 26 + debounce = True + if buttons[Button.RIGHT]: + #robot.buttons.set_pin(I2C_STRONG_PULL_RPIN_BIT, True) + write_mem_add += 1 + if write_mem_add > W_ADDRESS_MAX: + write_mem_add = W_ADDRESS + debounce = True + + + if not buttons[Button.UP] and not buttons[Button.DOWN] and not buttons[Button.RIGHT] and not buttons[Button.LEFT]: + debounce = False + utime.sleep(0.1) \ No newline at end of file diff --git a/menu_programs/i2c_slave.py b/menu_programs/i2c_slave.py index b8687b3447dd7ccf4794c9c2254bd652aee9f03e..c6d428ea19d80f69a71f697632e9ed2eef8f1694 100644 --- a/menu_programs/i2c_slave.py +++ b/menu_programs/i2c_slave.py @@ -1,43 +1,68 @@ import utime -from machine import mem32,mem8,Pin +from machine import mem32,mem8,Pin, from lib.robot_consts import Button from lib.hw_defs.pins import UTZ_I2C_SDA_PIN, UTZ_I2C_SCK_PIN, I2C_STRONG_PULL_RPIN ASCII_a = 97 ADDRESS = 0x44 +ADDRESS_MAX = 0x50 +W_ADDRESS = 0x0b +R_ADDRESS = 0x0a +drdy = 0 -def i2c_slave_run(robot): +def i2c_slave_irq(i2c_slave): + global drdy + if (i2c_slave.irq().flags() & i2c_slave.RECEIVED): + drdy = 1 - def i2c_slave_irq(i2c_slave): - print(i2c_slave) - print(robot.i2c_slave.read(1)) +def i2c_slave_run(robot): + global drdy,irq_c robot.init_i2c_slave(ADDRESS) - robot.i2c_slave.irq(i2c_slave_irq, robot.i2c_slave.READ | robot.i2c_slave.RECEIVED, False) + robot.i2c_slave.irq(i2c_slave_irq, (robot.i2c_slave.READ | robot.i2c_slave.RECEIVED), False) + data_received = None data_show = 0x5F data_sending = 0 debounce = False + slave_add = ADDRESS + received_add = 0 + + robot.i2c_slave.write(R_ADDRESS, data_sending + ASCII_a) robot.display.fill(0) robot.display.centered_text(f"I2C slave", 0, 1) robot.display.text('< exit', 0, 54, 1) robot.display.show() while True: + if drdy: + flags = robot.i2c_slave.written_flags() + for i in range(len(flags)): + flag_q = flags[i] + if flag_q > 0: + received_add = i * 64 + for j in range(64): + if flag_q & 1: + received_add += j + break + flag_q = flag_q >> 1 + break + drdy = 0 + + data_received = robot.i2c_slave.read(received_add) + if data_received: + data_show = data_received + robot.display.fill(0) robot.display.centered_text(f"I2C slave", 0, 1) - robot.display.text(f"Sending: {chr(data_sending+ASCII_a)}", 0, 16, 1) - robot.display.text(f"Received: {chr(data_show)}", 0, 26, 1) + robot.display.text(f"Slave add {slave_add}", 0, 16, 1) + robot.display.text(f"Send to {R_ADDRESS}: {chr(data_sending+ASCII_a)}", 0, 26, 1) + robot.display.text(f"Read from {received_add}: {chr(data_show)}", 0, 36, 1) robot.display.text('< exit char', 0, 54, 1) robot.display.draw_arrow(74, 56, robot.display.UP, 1) robot.display.draw_arrow(84, 61, robot.display.DOWN, 1) robot.display.show() - data_received = robot.i2c_slave.read(1) - - if data_received: - print(data_received) - data_show = data_received - + buttons = robot.buttons.pressed_since() if buttons[Button.LEFT]: break @@ -45,14 +70,22 @@ def i2c_slave_run(robot): if buttons[Button.UP]: data_sending -= 1 data_sending = data_sending % 26 - robot.i2c_slave.write(2, data_sending + ASCII_a) + robot.i2c_slave.write(R_ADDRESS, data_sending + ASCII_a) debounce = True if buttons[Button.DOWN]: data_sending += 1 data_sending = data_sending % 26 - robot.i2c_slave.write(2, data_sending + ASCII_a) + robot.i2c_slave.write(R_ADDRESS, data_sending + ASCII_a) + debounce = True + if buttons[Button.RIGHT]: + slave_add += 1 + if slave_add > ADDRESS_MAX: + slave_add = ADDRESS + robot.i2c_slave.init(address=slave_add) + robot.i2c_slave.write(R_ADDRESS, data_sending + ASCII_a) + robot.i2c_slave.irq(i2c_slave_irq, (robot.i2c_slave.READ | robot.i2c_slave.RECEIVED), False) debounce = True - if not buttons[Button.UP] and not buttons[Button.DOWN]: + if not buttons[Button.UP] and not buttons[Button.DOWN] and not buttons[Button.RIGHT]: debounce = False utime.sleep(0.1) \ No newline at end of file diff --git a/micropython/modules/opencube_brick/oc_i2c_slave.c b/micropython/modules/opencube_brick/oc_i2c_slave.c index 0c86d88c02ec7a771e2fe165eb8faaf07617473c..3b7411ee97c17df01fb2b11aa88868813d07796f 100644 --- a/micropython/modules/opencube_brick/oc_i2c_slave.c +++ b/micropython/modules/opencube_brick/oc_i2c_slave.c @@ -19,6 +19,8 @@ // sequentially from the current memory address. typedef struct { uint8_t mem[256]; + uint64_t mem_written[4]; + uint64_t mem_read[4]; uint8_t mem_address; bool mem_address_written; } oc_i2c_slave_memory; @@ -27,11 +29,11 @@ typedef struct _oc_i2c_slave_obj_t { mp_obj_base_t base; bool enabled; uint8_t address; - oc_i2c_slave_memory context; uint16_t mp_irq_trigger; // user IRQ trigger mask uint16_t mp_irq_flags; // user IRQ active IRQ flags uint16_t mp_irq_flags_unfinished; // future IRQ flags mp_irq_obj_t *mp_irq_obj; // user IRQ object + oc_i2c_slave_memory context; } oc_i2c_slave_obj_t; const mp_obj_type_t oc_i2c_slave_type; @@ -40,11 +42,11 @@ static oc_i2c_slave_obj_t oc_i2c_slave_obj = { {&oc_i2c_slave_type}, false, 0, - {{0}}, 0, 0, 0, - NULL + NULL, + {{0}}, }; static bool reserved_addr(uint8_t addr); @@ -64,13 +66,15 @@ static void oc_i2c_slave_handler(i2c_inst_t *i2c, i2c_slave_event_t event) { switch (event) { case I2C_SLAVE_RECEIVE: // master has written some data - if (oc_i2c_slave_obj.context.mem_address_written) { + if (!oc_i2c_slave_obj.context.mem_address_written) { // writes always start with the memory address oc_i2c_slave_obj.context.mem_address = i2c_read_byte_raw(i2c); oc_i2c_slave_obj.context.mem_address_written = true; } else { // save into memory oc_i2c_slave_obj.context.mem[oc_i2c_slave_obj.context.mem_address] = i2c_read_byte_raw(i2c); + // save a flag of the written memory address using bits withou using division uint64_t + oc_i2c_slave_obj.context.mem_written[oc_i2c_slave_obj.context.mem_address >> 6] |= 1 << (oc_i2c_slave_obj.context.mem_address & (0xff>>2)); oc_i2c_slave_obj.context.mem_address++; oc_i2c_slave_obj.mp_irq_flags_unfinished |= OC_I2C_SLAVE_RECEIVE; } @@ -79,12 +83,15 @@ static void oc_i2c_slave_handler(i2c_inst_t *i2c, i2c_slave_event_t event) { case I2C_SLAVE_REQUEST: // master is requesting data // load from memory i2c_write_byte_raw(i2c, oc_i2c_slave_obj.context.mem[oc_i2c_slave_obj.context.mem_address]); + //save a flag of read memory address + oc_i2c_slave_obj.context.mem_read[oc_i2c_slave_obj.context.mem_address >> 6] |= 1 << (oc_i2c_slave_obj.context.mem_address & (0xff>>2)); + oc_i2c_slave_obj.context.mem_address++; oc_i2c_slave_obj.mp_irq_flags_unfinished |= OC_I2C_SLAVE_READ; break; case I2C_SLAVE_FINISH: // master has signalled Stop / Restart - oc_i2c_slave_obj.context.mem_address = 0; + //oc_i2c_slave_obj.context.mem_address = 0; oc_i2c_slave_obj.context.mem_address_written = false; // Check the flags to see if the user handler should be called if (oc_i2c_slave_obj.mp_irq_trigger & oc_i2c_slave_obj.mp_irq_flags_unfinished) { @@ -118,10 +125,11 @@ static mp_obj_t oc_i2c_slave_init_helper(oc_i2c_slave_obj_t *self, size_t n_args if (self->enabled) { i2c_slave_deinit(UTZ_I2C_BUS); } - memset(&self->context, 0, sizeof(oc_i2c_slave_memory)); + self->mp_irq_obj = NULL; self->mp_irq_trigger = 0; self->mp_irq_flags = 0; + memset(&self->context, 0, sizeof(oc_i2c_slave_memory)); self->enabled = true; self->address = args[ARG_address].u_int; @@ -168,7 +176,8 @@ static MP_DEFINE_CONST_FUN_OBJ_KW(oc_i2c_slave_init_obj, 1, oc_i2c_slave_init); static void oc_i2c_slave_print(const mp_print_t *print, mp_obj_t self_in) { oc_i2c_slave_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_printf(print, "Open-Cube I2C slave at address %u, irq=%d", self->address,self->mp_irq_trigger); + mp_printf(print, "Open-Cube I2C slave at address %u, flags=%d", + self->address,self->mp_irq_trigger, self->mp_irq_flags); } // I2C_slave.read() @@ -176,6 +185,8 @@ static mp_obj_t oc_i2c_slave_read(mp_obj_t self_in, mp_obj_t addr) { oc_i2c_slave_obj_t *self = MP_OBJ_TO_PTR(self_in); if (mp_obj_is_int(addr)) { uint8_t address = mp_obj_get_int(addr); + // clear the flag of write memory address + self->context.mem_written[address >> 6] &= ~(1 << (address & (0xff>>2))); return mp_obj_new_int(self->context.mem[address]); } return mp_const_none; @@ -188,12 +199,40 @@ static mp_obj_t oc_i2c_slave_write(mp_obj_t self_in, mp_obj_t addr, mp_obj_t dat if (mp_obj_is_int(addr) && mp_obj_is_int(data)) { uint8_t address = mp_obj_get_int(addr); uint8_t value = mp_obj_get_int(data); + // clear the flag of read memory address + self->context.mem_read[address >> 6] &= ~(1 << (address & (0xff>>2))); self->context.mem[address] = value; } return mp_const_none; } static MP_DEFINE_CONST_FUN_OBJ_3(oc_i2c_slave_write_obj, oc_i2c_slave_write); +// I2C_slave.read_flags() +static mp_obj_t oc_i2c_slave_read_flags(mp_obj_t self_in) { + oc_i2c_slave_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t tuple[4] = { + tuple[0] = mp_obj_new_int_from_ull(self->context.mem_read[0]), + tuple[1] = mp_obj_new_int_from_ull(self->context.mem_read[1]), + tuple[2] = mp_obj_new_int_from_ull(self->context.mem_read[2]), + tuple[3] = mp_obj_new_int_from_ull(self->context.mem_read[3]), + }; + return mp_obj_new_tuple(4, tuple); +} +static MP_DEFINE_CONST_FUN_OBJ_1(oc_i2c_slave_read_flags_obj, oc_i2c_slave_read_flags); + +// I2C_slave.written_flags() +static mp_obj_t oc_i2c_slave_written_flags(mp_obj_t self_in) { + oc_i2c_slave_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t tuple[4] = { + tuple[0] = mp_obj_new_int_from_ull(self->context.mem_written[0]), + tuple[1] = mp_obj_new_int_from_ull(self->context.mem_written[1]), + tuple[2] = mp_obj_new_int_from_ull(self->context.mem_written[2]), + tuple[3] = mp_obj_new_int_from_ull(self->context.mem_written[3]), + }; + return mp_obj_new_tuple(4, tuple); +} +static MP_DEFINE_CONST_FUN_OBJ_1(oc_i2c_slave_written_flags_obj, oc_i2c_slave_written_flags); + // I2C_slave.irq() static mp_obj_t oc_i2c_slave_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { mp_arg_val_t args[MP_IRQ_ARG_INIT_NUM_ARGS]; @@ -210,8 +249,10 @@ static mp_obj_t oc_i2c_slave_deinit(mp_obj_t self_in) { i2c_slave_deinit(UTZ_I2C_BUS); i2c_deinit(UTZ_I2C_BUS); self->enabled = false; + MP_STATE_PORT(oc_i2c_slave_irq_obj) = NULL; self->mp_irq_obj = NULL; self->mp_irq_trigger = 0; + return mp_const_none; } static MP_DEFINE_CONST_FUN_OBJ_1(oc_i2c_slave_deinit_obj, oc_i2c_slave_deinit); @@ -241,6 +282,7 @@ static mp_irq_obj_t *oc_i2c_slave_irq_helper(oc_i2c_slave_obj_t *self, bool any_ if (self->mp_irq_obj == NULL) { self->mp_irq_trigger = 0; self->mp_irq_obj = mp_irq_new(&oc_i2c_slave_irq_methods, MP_OBJ_FROM_PTR(self)); + MP_STATE_PORT(oc_i2c_slave_irq_obj) = self->mp_irq_obj; } if (any_args) { @@ -270,6 +312,8 @@ static mp_irq_obj_t *oc_i2c_slave_irq_helper(oc_i2c_slave_obj_t *self, bool any_ static const mp_rom_map_elem_t oc_i2c_slave_locals_dict[] = { { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&oc_i2c_slave_read_obj) }, { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&oc_i2c_slave_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_read_flags), MP_ROM_PTR(&oc_i2c_slave_read_flags_obj) }, + { MP_ROM_QSTR(MP_QSTR_written_flags), MP_ROM_PTR(&oc_i2c_slave_written_flags_obj) }, { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&oc_i2c_slave_init_obj) }, { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&oc_i2c_slave_irq_obj) }, { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&oc_i2c_slave_deinit_obj) }, @@ -288,4 +332,6 @@ MP_DEFINE_CONST_OBJ_TYPE( make_new, &oc_i2c_slave_make_new, locals_dict, &oc_i2c_slave_locals_dict_obj, print, &oc_i2c_slave_print -); \ No newline at end of file +); + +MP_REGISTER_ROOT_POINTER(void *oc_i2c_slave_irq_obj); \ No newline at end of file diff --git a/micropython/mpy b/micropython/mpy index af2770e02c1fcd9e6517223ae81c9a0d089a23e1..3823aeb0f14c04084eba6566164d9b7dbd9e7ced 160000 --- a/micropython/mpy +++ b/micropython/mpy @@ -1 +1 @@ -Subproject commit af2770e02c1fcd9e6517223ae81c9a0d089a23e1 +Subproject commit 3823aeb0f14c04084eba6566164d9b7dbd9e7ced