Skip to content

Commit

Permalink
ports/psoc6/machine_i2c: WIP adding I2C Slave class.
Browse files Browse the repository at this point in the history
Signed-off-by: enriquezgarc <[email protected]>
  • Loading branch information
jaenrig-ifx committed Jan 26, 2024
1 parent f22fd15 commit 12fab71
Showing 1 changed file with 110 additions and 53 deletions.
163 changes: 110 additions & 53 deletions ports/psoc6/machine_i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,23 @@ typedef struct _machine_i2c_obj_t {
machine_pin_phy_obj_t *scl;
machine_pin_phy_obj_t *sda;
cyhal_i2c_cfg_t cfg;
mp_obj_t callback;
} machine_i2c_obj_t;

machine_i2c_obj_t *i2c_obj[MAX_I2C] = { NULL };

static inline machine_i2c_obj_t *i2c_obj_alloc() {
static inline machine_i2c_obj_t *i2c_obj_alloc(bool is_slave) {
for (uint8_t i = 0; i < MAX_I2C; i++)
{
if (i2c_obj[i] == NULL) {
i2c_obj[i] = mp_obj_malloc(machine_i2c_obj_t, &machine_i2c_type);

const mp_obj_type_t *obj_type;
if (is_slave) {
obj_type = &machine_i2c_slave_type;
} else {
obj_type = &machine_i2c_type;
}
i2c_obj[i] = mp_obj_malloc(machine_i2c_obj_t, obj_type);
return i2c_obj[i];
}
}
Expand Down Expand Up @@ -112,24 +120,28 @@ STATIC inline void i2c_scl_free(machine_i2c_obj_t *i2c_obj) {

STATIC void machine_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
machine_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_printf(print, "I2C(freq=%u, scl=%u, sda=%u)", self->cfg.frequencyhal_hz, self->scl->addr, self->sda->addr);
mp_printf(print, "I2C(freq=%u, scl=%u, sda=%u, mode=%u, addr=%u)", self->cfg.frequencyhal_hz, self->scl->addr, self->sda->addr, self->cfg.is_slave, self->cfg.address);
}

STATIC void machine_i2c_init(mp_obj_base_t *self_in, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_freq, ARG_scl, ARG_sda, ARG_addr };
mp_obj_t machine_i2c_master_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
mp_arg_check_num(n_args, n_kw, 0, 3, true);

enum { ARG_freq, ARG_scl, ARG_sda };

static const mp_arg_t allowed_args[] = {
{ MP_QSTR_freq, MP_ARG_INT, {.u_int = DEFAULT_I2C_FREQ} },
{ MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_I2C_FREQ} },
{ MP_QSTR_scl, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
{ MP_QSTR_sda, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
{ MP_QSTR_addr, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1}}
{ MP_QSTR_sda, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }
};

// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);

machine_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
machine_i2c_obj_t *self = i2c_obj_alloc(false);
if (self == NULL) {
return mp_const_none;
}

// get scl & sda pins & configure them
if (args[ARG_scl].u_obj != mp_const_none) {
Expand All @@ -145,21 +157,51 @@ STATIC void machine_i2c_init(mp_obj_base_t *self_in, size_t n_args, const mp_obj
}

// initialise I2C at cyhal level
i2c_init(self, args[ARG_freq].u_int, args[ARG_addr].u_int);
i2c_init(self, args[ARG_freq].u_int, 0);

return MP_OBJ_FROM_PTR(self);
}

mp_obj_t machine_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_obj_t machine_i2c_slave_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
mp_arg_check_num(n_args, n_kw, 0, 4, true);

machine_i2c_obj_t *self = i2c_obj_alloc();
enum { ARG_freq, ARG_scl, ARG_sda, ARG_addr };

static const mp_arg_t allowed_args[] = {
{ MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_I2C_FREQ} },
{ MP_QSTR_scl, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
{ MP_QSTR_sda, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
{ MP_QSTR_addr, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1}}
};

// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);

machine_i2c_obj_t *self = i2c_obj_alloc(true);
if (self == NULL) {
return mp_const_none;
}

mp_map_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
machine_i2c_init((mp_obj_base_t *)self, n_args, args, &kw_args);
// get scl & sda pins & configure them
if (args[ARG_scl].u_obj != mp_const_none) {
i2c_scl_alloc(self, args[ARG_scl].u_obj);
} else {
mp_raise_TypeError(MP_ERROR_TEXT("SCL pin must be provided"));
}

if (args[ARG_sda].u_obj != mp_const_none) {
i2c_sda_alloc(self, args[ARG_sda].u_obj);
} else {
mp_raise_TypeError(MP_ERROR_TEXT("SDA pin must be provided"));
}

if (args[ARG_addr].u_int <= 0) {
mp_raise_TypeError(MP_ERROR_TEXT("Slave address needs to be provided"));
}

// initialise I2C at cyhal level
i2c_init(self, args[ARG_freq].u_int, args[ARG_addr].u_int);

return MP_OBJ_FROM_PTR(self);
}
Expand All @@ -180,7 +222,7 @@ STATIC int machine_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t le

if ((flags & MP_MACHINE_I2C_FLAG_READ) == MP_MACHINE_I2C_FLAG_READ) {
result = cyhal_i2c_master_read(&self->i2c_obj, addr, buf, len, timeout, send_stop);
i2c_assert_raise_val("cyhal_i2c_master_read failed with return code %lx !", result);
i2c_assert_raise_val("I2C transfer failed with return code %lx !", result);

return len;
} else {
Expand All @@ -192,7 +234,7 @@ STATIC int machine_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t le
// these 2 errors occur if nothing is attached to sda/scl, but they are pulled-up (0xaa2004) or not pulled-up (0xaa2003).
// In the latter case, due to not reaction at all the timeout has to expire. Latency is therefore high.
if (result != 0xaa2004 && result != 0xaa2003) {
i2c_assert_raise_val("cyhal_i2c_master_write failed with return code %lx !", result);
i2c_assert_raise_val("I2C transfer failed with return code %lx !", result);
}

return 1;
Expand All @@ -201,59 +243,71 @@ STATIC int machine_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t le
return len;
} else {
result = cyhal_i2c_master_write(&self->i2c_obj, addr, buf, len, timeout, send_stop);
i2c_assert_raise_val("cyhal_i2c_master_write failed with return code %lx !", result);
i2c_assert_raise_val("I2C transfer failed with return code %lx !", result);
}

return len;
}
}

