Skip to content

add keyword timeout to I2C -- only used for bitbangioi #829

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ports/atmel-samd/common-hal/busio/I2C.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
#define ATTEMPTS 2

void common_hal_busio_i2c_construct(busio_i2c_obj_t *self,
const mcu_pin_obj_t* scl, const mcu_pin_obj_t* sda, uint32_t frequency) {
const mcu_pin_obj_t* scl, const mcu_pin_obj_t* sda, uint32_t frequency, uint32_t timeout) {
Sercom* sercom = NULL;
uint8_t sercom_index;
uint32_t sda_pinmux = 0;
Expand Down
2 changes: 1 addition & 1 deletion ports/nrf/common-hal/busio/I2C.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
#include "pins.h"
#include "nrf.h"

void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, const mcu_pin_obj_t* scl, const mcu_pin_obj_t* sda, uint32_t frequency) {
void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, const mcu_pin_obj_t* scl, const mcu_pin_obj_t* sda, uint32_t frequency, uint32_t timeout ) {
if (scl->pin == sda->pin) {
mp_raise_ValueError("Invalid pins");
}
Expand Down
4 changes: 1 addition & 3 deletions py/objexcept.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,9 +275,7 @@ MP_DEFINE_EXCEPTION(Exception, BaseException)
MP_DEFINE_EXCEPTION(UnboundLocalError, NameError)
*/
MP_DEFINE_EXCEPTION(OSError, Exception)
#if MICROPY_PY_BUILTINS_TIMEOUTERROR
MP_DEFINE_EXCEPTION(TimeoutError, OSError)
#endif
MP_DEFINE_EXCEPTION(TimeoutError, OSError)
/*
MP_DEFINE_EXCEPTION(BlockingIOError, OSError)
MP_DEFINE_EXCEPTION(ChildProcessError, OSError)
Expand Down
7 changes: 5 additions & 2 deletions shared-bindings/bitbangio/I2C.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "lib/utils/context_manager_helpers.h"
#include "py/mperrno.h"
#include "py/runtime.h"

//| .. currentmodule:: bitbangio
//|
//| :class:`I2C` --- Two wire serial protocol
Expand All @@ -49,6 +50,7 @@
//| :param ~microcontroller.Pin scl: The clock pin
//| :param ~microcontroller.Pin sda: The data pin
//| :param int frequency: The clock frequency of the bus
//| :param int timeout: The maximum clock stretching timeout in microseconds
//|
STATIC mp_obj_t bitbangio_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) {
mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, true);
Expand All @@ -57,19 +59,20 @@ STATIC mp_obj_t bitbangio_i2c_make_new(const mp_obj_type_t *type, size_t n_args,
self->base.type = &bitbangio_i2c_type;
mp_map_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw, pos_args + n_args);
enum { ARG_scl, ARG_sda, ARG_frequency };
enum { ARG_scl, ARG_sda, ARG_frequency, ARG_timeout };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_sda, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} },
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 255} },
};
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);
assert_pin(args[ARG_scl].u_obj, false);
assert_pin(args[ARG_sda].u_obj, false);
const mcu_pin_obj_t* scl = MP_OBJ_TO_PTR(args[ARG_scl].u_obj);
const mcu_pin_obj_t* sda = MP_OBJ_TO_PTR(args[ARG_sda].u_obj);
shared_module_bitbangio_i2c_construct(self, scl, sda, args[ARG_frequency].u_int);
shared_module_bitbangio_i2c_construct(self, scl, sda, args[ARG_frequency].u_int, args[ARG_timeout].u_int);
return (mp_obj_t)self;
}

Expand Down
3 changes: 2 additions & 1 deletion shared-bindings/bitbangio/I2C.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ extern const mp_obj_type_t bitbangio_i2c_type;
extern void shared_module_bitbangio_i2c_construct(bitbangio_i2c_obj_t *self,
const mcu_pin_obj_t * scl,
const mcu_pin_obj_t * sda,
uint32_t frequency);
uint32_t frequency,
uint32_t us_timeout);

extern void shared_module_bitbangio_i2c_deinit(bitbangio_i2c_obj_t *self);
extern bool shared_module_bitbangio_i2c_deinited(bitbangio_i2c_obj_t *self);
Expand Down
6 changes: 4 additions & 2 deletions shared-bindings/busio/I2C.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,20 @@
//| :param ~microcontroller.Pin scl: The clock pin
//| :param ~microcontroller.Pin sda: The data pin
//| :param int frequency: The clock frequency in Hertz
//| :param int timeout: The maximum clock stretching timeut - only for bitbang
//|
STATIC mp_obj_t busio_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) {
mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, true);
busio_i2c_obj_t *self = m_new_obj(busio_i2c_obj_t);
self->base.type = &busio_i2c_type;
mp_map_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw, pos_args + n_args);
enum { ARG_scl, ARG_sda, ARG_frequency };
enum { ARG_scl, ARG_sda, ARG_frequency, ARG_timeout };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_sda, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} },
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 255} },
};
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);
Expand All @@ -77,7 +79,7 @@ STATIC mp_obj_t busio_i2c_make_new(const mp_obj_type_t *type, size_t n_args, siz
assert_pin_free(scl);
const mcu_pin_obj_t* sda = MP_OBJ_TO_PTR(args[ARG_sda].u_obj);
assert_pin_free(sda);
common_hal_busio_i2c_construct(self, scl, sda, args[ARG_frequency].u_int);
common_hal_busio_i2c_construct(self, scl, sda, args[ARG_frequency].u_int, args[ARG_timeout].u_int);
return (mp_obj_t)self;
}

Expand Down
3 changes: 2 additions & 1 deletion shared-bindings/busio/I2C.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ extern const mp_obj_type_t busio_i2c_type;
extern void common_hal_busio_i2c_construct(busio_i2c_obj_t *self,
const mcu_pin_obj_t * scl,
const mcu_pin_obj_t * sda,
uint32_t frequency);
uint32_t frequency,
uint32_t timeout);

extern void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self);
extern bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self);
Expand Down
15 changes: 11 additions & 4 deletions shared-module/bitbangio/I2C.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,15 @@
*/

#include "shared-bindings/bitbangio/I2C.h"

#include "py/mperrno.h"
#include "py/obj.h"
#include "py/runtime.h"

#include "common-hal/microcontroller/Pin.h"
#include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/digitalio/DigitalInOut.h"
#include "shared-module/bitbangio/types.h"

#define I2C_STRETCH_LIMIT 255

STATIC void delay(bitbangio_i2c_obj_t *self) {
// We need to use an accurate delay to get acceptable I2C
Expand All @@ -48,11 +47,16 @@ STATIC void scl_low(bitbangio_i2c_obj_t *self) {

STATIC void scl_release(bitbangio_i2c_obj_t *self) {
common_hal_digitalio_digitalinout_set_value(&self->scl, true);
uint32_t count = self->us_timeout;
delay(self);
// For clock stretching, wait for the SCL pin to be released, with timeout.
for (int count = I2C_STRETCH_LIMIT; !common_hal_digitalio_digitalinout_get_value(&self->scl) && count; --count) {
for (; !common_hal_digitalio_digitalinout_get_value(&self->scl) && count; --count) {
common_hal_mcu_delay_us(1);
}
// raise exception on timeout
if (count == 0) {
mp_raise_msg(&mp_type_TimeoutError, "Clock stretch too long");
}
}

STATIC void sda_low(bitbangio_i2c_obj_t *self) {
Expand Down Expand Up @@ -142,7 +146,10 @@ STATIC bool read_byte(bitbangio_i2c_obj_t *self, uint8_t *val, bool ack) {
void shared_module_bitbangio_i2c_construct(bitbangio_i2c_obj_t *self,
const mcu_pin_obj_t * scl,
const mcu_pin_obj_t * sda,
uint32_t frequency) {
uint32_t frequency,
uint32_t us_timeout) {

self->us_timeout = us_timeout;
self->us_delay = 500000 / frequency;
if (self->us_delay == 0) {
self->us_delay = 1;
Expand Down
1 change: 1 addition & 0 deletions shared-module/bitbangio/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ typedef struct {
digitalio_digitalinout_obj_t scl;
digitalio_digitalinout_obj_t sda;
uint32_t us_delay;
uint32_t us_timeout;
volatile bool locked;
} bitbangio_i2c_obj_t;

Expand Down
4 changes: 2 additions & 2 deletions shared-module/busio/I2C.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@
#include "py/nlr.h"

void common_hal_busio_i2c_construct(busio_i2c_obj_t *self,
const mcu_pin_obj_t* scl, const mcu_pin_obj_t* sda, uint32_t freq) {
shared_module_bitbangio_i2c_construct(&self->bitbang, scl, sda, freq);
const mcu_pin_obj_t* scl, const mcu_pin_obj_t* sda, uint32_t freq, uint32_t timeout) {
shared_module_bitbangio_i2c_construct(&self->bitbang, scl, sda, freq, timeout);
}

bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self) {
Expand Down