extmod/machine_i2c: Make C-level functions return -errno on I2C error.

This commit is contained in:
Damien George 2016-11-23 13:23:50 +11:00
parent 946f8dd46f
commit ced240e72a
1 changed files with 144 additions and 78 deletions

View File

@ -62,7 +62,10 @@ STATIC int mp_hal_i2c_scl_release(machine_i2c_obj_t *self) {
for (; mp_hal_pin_read(self->scl) == 0 && count; --count) { for (; mp_hal_pin_read(self->scl) == 0 && count; --count) {
mp_hal_delay_us_fast(1); mp_hal_delay_us_fast(1);
} }
return count != 0; if (count == 0) {
return -MP_ETIMEDOUT;
}
return 0; // success
} }
STATIC void mp_hal_i2c_sda_low(machine_i2c_obj_t *self) { STATIC void mp_hal_i2c_sda_low(machine_i2c_obj_t *self) {
@ -81,9 +84,12 @@ STATIC int mp_hal_i2c_start(machine_i2c_obj_t *self) {
mp_hal_i2c_sda_release(self); mp_hal_i2c_sda_release(self);
mp_hal_i2c_delay(self); mp_hal_i2c_delay(self);
int ret = mp_hal_i2c_scl_release(self); int ret = mp_hal_i2c_scl_release(self);
if (ret != 0) {
return ret;
}
mp_hal_i2c_sda_low(self); mp_hal_i2c_sda_low(self);
mp_hal_i2c_delay(self); mp_hal_i2c_delay(self);
return ret; return 0; // success
} }
STATIC int mp_hal_i2c_stop(machine_i2c_obj_t *self) { STATIC int mp_hal_i2c_stop(machine_i2c_obj_t *self) {
@ -106,6 +112,10 @@ STATIC void mp_hal_i2c_init(machine_i2c_obj_t *self, uint32_t freq) {
mp_hal_i2c_stop(self); // ignore error mp_hal_i2c_stop(self); // ignore error
} }
// return value:
// 0 - byte written and ack received
// 1 - byte written and nack received
// <0 - error, with errno being the negative of the return value
STATIC int mp_hal_i2c_write_byte(machine_i2c_obj_t *self, uint8_t val) { STATIC int mp_hal_i2c_write_byte(machine_i2c_obj_t *self, uint8_t val) {
mp_hal_i2c_delay(self); mp_hal_i2c_delay(self);
mp_hal_i2c_scl_low(self); mp_hal_i2c_scl_low(self);
@ -117,26 +127,31 @@ STATIC int mp_hal_i2c_write_byte(machine_i2c_obj_t *self, uint8_t val) {
mp_hal_i2c_sda_low(self); mp_hal_i2c_sda_low(self);
} }
mp_hal_i2c_delay(self); mp_hal_i2c_delay(self);
if (!mp_hal_i2c_scl_release(self)) { int ret = mp_hal_i2c_scl_release(self);
if (ret != 0) {
mp_hal_i2c_sda_release(self); mp_hal_i2c_sda_release(self);
return 0; // failure return ret;
} }
mp_hal_i2c_scl_low(self); mp_hal_i2c_scl_low(self);
} }
mp_hal_i2c_sda_release(self); mp_hal_i2c_sda_release(self);
mp_hal_i2c_delay(self); mp_hal_i2c_delay(self);
if (!mp_hal_i2c_scl_release(self)) { int ret = mp_hal_i2c_scl_release(self);
return 0; // failure if (ret != 0) {
return ret;
} }
int ret = mp_hal_i2c_sda_read(self); int ack = mp_hal_i2c_sda_read(self);
mp_hal_i2c_delay(self); mp_hal_i2c_delay(self);
mp_hal_i2c_scl_low(self); mp_hal_i2c_scl_low(self);
return !ret; return ack;
} }
// return value:
// 0 - success
// <0 - error, with errno being the negative of the return value
STATIC int mp_hal_i2c_read_byte(machine_i2c_obj_t *self, uint8_t *val, int nack) { STATIC int mp_hal_i2c_read_byte(machine_i2c_obj_t *self, uint8_t *val, int nack) {
mp_hal_i2c_delay(self); mp_hal_i2c_delay(self);
mp_hal_i2c_scl_low(self); mp_hal_i2c_scl_low(self);
@ -144,8 +159,9 @@ STATIC int mp_hal_i2c_read_byte(machine_i2c_obj_t *self, uint8_t *val, int nack)
uint8_t data = 0; uint8_t data = 0;
for (int i = 7; i >= 0; i--) { for (int i = 7; i >= 0; i--) {
if (!mp_hal_i2c_scl_release(self)) { int ret = mp_hal_i2c_scl_release(self);
return 0; if (ret != 0) {
return ret;
} }
data = (data << 1) | mp_hal_i2c_sda_read(self); data = (data << 1) | mp_hal_i2c_sda_read(self);
mp_hal_i2c_scl_low(self); mp_hal_i2c_scl_low(self);
@ -158,67 +174,98 @@ STATIC int mp_hal_i2c_read_byte(machine_i2c_obj_t *self, uint8_t *val, int nack)
mp_hal_i2c_sda_low(self); mp_hal_i2c_sda_low(self);
} }
mp_hal_i2c_delay(self); mp_hal_i2c_delay(self);
if (!mp_hal_i2c_scl_release(self)) { int ret = mp_hal_i2c_scl_release(self);
if (ret != 0) {
mp_hal_i2c_sda_release(self); mp_hal_i2c_sda_release(self);
return 0; // failure return ret;
} }
mp_hal_i2c_scl_low(self); mp_hal_i2c_scl_low(self);
mp_hal_i2c_sda_release(self); mp_hal_i2c_sda_release(self);
return 1; // success return 0; // success
} }
STATIC void mp_hal_i2c_write(machine_i2c_obj_t *self, uint8_t addr, const uint8_t *src, size_t len, bool stop) { // return value:
// >=0 - number of acks received
// <0 - error, with errno being the negative of the return value
STATIC int mp_hal_i2c_write(machine_i2c_obj_t *self, uint8_t addr, const uint8_t *src, size_t len, bool stop) {
// start the I2C transaction // start the I2C transaction
if (!mp_hal_i2c_start(self)) { int ret = mp_hal_i2c_start(self);
goto er; if (ret != 0) {
return ret;
} }
// write the slave address // write the slave address
if (!mp_hal_i2c_write_byte(self, addr << 1)) { ret = mp_hal_i2c_write_byte(self, addr << 1);
goto er; if (ret < 0) {
return ret;
} else if (ret != 0) {
// nack received, release the bus cleanly
mp_hal_i2c_stop(self);
return -MP_ENODEV;
} }
// write the buffer to the I2C memory // write the buffer to the I2C memory
int num_acks = 0;
while (len--) { while (len--) {
if (!mp_hal_i2c_write_byte(self, *src++)) { ret = mp_hal_i2c_write_byte(self, *src++);
goto er; if (ret < 0) {
return ret;
} else if (ret != 0) {
// nack received, stop sending
break;
}
++num_acks;
}
// finish the I2C transaction
if (stop) {
ret = mp_hal_i2c_stop(self);
if (ret != 0) {
return ret;
}
}
return num_acks;
}
// return value:
// 0 - success
// <0 - error, with errno being the negative of the return value
STATIC int mp_hal_i2c_read(machine_i2c_obj_t *self, uint8_t addr, uint8_t *dest, size_t len, bool stop) {
// start the I2C transaction
int ret = mp_hal_i2c_start(self);
if (ret != 0) {
return ret;
}
// write the slave address
ret = mp_hal_i2c_write_byte(self, (addr << 1) | 1);
if (ret < 0) {
return ret;
} else if (ret != 0) {
// nack received, release the bus cleanly
mp_hal_i2c_stop(self);
return -MP_ENODEV;
}
// read the bytes from the slave
while (len--) {
ret = mp_hal_i2c_read_byte(self, dest++, len == 0);
if (ret != 0) {
return ret;
} }
} }
// finish the I2C transaction // finish the I2C transaction
if (stop && !mp_hal_i2c_stop(self)) { if (stop) {
goto er; ret = mp_hal_i2c_stop(self);
} if (ret != 0) {
return; return ret;
er:
mp_hal_i2c_stop(self); // ignore error
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "I2C bus error"));
}
STATIC void mp_hal_i2c_read(machine_i2c_obj_t *self, uint8_t addr, uint8_t *dest, size_t len, bool stop) {
// start the I2C transaction
if (!mp_hal_i2c_start(self)) {
goto er;
}
if (!mp_hal_i2c_write_byte(self, (addr << 1) | 1)) {
goto er;
}
while (len--) {
if (!mp_hal_i2c_read_byte(self, dest++, len == 0)) {
goto er;
} }
} }
if (stop && !mp_hal_i2c_stop(self)) {
goto er;
}
return;
er: return 0; // success
mp_hal_i2c_stop(self); // ignore error
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "I2C bus error"));
} }
/******************************************************************************/ /******************************************************************************/
@ -279,7 +326,7 @@ STATIC mp_obj_t machine_i2c_start(mp_obj_t self_in) {
} }
int ret = i2c_p->start(self); int ret = i2c_p->start(self);
if (ret != 0) { if (ret != 0) {
mp_raise_OSError(ret); mp_raise_OSError(-ret);
} }
return mp_const_none; return mp_const_none;
} }
@ -293,7 +340,7 @@ STATIC mp_obj_t machine_i2c_stop(mp_obj_t self_in) {
} }
int ret = i2c_p->stop(self); int ret = i2c_p->stop(self);
if (ret != 0) { if (ret != 0) {
mp_raise_OSError(ret); mp_raise_OSError(-ret);
} }
return mp_const_none; return mp_const_none;
} }
@ -313,7 +360,7 @@ STATIC mp_obj_t machine_i2c_readinto(mp_obj_t self_in, mp_obj_t buf_in) {
// do the read // do the read
int ret = i2c_p->read(self, bufinfo.buf, bufinfo.len); int ret = i2c_p->read(self, bufinfo.buf, bufinfo.len);
if (ret != 0) { if (ret != 0) {
mp_raise_OSError(ret); mp_raise_OSError(-ret);
} }
return mp_const_none; return mp_const_none;
@ -333,8 +380,8 @@ STATIC mp_obj_t machine_i2c_write(mp_obj_t self_in, mp_obj_t buf_in) {
// do the write // do the write
int ret = i2c_p->write(self, bufinfo.buf, bufinfo.len); int ret = i2c_p->write(self, bufinfo.buf, bufinfo.len);
if (ret != 0) { if (ret < 0) {
mp_raise_OSError(ret); mp_raise_OSError(-ret);
} }
return mp_const_none; return mp_const_none;
@ -346,7 +393,10 @@ STATIC mp_obj_t machine_i2c_readfrom(mp_obj_t self_in, mp_obj_t addr_in, mp_obj_
mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol; mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol;
vstr_t vstr; vstr_t vstr;
vstr_init_len(&vstr, mp_obj_get_int(nbytes_in)); vstr_init_len(&vstr, mp_obj_get_int(nbytes_in));
i2c_p->readfrom(self, mp_obj_get_int(addr_in), (uint8_t*)vstr.buf, vstr.len, true); int ret = i2c_p->readfrom(self, mp_obj_get_int(addr_in), (uint8_t*)vstr.buf, vstr.len, true);
if (ret < 0) {
mp_raise_OSError(-ret);
}
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
} }
MP_DEFINE_CONST_FUN_OBJ_3(machine_i2c_readfrom_obj, machine_i2c_readfrom); MP_DEFINE_CONST_FUN_OBJ_3(machine_i2c_readfrom_obj, machine_i2c_readfrom);
@ -356,7 +406,10 @@ STATIC mp_obj_t machine_i2c_readfrom_into(mp_obj_t self_in, mp_obj_t addr_in, mp
mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol; mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol;
mp_buffer_info_t bufinfo; mp_buffer_info_t bufinfo;
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE); mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE);
i2c_p->readfrom(self, mp_obj_get_int(addr_in), bufinfo.buf, bufinfo.len, true); int ret = i2c_p->readfrom(self, mp_obj_get_int(addr_in), bufinfo.buf, bufinfo.len, true);
if (ret < 0) {
mp_raise_OSError(-ret);
}
return mp_const_none; return mp_const_none;
} }
MP_DEFINE_CONST_FUN_OBJ_3(machine_i2c_readfrom_into_obj, machine_i2c_readfrom_into); MP_DEFINE_CONST_FUN_OBJ_3(machine_i2c_readfrom_into_obj, machine_i2c_readfrom_into);
@ -366,7 +419,10 @@ STATIC mp_obj_t machine_i2c_writeto(mp_obj_t self_in, mp_obj_t addr_in, mp_obj_t
mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol; mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol;
mp_buffer_info_t bufinfo; mp_buffer_info_t bufinfo;
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
i2c_p->writeto(self, mp_obj_get_int(addr_in), bufinfo.buf, bufinfo.len, true); int ret = i2c_p->writeto(self, mp_obj_get_int(addr_in), bufinfo.buf, bufinfo.len, true);
if (ret < 0) {
mp_raise_OSError(-ret);
}
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_3(machine_i2c_writeto_obj, machine_i2c_writeto); STATIC MP_DEFINE_CONST_FUN_OBJ_3(machine_i2c_writeto_obj, machine_i2c_writeto);
@ -380,7 +436,7 @@ STATIC int read_mem(mp_obj_t self_in, uint16_t addr, uint32_t memaddr, uint8_t a
memaddr_buf[memaddr_len++] = memaddr >> i; memaddr_buf[memaddr_len++] = memaddr >> i;
} }
int ret = i2c_p->writeto(self, addr, memaddr_buf, memaddr_len, false); int ret = i2c_p->writeto(self, addr, memaddr_buf, memaddr_len, false);
if (ret != 0) { if (ret != memaddr_len) {
// must generate STOP // must generate STOP
i2c_p->writeto(self, addr, NULL, 0, true); i2c_p->writeto(self, addr, NULL, 0, true);
return ret; return ret;
@ -438,8 +494,12 @@ STATIC mp_obj_t machine_i2c_readfrom_mem(size_t n_args, const mp_obj_t *pos_args
vstr_init_len(&vstr, mp_obj_get_int(args[ARG_n].u_obj)); vstr_init_len(&vstr, mp_obj_get_int(args[ARG_n].u_obj));
// do the transfer // do the transfer
read_mem(pos_args[0], args[ARG_addr].u_int, args[ARG_memaddr].u_int, int ret = read_mem(pos_args[0], args[ARG_addr].u_int, args[ARG_memaddr].u_int,
args[ARG_addrsize].u_int, (uint8_t*)vstr.buf, vstr.len); args[ARG_addrsize].u_int, (uint8_t*)vstr.buf, vstr.len);
if (ret < 0) {
mp_raise_OSError(-ret);
}
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
} }
MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_readfrom_mem_obj, 1, machine_i2c_readfrom_mem); MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_readfrom_mem_obj, 1, machine_i2c_readfrom_mem);
@ -456,8 +516,11 @@ STATIC mp_obj_t machine_i2c_readfrom_mem_into(size_t n_args, const mp_obj_t *pos
mp_get_buffer_raise(args[ARG_buf].u_obj, &bufinfo, MP_BUFFER_WRITE); mp_get_buffer_raise(args[ARG_buf].u_obj, &bufinfo, MP_BUFFER_WRITE);
// do the transfer // do the transfer
read_mem(pos_args[0], args[ARG_addr].u_int, args[ARG_memaddr].u_int, int ret = read_mem(pos_args[0], args[ARG_addr].u_int, args[ARG_memaddr].u_int,
args[ARG_addrsize].u_int, bufinfo.buf, bufinfo.len); args[ARG_addrsize].u_int, bufinfo.buf, bufinfo.len);
if (ret < 0) {
mp_raise_OSError(-ret);
}
return mp_const_none; return mp_const_none;
} }
MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_readfrom_mem_into_obj, 1, machine_i2c_readfrom_mem_into); MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_readfrom_mem_into_obj, 1, machine_i2c_readfrom_mem_into);
@ -473,8 +536,12 @@ STATIC mp_obj_t machine_i2c_writeto_mem(size_t n_args, const mp_obj_t *pos_args,
mp_get_buffer_raise(args[ARG_buf].u_obj, &bufinfo, MP_BUFFER_READ); mp_get_buffer_raise(args[ARG_buf].u_obj, &bufinfo, MP_BUFFER_READ);
// do the transfer // do the transfer
write_mem(pos_args[0], args[ARG_addr].u_int, args[ARG_memaddr].u_int, int ret = write_mem(pos_args[0], args[ARG_addr].u_int, args[ARG_memaddr].u_int,
args[ARG_addrsize].u_int, bufinfo.buf, bufinfo.len); args[ARG_addrsize].u_int, bufinfo.buf, bufinfo.len);
if (ret < 0) {
mp_raise_OSError(-ret);
}
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_writeto_mem_obj, 1, machine_i2c_writeto_mem); STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_writeto_mem_obj, 1, machine_i2c_writeto_mem);
@ -504,25 +571,20 @@ STATIC MP_DEFINE_CONST_DICT(machine_i2c_locals_dict, machine_i2c_locals_dict_tab
int mp_machine_soft_i2c_start(mp_obj_base_t *self_in) { int mp_machine_soft_i2c_start(mp_obj_base_t *self_in) {
machine_i2c_obj_t *self = (machine_i2c_obj_t*)self_in; machine_i2c_obj_t *self = (machine_i2c_obj_t*)self_in;
if (!mp_hal_i2c_start(self)) { return mp_hal_i2c_start(self);
return MP_ETIMEDOUT;
}
return 0; // success
} }
int mp_machine_soft_i2c_stop(mp_obj_base_t *self_in) { int mp_machine_soft_i2c_stop(mp_obj_base_t *self_in) {
machine_i2c_obj_t *self = (machine_i2c_obj_t*)self_in; machine_i2c_obj_t *self = (machine_i2c_obj_t*)self_in;
if (!mp_hal_i2c_stop(self)) { return mp_hal_i2c_stop(self);
return MP_ETIMEDOUT;
}
return 0; // success
} }
int mp_machine_soft_i2c_read(mp_obj_base_t *self_in, uint8_t *dest, size_t len) { int mp_machine_soft_i2c_read(mp_obj_base_t *self_in, uint8_t *dest, size_t len) {
machine_i2c_obj_t *self = (machine_i2c_obj_t*)self_in; machine_i2c_obj_t *self = (machine_i2c_obj_t*)self_in;
while (len--) { while (len--) {
if (!mp_hal_i2c_read_byte(self, dest++, len == 0)) { int ret = mp_hal_i2c_read_byte(self, dest++, len == 0);
return MP_ETIMEDOUT; if (ret != 0) {
return ret;
} }
} }
return 0; // success return 0; // success
@ -530,24 +592,28 @@ int mp_machine_soft_i2c_read(mp_obj_base_t *self_in, uint8_t *dest, size_t len)
int mp_machine_soft_i2c_write(mp_obj_base_t *self_in, const uint8_t *src, size_t len) { int mp_machine_soft_i2c_write(mp_obj_base_t *self_in, const uint8_t *src, size_t len) {
machine_i2c_obj_t *self = (machine_i2c_obj_t*)self_in; machine_i2c_obj_t *self = (machine_i2c_obj_t*)self_in;
int num_acks = 0;
while (len--) { while (len--) {
if (!mp_hal_i2c_write_byte(self, *src++)) { int ret = mp_hal_i2c_write_byte(self, *src++);
return MP_ETIMEDOUT; if (ret < 0) {
return ret;
} else if (ret != 0) {
// nack received, stop sending
break;
} }
++num_acks;
} }
return 0; // success return num_acks;
} }
int mp_machine_soft_i2c_readfrom(mp_obj_base_t *self_in, uint16_t addr, uint8_t *dest, size_t len, bool stop) { int mp_machine_soft_i2c_readfrom(mp_obj_base_t *self_in, uint16_t addr, uint8_t *dest, size_t len, bool stop) {
machine_i2c_obj_t *self = (machine_i2c_obj_t*)self_in; machine_i2c_obj_t *self = (machine_i2c_obj_t*)self_in;
mp_hal_i2c_read(self, addr, dest, len, stop); return mp_hal_i2c_read(self, addr, dest, len, stop);
return 0; // success
} }
int mp_machine_soft_i2c_writeto(mp_obj_base_t *self_in, uint16_t addr, const uint8_t *src, size_t len, bool stop) { int mp_machine_soft_i2c_writeto(mp_obj_base_t *self_in, uint16_t addr, const uint8_t *src, size_t len, bool stop) {
machine_i2c_obj_t *self = (machine_i2c_obj_t*)self_in; machine_i2c_obj_t *self = (machine_i2c_obj_t*)self_in;
mp_hal_i2c_write(self, addr, src, len, stop); return mp_hal_i2c_write(self, addr, src, len, stop);
return 0; // success
} }
STATIC const mp_machine_i2c_p_t mp_machine_soft_i2c_p = { STATIC const mp_machine_i2c_p_t mp_machine_soft_i2c_p = {