From f56b7a6b93c63fe990a0944682a7af3aad948c4b Mon Sep 17 00:00:00 2001 From: Jean-Marc CHIAPPA Date: Fri, 13 Sep 2019 11:47:59 +0200 Subject: [PATCH 1/4] Added the repeated-start feature in I2C driver (#590) Fixes #583 --- cores/arduino/stm32/twi.c | 16 ++++++++++++++++ libraries/Wire/src/Wire.cpp | 22 ++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/cores/arduino/stm32/twi.c b/cores/arduino/stm32/twi.c index 92c83af19b..d48b2fc163 100644 --- a/cores/arduino/stm32/twi.c +++ b/cores/arduino/stm32/twi.c @@ -740,8 +740,16 @@ i2c_status_e i2c_master_write(i2c_t *obj, uint8_t dev_address, return i2c_IsDeviceReady(obj, dev_address, 1); } +#if defined(I2C_OTHER_FRAME) + uint32_t XferOptions = obj->handle.XferOptions; // save XferOptions value, because handle can be modified by HAL, which cause issue in case of NACK from slave +#endif + do { +#if defined(I2C_OTHER_FRAME) + if (HAL_I2C_Master_Seq_Transmit_IT(&(obj->handle), dev_address, data, size, XferOptions) == HAL_OK) { +#else if (HAL_I2C_Master_Transmit_IT(&(obj->handle), dev_address, data, size) == HAL_OK) { +#endif ret = I2C_OK; // wait for transfer completion while ((HAL_I2C_GetState(&(obj->handle)) != HAL_I2C_STATE_READY) @@ -803,8 +811,16 @@ i2c_status_e i2c_master_read(i2c_t *obj, uint8_t dev_address, uint8_t *data, uin uint32_t tickstart = HAL_GetTick(); uint32_t delta = 0; +#if defined(I2C_OTHER_FRAME) + uint32_t XferOptions = obj->handle.XferOptions; // save XferOptions value, because handle can be modified by HAL, which cause issue in case of NACK from slave +#endif + do { +#if defined(I2C_OTHER_FRAME) + if (HAL_I2C_Master_Seq_Receive_IT(&(obj->handle), dev_address, data, size, XferOptions) == HAL_OK) { +#else if (HAL_I2C_Master_Receive_IT(&(obj->handle), dev_address, data, size) == HAL_OK) { +#endif ret = I2C_OK; // wait for transfer completion while ((HAL_I2C_GetState(&(obj->handle)) != HAL_I2C_STATE_READY) diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index f501896102..0d80d5aabd 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -116,7 +116,10 @@ void TwoWire::setClock(uint32_t frequency) uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddress, uint8_t isize, uint8_t sendStop) { +#if !defined(I2C_OTHER_FRAME) UNUSED(sendStop); +#endif + if (_i2c.isMaster == 1) { allocateRxBuffer(quantity); // error if no memory block available to allocate the buffer @@ -146,6 +149,15 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddres // perform blocking read into buffer uint8_t read = 0; + +#if defined(I2C_OTHER_FRAME) + if (sendStop == 0) { + _i2c.handle.XferOptions = I2C_OTHER_FRAME ; + } else { + _i2c.handle.XferOptions = I2C_OTHER_AND_LAST_FRAME; + } +#endif + if (I2C_OK == i2c_master_read(&_i2c, address << 1, rxBuffer, quantity)) { read = quantity; } @@ -211,8 +223,18 @@ void TwoWire::beginTransmission(int address) // uint8_t TwoWire::endTransmission(uint8_t sendStop) { +#if !defined(I2C_OTHER_FRAME) UNUSED(sendStop); +#endif int8_t ret = 4; + // check transfer options and store it in the I2C handle +#if defined(I2C_OTHER_FRAME) + if (sendStop == 0) { + _i2c.handle.XferOptions = I2C_OTHER_FRAME ; + } else { + _i2c.handle.XferOptions = I2C_OTHER_AND_LAST_FRAME; + } +#endif if (_i2c.isMaster == 1) { // transmit buffer (blocking) From c46e7e315325cd722c19e139e592243b84d67655 Mon Sep 17 00:00:00 2001 From: Alexandre Bourdiol Date: Wed, 9 Oct 2019 14:04:53 +0200 Subject: [PATCH 2/4] [I2C] Fix error management in Read/Write When NACK is received by master, instead of immediate re-transmission by twi driver, error is reported. Up to application to manage re-transmission. This fix regression found on STM32F2 and STM32F4 when using I2C_OTHER_FRAME. See PR #663 --- cores/arduino/stm32/twi.c | 77 +++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 40 deletions(-) diff --git a/cores/arduino/stm32/twi.c b/cores/arduino/stm32/twi.c index d48b2fc163..5858718b8a 100644 --- a/cores/arduino/stm32/twi.c +++ b/cores/arduino/stm32/twi.c @@ -731,9 +731,10 @@ i2c_status_e i2c_master_write(i2c_t *obj, uint8_t dev_address, uint8_t *data, uint16_t size) { - i2c_status_e ret = I2C_ERROR; + i2c_status_e ret = I2C_OK; uint32_t tickstart = HAL_GetTick(); uint32_t delta = 0; + uint32_t err = 0; /* When size is 0, this is usually an I2C scan / ping to check if device is there and ready */ if (size == 0) { @@ -744,30 +745,28 @@ i2c_status_e i2c_master_write(i2c_t *obj, uint8_t dev_address, uint32_t XferOptions = obj->handle.XferOptions; // save XferOptions value, because handle can be modified by HAL, which cause issue in case of NACK from slave #endif - do { #if defined(I2C_OTHER_FRAME) - if (HAL_I2C_Master_Seq_Transmit_IT(&(obj->handle), dev_address, data, size, XferOptions) == HAL_OK) { + if (HAL_I2C_Master_Seq_Transmit_IT(&(obj->handle), dev_address, data, size, XferOptions) == HAL_OK) { #else - if (HAL_I2C_Master_Transmit_IT(&(obj->handle), dev_address, data, size) == HAL_OK) { + if (HAL_I2C_Master_Transmit_IT(&(obj->handle), dev_address, data, size) == HAL_OK) { #endif - ret = I2C_OK; - // wait for transfer completion - while ((HAL_I2C_GetState(&(obj->handle)) != HAL_I2C_STATE_READY) - && (ret == I2C_OK)) { - delta = (HAL_GetTick() - tickstart); - uint32_t err = HAL_I2C_GetError(&(obj->handle)); - if ((delta > I2C_TIMEOUT_TICK) - || ((err & HAL_I2C_ERROR_TIMEOUT) == HAL_I2C_ERROR_TIMEOUT)) { - ret = I2C_TIMEOUT; - } else if (err != HAL_I2C_ERROR_NONE) { - ret = I2C_ERROR; - } + // wait for transfer completion + while ((HAL_I2C_GetState(&(obj->handle)) != HAL_I2C_STATE_READY) && (delta < I2C_TIMEOUT_TICK)) { + delta = (HAL_GetTick() - tickstart); + if (HAL_I2C_GetError(&(obj->handle)) != HAL_I2C_ERROR_NONE) { + break; } } - /* When Acknowledge failure occurs (Slave don't acknowledge it's address) - Master restarts communication */ - } while (((HAL_I2C_GetError(&(obj->handle)) & HAL_I2C_ERROR_AF) == HAL_I2C_ERROR_AF) - && (delta < I2C_TIMEOUT_TICK)); + + err = HAL_I2C_GetError(&(obj->handle)); + if ((delta > I2C_TIMEOUT_TICK) + || ((err & HAL_I2C_ERROR_TIMEOUT) == HAL_I2C_ERROR_TIMEOUT)) { + ret = I2C_TIMEOUT; + } else if (err != HAL_I2C_ERROR_NONE) { + ret = I2C_ERROR; + } + } + return ret; } @@ -807,38 +806,36 @@ i2c_status_e i2c_slave_write_IT(i2c_t *obj, uint8_t *data, uint16_t size) */ i2c_status_e i2c_master_read(i2c_t *obj, uint8_t dev_address, uint8_t *data, uint16_t size) { - i2c_status_e ret = I2C_ERROR; + i2c_status_e ret = I2C_OK; uint32_t tickstart = HAL_GetTick(); uint32_t delta = 0; + uint32_t err = 0; #if defined(I2C_OTHER_FRAME) uint32_t XferOptions = obj->handle.XferOptions; // save XferOptions value, because handle can be modified by HAL, which cause issue in case of NACK from slave #endif - do { #if defined(I2C_OTHER_FRAME) - if (HAL_I2C_Master_Seq_Receive_IT(&(obj->handle), dev_address, data, size, XferOptions) == HAL_OK) { + if (HAL_I2C_Master_Seq_Receive_IT(&(obj->handle), dev_address, data, size, XferOptions) == HAL_OK) { #else - if (HAL_I2C_Master_Receive_IT(&(obj->handle), dev_address, data, size) == HAL_OK) { + if (HAL_I2C_Master_Receive_IT(&(obj->handle), dev_address, data, size) == HAL_OK) { #endif - ret = I2C_OK; - // wait for transfer completion - while ((HAL_I2C_GetState(&(obj->handle)) != HAL_I2C_STATE_READY) - && (ret == I2C_OK)) { - delta = (HAL_GetTick() - tickstart); - uint32_t err = HAL_I2C_GetError(&(obj->handle)); - if ((delta > I2C_TIMEOUT_TICK) - || ((err & HAL_I2C_ERROR_TIMEOUT) == HAL_I2C_ERROR_TIMEOUT)) { - ret = I2C_TIMEOUT; - } else if (err != HAL_I2C_ERROR_NONE) { - ret = I2C_ERROR; - } + // wait for transfer completion + while ((HAL_I2C_GetState(&(obj->handle)) != HAL_I2C_STATE_READY) && (delta < I2C_TIMEOUT_TICK)) { + delta = (HAL_GetTick() - tickstart); + if (HAL_I2C_GetError(&(obj->handle)) != HAL_I2C_ERROR_NONE) { + break; } } - /* When Acknowledge failure occurs (Slave don't acknowledge it's address) - Master restarts communication */ - } while (((HAL_I2C_GetError(&(obj->handle)) & HAL_I2C_ERROR_AF) == HAL_I2C_ERROR_AF) - && (delta < I2C_TIMEOUT_TICK)); + + err = HAL_I2C_GetError(&(obj->handle)); + if ((delta > I2C_TIMEOUT_TICK) + || ((err & HAL_I2C_ERROR_TIMEOUT) == HAL_I2C_ERROR_TIMEOUT)) { + ret = I2C_TIMEOUT; + } else if (err != HAL_I2C_ERROR_NONE) { + ret = I2C_ERROR; + } + } return ret; } From dd3050a51424f8ce1a119453fd15ead5eafa4a9d Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Tue, 15 Oct 2019 16:11:04 +0200 Subject: [PATCH 3/4] [I2C] Only one return per function/method if possible Signed-off-by: Frederic Pillon --- cores/arduino/stm32/twi.c | 439 ++++++++++++++++++------------------ libraries/Wire/src/Wire.cpp | 165 +++++++------- 2 files changed, 294 insertions(+), 310 deletions(-) diff --git a/cores/arduino/stm32/twi.c b/cores/arduino/stm32/twi.c index 5858718b8a..d43010ee28 100644 --- a/cores/arduino/stm32/twi.c +++ b/cores/arduino/stm32/twi.c @@ -365,102 +365,102 @@ static uint32_t i2c_computeTiming(uint32_t clkSrcFreq, uint32_t i2c_speed) uint8_t presc, scldel, sdadel; uint32_t tafdel_min, tafdel_max; - if (i2c_speed > I2C_SPEED_FREQ_NUMBER) { - return ret; - } - /* Don't compute timing if already available value for the requested speed with the same I2C input frequency */ - if ((I2C_ClockTiming[i2c_speed].input_clock == clkSrcFreq) && (I2C_ClockTiming[i2c_speed].timing != 0U)) { - return I2C_ClockTiming[i2c_speed].timing; - } - - /* Save the I2C input clock for which the timing will be saved */ - I2C_ClockTiming[i2c_speed].input_clock = clkSrcFreq; + if (i2c_speed < I2C_SPEED_FREQ_NUMBER) { - ti2cclk = (SEC2NSEC + (clkSrcFreq / 2U)) / clkSrcFreq; - ti2cspeed = (SEC2NSEC + (I2C_Charac[i2c_speed].freq / 2U)) / I2C_Charac[i2c_speed].freq; - - tafdel_min = (I2C_USE_ANALOG_FILTER == 1U) ? I2C_ANALOG_FILTER_DELAY_MIN : 0U; - tafdel_max = (I2C_USE_ANALOG_FILTER == 1U) ? I2C_ANALOG_FILTER_DELAY_MAX : 0U; - /* - * tDNF = DNF x tI2CCLK - * tPRESC = (PRESC+1) x tI2CCLK - * SDADEL >= {tf +tHD;DAT(min) - tAF(min) - tDNF - [3 x tI2CCLK]} / {tPRESC} - * SDADEL <= {tVD;DAT(max) - tr - tAF(max) - tDNF- [4 x tI2CCLK]} / {tPRESC} - */ - tsdadel_min = (int32_t)I2C_Charac[i2c_speed].tfall + - (int32_t)I2C_Charac[i2c_speed].hddat_min - - (int32_t)tafdel_min - (int32_t)(((int32_t)I2C_Charac[i2c_speed].dnf + - 3) * (int32_t)ti2cclk); - tsdadel_max = (int32_t)I2C_Charac[i2c_speed].vddat_max - - (int32_t)I2C_Charac[i2c_speed].trise - - (int32_t)tafdel_max - (int32_t)(((int32_t)I2C_Charac[i2c_speed].dnf + - 4) * (int32_t)ti2cclk); - /* {[tr+ tSU;DAT(min)] / [tPRESC]} - 1 <= SCLDEL */ - tscldel_min = (int32_t)I2C_Charac[i2c_speed].trise + - (int32_t)I2C_Charac[i2c_speed].sudat_min; - if (tsdadel_min <= 0) { - tsdadel_min = 0; - } - if (tsdadel_max <= 0) { - tsdadel_max = 0; - } + /* Don't compute timing if already available value for the requested speed with the same I2C input frequency */ + if ((I2C_ClockTiming[i2c_speed].input_clock == clkSrcFreq) && (I2C_ClockTiming[i2c_speed].timing != 0U)) { + ret = I2C_ClockTiming[i2c_speed].timing; + } else { + /* Save the I2C input clock for which the timing will be saved */ + I2C_ClockTiming[i2c_speed].input_clock = clkSrcFreq; + + ti2cclk = (SEC2NSEC + (clkSrcFreq / 2U)) / clkSrcFreq; + ti2cspeed = (SEC2NSEC + (I2C_Charac[i2c_speed].freq / 2U)) / I2C_Charac[i2c_speed].freq; + + tafdel_min = (I2C_USE_ANALOG_FILTER == 1U) ? I2C_ANALOG_FILTER_DELAY_MIN : 0U; + tafdel_max = (I2C_USE_ANALOG_FILTER == 1U) ? I2C_ANALOG_FILTER_DELAY_MAX : 0U; + /* + * tDNF = DNF x tI2CCLK + * tPRESC = (PRESC+1) x tI2CCLK + * SDADEL >= {tf +tHD;DAT(min) - tAF(min) - tDNF - [3 x tI2CCLK]} / {tPRESC} + * SDADEL <= {tVD;DAT(max) - tr - tAF(max) - tDNF- [4 x tI2CCLK]} / {tPRESC} + */ + tsdadel_min = (int32_t)I2C_Charac[i2c_speed].tfall + + (int32_t)I2C_Charac[i2c_speed].hddat_min - + (int32_t)tafdel_min - (int32_t)(((int32_t)I2C_Charac[i2c_speed].dnf + + 3) * (int32_t)ti2cclk); + tsdadel_max = (int32_t)I2C_Charac[i2c_speed].vddat_max - + (int32_t)I2C_Charac[i2c_speed].trise - + (int32_t)tafdel_max - (int32_t)(((int32_t)I2C_Charac[i2c_speed].dnf + + 4) * (int32_t)ti2cclk); + /* {[tr+ tSU;DAT(min)] / [tPRESC]} - 1 <= SCLDEL */ + tscldel_min = (int32_t)I2C_Charac[i2c_speed].trise + + (int32_t)I2C_Charac[i2c_speed].sudat_min; + if (tsdadel_min <= 0) { + tsdadel_min = 0; + } + if (tsdadel_max <= 0) { + tsdadel_max = 0; + } - /* tDNF = DNF x tI2CCLK */ - dnf_delay = I2C_Charac[i2c_speed].dnf * ti2cclk; - - clk_max = SEC2NSEC / I2C_Charac[i2c_speed].freq_min; - clk_min = SEC2NSEC / I2C_Charac[i2c_speed].freq_max; - - prev_error = ti2cspeed; - - for (presc = 0; presc < I2C_PRESC_MAX; presc++) { - for (scldel = 0; scldel < I2C_SCLDEL_MAX; scldel++) { - /* TSCLDEL = (SCLDEL+1) * (PRESC+1) * TI2CCLK */ - uint32_t tscldel = (scldel + 1U) * (presc + 1U) * ti2cclk; - if (tscldel >= (uint32_t)tscldel_min) { - - for (sdadel = 0; sdadel < I2C_SDADEL_MAX; sdadel++) { - /* TSDADEL = SDADEL * (PRESC+1) * TI2CCLK */ - uint32_t tsdadel = (sdadel * (presc + 1U)) * ti2cclk; - if ((tsdadel >= (uint32_t)tsdadel_min) && (tsdadel <= - (uint32_t)tsdadel_max)) { - if (presc != prev_presc) { - valid_timing_nbr ++; - if (valid_timing_nbr >= I2C_VALID_TIMING_NBR) { - return ret; - } - /* tPRESC = (PRESC+1) x tI2CCLK*/ - uint32_t tpresc = (presc + 1U) * ti2cclk; - for (scll = 0; scll < I2C_SCLL_MAX; scll++) { - /* tLOW(min) <= tAF(min) + tDNF + 2 x tI2CCLK + [(SCLL+1) x tPRESC ] */ - uint32_t tscl_l = tafdel_min + dnf_delay + (2U * ti2cclk) + ((scll + 1U) * tpresc); - /* The I2CCLK period tI2CCLK must respect the following conditions: - tI2CCLK < (tLOW - tfilters) / 4 and tI2CCLK < tHIGH */ - if ((tscl_l > I2C_Charac[i2c_speed].lscl_min) && - (ti2cclk < ((tscl_l - tafdel_min - dnf_delay) / 4U))) { - for (sclh = 0; sclh < I2C_SCLH_MAX; sclh++) { - /* tHIGH(min) <= tAF(min) + tDNF + 2 x tI2CCLK + [(SCLH+1) x tPRESC] */ - uint32_t tscl_h = tafdel_min + dnf_delay + (2U * ti2cclk) + ((sclh + 1U) * tpresc); - /* tSCL = tf + tLOW + tr + tHIGH */ - uint32_t tscl = tscl_l + tscl_h + I2C_Charac[i2c_speed].trise + - I2C_Charac[i2c_speed].tfall; - if ((tscl >= clk_min) && (tscl <= clk_max) && - (tscl_h >= I2C_Charac[i2c_speed].hscl_min) && (ti2cclk < tscl_h)) { - int32_t error = (int32_t)tscl - (int32_t)ti2cspeed; - if (error < 0) { - error = -error; - } - /* look for the timings with the lowest clock error */ - if ((uint32_t)error < prev_error) { - prev_error = (uint32_t)error; - ret = ((presc & 0x0FU) << 28) | \ - ((scldel & 0x0FU) << 20) | \ - ((sdadel & 0x0FU) << 16) | \ - ((sclh & 0xFFU) << 8) | \ - ((scll & 0xFFU) << 0); - prev_presc = presc; - /* Save I2C Timing found for further reuse (and avoid to compute again) */ - I2C_ClockTiming[i2c_speed].timing = ret; + /* tDNF = DNF x tI2CCLK */ + dnf_delay = I2C_Charac[i2c_speed].dnf * ti2cclk; + + clk_max = SEC2NSEC / I2C_Charac[i2c_speed].freq_min; + clk_min = SEC2NSEC / I2C_Charac[i2c_speed].freq_max; + + prev_error = ti2cspeed; + + for (presc = 0; presc < I2C_PRESC_MAX; presc++) { + for (scldel = 0; scldel < I2C_SCLDEL_MAX; scldel++) { + /* TSCLDEL = (SCLDEL+1) * (PRESC+1) * TI2CCLK */ + uint32_t tscldel = (scldel + 1U) * (presc + 1U) * ti2cclk; + if (tscldel >= (uint32_t)tscldel_min) { + + for (sdadel = 0; sdadel < I2C_SDADEL_MAX; sdadel++) { + /* TSDADEL = SDADEL * (PRESC+1) * TI2CCLK */ + uint32_t tsdadel = (sdadel * (presc + 1U)) * ti2cclk; + if ((tsdadel >= (uint32_t)tsdadel_min) && (tsdadel <= + (uint32_t)tsdadel_max)) { + if (presc != prev_presc) { + valid_timing_nbr ++; + if (valid_timing_nbr >= I2C_VALID_TIMING_NBR) { + return ret; + } + /* tPRESC = (PRESC+1) x tI2CCLK*/ + uint32_t tpresc = (presc + 1U) * ti2cclk; + for (scll = 0; scll < I2C_SCLL_MAX; scll++) { + /* tLOW(min) <= tAF(min) + tDNF + 2 x tI2CCLK + [(SCLL+1) x tPRESC ] */ + uint32_t tscl_l = tafdel_min + dnf_delay + (2U * ti2cclk) + ((scll + 1U) * tpresc); + /* The I2CCLK period tI2CCLK must respect the following conditions: + tI2CCLK < (tLOW - tfilters) / 4 and tI2CCLK < tHIGH */ + if ((tscl_l > I2C_Charac[i2c_speed].lscl_min) && + (ti2cclk < ((tscl_l - tafdel_min - dnf_delay) / 4U))) { + for (sclh = 0; sclh < I2C_SCLH_MAX; sclh++) { + /* tHIGH(min) <= tAF(min) + tDNF + 2 x tI2CCLK + [(SCLH+1) x tPRESC] */ + uint32_t tscl_h = tafdel_min + dnf_delay + (2U * ti2cclk) + ((sclh + 1U) * tpresc); + /* tSCL = tf + tLOW + tr + tHIGH */ + uint32_t tscl = tscl_l + tscl_h + I2C_Charac[i2c_speed].trise + + I2C_Charac[i2c_speed].tfall; + if ((tscl >= clk_min) && (tscl <= clk_max) && + (tscl_h >= I2C_Charac[i2c_speed].hscl_min) && (ti2cclk < tscl_h)) { + int32_t error = (int32_t)tscl - (int32_t)ti2cspeed; + if (error < 0) { + error = -error; + } + /* look for the timings with the lowest clock error */ + if ((uint32_t)error < prev_error) { + prev_error = (uint32_t)error; + ret = ((presc & 0x0FU) << 28) | \ + ((scldel & 0x0FU) << 20) | \ + ((sdadel & 0x0FU) << 16) | \ + ((sclh & 0xFFU) << 8) | \ + ((scll & 0xFFU) << 0); + prev_presc = presc; + /* Save I2C Timing found for further reuse (and avoid to compute again) */ + I2C_ClockTiming[i2c_speed].timing = ret; + } + } } } } @@ -559,123 +559,124 @@ void i2c_init(i2c_t *obj) */ void i2c_custom_init(i2c_t *obj, uint32_t timing, uint32_t addressingMode, uint32_t ownAddress) { - if (obj == NULL) { - return; - } + if (obj != NULL) { - I2C_HandleTypeDef *handle = &(obj->handle); - // Determine the I2C to use - I2C_TypeDef *i2c_sda = pinmap_peripheral(obj->sda, PinMap_I2C_SDA); - I2C_TypeDef *i2c_scl = pinmap_peripheral(obj->scl, PinMap_I2C_SCL); + I2C_HandleTypeDef *handle = &(obj->handle); - //Pins SDA/SCL must not be NP - if (i2c_sda == NP || i2c_scl == NP) { - core_debug("ERROR: at least one I2C pin has no peripheral\n"); - return; - } + // Determine the I2C to use + I2C_TypeDef *i2c_sda = pinmap_peripheral(obj->sda, PinMap_I2C_SDA); + I2C_TypeDef *i2c_scl = pinmap_peripheral(obj->scl, PinMap_I2C_SCL); + + //Pins SDA/SCL must not be NP + if (i2c_sda == NP || i2c_scl == NP) { + core_debug("ERROR: at least one I2C pin has no peripheral\n"); + } else { - obj->i2c = pinmap_merge_peripheral(i2c_sda, i2c_scl); + obj->i2c = pinmap_merge_peripheral(i2c_sda, i2c_scl); - if (obj->i2c == NP) { - core_debug("ERROR: I2C pins mismatch\n"); - return; - } + if (obj->i2c == NP) { + core_debug("ERROR: I2C pins mismatch\n"); + + } else { #if defined I2C1_BASE - // Enable I2C1 clock if not done - if (obj->i2c == I2C1) { - __HAL_RCC_I2C1_CLK_ENABLE(); - __HAL_RCC_I2C1_FORCE_RESET(); - __HAL_RCC_I2C1_RELEASE_RESET(); + // Enable I2C1 clock if not done + if (obj->i2c == I2C1) { + __HAL_RCC_I2C1_CLK_ENABLE(); + __HAL_RCC_I2C1_FORCE_RESET(); + __HAL_RCC_I2C1_RELEASE_RESET(); - obj->irq = I2C1_EV_IRQn; + obj->irq = I2C1_EV_IRQn; #if !defined(STM32F0xx) && !defined(STM32G0xx) && !defined(STM32L0xx) - obj->irqER = I2C1_ER_IRQn; + obj->irqER = I2C1_ER_IRQn; #endif /* !STM32F0xx && !STM32G0xx && !STM32L0xx */ - i2c_handles[I2C1_INDEX] = handle; - } + i2c_handles[I2C1_INDEX] = handle; + } #endif // I2C1_BASE #if defined I2C2_BASE - // Enable I2C2 clock if not done - if (obj->i2c == I2C2) { - __HAL_RCC_I2C2_CLK_ENABLE(); - __HAL_RCC_I2C2_FORCE_RESET(); - __HAL_RCC_I2C2_RELEASE_RESET(); - obj->irq = I2C2_EV_IRQn; + // Enable I2C2 clock if not done + if (obj->i2c == I2C2) { + __HAL_RCC_I2C2_CLK_ENABLE(); + __HAL_RCC_I2C2_FORCE_RESET(); + __HAL_RCC_I2C2_RELEASE_RESET(); + obj->irq = I2C2_EV_IRQn; #if !defined(STM32F0xx) && !defined(STM32G0xx) && !defined(STM32L0xx) - obj->irqER = I2C2_ER_IRQn; + obj->irqER = I2C2_ER_IRQn; #endif /* !STM32F0xx && !STM32G0xx && !STM32L0xx */ - i2c_handles[I2C2_INDEX] = handle; - } + i2c_handles[I2C2_INDEX] = handle; + } #endif // I2C2_BASE #if defined I2C3_BASE - // Enable I2C3 clock if not done - if (obj->i2c == I2C3) { - __HAL_RCC_I2C3_CLK_ENABLE(); - __HAL_RCC_I2C3_FORCE_RESET(); - __HAL_RCC_I2C3_RELEASE_RESET(); - obj->irq = I2C3_EV_IRQn; + // Enable I2C3 clock if not done + if (obj->i2c == I2C3) { + __HAL_RCC_I2C3_CLK_ENABLE(); + __HAL_RCC_I2C3_FORCE_RESET(); + __HAL_RCC_I2C3_RELEASE_RESET(); + obj->irq = I2C3_EV_IRQn; #if !defined(STM32L0xx) - obj->irqER = I2C3_ER_IRQn; + obj->irqER = I2C3_ER_IRQn; #endif /* !STM32L0xx */ - i2c_handles[I2C3_INDEX] = handle; - } + i2c_handles[I2C3_INDEX] = handle; + } #endif // I2C3_BASE #if defined I2C4_BASE - // Enable I2C4 clock if not done - if (obj->i2c == I2C4) { - __HAL_RCC_I2C4_CLK_ENABLE(); - __HAL_RCC_I2C4_FORCE_RESET(); - __HAL_RCC_I2C4_RELEASE_RESET(); - obj->irq = I2C4_EV_IRQn; - obj->irqER = I2C4_ER_IRQn; - i2c_handles[I2C4_INDEX] = handle; - } + // Enable I2C4 clock if not done + if (obj->i2c == I2C4) { + __HAL_RCC_I2C4_CLK_ENABLE(); + __HAL_RCC_I2C4_FORCE_RESET(); + __HAL_RCC_I2C4_RELEASE_RESET(); + obj->irq = I2C4_EV_IRQn; + obj->irqER = I2C4_ER_IRQn; + i2c_handles[I2C4_INDEX] = handle; + } #endif // I2C4_BASE - /* Configure I2C GPIO pins */ - pinmap_pinout(obj->scl, PinMap_I2C_SCL); - pinmap_pinout(obj->sda, PinMap_I2C_SDA); + /* Configure I2C GPIO pins */ + pinmap_pinout(obj->scl, PinMap_I2C_SCL); + pinmap_pinout(obj->sda, PinMap_I2C_SDA); - handle->Instance = obj->i2c; + handle->Instance = obj->i2c; #ifdef I2C_TIMING - handle->Init.Timing = i2c_getTiming(obj, timing); + handle->Init.Timing = i2c_getTiming(obj, timing); #else - handle->Init.ClockSpeed = i2c_getTiming(obj, timing); - /* Standard mode (sm) is up to 100kHz, then it's Fast mode (fm) */ - /* In fast mode duty cyble bit must be set in CCR register */ - if (timing > 100000) { - handle->Init.DutyCycle = I2C_DUTYCYCLE_16_9; - } else { - handle->Init.DutyCycle = I2C_DUTYCYCLE_2; - } + handle->Init.ClockSpeed = i2c_getTiming(obj, timing); + /* Standard mode (sm) is up to 100kHz, then it's Fast mode (fm) */ + /* In fast mode duty cyble bit must be set in CCR register */ + if (timing > 100000) { + handle->Init.DutyCycle = I2C_DUTYCYCLE_16_9; + } else { + handle->Init.DutyCycle = I2C_DUTYCYCLE_2; + } #endif - handle->Init.OwnAddress1 = ownAddress; - handle->Init.OwnAddress2 = 0xFF; - handle->Init.AddressingMode = addressingMode; - handle->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; - handle->Init.GeneralCallMode = (obj->generalCall == 0) ? I2C_GENERALCALL_DISABLE : I2C_GENERALCALL_ENABLE; - handle->Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; + handle->Init.OwnAddress1 = ownAddress; + handle->Init.OwnAddress2 = 0xFF; + handle->Init.AddressingMode = addressingMode; + handle->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; + handle->Init.GeneralCallMode = (obj->generalCall == 0) ? I2C_GENERALCALL_DISABLE : I2C_GENERALCALL_ENABLE; + handle->Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; - handle->State = HAL_I2C_STATE_RESET; + handle->State = HAL_I2C_STATE_RESET; - HAL_NVIC_SetPriority(obj->irq, I2C_IRQ_PRIO, I2C_IRQ_SUBPRIO); - HAL_NVIC_EnableIRQ(obj->irq); + HAL_NVIC_SetPriority(obj->irq, I2C_IRQ_PRIO, I2C_IRQ_SUBPRIO); + HAL_NVIC_EnableIRQ(obj->irq); #if !defined(STM32F0xx) && !defined(STM32G0xx) && !defined(STM32L0xx) - HAL_NVIC_SetPriority(obj->irqER, I2C_IRQ_PRIO, I2C_IRQ_SUBPRIO); - HAL_NVIC_EnableIRQ(obj->irqER); + HAL_NVIC_SetPriority(obj->irqER, I2C_IRQ_PRIO, I2C_IRQ_SUBPRIO); + HAL_NVIC_EnableIRQ(obj->irqER); #endif /* !STM32F0xx && !STM32G0xx && !STM32L0xx */ - /* Init the I2C */ - if (HAL_I2C_Init(handle) != HAL_OK) { - /* Initialization Error */ - Error_Handler(); - } + /* Init the I2C */ + if (HAL_I2C_Init(handle) != HAL_OK) { + /* Initialization Error */ + Error_Handler(); + } - /* Initialize default values */ - obj->slaveRxNbData = 0; - obj->slaveMode = SLAVE_MODE_LISTEN; + /* Initialize default values */ + obj->slaveRxNbData = 0; + obj->slaveMode = SLAVE_MODE_LISTEN; + } + } + } } /** @@ -738,35 +739,34 @@ i2c_status_e i2c_master_write(i2c_t *obj, uint8_t dev_address, /* When size is 0, this is usually an I2C scan / ping to check if device is there and ready */ if (size == 0) { - return i2c_IsDeviceReady(obj, dev_address, 1); - } - + ret = i2c_IsDeviceReady(obj, dev_address, 1); + } else { #if defined(I2C_OTHER_FRAME) - uint32_t XferOptions = obj->handle.XferOptions; // save XferOptions value, because handle can be modified by HAL, which cause issue in case of NACK from slave + uint32_t XferOptions = obj->handle.XferOptions; // save XferOptions value, because handle can be modified by HAL, which cause issue in case of NACK from slave #endif #if defined(I2C_OTHER_FRAME) - if (HAL_I2C_Master_Seq_Transmit_IT(&(obj->handle), dev_address, data, size, XferOptions) == HAL_OK) { + if (HAL_I2C_Master_Seq_Transmit_IT(&(obj->handle), dev_address, data, size, XferOptions) == HAL_OK) { #else - if (HAL_I2C_Master_Transmit_IT(&(obj->handle), dev_address, data, size) == HAL_OK) { + if (HAL_I2C_Master_Transmit_IT(&(obj->handle), dev_address, data, size) == HAL_OK) { #endif - // wait for transfer completion - while ((HAL_I2C_GetState(&(obj->handle)) != HAL_I2C_STATE_READY) && (delta < I2C_TIMEOUT_TICK)) { - delta = (HAL_GetTick() - tickstart); - if (HAL_I2C_GetError(&(obj->handle)) != HAL_I2C_ERROR_NONE) { - break; + // wait for transfer completion + while ((HAL_I2C_GetState(&(obj->handle)) != HAL_I2C_STATE_READY) && (delta < I2C_TIMEOUT_TICK)) { + delta = (HAL_GetTick() - tickstart); + if (HAL_I2C_GetError(&(obj->handle)) != HAL_I2C_ERROR_NONE) { + break; + } } - } - err = HAL_I2C_GetError(&(obj->handle)); - if ((delta > I2C_TIMEOUT_TICK) - || ((err & HAL_I2C_ERROR_TIMEOUT) == HAL_I2C_ERROR_TIMEOUT)) { - ret = I2C_TIMEOUT; - } else if (err != HAL_I2C_ERROR_NONE) { - ret = I2C_ERROR; + err = HAL_I2C_GetError(&(obj->handle)); + if ((delta > I2C_TIMEOUT_TICK) + || ((err & HAL_I2C_ERROR_TIMEOUT) == HAL_I2C_ERROR_TIMEOUT)) { + ret = I2C_TIMEOUT; + } else if (err != HAL_I2C_ERROR_NONE) { + ret = I2C_ERROR; + } } } - return ret; } @@ -780,20 +780,20 @@ i2c_status_e i2c_master_write(i2c_t *obj, uint8_t dev_address, i2c_status_e i2c_slave_write_IT(i2c_t *obj, uint8_t *data, uint16_t size) { uint8_t i = 0; + i2c_status_e ret = I2C_OK; // Protection to not override the TxBuffer if (size > I2C_TXRX_BUFFER_SIZE) { - return I2C_ERROR; - } + ret = I2C_ERROR; + } else { + // Check the communication status + for (i = 0; i < size; i++) { + obj->i2cTxRxBuffer[i] = *(data + i); + } - // Check the communication status - for (i = 0; i < size; i++) { - obj->i2cTxRxBuffer[i] = *(data + i); + obj->i2cTxRxBufferSize = size; } - - obj->i2cTxRxBufferSize = size; - - return I2C_OK; + return ret; } /** @@ -836,7 +836,6 @@ i2c_status_e i2c_master_read(i2c_t *obj, uint8_t dev_address, uint8_t *data, uin ret = I2C_ERROR; } } - return ret; } @@ -865,7 +864,6 @@ i2c_status_e i2c_IsDeviceReady(i2c_t *obj, uint8_t devAddr, uint32_t trials) ret = I2C_TIMEOUT; break; } - return ret; } @@ -890,12 +888,10 @@ i2c_t *get_i2c_obj(I2C_HandleTypeDef *hi2c) */ void i2c_attachSlaveRxEvent(i2c_t *obj, void (*function)(uint8_t *, int)) { - if ((obj == NULL) || (function == NULL)) { - return; + if ((obj != NULL) && (function != NULL)) { + obj->i2c_onSlaveReceive = function; + HAL_I2C_EnableListen_IT(&(obj->handle)); } - - obj->i2c_onSlaveReceive = function; - HAL_I2C_EnableListen_IT(&(obj->handle)); } /** @brief sets function called before a slave write operation @@ -905,12 +901,10 @@ void i2c_attachSlaveRxEvent(i2c_t *obj, void (*function)(uint8_t *, int)) */ void i2c_attachSlaveTxEvent(i2c_t *obj, void (*function)(void)) { - if ((obj == NULL) || (function == NULL)) { - return; + if ((obj != NULL) && (function != NULL)) { + obj->i2c_onSlaveTransmit = function; + HAL_I2C_EnableListen_IT(&(obj->handle)); } - - obj->i2c_onSlaveTransmit = function; - HAL_I2C_EnableListen_IT(&(obj->handle)); } /** @@ -969,11 +963,8 @@ void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c) /* Previous master transaction now ended, so inform upper layer if needed * then prepare for listening to next request */ - if ((obj->i2c_onSlaveReceive != NULL) && - (obj->slaveMode == SLAVE_MODE_RECEIVE)) { - if (obj->slaveRxNbData != 0) { - obj->i2c_onSlaveReceive((uint8_t *) obj->i2cTxRxBuffer, obj->slaveRxNbData); - } + if ((obj->slaveMode == SLAVE_MODE_RECEIVE) && (obj->slaveRxNbData != 0)) { + obj->i2c_onSlaveReceive((uint8_t *) obj->i2cTxRxBuffer, obj->slaveRxNbData); } obj->slaveMode = SLAVE_MODE_LISTEN; obj->slaveRxNbData = 0; diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index 0d80d5aabd..8f1f8acda6 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -119,57 +119,54 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddres #if !defined(I2C_OTHER_FRAME) UNUSED(sendStop); #endif + uint8_t read = 0; if (_i2c.isMaster == 1) { allocateRxBuffer(quantity); // error if no memory block available to allocate the buffer if (rxBuffer == nullptr) { setWriteError(); - return 0; - } + } else { - if (isize > 0) { - // send internal address; this mode allows sending a repeated start to access - // some devices' internal registers. This function is executed by the hardware - // TWI module on other processors (for example Due's TWI_IADR and TWI_MMR registers) + if (isize > 0) { + // send internal address; this mode allows sending a repeated start to access + // some devices' internal registers. This function is executed by the hardware + // TWI module on other processors (for example Due's TWI_IADR and TWI_MMR registers) - beginTransmission(address); + beginTransmission(address); - // the maximum size of internal address is 3 bytes - if (isize > 3) { - isize = 3; - } + // the maximum size of internal address is 3 bytes + if (isize > 3) { + isize = 3; + } - // write internal register address - most significant byte first - while (isize-- > 0) { - write((uint8_t)(iaddress >> (isize * 8))); + // write internal register address - most significant byte first + while (isize-- > 0) { + write((uint8_t)(iaddress >> (isize * 8))); + } + endTransmission(false); } - endTransmission(false); - } - - // perform blocking read into buffer - uint8_t read = 0; + // perform blocking read into buffer #if defined(I2C_OTHER_FRAME) - if (sendStop == 0) { - _i2c.handle.XferOptions = I2C_OTHER_FRAME ; - } else { - _i2c.handle.XferOptions = I2C_OTHER_AND_LAST_FRAME; - } + if (sendStop == 0) { + _i2c.handle.XferOptions = I2C_OTHER_FRAME ; + } else { + _i2c.handle.XferOptions = I2C_OTHER_AND_LAST_FRAME; + } #endif - if (I2C_OK == i2c_master_read(&_i2c, address << 1, rxBuffer, quantity)) { - read = quantity; - } + if (I2C_OK == i2c_master_read(&_i2c, address << 1, rxBuffer, quantity)) { + read = quantity; + } - // set rx buffer iterator vars - rxBufferIndex = 0; - rxBufferLength = read; + // set rx buffer iterator vars + rxBufferIndex = 0; + rxBufferLength = read; - return read; + } } - - return 0; + return read; } uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop) @@ -260,7 +257,6 @@ uint8_t TwoWire::endTransmission(uint8_t sendStop) // indicate that we are done transmitting transmitting = 0; } - return ret; } @@ -277,27 +273,29 @@ uint8_t TwoWire::endTransmission(void) // or after beginTransmission(address) size_t TwoWire::write(uint8_t data) { + size_t ret = 1; if (transmitting) { // in master transmitter mode allocateTxBuffer(txBufferLength + 1); // error if no memory block available to allocate the buffer if (txBuffer == nullptr) { setWriteError(); - return 0; + ret = 0; + } else { + // put byte in tx buffer + txBuffer[txBufferIndex] = data; + ++txBufferIndex; + // update amount in buffer + txBufferLength = txBufferIndex; } - // put byte in tx buffer - txBuffer[txBufferIndex] = data; - ++txBufferIndex; - // update amount in buffer - txBufferLength = txBufferIndex; } else { // in slave send mode // reply to master if (i2c_slave_write_IT(&_i2c, &data, 1) != I2C_OK) { - return 0; + ret = 0; } } - return 1; + return ret; } /** @@ -309,28 +307,30 @@ size_t TwoWire::write(uint8_t data) */ size_t TwoWire::write(const uint8_t *data, size_t quantity) { + size_t ret = quantity; + if (transmitting) { // in master transmitter mode allocateTxBuffer(txBufferLength + quantity); // error if no memory block available to allocate the buffer if (txBuffer == nullptr) { setWriteError(); - return 0; + ret = 0; + } else { + // put bytes in tx buffer + memcpy(&(txBuffer[txBufferIndex]), data, quantity); + txBufferIndex = txBufferIndex + quantity; + // update amount in buffer + txBufferLength = txBufferIndex; } - // put bytes in tx buffer - memcpy(&(txBuffer[txBufferIndex]), data, quantity); - txBufferIndex = txBufferIndex + quantity; - // update amount in buffer - txBufferLength = txBufferIndex; - return quantity; } else { // in slave send mode // reply to master - if (i2c_slave_write_IT(&_i2c, (uint8_t *)data, quantity) == I2C_OK) { - return quantity; + if (i2c_slave_write_IT(&_i2c, (uint8_t *)data, quantity) != I2C_OK) { + ret = 0; } } - return 0; + return ret; } // must be called in: @@ -360,7 +360,6 @@ int TwoWire::read(void) resetRxBuffer(); }*/ } - return value; } @@ -374,7 +373,6 @@ int TwoWire::peek(void) if (rxBufferIndex < rxBufferLength) { value = rxBuffer[rxBufferIndex]; } - return value; } @@ -392,47 +390,42 @@ void TwoWire::flush(void) void TwoWire::onReceiveService(uint8_t *inBytes, int numBytes) { // don't bother if user hasn't registered a callback - if (!user_onReceive) { - return; - } - - // don't bother if rx buffer is in use by a master requestFrom() op - // i know this drops data, but it allows for slight stupidity - // meaning, they may not have read all the master requestFrom() data yet - if (rxBufferIndex < rxBufferLength) { - return; - } + if (user_onReceive) { + // don't bother if rx buffer is in use by a master requestFrom() op + // i know this drops data, but it allows for slight stupidity + // meaning, they may not have read all the master requestFrom() data yet + if (rxBufferIndex >= rxBufferLength) { + + allocateRxBuffer(numBytes); + // error if no memory block available to allocate the buffer + if (rxBuffer == nullptr) { + Error_Handler(); + } - allocateRxBuffer(numBytes); - // error if no memory block available to allocate the buffer - if (rxBuffer == nullptr) { - Error_Handler(); + // copy twi rx buffer into local read buffer + // this enables new reads to happen in parallel + memcpy(rxBuffer, inBytes, numBytes); + // set rx iterator vars + rxBufferIndex = 0; + rxBufferLength = numBytes; + // alert user program + user_onReceive(numBytes); + } } - - // copy twi rx buffer into local read buffer - // this enables new reads to happen in parallel - memcpy(rxBuffer, inBytes, numBytes); - // set rx iterator vars - rxBufferIndex = 0; - rxBufferLength = numBytes; - // alert user program - user_onReceive(numBytes); } // behind the scenes function that is called when data is requested void TwoWire::onRequestService(void) { // don't bother if user hasn't registered a callback - if (!user_onRequest) { - return; + if (user_onRequest) { + // reset tx buffer iterator vars + // !!! this will kill any pending pre-master sendTo() activity + txBufferIndex = 0; + txBufferLength = 0; + // alert user program + user_onRequest(); } - - // reset tx buffer iterator vars - // !!! this will kill any pending pre-master sendTo() activity - txBufferIndex = 0; - txBufferLength = 0; - // alert user program - user_onRequest(); } // sets function called on slave write From 431ba4bfdece4160738e2037ae758fdf60709c42 Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Tue, 15 Oct 2019 16:12:58 +0200 Subject: [PATCH 4/4] [I2C] Review errors management Signed-off-by: Frederic Pillon --- cores/arduino/stm32/twi.c | 24 ++++++++++++++++-------- cores/arduino/stm32/twi.h | 9 ++++++--- libraries/Wire/src/Wire.cpp | 15 ++++++++++++--- 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/cores/arduino/stm32/twi.c b/cores/arduino/stm32/twi.c index d43010ee28..a6124d0e04 100644 --- a/cores/arduino/stm32/twi.c +++ b/cores/arduino/stm32/twi.c @@ -762,8 +762,12 @@ i2c_status_e i2c_master_write(i2c_t *obj, uint8_t dev_address, if ((delta > I2C_TIMEOUT_TICK) || ((err & HAL_I2C_ERROR_TIMEOUT) == HAL_I2C_ERROR_TIMEOUT)) { ret = I2C_TIMEOUT; - } else if (err != HAL_I2C_ERROR_NONE) { - ret = I2C_ERROR; + } else { + if ((err & HAL_I2C_ERROR_AF) == HAL_I2C_ERROR_AF) { + ret = I2C_NACK_DATA; + } else if (err != HAL_I2C_ERROR_NONE) { + ret = I2C_ERROR; + } } } } @@ -784,7 +788,7 @@ i2c_status_e i2c_slave_write_IT(i2c_t *obj, uint8_t *data, uint16_t size) // Protection to not override the TxBuffer if (size > I2C_TXRX_BUFFER_SIZE) { - ret = I2C_ERROR; + ret = I2C_DATA_TOO_LONG; } else { // Check the communication status for (i = 0; i < size; i++) { @@ -832,8 +836,12 @@ i2c_status_e i2c_master_read(i2c_t *obj, uint8_t dev_address, uint8_t *data, uin if ((delta > I2C_TIMEOUT_TICK) || ((err & HAL_I2C_ERROR_TIMEOUT) == HAL_I2C_ERROR_TIMEOUT)) { ret = I2C_TIMEOUT; - } else if (err != HAL_I2C_ERROR_NONE) { - ret = I2C_ERROR; + } else { + if ((err & HAL_I2C_ERROR_AF) == HAL_I2C_ERROR_AF) { + ret = I2C_NACK_DATA; + } else if (err != HAL_I2C_ERROR_NONE) { + ret = I2C_ERROR; + } } } return ret; @@ -855,13 +863,13 @@ i2c_status_e i2c_IsDeviceReady(i2c_t *obj, uint8_t devAddr, uint32_t trials) ret = I2C_OK; break; case HAL_TIMEOUT: - ret = I2C_TIMEOUT; + ret = (obj->handle.State != HAL_I2C_STATE_READY) ? I2C_TIMEOUT : I2C_NACK_ADDR; break; case HAL_BUSY: - ret = I2C_BUSY; + ret = (obj->handle.State != HAL_I2C_STATE_READY) ? I2C_BUSY : I2C_NACK_ADDR; break; default: - ret = I2C_TIMEOUT; + ret = (obj->handle.State != HAL_I2C_STATE_READY) ? I2C_ERROR : I2C_NACK_ADDR; break; } return ret; diff --git a/cores/arduino/stm32/twi.h b/cores/arduino/stm32/twi.h index a5b687300b..37881212ff 100644 --- a/cores/arduino/stm32/twi.h +++ b/cores/arduino/stm32/twi.h @@ -115,9 +115,12 @@ struct i2c_s { ///@brief I2C state typedef enum { I2C_OK = 0, - I2C_TIMEOUT = 1, - I2C_ERROR = 2, - I2C_BUSY = 3 + I2C_DATA_TOO_LONG = 1, + I2C_NACK_ADDR = 2, + I2C_NACK_DATA = 3, + I2C_ERROR = 4, + I2C_TIMEOUT = 5, + I2C_BUSY = 6 } i2c_status_e; /* Exported functions ------------------------------------------------------- */ diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index 8f1f8acda6..5ed1012487 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -100,13 +100,13 @@ void TwoWire::begin(int address, bool generalCall) void TwoWire::end(void) { + i2c_deinit(&_i2c); free(txBuffer); txBuffer = nullptr; txBufferAllocated = 0; free(rxBuffer); rxBuffer = nullptr; rxBufferAllocated = 0; - i2c_deinit(&_i2c); } void TwoWire::setClock(uint32_t frequency) @@ -237,11 +237,20 @@ uint8_t TwoWire::endTransmission(uint8_t sendStop) // transmit buffer (blocking) switch (i2c_master_write(&_i2c, txAddress, txBuffer, txBufferLength)) { case I2C_OK : - ret = 0; + ret = 0; // Success break; - case I2C_TIMEOUT : + case I2C_DATA_TOO_LONG : ret = 1; break; + case I2C_NACK_ADDR: + ret = 2; + break; + case I2C_NACK_DATA: + ret = 3; + break; + case I2C_TIMEOUT: + case I2C_BUSY: + case I2C_ERROR: default: ret = 4; break;