// configure slave buffers
// i2c_master writes
// i2c_slave reads from write buffer
// i2c_slave does something about it
// i2c_master reads
// i2c_slave needs needs to have something there is the buffer

STATIC mp_obj_t machine_i2c_slave_configure_receive_buffer(mp_obj_t self_in /*pass a buffer*/) {
STATIC mp_obj_t machine_i2c_slave_configure_receive_buffer(mp_obj_t self_in, mp_obj_t buf_in) {
machine_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
(void)self->scl;
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_i2c_slave_conf_rx_buffer_obj, machine_i2c_slave_configure_receive_buffer);

// STATIC mp_obj_t machine_i2c_slave_configure_transmit_buffer(mp_obj_t self_in /*pass a buffer*/) {
// machine_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);

// return mp_const_none;
// }
// machine_i2c_slave_configure_rx_buffer() {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);

// }
cy_rslt_t result = cyhal_i2c_slave_config_write_buffer(&self->i2c_obj, bufinfo.buf, bufinfo.len);
i2c_assert_raise_val("I2C Slave configure receive buffer failed with return code %lx !", result);

// machine_i2c_skave_configure_tx_buffer() {
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_i2c_slave_conf_rx_buffer_obj, machine_i2c_slave_configure_receive_buffer);

// }
STATIC mp_obj_t machine_i2c_slave_configure_transmit_buffer(mp_obj_t self_in, mp_obj_t buf_in) {
machine_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);

