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:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user