From 583e80a9ceb5b86fd18b837480fbf9c265df7a6d Mon Sep 17 00:00:00 2001 From: Juha Niskanen Date: Tue, 11 Dec 2018 07:09:03 -0600 Subject: [PATCH] drivers/1wire/ds28e17.c: Optimize I2C write followed by read to same address. --- drivers/1wire/1wire.c | 5 ++ drivers/1wire/ds28e17.c | 131 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 131 insertions(+), 5 deletions(-) diff --git a/drivers/1wire/1wire.c b/drivers/1wire/1wire.c index 61ea0f7885..f3d0dd75f1 100644 --- a/drivers/1wire/1wire.c +++ b/drivers/1wire/1wire.c @@ -206,6 +206,11 @@ static int onewire_pm_prepare(FAR struct pm_callback_s *cb, int domain, } break; + + default: + /* Should not get here */ + + break; } return OK; diff --git a/drivers/1wire/ds28e17.c b/drivers/1wire/ds28e17.c index 794f19a3cf..b183e22287 100644 --- a/drivers/1wire/ds28e17.c +++ b/drivers/1wire/ds28e17.c @@ -375,7 +375,7 @@ static int ds_i2c_write(FAR struct ds_i2c_inst_s *inst, uint16_t i2c_addr, FAR struct onewire_master_s *master = inst->master; uint16_t crc; int ret; - uint8_t buf[5]; + uint8_t buf[3]; if (length <= 0) { @@ -453,6 +453,105 @@ static int ds_i2c_write(FAR struct ds_i2c_inst_s *inst, uint16_t i2c_addr, return length; } +/**************************************************************************** + * Name: ds_i2c_write_read + * + * Description: + * Write data to I2C slave and read from same address. + * + ****************************************************************************/ + +static int ds_i2c_write_read(FAR struct ds_i2c_inst_s *inst, uint16_t i2c_addr, + FAR const uint8_t *wbuffer, ssize_t wlength, + FAR uint8_t *rbuffer, ssize_t rlength) +{ + FAR struct onewire_master_s *master = inst->master; + uint16_t crc; + int ret; + uint8_t buf[3]; + + if (wlength <= 0 || rlength <= 0) + { + return -EINVAL; + } + + if (wlength > DS_DATA_LIMIT) + { + i2cerr("ERROR: writing too many bytes!\n"); + return -EINVAL; + } + + if (rlength > DS_DATA_LIMIT) + { + i2cerr("ERROR: reading too many bytes!\n"); + return -EINVAL; + } + + /* Write command header. */ + + buf[0] = DS_WRITE_READ_DATA_WITH_STOP; + buf[1] = i2c_addr << 1; + buf[2] = wlength; + crc = onewire_crc16(buf, 3, 0); + + ret = ONEWIRE_WRITE(master->dev, buf, 3); + if (ret < 0) + { + return ret; + } + + /* Write payload I2C data to DS28E17. */ + + crc = onewire_crc16(wbuffer, wlength, crc); + + ret = ONEWIRE_WRITE(master->dev, wbuffer, wlength); + if (ret < 0) + { + return ret; + } + + /* Write read length and checksum. */ + + buf[0] = rlength; + crc = onewire_crc16(buf, 1, crc); + buf[1] = ~(crc & 0xff); + buf[2] = ~((crc >> 8) & 0xff); + + ret = ONEWIRE_WRITE(master->dev, buf, 3); + if (ret < 0) + { + return ret; + } + + /* Wait busy indication to vanish. */ + + ret = ds_busywait(inst, wlength + 1 + rlength + 1); + if (ret < 0) + { + return ret; + } + + /* Read status from DS28E17. */ + + ret = ONEWIRE_READ(master->dev, buf, 2); + if (ret < 0) + { + return ret; + } + + /* Check error conditions. */ + + ret = ds_error(buf); + if (ret < 0) + { + return ret; + } + + /* Read received I2C data from DS28E17. */ + + return ONEWIRE_READ(master->dev, rbuffer, rlength); +} + static int ds_i2c_setfrequency(FAR struct ds_i2c_inst_s *inst, uint32_t frequency) { FAR struct onewire_master_s *master = inst->master; @@ -542,11 +641,30 @@ static int ds_i2c_process(FAR struct i2c_master_s *i2cdev, while (i < count) { - /* TODO: we could use DS_WRITE_READ_DATA_WITH_STOP to optimize the - * common case of write followed by read to a same address. + /* First we try to use DS_WRITE_READ_DATA_WITH_STOP to optimize + * the common case of write followed by read to a same address. */ - if (msgs[i].flags & I2C_M_READ) + if (i < count - 1 && msgs[i].addr == msgs[i+1].addr && + (msgs[i].flags & I2C_M_READ) == 0 && + (msgs[i+1].flags & I2C_M_READ)) + { + /* Write-read combined transfer. */ + + ret = ds_i2c_write_read(inst, msgs[i].addr, + msgs[i].buffer, msgs[i].length, + msgs[i+1].buffer, msgs[i+1].length); + if (ret < 0) + { + i = ret; + goto errout; + } + + /* We processed two messages here. */ + + i += 2; + } + else if (msgs[i].flags & I2C_M_READ) { /* Read transfer. */ @@ -556,6 +674,8 @@ static int ds_i2c_process(FAR struct i2c_master_s *i2cdev, i = ret; goto errout; } + + i++; } else { @@ -568,11 +688,12 @@ static int ds_i2c_process(FAR struct i2c_master_s *i2cdev, i = ret; goto errout; } + + i++; } /* Any more messages to process? */ - i++; if (i < count) { /* Yes. Resume to same DS28E17. */