From 304cdf9e702523fc0b861240af5f34c0b2f56f38 Mon Sep 17 00:00:00 2001 From: Rob Tillaart Date: Wed, 26 Mar 2025 18:53:53 +0100 Subject: [PATCH 1/4] add I2C_TIMEOUT --- CHANGELOG.md | 102 ++++++++++++++++++ LICENSE | 2 +- MultiSpeedI2CScanner.ino | 72 ++++++++----- README.md | 47 +++++++- .../MultiSpeedI2CScanner.ino | 72 ++++++++----- 5 files changed, 240 insertions(+), 55 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..ca99424 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,102 @@ +# Change Log MultiSpeedI2CScanner + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + + +https://github.com/RobTillaart/MultiSpeedI2CScanner + + +## 0.2.0 2025-03-25 +- add wire->setWireTimeout, after selecting the wire bus ~line 160 +- add **uint32_t I2C_TIMEOUT = 25000;** +- add **experimental** "e" command to toggle errorCodes in output. +- update license. +- rename releaseNotes to CHANGELOG.md. +- bumped version to 0.2.0 + +---- + +## 0.1.17 2023-11-14 +- update readme.md + +## 0.1.16 2023-01-20 + +- update build-ci +- add link to I2C scanner class in readme.md + +## 0.1.15 2021-12-22 + +- change Khz =>KHz +- update license + +## 0.1.14 2021-11-10 + +- update Arduino-CI build process +- add badges to readme.md +- updated readme.md +- support up to 5 Wire buses +- added an I2C bus counter sketch (very minimal) +- minor edits release notes. + +## 0.1.13 2020-12-12 + +- Add Arduino-CI build process. +- Added a dummy examples folder with the same .ino source. +- This shows that the sketch compiles well. + +## 0.1.12 2020-12-12 + +- Fix #4, default address range = 08...119 (0-7 and 120-127 are special) + +## 0.1.11 2018-07-20 + +- Fix failing TWBR setting +- added yield() during scan to improve ESP behaviour. +- added disable interrupts flag +- refactor / clean up + +## 0.1.10 2018-04-02 + +- Fix #152 +- improved support for ESP32 +- changed multispeed ranges a bit (option 0 and 9) +- refactor +- added experimental high speeds 1000, 3400, 5000 KHz. + +verified on UNO and ESP32, +note the latter one must adjust the pins in the code. + +## 0.1.9 2018-04-02 + +- '9' command to scan up to 400 KHz only to prevent blocking +- changed "scan up to 400 KHz" as default at startup + +## 0.1.8 2017-08-03 + +- DUE support + +## 0.1.7 2017-07-17 + +- TEENSY support - multiple I2C ports +- '@' command to select I2C Port +- changed # speeds steps of 100 + +## 0.1.6 2015-03-29 + +- Wire.setClock as more portable way to set I2C clock + +## 0.1.5 2014-07-06 + +- void setSpeed() - more control about what is scanned +- void setAddress() - address range +- extended help + +## older versions not documented +(started 2013-11-05 ?) + + +// -- END OF FILE -- + diff --git a/LICENSE b/LICENSE index 9a9ac5a..ea1e69a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2013-2024 Rob Tillaart +Copyright (c) 2013-2025 Rob Tillaart Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/MultiSpeedI2CScanner.ino b/MultiSpeedI2CScanner.ino index be76428..6a25d04 100644 --- a/MultiSpeedI2CScanner.ino +++ b/MultiSpeedI2CScanner.ino @@ -1,7 +1,7 @@ // // FILE: MultiSpeedI2CScanner.ino // AUTHOR: Rob Tillaart -// VERSION: 0.1.17 +// VERSION: 0.2.0 // PURPOSE: I2C scanner at different speeds // DATE: 2013-11-05 // URL: https://github.com/RobTillaart/MultiSpeedI2CScanner @@ -12,13 +12,16 @@ #include #include + // FOR INTERNAL I2C BUS NANO 33 BLE // #define WIRE_IMPLEMENT_WIRE1 1 // extern TwoWire Wire1; + TwoWire *wire; -const char version[] = "0.1.16"; + +const char version[] = "0.2.0"; // INTERFACE COUNT (TESTED TEENSY 3.5 AND ARDUINO DUE ONLY) @@ -47,6 +50,7 @@ bool delayFlag = false; // MINIMIZE OUTPUT bool printAll = true; bool header = true; +bool errorCode = false; bool disableIRQ = false; @@ -62,6 +66,12 @@ uint32_t startScan; uint32_t stopScan; +// I2C TIMEOUT in microseconds. +// set to zero to disable. +uint32_t I2C_TIMEOUT = 25000; + + + /////////////////////////////////////////////////////////////////////////// // // MAIN CODE @@ -149,6 +159,9 @@ void loop() break; #endif } +#if defined(WIRE_HAS_TIMEOUT) + wire->setWireTimeout(I2C_TIMEOUT, false /* NO RESET */); +#endif break; case 's': @@ -164,7 +177,9 @@ void loop() break; case 'e': - // eeprom test TODO + errorCode = !errorCode; + Serial.print(F("") : F("no>")); break; case 'h': @@ -241,10 +256,11 @@ void reset() selectedWirePort = 0; addressStart = 8; addressEnd = 119; - + delayFlag = false; printAll = true; header = true; + errorCode = false; disableIRQ = false; state = STOP; @@ -368,6 +384,7 @@ void displayHelp() Serial.println(F("\tp = toggle printAll - printFound.")); Serial.println(F("\th = toggle header - noHeader.")); Serial.println(F("\ta = toggle address range, 0..127 - 8..119 (default)")); + Serial.println(F("\te = toggle . or errorCode e.g. E02")); Serial.println(F("Speeds:")); Serial.println(F("\t0 = 100..800 KHz - step 100 (warning - can block!!)")); @@ -418,7 +435,7 @@ void I2Cscan() for (uint8_t address = addressStart; address <= addressEnd; address++) { bool printLine = printAll; - bool found[speeds]; + char found[speeds][8]; bool fnd = false; for (uint8_t s = 0; s < speeds ; s++) @@ -438,8 +455,14 @@ void I2Cscan() wire->setClock(speed[s] * 1000UL); #endif wire->beginTransmission (address); - found[s] = (wire->endTransmission () == 0); - fnd |= found[s]; + int code = wire->endTransmission(); + fnd |= (code == 0); + if (code == 0) strcpy(found[s], "OK"); + else + { + if (errorCode) sprintf(found[s], "E%02d", code); + else strcpy(found[s], "."); + } // give device 5 millis if (fnd && delayFlag) delay(RESTORE_LATENCY); } @@ -460,31 +483,31 @@ void I2Cscan() for (uint8_t s = 0; s < speeds ; s++) { Serial.print(F("\t")); - Serial.print(found[s] ? F("V") : F(".")); + Serial.print(found[s]); } Serial.println(); } } -/* - // FOOTER - if (header) - { - for (uint8_t s = 0; s < speeds + 5; s++) + /* + // FOOTER + if (header) { - Serial.print(F("--------")); - } - Serial.println(); + for (uint8_t s = 0; s < speeds + 5; s++) + { + Serial.print(F("--------")); + } + Serial.println(); - Serial.print(F("TIME\tDEC\tHEX\t")); - for (uint8_t s = 0; s < speeds; s++) - { - Serial.print(F("\t")); - Serial.print(speed[s]); + Serial.print(F("TIME\tDEC\tHEX\t")); + for (uint8_t s = 0; s < speeds; s++) + { + Serial.print(F("\t")); + Serial.print(speed[s]); + } + Serial.println(F("\t[KHz]")); } - Serial.println(F("\t[KHz]")); - } -*/ + */ stopScan = millis(); if (header) @@ -501,4 +524,3 @@ void I2Cscan() // -- END OF FILE -- - diff --git a/README.md b/README.md index 7881562..4afd07c 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,21 @@ The scanner provides an overview of which addresses can be found at which speed. This allows one to optimize the I2C performance of many devices above the standard 100KHz speed. -#### Related +### I2C TIMEOUT + +Since version 0.1.18 the MultiSpeed I2C Scanner has a time out +of default 25 milliseconds on the I2C transactions. +This feature prevents locking of the I2C scanner and is large +enough even for low I2C speeds. + +Not all platforms support the I2C timeout, so it is implemented +conditional. + +Set the value of **I2C_TIMEOUT** to zero to disable it. +Note this is not a menu option and must be done compile time (for now). + + +### Related build your own I2C scanner with: - https://github.com/RobTillaart/I2C_SCANNER @@ -54,6 +68,7 @@ Output: p = toggle printAll - printFound. h = toggle header - noHeader. a = toggle address range, 0..127 - 8..119 (default) + e = toggle . or errorCode e.g. E02 Speeds: 0 = 100..800 KHz - step 100 (warning - can block!!) 1 = 100 KHz @@ -106,6 +121,26 @@ PrintFound will only generate a line if an I2C device is found on that address. **a** toggles the range of addresses scanned, default the range 8 .. 119 is scanned, but one can extend this range to 0 .. 127. **Note:** some addresses are reserved. +Experimental in 0.2.0 + +**e** toggles the output between . and the code returned by **endTransmission()**. +When an device is found it will print OK. Might help for diagnosis, but one need +to dive in the source code of the board. See table below for AVR. + +#### ErrorCodes AVR + +Based on twi_writeTo(), other boards might have different codes. + +``` +Value Meaning + 0 .. success +E01 .. length to long for buffer +E02 .. address send, NACK received +E03 .. data send, NACK received +E04 .. other twi error (lost bus arbitration, bus error, ..) +E05 .. timeout +``` + ### Speeds @@ -125,19 +160,23 @@ Check your datasheet to see which speeds are applicable for the processor in use #### Must - update documentation -- test on RP2040 +- test on RP2040 and other platforms. #### Should + #### Could -- add watchdog reset (at least AVR - 8 seconds 0.2.0 ) +- add "T" command to toggle I2C_TIMEOUT 0 - 25000 ? - non-AVR command behind a ```#ifdef``` ? -- rename releaseNotes.md to changelog.md (in line with libraries) - I2C GENERIC RESET address 0x00 CMD 0x06 +- I2C GENERIC DEVICEID -> under investigation in PCA9671 + #### Wont +- add watchdog reset (at least AVR - 8 seconds 0.2.0 ) => solved with I2C_TIMEOUT. + ## Support diff --git a/examples/MultiSpeedI2CScanner/MultiSpeedI2CScanner.ino b/examples/MultiSpeedI2CScanner/MultiSpeedI2CScanner.ino index be76428..6a25d04 100644 --- a/examples/MultiSpeedI2CScanner/MultiSpeedI2CScanner.ino +++ b/examples/MultiSpeedI2CScanner/MultiSpeedI2CScanner.ino @@ -1,7 +1,7 @@ // // FILE: MultiSpeedI2CScanner.ino // AUTHOR: Rob Tillaart -// VERSION: 0.1.17 +// VERSION: 0.2.0 // PURPOSE: I2C scanner at different speeds // DATE: 2013-11-05 // URL: https://github.com/RobTillaart/MultiSpeedI2CScanner @@ -12,13 +12,16 @@ #include #include + // FOR INTERNAL I2C BUS NANO 33 BLE // #define WIRE_IMPLEMENT_WIRE1 1 // extern TwoWire Wire1; + TwoWire *wire; -const char version[] = "0.1.16"; + +const char version[] = "0.2.0"; // INTERFACE COUNT (TESTED TEENSY 3.5 AND ARDUINO DUE ONLY) @@ -47,6 +50,7 @@ bool delayFlag = false; // MINIMIZE OUTPUT bool printAll = true; bool header = true; +bool errorCode = false; bool disableIRQ = false; @@ -62,6 +66,12 @@ uint32_t startScan; uint32_t stopScan; +// I2C TIMEOUT in microseconds. +// set to zero to disable. +uint32_t I2C_TIMEOUT = 25000; + + + /////////////////////////////////////////////////////////////////////////// // // MAIN CODE @@ -149,6 +159,9 @@ void loop() break; #endif } +#if defined(WIRE_HAS_TIMEOUT) + wire->setWireTimeout(I2C_TIMEOUT, false /* NO RESET */); +#endif break; case 's': @@ -164,7 +177,9 @@ void loop() break; case 'e': - // eeprom test TODO + errorCode = !errorCode; + Serial.print(F("") : F("no>")); break; case 'h': @@ -241,10 +256,11 @@ void reset() selectedWirePort = 0; addressStart = 8; addressEnd = 119; - + delayFlag = false; printAll = true; header = true; + errorCode = false; disableIRQ = false; state = STOP; @@ -368,6 +384,7 @@ void displayHelp() Serial.println(F("\tp = toggle printAll - printFound.")); Serial.println(F("\th = toggle header - noHeader.")); Serial.println(F("\ta = toggle address range, 0..127 - 8..119 (default)")); + Serial.println(F("\te = toggle . or errorCode e.g. E02")); Serial.println(F("Speeds:")); Serial.println(F("\t0 = 100..800 KHz - step 100 (warning - can block!!)")); @@ -418,7 +435,7 @@ void I2Cscan() for (uint8_t address = addressStart; address <= addressEnd; address++) { bool printLine = printAll; - bool found[speeds]; + char found[speeds][8]; bool fnd = false; for (uint8_t s = 0; s < speeds ; s++) @@ -438,8 +455,14 @@ void I2Cscan() wire->setClock(speed[s] * 1000UL); #endif wire->beginTransmission (address); - found[s] = (wire->endTransmission () == 0); - fnd |= found[s]; + int code = wire->endTransmission(); + fnd |= (code == 0); + if (code == 0) strcpy(found[s], "OK"); + else + { + if (errorCode) sprintf(found[s], "E%02d", code); + else strcpy(found[s], "."); + } // give device 5 millis if (fnd && delayFlag) delay(RESTORE_LATENCY); } @@ -460,31 +483,31 @@ void I2Cscan() for (uint8_t s = 0; s < speeds ; s++) { Serial.print(F("\t")); - Serial.print(found[s] ? F("V") : F(".")); + Serial.print(found[s]); } Serial.println(); } } -/* - // FOOTER - if (header) - { - for (uint8_t s = 0; s < speeds + 5; s++) + /* + // FOOTER + if (header) { - Serial.print(F("--------")); - } - Serial.println(); + for (uint8_t s = 0; s < speeds + 5; s++) + { + Serial.print(F("--------")); + } + Serial.println(); - Serial.print(F("TIME\tDEC\tHEX\t")); - for (uint8_t s = 0; s < speeds; s++) - { - Serial.print(F("\t")); - Serial.print(speed[s]); + Serial.print(F("TIME\tDEC\tHEX\t")); + for (uint8_t s = 0; s < speeds; s++) + { + Serial.print(F("\t")); + Serial.print(speed[s]); + } + Serial.println(F("\t[KHz]")); } - Serial.println(F("\t[KHz]")); - } -*/ + */ stopScan = millis(); if (header) @@ -501,4 +524,3 @@ void I2Cscan() // -- END OF FILE -- - From 35d6724bd73f7964b87eb815f4ac4b6f0dad1cfd Mon Sep 17 00:00:00 2001 From: Rob Tillaart Date: Wed, 26 Mar 2025 19:00:17 +0100 Subject: [PATCH 2/4] add I2C_TIMEOUT --- MultiSpeedI2CScanner.ino | 3 +++ examples/MultiSpeedI2CScanner/MultiSpeedI2CScanner.ino | 3 +++ 2 files changed, 6 insertions(+) diff --git a/MultiSpeedI2CScanner.ino b/MultiSpeedI2CScanner.ino index 6a25d04..e080671 100644 --- a/MultiSpeedI2CScanner.ino +++ b/MultiSpeedI2CScanner.ino @@ -111,6 +111,9 @@ void setup() #endif wire = &Wire; +#if defined(WIRE_HAS_TIMEOUT) + wire->setWireTimeout(I2C_TIMEOUT, false /* NO RESET */); +#endif Serial.println(); reset(); diff --git a/examples/MultiSpeedI2CScanner/MultiSpeedI2CScanner.ino b/examples/MultiSpeedI2CScanner/MultiSpeedI2CScanner.ino index 6a25d04..e080671 100644 --- a/examples/MultiSpeedI2CScanner/MultiSpeedI2CScanner.ino +++ b/examples/MultiSpeedI2CScanner/MultiSpeedI2CScanner.ino @@ -111,6 +111,9 @@ void setup() #endif wire = &Wire; +#if defined(WIRE_HAS_TIMEOUT) + wire->setWireTimeout(I2C_TIMEOUT, false /* NO RESET */); +#endif Serial.println(); reset(); From d3d757a62dbfc5737dcd4466b2711bbca3b92ed2 Mon Sep 17 00:00:00 2001 From: Rob Tillaart Date: Wed, 26 Mar 2025 19:04:34 +0100 Subject: [PATCH 3/4] add I2C_TIMEOUT --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4afd07c..ae02573 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ not used. # Arduino MultiSpeed I2C Scanner -## Version: 0.1.17 +## Version: 0.2.0 ## Description From d2e670ad027e28a40937499b3838d3ed82a5737a Mon Sep 17 00:00:00 2001 From: Rob Tillaart Date: Wed, 26 Mar 2025 19:07:44 +0100 Subject: [PATCH 4/4] add I2C_TIMEOUT --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ae02573..65c56b0 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ many devices above the standard 100KHz speed. ### I2C TIMEOUT -Since version 0.1.18 the MultiSpeed I2C Scanner has a time out +Since version 0.2.0 the MultiSpeed I2C Scanner has a time out of default 25 milliseconds on the I2C transactions. This feature prevents locking of the I2C scanner and is large enough even for low I2C speeds.