From a99ecf71d8d33e48a9e901fbf030e52f5dbad159 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 10 Aug 2016 23:04:18 -0700 Subject: [PATCH 1/3] Add support for i2c slave address --- Marlin/Configuration_adv.h | 1 + Marlin/Marlin_main.cpp | 12 +++ .../Cartesio/Configuration_adv.h | 1 + .../Felix/Configuration_adv.h | 1 + .../Hephestos/Configuration_adv.h | 1 + .../Hephestos_2/Configuration_adv.h | 1 + .../K8200/Configuration_adv.h | 1 + .../K8400/Configuration_adv.h | 1 + .../RigidBot/Configuration_adv.h | 1 + .../SCARA/Configuration_adv.h | 1 + .../TAZ4/Configuration_adv.h | 1 + .../WITBOX/Configuration_adv.h | 1 + .../delta/biv2.5/Configuration_adv.h | 1 + .../delta/generic/Configuration_adv.h | 1 + .../delta/kossel_mini/Configuration_adv.h | 1 + .../delta/kossel_pro/Configuration_adv.h | 1 + .../delta/kossel_xl/Configuration_adv.h | 1 + .../makibox/Configuration_adv.h | 1 + .../tvrrug/Round2/Configuration_adv.h | 1 + Marlin/twibus.cpp | 41 +++++----- Marlin/twibus.h | 77 +++++++++++++------ 21 files changed, 104 insertions(+), 44 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index a822c83b1..2def9b386 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -795,5 +795,6 @@ const unsigned int dropsegments = 5; //everything with less than this number of // @section i2cbus //#define EXPERIMENTAL_I2CBUS +#define I2C_SLAVE_ADDRESS 0 // Set non-zero to act as a slave #endif // CONFIGURATION_ADV_H diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 995f6d803..c81f3d39f 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -835,6 +835,14 @@ void servo_init() { void enableStepperDrivers() { pinMode(STEPPER_RESET_PIN, INPUT); } // set to input, which allows it to be pulled high by pullups #endif +#if ENABLED(EXPERIMENTAL_I2CBUS) && I2C_SLAVE_ADDRESS > 0 + + void i2c_listener(int bytes) { + i2c.receive(bytes); // just echo all bytes received to serial + } + +#endif + /** * Marlin entry-point: Set up before the program loop * - Set up the kill pin, filament runout, power hold @@ -981,6 +989,10 @@ void setup() { for (uint8_t i = 0; i < MIXING_STEPPERS; i++) mixing_virtual_tool_mix[t][i] = mixing_factor[i]; #endif + + #if ENABLED(EXPERIMENTAL_I2CBUS) && I2C_SLAVE_ADDRESS > 0 + i2c.onReceive(i2c_listener); + #endif } /** diff --git a/Marlin/example_configurations/Cartesio/Configuration_adv.h b/Marlin/example_configurations/Cartesio/Configuration_adv.h index 3e10c3f85..444fc7b2d 100644 --- a/Marlin/example_configurations/Cartesio/Configuration_adv.h +++ b/Marlin/example_configurations/Cartesio/Configuration_adv.h @@ -795,5 +795,6 @@ const unsigned int dropsegments = 5; //everything with less than this number of // @section i2cbus //#define EXPERIMENTAL_I2CBUS +#define I2C_SLAVE_ADDRESS 0 // Set non-zero to act as a slave #endif // CONFIGURATION_ADV_H diff --git a/Marlin/example_configurations/Felix/Configuration_adv.h b/Marlin/example_configurations/Felix/Configuration_adv.h index 570073579..6f4d1139c 100644 --- a/Marlin/example_configurations/Felix/Configuration_adv.h +++ b/Marlin/example_configurations/Felix/Configuration_adv.h @@ -795,5 +795,6 @@ const unsigned int dropsegments = 5; //everything with less than this number of // @section i2cbus //#define EXPERIMENTAL_I2CBUS +#define I2C_SLAVE_ADDRESS 0 // Set non-zero to act as a slave #endif // CONFIGURATION_ADV_H diff --git a/Marlin/example_configurations/Hephestos/Configuration_adv.h b/Marlin/example_configurations/Hephestos/Configuration_adv.h index b719e6072..d26e2207b 100644 --- a/Marlin/example_configurations/Hephestos/Configuration_adv.h +++ b/Marlin/example_configurations/Hephestos/Configuration_adv.h @@ -795,5 +795,6 @@ const unsigned int dropsegments = 5; //everything with less than this number of // @section i2cbus //#define EXPERIMENTAL_I2CBUS +#define I2C_SLAVE_ADDRESS 0 // Set non-zero to act as a slave #endif // CONFIGURATION_ADV_H diff --git a/Marlin/example_configurations/Hephestos_2/Configuration_adv.h b/Marlin/example_configurations/Hephestos_2/Configuration_adv.h index eeb11da2d..4b771d5d5 100644 --- a/Marlin/example_configurations/Hephestos_2/Configuration_adv.h +++ b/Marlin/example_configurations/Hephestos_2/Configuration_adv.h @@ -795,5 +795,6 @@ const unsigned int dropsegments = 5; //everything with less than this number of // @section i2cbus //#define EXPERIMENTAL_I2CBUS +#define I2C_SLAVE_ADDRESS 0 // Set non-zero to act as a slave #endif // CONFIGURATION_ADV_H diff --git a/Marlin/example_configurations/K8200/Configuration_adv.h b/Marlin/example_configurations/K8200/Configuration_adv.h index dc26fd603..92a81b22c 100644 --- a/Marlin/example_configurations/K8200/Configuration_adv.h +++ b/Marlin/example_configurations/K8200/Configuration_adv.h @@ -801,5 +801,6 @@ const unsigned int dropsegments = 2; //everything with less than this number of // @section i2cbus //#define EXPERIMENTAL_I2CBUS +#define I2C_SLAVE_ADDRESS 0 // Set non-zero to act as a slave #endif // CONFIGURATION_ADV_H diff --git a/Marlin/example_configurations/K8400/Configuration_adv.h b/Marlin/example_configurations/K8400/Configuration_adv.h index 64efac984..dde4547f4 100644 --- a/Marlin/example_configurations/K8400/Configuration_adv.h +++ b/Marlin/example_configurations/K8400/Configuration_adv.h @@ -795,5 +795,6 @@ const unsigned int dropsegments = 5; //everything with less than this number of // @section i2cbus //#define EXPERIMENTAL_I2CBUS +#define I2C_SLAVE_ADDRESS 0 // Set non-zero to act as a slave #endif // CONFIGURATION_ADV_H diff --git a/Marlin/example_configurations/RigidBot/Configuration_adv.h b/Marlin/example_configurations/RigidBot/Configuration_adv.h index 2118f83d5..d077ae28e 100644 --- a/Marlin/example_configurations/RigidBot/Configuration_adv.h +++ b/Marlin/example_configurations/RigidBot/Configuration_adv.h @@ -795,5 +795,6 @@ const unsigned int dropsegments = 5; //everything with less than this number of // @section i2cbus //#define EXPERIMENTAL_I2CBUS +#define I2C_SLAVE_ADDRESS 0 // Set non-zero to act as a slave #endif // CONFIGURATION_ADV_H diff --git a/Marlin/example_configurations/SCARA/Configuration_adv.h b/Marlin/example_configurations/SCARA/Configuration_adv.h index 07f1e5654..bf4d32351 100644 --- a/Marlin/example_configurations/SCARA/Configuration_adv.h +++ b/Marlin/example_configurations/SCARA/Configuration_adv.h @@ -795,5 +795,6 @@ const unsigned int dropsegments = 5; //everything with less than this number of // @section i2cbus //#define EXPERIMENTAL_I2CBUS +#define I2C_SLAVE_ADDRESS 0 // Set non-zero to act as a slave #endif // CONFIGURATION_ADV_H diff --git a/Marlin/example_configurations/TAZ4/Configuration_adv.h b/Marlin/example_configurations/TAZ4/Configuration_adv.h index d0d98fb9f..1417c803d 100644 --- a/Marlin/example_configurations/TAZ4/Configuration_adv.h +++ b/Marlin/example_configurations/TAZ4/Configuration_adv.h @@ -803,5 +803,6 @@ const unsigned int dropsegments = 5; //everything with less than this number of // @section i2cbus //#define EXPERIMENTAL_I2CBUS +#define I2C_SLAVE_ADDRESS 0 // Set non-zero to act as a slave #endif // CONFIGURATION_ADV_H diff --git a/Marlin/example_configurations/WITBOX/Configuration_adv.h b/Marlin/example_configurations/WITBOX/Configuration_adv.h index b719e6072..d26e2207b 100644 --- a/Marlin/example_configurations/WITBOX/Configuration_adv.h +++ b/Marlin/example_configurations/WITBOX/Configuration_adv.h @@ -795,5 +795,6 @@ const unsigned int dropsegments = 5; //everything with less than this number of // @section i2cbus //#define EXPERIMENTAL_I2CBUS +#define I2C_SLAVE_ADDRESS 0 // Set non-zero to act as a slave #endif // CONFIGURATION_ADV_H diff --git a/Marlin/example_configurations/delta/biv2.5/Configuration_adv.h b/Marlin/example_configurations/delta/biv2.5/Configuration_adv.h index 9183be44b..828391a3f 100644 --- a/Marlin/example_configurations/delta/biv2.5/Configuration_adv.h +++ b/Marlin/example_configurations/delta/biv2.5/Configuration_adv.h @@ -797,5 +797,6 @@ const unsigned int dropsegments = 5; //everything with less than this number of // @section i2cbus //#define EXPERIMENTAL_I2CBUS +#define I2C_SLAVE_ADDRESS 0 // Set non-zero to act as a slave #endif // CONFIGURATION_ADV_H diff --git a/Marlin/example_configurations/delta/generic/Configuration_adv.h b/Marlin/example_configurations/delta/generic/Configuration_adv.h index eb79a3041..967a3e6b5 100644 --- a/Marlin/example_configurations/delta/generic/Configuration_adv.h +++ b/Marlin/example_configurations/delta/generic/Configuration_adv.h @@ -797,5 +797,6 @@ const unsigned int dropsegments = 5; //everything with less than this number of // @section i2cbus //#define EXPERIMENTAL_I2CBUS +#define I2C_SLAVE_ADDRESS 0 // Set non-zero to act as a slave #endif // CONFIGURATION_ADV_H diff --git a/Marlin/example_configurations/delta/kossel_mini/Configuration_adv.h b/Marlin/example_configurations/delta/kossel_mini/Configuration_adv.h index 7ec5948d0..64ea68fcd 100644 --- a/Marlin/example_configurations/delta/kossel_mini/Configuration_adv.h +++ b/Marlin/example_configurations/delta/kossel_mini/Configuration_adv.h @@ -796,5 +796,6 @@ const unsigned int dropsegments = 5; //everything with less than this number of // @section i2cbus //#define EXPERIMENTAL_I2CBUS +#define I2C_SLAVE_ADDRESS 0 // Set non-zero to act as a slave #endif // CONFIGURATION_ADV_H diff --git a/Marlin/example_configurations/delta/kossel_pro/Configuration_adv.h b/Marlin/example_configurations/delta/kossel_pro/Configuration_adv.h index 811477921..99fbcf08f 100644 --- a/Marlin/example_configurations/delta/kossel_pro/Configuration_adv.h +++ b/Marlin/example_configurations/delta/kossel_pro/Configuration_adv.h @@ -801,5 +801,6 @@ const unsigned int dropsegments = 5; //everything with less than this number of // @section i2cbus //#define EXPERIMENTAL_I2CBUS +#define I2C_SLAVE_ADDRESS 0 // Set non-zero to act as a slave #endif // CONFIGURATION_ADV_H diff --git a/Marlin/example_configurations/delta/kossel_xl/Configuration_adv.h b/Marlin/example_configurations/delta/kossel_xl/Configuration_adv.h index 2a7399bb0..0af7481f9 100644 --- a/Marlin/example_configurations/delta/kossel_xl/Configuration_adv.h +++ b/Marlin/example_configurations/delta/kossel_xl/Configuration_adv.h @@ -797,5 +797,6 @@ const unsigned int dropsegments = 5; //everything with less than this number of // @section i2cbus //#define EXPERIMENTAL_I2CBUS +#define I2C_SLAVE_ADDRESS 0 // Set non-zero to act as a slave #endif // CONFIGURATION_ADV_H diff --git a/Marlin/example_configurations/makibox/Configuration_adv.h b/Marlin/example_configurations/makibox/Configuration_adv.h index 22cefd538..7715b71a3 100644 --- a/Marlin/example_configurations/makibox/Configuration_adv.h +++ b/Marlin/example_configurations/makibox/Configuration_adv.h @@ -795,5 +795,6 @@ const unsigned int dropsegments = 5; //everything with less than this number of // @section i2cbus //#define EXPERIMENTAL_I2CBUS +#define I2C_SLAVE_ADDRESS 0 // Set non-zero to act as a slave #endif // CONFIGURATION_ADV_H diff --git a/Marlin/example_configurations/tvrrug/Round2/Configuration_adv.h b/Marlin/example_configurations/tvrrug/Round2/Configuration_adv.h index 2ececd4c3..3cfe5860b 100644 --- a/Marlin/example_configurations/tvrrug/Round2/Configuration_adv.h +++ b/Marlin/example_configurations/tvrrug/Round2/Configuration_adv.h @@ -795,5 +795,6 @@ const unsigned int dropsegments = 5; //everything with less than this number of // @section i2cbus //#define EXPERIMENTAL_I2CBUS +#define I2C_SLAVE_ADDRESS 0 // Set non-zero to act as a slave #endif // CONFIGURATION_ADV_H diff --git a/Marlin/twibus.cpp b/Marlin/twibus.cpp index c1d6008dd..cbefbfdfb 100644 --- a/Marlin/twibus.cpp +++ b/Marlin/twibus.cpp @@ -29,25 +29,28 @@ #include TWIBus::TWIBus() { - Wire.begin(); // We use no address so we will join the BUS as the master + #if I2C_SLAVE_ADDRESS == 0 + Wire.begin(); // No address joins the BUS as the master + #else + Wire.begin(I2C_SLAVE_ADDRESS); // Join the bus as a slave + #endif this->reset(); } void TWIBus::reset() { - this->addr = 0; this->buffer_s = 0; this->buffer[0] = 0x00; } -void TWIBus::address(uint8_t addr) { +void TWIBus::address(const uint8_t addr) { this->addr = addr; #if ENABLED(DEBUG_TWIBUS) - debug(PSTR("sendto"), this->addr); + debug(PSTR("address"), this->addr); #endif } -void TWIBus::addbyte(char c) { +void TWIBus::addbyte(const char c) { if (buffer_s >= sizeof(this->buffer)) return; this->buffer[this->buffer_s++] = c; @@ -67,39 +70,35 @@ void TWIBus::send() { Wire.write(this->buffer, this->buffer_s); Wire.endTransmission(); - // Reset the buffer after sending the data + // Reset the buffer after sending the data this->reset(); } -void TWIBus::reqbytes(uint8_t bytes) { +void TWIBus::reqbytes(const uint8_t bytes) { if (!this->addr) return; #if ENABLED(DEBUG_TWIBUS) debug(PSTR("reqbytes"), bytes); #endif + // requestFrom() is a blocking function millis_t t = millis() + this->timeout; Wire.requestFrom(this->addr, bytes); + while (Wire.available() < bytes && PENDING(millis(), t)) { /*nada*/ } - // requestFrom() is a blocking function - while (Wire.available() < bytes) { - if (ELAPSED(millis(), t)) break; - else continue; - } + this->relaydata(bytes); + // Reset the buffer after sending the data + this->reset(); +} + +void TWIBus::relaydata(uint8_t bytes) { SERIAL_ECHO_START; SERIAL_ECHOPAIR("i2c-reply: from:", this->addr); - SERIAL_ECHOPAIR(" bytes:", Wire.available()); + SERIAL_ECHOPAIR(" bytes:", bytes); SERIAL_ECHOPGM (" data:"); - - // Protect against buffer overflows if the number of received bytes - // is less than the number of requested bytes - uint8_t wba = Wire.available(); - for (int i = 0; i < wba; i++) SERIAL_CHAR(Wire.read()); + while (bytes-- && Wire.available()) SERIAL_CHAR(Wire.read()); SERIAL_EOL; - - // Reset the buffer after sending the data - this->reset(); } #if ENABLED(DEBUG_TWIBUS) diff --git a/Marlin/twibus.h b/Marlin/twibus.h index d0d0e0ff3..5901aec53 100644 --- a/Marlin/twibus.h +++ b/Marlin/twibus.h @@ -25,9 +25,13 @@ #include "macros.h" +#include + // Print debug messages with M111 S2 (Uses 236 bytes of PROGMEM) //#define DEBUG_TWIBUS +typedef void (*twiSlaveFunc_t)(int bytes); + /** * TWIBUS class * @@ -49,29 +53,28 @@ class TWIBus { private: /** * @brief Timeout value in milliseconds - * @details For blocking operations this constant value will set the max - * amount of time Marlin will keep waiting for a reply. Useful is something - * goes wrong on the bus and the SDA/SCL lines are held up by another device. + * @details Maximum amount of time (ms) to wait for a reply. + * Useful if something goes wrong on the bus and the + * SDA/SCL lines are held up by another device. */ const int timeout = 5; /** * @brief Target device address - * @description This stores, until the buffer is flushed, the target device - * address, take not we do follow Arduino 7bit addressing. + * @description The target device address. Persists until changed. + * */ uint8_t addr = 0; /** * @brief Number of bytes on buffer - * @description This var holds the total number of bytes on our buffer - * waiting to be flushed to the bus. + * @description Number of bytes in the buffer waiting to be flushed to the bus. */ uint8_t buffer_s = 0; /** * @brief Internal buffer - * @details This is a fixed buffer, TWI command cannot be longer than this + * @details A fixed buffer. TWI commands can be no longer than this. */ char buffer[30]; @@ -79,49 +82,77 @@ class TWIBus { public: /** * @brief Class constructor - * @details Initialized the TWI bus and clears the buffer + * @details Initialize the TWI bus and clear the buffer */ TWIBus(); /** * @brief Reset the buffer - * @details Brings the internal buffer to a known-empty state + * @details Set the buffer to a known-empty state */ void reset(); /** * @brief Send the buffer data to the bus - * @details Flushed the buffer into the bus targeting the cached slave device - * address. + * @details Flush the buffer to the bus at the target address. */ void send(); /** * @brief Add one byte to the buffer - * @details Adds the byte to the buffer in a sequential way, if buffer is full - * the request is silently ignored. + * @details Add a byte to the end of the buffer. + * Silently fails if the buffer is full. * * @param c a data byte */ - void addbyte(char c); + void addbyte(const char c); /** - * @brief Sets the target slave address - * @details The target slave address is stored so it can be later used when - * the complete packet needs to be sent over the bus. + * @brief Set the target slave address + * @details The target slave address for sending the full packet. * * @param addr 7-bit integer address */ - void address(uint8_t addr); + void address(const uint8_t addr); + + /** + * @brief Request data from the slave device + * @details Request a number of bytes from a slave device. + * This implementation simply sends the data to serial + * in a parser-friendly format. + * + * @param bytes the number of bytes to request + */ + void reqbytes(const uint8_t bytes); /** - * @brief Request data from slave device - * @details Requests data from a slave device, when the data is received it will - * be relayed to the serial line using a parser-friendly formatting. + * @brief Relay data from the slave device to serial + * @details Relay a number of bytes from the bus to + * serial in a parser-friendly format. * * @param bytes the number of bytes to request */ - void reqbytes(uint8_t bytes); + void relaydata(uint8_t bytes); + + #if I2C_SLAVE_ADDRESS > 0 + + /** + * @brief Receive bytes (passively) + * @details Receive bytes sent to our slave address. + * and simply echo them to serial. + */ + inline void receive(uint8_t bytes) { relaydata(bytes); } + + /** + * @brief Register a slave handler + * @details Set a handler to receive data from the bus, + * so we can act as a slave. + * + * @param handler A function to handle receiving bytes + */ + inline void onReceive(const twiSlaveFunc_t handler) { Wire.onReceive(handler); } + + #endif #if ENABLED(DEBUG_TWIBUS) From e3efb04295e6bb526154064e842d3eaddb9ddb91 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 10 Aug 2016 23:35:46 -0700 Subject: [PATCH 2/3] Shoehorn EXPERIMENTAL_I2CBUS into Travis test --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 728281e5a..251a6212b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -205,10 +205,11 @@ script: - opt_enable ULTIMAKERCONTROLLER FILAMENT_LCD_DISPLAY - build_marlin # - # Enable BEZIER_CURVE_SUPPORT + # Enable BEZIER_CURVE_SUPPORT, EXPERIMENTAL_I2CBUS, and I2C_SLAVE_ADDRESS # - restore_configs - - opt_enable_adv BEZIER_CURVE_SUPPORT + - opt_enable_adv BEZIER_CURVE_SUPPORT EXPERIMENTAL_I2CBUS + - opt_set_adv I2C_SLAVE_ADDRESS 1 - build_marlin # # Enable COREXY From dd75fca4d918df43b7f3bad530f6ed72e4839948 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 11 Aug 2016 00:16:14 -0700 Subject: [PATCH 3/3] Make M155 / M156 a bit more flexible --- Marlin/Marlin_main.cpp | 16 +++++++--------- Marlin/twibus.h | 15 +++++++-------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index c81f3d39f..87b4d309b 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -5259,15 +5259,13 @@ inline void gcode_M121() { endstops.enable_globally(false); } */ inline void gcode_M155() { // Set the target address - if (code_seen('A')) - i2c.address(code_value_byte()); + if (code_seen('A')) i2c.address(code_value_byte()); // Add a new byte to the buffer - else if (code_seen('B')) - i2c.addbyte(code_value_int()); + if (code_seen('B')) i2c.addbyte(code_value_byte()); // Flush the buffer to the bus - else if (code_seen('S')) i2c.send(); + if (code_seen('S')) i2c.send(); // Reset and rewind the buffer else if (code_seen('R')) i2c.reset(); @@ -5279,11 +5277,11 @@ inline void gcode_M121() { endstops.enable_globally(false); } * Usage: M156 A B */ inline void gcode_M156() { - uint8_t addr = code_seen('A') ? code_value_byte() : 0; - int bytes = code_seen('B') ? code_value_int() : 1; + if (code_seen('A')) i2c.address(code_value_byte()); - if (addr && bytes > 0 && bytes <= 32) { - i2c.address(addr); + uint8_t bytes = code_seen('B') ? code_value_byte() : 1; + + if (i2c.addr > 0 && bytes > 0 && bytes <= 32) { i2c.reqbytes(bytes); } else { diff --git a/Marlin/twibus.h b/Marlin/twibus.h index 5901aec53..d78e646e5 100644 --- a/Marlin/twibus.h +++ b/Marlin/twibus.h @@ -59,13 +59,6 @@ class TWIBus { */ const int timeout = 5; - /** - * @brief Target device address - * @description The target device address. Persists until changed. - * - */ - uint8_t addr = 0; - /** * @brief Number of bytes on buffer * @description Number of bytes in the buffer waiting to be flushed to the bus. @@ -76,10 +69,16 @@ class TWIBus { * @brief Internal buffer * @details A fixed buffer. TWI commands can be no longer than this. */ - char buffer[30]; + char buffer[32]; public: + /** + * @brief Target device address + * @description The target device address. Persists until changed. + */ + uint8_t addr = 0; + /** * @brief Class constructor * @details Initialize the TWI bus and clear the buffer