// STATIC mp_obj_t machine_i2c_slave_configure_transmit_buffer(mp_obj_t self_in /*pass a buffer*/) {
// machine_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
cy_rslt_t result = cyhal_i2c_slave_config_read_buffer(&self->i2c_obj, bufinfo.buf, bufinfo.len);
i2c_assert_raise_val("I2C Slave configure receive buffer failed with return code %lx !", result);

// return mp_const_none;
// }
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_i2c_slave_conf_tx_buffer_obj, machine_i2c_slave_configure_transmit_buffer);

// machine_i2c_slave_register_callback(callback_function) {
static void i2c_irq_handler(void *callback_arg, cyhal_i2c_event_t event) {
machine_i2c_obj_t *self = callback_arg;
mp_sched_schedule(self->callback, MP_OBJ_FROM_PTR(self));
}

// }
STATIC mp_obj_t machine_i2c_slave_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_callback, ARG_events, ARG_priority};
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_callback, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
{ MP_QSTR_events, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = CYHAL_I2C_EVENT_NONE }},
{ MP_QSTR_priority, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 3 }},
};
machine_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);

// machine_i2c_slave_tx_register_callback(callback_function) {
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);

// }
self->callback = args[ARG_callback].u_obj;

cyhal_i2c_register_callback(&self->i2c_obj, i2c_irq_handler, self);
cyhal_i2c_enable_event(&self->i2c_obj, args[ARG_callback].u_int, args[ARG_priority].u_int, true);

return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_slave_irq_obj, 1, machine_i2c_slave_irq);

STATIC mp_obj_t machine_i2c_slave_irq_disable(mp_obj_t self_in) {
machine_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
cyhal_i2c_enable_event(&self->i2c_obj, CYHAL_I2C_EVENT_NONE, 3, false);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_i2c_slave_irq_disable_obj, machine_i2c_slave_irq_disable);

STATIC const mp_machine_i2c_p_t machine_i2c_p = {
.init = machine_i2c_init,
.deinit = machine_i2c_deinit,
.transfer_single = machine_i2c_transfer,
.transfer = mp_machine_i2c_transfer_adaptor
Expand All @@ -263,7 +317,7 @@ MP_DEFINE_CONST_OBJ_TYPE(
machine_i2c_type,
MP_QSTR_I2C,
MP_TYPE_FLAG_NONE,
make_new, machine_i2c_make_new,
make_new, machine_i2c_master_make_new,
print, machine_i2c_print,
protocol, &machine_i2c_p,
locals_dict, &mp_machine_i2c_locals_dict
Expand All @@ -273,7 +327,10 @@ MP_DEFINE_CONST_OBJ_TYPE(

STATIC const mp_rom_map_elem_t machine_i2c_slave_locals_dict_table[] = {
// Functions
{ MP_ROM_QSTR(MP_QSTR_slave_conf_rx_buffer), MP_ROM_PTR(&machine_i2c_slave_conf_rx_buffer_obj) },
{ MP_ROM_QSTR(MP_QSTR_conf_receive_buffer), MP_ROM_PTR(&machine_i2c_slave_conf_rx_buffer_obj) },
{ MP_ROM_QSTR(MP_QSTR_conf_transmit_buffer), MP_ROM_PTR(&machine_i2c_slave_conf_tx_buffer_obj) },
{ MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&machine_i2c_slave_irq_obj) },
{ MP_ROM_QSTR(MP_QSTR_irq_disable), MP_ROM_PTR(&machine_i2c_slave_irq_disable_obj) },

// Const
{ MP_ROM_QSTR(MP_QSTR_RD_EVENT), MP_ROM_INT(CYHAL_I2C_SLAVE_READ_EVENT) },
Expand All @@ -290,7 +347,7 @@ MP_DEFINE_CONST_OBJ_TYPE(
machine_i2c_slave_type,
MP_QSTR_I2CSlave,
MP_TYPE_FLAG_NONE,
make_new, machine_i2c_make_new,
make_new, machine_i2c_slave_make_new,
print, machine_i2c_print,
locals_dict, &machine_i2c_slave_locals_dict
);
Expand Down

0 comments on commit 12fab71

Please sign in to comment.