samd/machine_i2c: Add the timeout keyword argument to the constructor.

To make it compliant with the documentation.  The default value is 50000us.

Signed-off-by: robert-hh <robert@hammelrath.com>
This commit is contained in:
robert-hh
2025-03-12 20:28:51 +01:00
committed by Damien George
parent 8e328da9bf
commit 2fda4bbe05

View File

@@ -37,9 +37,9 @@
#include "genhdr/pins.h" #include "genhdr/pins.h"
#include "clock_config.h" #include "clock_config.h"
#define DEFAULT_I2C_FREQ (400000) #define DEFAULT_I2C_FREQ (400000)
#define RISETIME_NS (200) #define RISETIME_NS (200)
#define I2C_TIMEOUT (100) #define DEFAULT_I2C_TIMEOUT (50000)
#define IS_BUS_BUSY (i2c->I2CM.STATUS.bit.BUSSTATE == 3) #define IS_BUS_BUSY (i2c->I2CM.STATUS.bit.BUSSTATE == 3)
#define NACK_RECVD (i2c->I2CM.STATUS.bit.RXNACK == 1) #define NACK_RECVD (i2c->I2CM.STATUS.bit.RXNACK == 1)
@@ -67,6 +67,7 @@ typedef struct _machine_i2c_obj_t {
uint8_t state; uint8_t state;
uint32_t freq; uint32_t freq;
uint32_t timeout; uint32_t timeout;
uint32_t timer;
size_t len; size_t len;
uint8_t *buf; uint8_t *buf;
} machine_i2c_obj_t; } machine_i2c_obj_t;
@@ -88,7 +89,7 @@ void common_i2c_irq_handler(int i2c_id) {
if (self->len > 0) { if (self->len > 0) {
*(self->buf)++ = i2c->I2CM.DATA.reg; *(self->buf)++ = i2c->I2CM.DATA.reg;
self->len--; self->len--;
self->timeout = I2C_TIMEOUT; self->timer = self->timeout;
} }
if (self->len > 0) { // no ACK at the last byte if (self->len > 0) { // no ACK at the last byte
PREPARE_ACK; // Send ACK PREPARE_ACK; // Send ACK
@@ -105,7 +106,7 @@ void common_i2c_irq_handler(int i2c_id) {
} else if (self->len > 0) { // data to be sent } else if (self->len > 0) { // data to be sent
i2c->I2CM.DATA.bit.DATA = *(self->buf)++; i2c->I2CM.DATA.bit.DATA = *(self->buf)++;
self->len--; self->len--;
self->timeout = I2C_TIMEOUT; self->timer = self->timeout;
} else { // No data left, if there was any. } else { // No data left, if there was any.
self->state = state_done; self->state = state_done;
i2c->I2CM.INTFLAG.reg |= SERCOM_I2CM_INTFLAG_MB; i2c->I2CM.INTFLAG.reg |= SERCOM_I2CM_INTFLAG_MB;
@@ -120,12 +121,13 @@ void common_i2c_irq_handler(int i2c_id) {
static void machine_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { 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); machine_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_printf(print, "I2C(%u, freq=%u, scl=\"%q\", sda=\"%q\")", mp_printf(print, "I2C(%u, freq=%u, scl=\"%q\", sda=\"%q\", timeout=%u)",
self->id, self->freq, pin_find_by_id(self->scl)->name, pin_find_by_id(self->sda)->name); self->id, self->freq, pin_find_by_id(self->scl)->name, pin_find_by_id(self->sda)->name,
self->timeout * 1000);
} }
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 *all_args) { 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 *all_args) {
enum { ARG_id, ARG_freq, ARG_scl, ARG_sda }; enum { ARG_id, ARG_freq, ARG_scl, ARG_sda, ARG_timeout };
static const mp_arg_t allowed_args[] = { static const mp_arg_t allowed_args[] = {
#if MICROPY_HW_DEFAULT_I2C_ID < 0 #if MICROPY_HW_DEFAULT_I2C_ID < 0
{ MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} },
@@ -140,6 +142,7 @@ mp_obj_t machine_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n
{ MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
{ MP_QSTR_sda, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_sda, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
#endif #endif
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_I2C_TIMEOUT} },
}; };
// Parse args. // Parse args.
@@ -168,6 +171,8 @@ mp_obj_t machine_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n
} }
MP_STATE_PORT(sercom_table[self->id]) = self; MP_STATE_PORT(sercom_table[self->id]) = self;
self->freq = args[ARG_freq].u_int; self->freq = args[ARG_freq].u_int;
// The unit for ARG_timeout is us, but the code uses ms.
self->timeout = args[ARG_timeout].u_int / 1000;
// Configure the Pin mux. // Configure the Pin mux.
mp_hal_set_pin_mux(self->scl, scl_pad_config.alt_fct); mp_hal_set_pin_mux(self->scl, scl_pad_config.alt_fct);
@@ -224,13 +229,13 @@ static int machine_i2c_transfer_single(mp_obj_base_t *self_in, uint16_t addr, si
machine_i2c_obj_t *self = (machine_i2c_obj_t *)self_in; machine_i2c_obj_t *self = (machine_i2c_obj_t *)self_in;
Sercom *i2c = self->instance; Sercom *i2c = self->instance;
self->timeout = I2C_TIMEOUT; self->timer = self->timeout;
self->len = len; self->len = len;
self->buf = buf; self->buf = buf;
// Wait a while if the bus is busy // Wait a while if the bus is busy
while (IS_BUS_BUSY && self->timeout) { while (IS_BUS_BUSY && self->timer) {
MICROPY_EVENT_POLL_HOOK MICROPY_EVENT_POLL_HOOK
if (--self->timeout == 0) { if (--self->timer == 0) {
return -MP_ETIMEDOUT; return -MP_ETIMEDOUT;
} }
} }
@@ -242,9 +247,9 @@ static int machine_i2c_transfer_single(mp_obj_base_t *self_in, uint16_t addr, si
i2c->I2CM.ADDR.bit.ADDR = (addr << 1) | READ_MODE; i2c->I2CM.ADDR.bit.ADDR = (addr << 1) | READ_MODE;
// Transfer the data // Transfer the data
self->timeout = I2C_TIMEOUT; self->timer = self->timeout;
while (self->state == state_busy && self->timeout) { while (self->state == state_busy && self->timer) {
self->timeout--; self->timer--;
MICROPY_EVENT_POLL_HOOK MICROPY_EVENT_POLL_HOOK
} }
i2c->I2CM.INTENCLR.reg = SERCOM_I2CM_INTENSET_MB | SERCOM_I2CM_INTENSET_SB | SERCOM_I2CM_INTENSET_ERROR; i2c->I2CM.INTENCLR.reg = SERCOM_I2CM_INTENSET_MB | SERCOM_I2CM_INTENSET_SB | SERCOM_I2CM_INTENSET_ERROR;
@@ -256,7 +261,7 @@ static int machine_i2c_transfer_single(mp_obj_base_t *self_in, uint16_t addr, si
} else if (self->state == state_buserr) { } else if (self->state == state_buserr) {
SET_STOP_STATE; SET_STOP_STATE;
return -MP_EIO; return -MP_EIO;
} else if (self->timeout == 0) { } else if (self->timer == 0) {
SET_STOP_STATE; SET_STOP_STATE;
return -MP_ETIMEDOUT; return -MP_ETIMEDOUT;
} }