From 0cdbd356fdd9dc5ad9c88bb0ee9b027b98981386 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 14 Mar 2016 11:56:23 +0000 Subject: [PATCH] esp8266: Implement bit-bang I2C read, and add i2c.readfrom method. I2C reading tested with TSL2561 luminosity sensor. --- esp8266/modpybi2c.c | 67 ++++++++++++++++++++++++++++++++++++++++++ esp8266/qstrdefsport.h | 2 ++ 2 files changed, 69 insertions(+) diff --git a/esp8266/modpybi2c.c b/esp8266/modpybi2c.c index ad65d431b5..0216abeb99 100644 --- a/esp8266/modpybi2c.c +++ b/esp8266/modpybi2c.c @@ -186,6 +186,52 @@ er: nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "I2C bus error")); } +STATIC int mphal_i2c_read_byte(pyb_i2c_obj_t *self, uint8_t *val) { + mphal_i2c_wait_a(); + mphal_i2c_set_scl(self, 0); + mphal_i2c_wait_a(); + + uint8_t dat = 0; + for (int i = 7; i >= 0; i--) { + mphal_i2c_set_scl(self, 1); + mphal_i2c_wait_a(); + dat = (dat << 1) | mphal_i2c_get_sda(self); + mphal_i2c_wait_a(); + mphal_i2c_set_scl(self, 0); + mphal_i2c_wait_a(); + } + *val = dat; + + mphal_i2c_wait_a(); + mphal_i2c_set_scl(self, 1); + mphal_i2c_wait_a(); + mphal_i2c_wait_b(); + mphal_i2c_set_scl(self, 0); + mphal_i2c_wait_a(); + + return 1; // success +} + +STATIC void mphal_i2c_read(pyb_i2c_obj_t *self, uint8_t addr, uint8_t *data, size_t len, bool stop) { + mphal_i2c_start(self); + if (!mphal_i2c_write_byte(self, (addr << 1) | 1)) { + goto er; + } + while (len--) { + if (!mphal_i2c_read_byte(self, data++)) { + goto er; + } + } + if (stop) { + mphal_i2c_stop(self); + } + return; + +er: + mphal_i2c_stop(self); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "I2C bus error")); +} + /******************************************************************************/ // MicroPython bindings for I2C @@ -219,6 +265,26 @@ STATIC mp_obj_t pyb_i2c_obj_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_ } MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_init_obj, 1, pyb_i2c_obj_init); +STATIC mp_obj_t pyb_i2c_readfrom(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_addr, ARG_n, ARG_stop }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_n, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_stop, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, + }; + pyb_i2c_obj_t *self = pos_args[0]; + 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); + + // do the I2C transfer + vstr_t vstr; + vstr_init_len(&vstr, args[ARG_n].u_int); + mphal_i2c_read(self, args[ARG_addr].u_int, (uint8_t*)vstr.buf, vstr.len, args[ARG_stop].u_bool); + + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_readfrom_obj, 1, pyb_i2c_readfrom); + STATIC mp_obj_t pyb_i2c_writeto(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_addr, ARG_buf, ARG_stop }; static const mp_arg_t allowed_args[] = { @@ -243,6 +309,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_writeto_obj, 1, pyb_i2c_writeto); STATIC const mp_rom_map_elem_t pyb_i2c_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_i2c_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_readfrom), MP_ROM_PTR(&pyb_i2c_readfrom_obj) }, { MP_ROM_QSTR(MP_QSTR_writeto), MP_ROM_PTR(&pyb_i2c_writeto_obj) }, }; diff --git a/esp8266/qstrdefsport.h b/esp8266/qstrdefsport.h index 30b811e0c1..5687538928 100644 --- a/esp8266/qstrdefsport.h +++ b/esp8266/qstrdefsport.h @@ -148,10 +148,12 @@ Q(init) Q(scl) Q(sda) Q(freq) +Q(readfrom) Q(writeto) Q(stop) Q(buf) Q(addr) +Q(n) // utime Q(utime)