From dd3a06a95a73fd79da1fac16dffbaa51c80b1149 Mon Sep 17 00:00:00 2001 From: jbrazio Date: Sat, 26 Mar 2016 23:25:28 +0000 Subject: [PATCH] Implemented M155 and M156, a generic TWI/I2C interface for Marlin --- Marlin/Configuration_adv.h | 32 +++++ Marlin/Marlin_main.cpp | 71 ++++++++++ .../Felix/Configuration_adv.h | 32 +++++ .../Hephestos/Configuration_adv.h | 32 +++++ .../Hephestos_2/Configuration_adv.h | 32 +++++ .../K8200/Configuration_adv.h | 32 +++++ .../RigidBot/Configuration_adv.h | 32 +++++ .../SCARA/Configuration_adv.h | 32 +++++ .../TAZ4/Configuration_adv.h | 32 +++++ .../WITBOX/Configuration_adv.h | 32 +++++ .../delta/biv2.5/Configuration_adv.h | 32 +++++ .../delta/generic/Configuration_adv.h | 32 +++++ .../delta/kossel_mini/Configuration_adv.h | 32 +++++ .../delta/kossel_pro/Configuration_adv.h | 32 +++++ .../delta/kossel_xl/Configuration_adv.h | 32 +++++ .../makibox/Configuration_adv.h | 32 +++++ .../tvrrug/Round2/Configuration_adv.h | 32 +++++ Marlin/twibus.cpp | 104 +++++++++++++++ Marlin/twibus.h | 122 ++++++++++++++++++ 19 files changed, 809 insertions(+) create mode 100644 Marlin/twibus.cpp create mode 100644 Marlin/twibus.h diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 4dd7739d2f..3b26237386 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -653,6 +653,38 @@ const unsigned int dropsegments = 5; //everything with less than this number of #endif +/** + * TWI/I2C BUS + * + * This feature is an EXPERIMENTAL feature so it shall not be used on production + * machines. Enabling this will allow you to send and receive I2C data from slave + * devices on the bus. + * + * ; Example #1 + * ; This macro send the string "Marlin" to the slave device with address 0x63 + * ; It uses multiple M155 commands with one B arg + * M155 A63 ; Target slave address + * M155 B77 ; M + * M155 B97 ; a + * M155 B114 ; r + * M155 B108 ; l + * M155 B105 ; i + * M155 B110 ; n + * M155 S1 ; Send the current buffer + * + * ; Example #2 + * ; Request 6 bytes from slave device with address 0x63 + * M156 A63 B5 + * + * ; Example #3 + * ; Example serial output of a M156 request + * echo:i2c-reply: from:63 bytes:5 data:hello + */ + +// @section i2cbus + +//#define EXPERIMENTAL_I2CBUS + #include "Conditionals.h" #include "SanityCheck.h" diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index f67461baf2..f9bb9de309 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -77,6 +77,10 @@ #include "stepper_dac.h" #endif +#if ENABLED(EXPERIMENTAL_I2CBUS) + #include "twibus.h" +#endif + /** * Look here for descriptions of G-codes: * - http://linuxcnc.org/handbook/gcode/g-code.html @@ -248,6 +252,10 @@ CardReader card; #endif +#if ENABLED(EXPERIMENTAL_I2CBUS) + TWIBus i2c; +#endif + bool Running = true; uint8_t marlin_debug_flags = DEBUG_NONE; @@ -4771,6 +4779,57 @@ inline void gcode_M121() { enable_endstops_globally(false); } #endif // BLINKM +#if ENABLED(EXPERIMENTAL_I2CBUS) + + /** + * M155: Send data to a I2C slave device + * + * This is a PoC, the formating and arguments for the GCODE will + * change to be more compatible, the current proposal is: + * + * M155 A ; Sets the I2C slave address the data will be sent to + * + * M155 B + * M155 B + * M155 B + * + * M155 S1 ; Send the buffered data and reset the buffer + * M155 R1 ; Reset the buffer without sending data + * + */ + inline void gcode_M155() { + // Set the target address + if (code_seen('A')) + i2c.address((uint8_t) code_value_short()); + + // Add a new byte to the buffer + else if (code_seen('B')) + i2c.addbyte((int) code_value_short()); + + // Flush the buffer to the bus + else if (code_seen('S')) i2c.send(); + + // Reset and rewind the buffer + else if (code_seen('R')) i2c.reset(); + } + + /** + * M156: Request X bytes from I2C slave device + * + * Usage: M156 A B + */ + inline void gcode_M156() { + uint8_t addr = code_seen('A') ? code_value_short() : 0; + int bytes = code_seen('B') ? code_value_short() : 0; + + if (addr && bytes) { + i2c.address(addr); + i2c.reqbytes(bytes); + } + } + +#endif //EXPERIMENTAL_I2CBUS + /** * M200: Set filament diameter and set E axis units to cubic millimeters * @@ -6439,6 +6498,18 @@ void process_next_command() { #endif //BLINKM + #if ENABLED(EXPERIMENTAL_I2CBUS) + + case 155: + gcode_M155(); + break; + + case 156: + gcode_M156(); + break; + + #endif //EXPERIMENTAL_I2CBUS + case 200: // M200 D set filament diameter and set E axis units to cubic millimeters (use S0 to set back to millimeters). gcode_M200(); break; diff --git a/Marlin/example_configurations/Felix/Configuration_adv.h b/Marlin/example_configurations/Felix/Configuration_adv.h index d5b2942d64..e8e2c1876c 100644 --- a/Marlin/example_configurations/Felix/Configuration_adv.h +++ b/Marlin/example_configurations/Felix/Configuration_adv.h @@ -653,6 +653,38 @@ const unsigned int dropsegments = 5; //everything with less than this number of #endif +/** + * TWI/I2C BUS + * + * This feature is an EXPERIMENTAL feature so it shall not be used on production + * machines. Enabling this will allow you to send and receive I2C data from slave + * devices on the bus. + * + * ; Example #1 + * ; This macro send the string "Marlin" to the slave device with address 0x63 + * ; It uses multiple M155 commands with one B arg + * M155 A63 ; Target slave address + * M155 B77 ; M + * M155 B97 ; a + * M155 B114 ; r + * M155 B108 ; l + * M155 B105 ; i + * M155 B110 ; n + * M155 S1 ; Send the current buffer + * + * ; Example #2 + * ; Request 6 bytes from slave device with address 0x63 + * M156 A63 B5 + * + * ; Example #3 + * ; Example serial output of a M156 request + * echo:i2c-reply: from:63 bytes:5 data:hello + */ + +// @section i2cbus + +//#define EXPERIMENTAL_I2CBUS + #include "Conditionals.h" #include "SanityCheck.h" diff --git a/Marlin/example_configurations/Hephestos/Configuration_adv.h b/Marlin/example_configurations/Hephestos/Configuration_adv.h index b92a737983..ab8000a88b 100644 --- a/Marlin/example_configurations/Hephestos/Configuration_adv.h +++ b/Marlin/example_configurations/Hephestos/Configuration_adv.h @@ -653,6 +653,38 @@ const unsigned int dropsegments = 5; //everything with less than this number of #endif +/** + * TWI/I2C BUS + * + * This feature is an EXPERIMENTAL feature so it shall not be used on production + * machines. Enabling this will allow you to send and receive I2C data from slave + * devices on the bus. + * + * ; Example #1 + * ; This macro send the string "Marlin" to the slave device with address 0x63 + * ; It uses multiple M155 commands with one B arg + * M155 A63 ; Target slave address + * M155 B77 ; M + * M155 B97 ; a + * M155 B114 ; r + * M155 B108 ; l + * M155 B105 ; i + * M155 B110 ; n + * M155 S1 ; Send the current buffer + * + * ; Example #2 + * ; Request 6 bytes from slave device with address 0x63 + * M156 A63 B5 + * + * ; Example #3 + * ; Example serial output of a M156 request + * echo:i2c-reply: from:63 bytes:5 data:hello + */ + +// @section i2cbus + +//#define EXPERIMENTAL_I2CBUS + #include "Conditionals.h" #include "SanityCheck.h" diff --git a/Marlin/example_configurations/Hephestos_2/Configuration_adv.h b/Marlin/example_configurations/Hephestos_2/Configuration_adv.h index b5a451c53f..be87d38ff4 100644 --- a/Marlin/example_configurations/Hephestos_2/Configuration_adv.h +++ b/Marlin/example_configurations/Hephestos_2/Configuration_adv.h @@ -653,6 +653,38 @@ const unsigned int dropsegments = 5; //everything with less than this number of #endif +/** + * TWI/I2C BUS + * + * This feature is an EXPERIMENTAL feature so it shall not be used on production + * machines. Enabling this will allow you to send and receive I2C data from slave + * devices on the bus. + * + * ; Example #1 + * ; This macro send the string "Marlin" to the slave device with address 0x63 + * ; It uses multiple M155 commands with one B arg + * M155 A63 ; Target slave address + * M155 B77 ; M + * M155 B97 ; a + * M155 B114 ; r + * M155 B108 ; l + * M155 B105 ; i + * M155 B110 ; n + * M155 S1 ; Send the current buffer + * + * ; Example #2 + * ; Request 6 bytes from slave device with address 0x63 + * M156 A63 B5 + * + * ; Example #3 + * ; Example serial output of a M156 request + * echo:i2c-reply: from:63 bytes:5 data:hello + */ + +// @section i2cbus + +//#define EXPERIMENTAL_I2CBUS + #include "Conditionals.h" #include "SanityCheck.h" diff --git a/Marlin/example_configurations/K8200/Configuration_adv.h b/Marlin/example_configurations/K8200/Configuration_adv.h index 5c47bde71b..429a1ad7b5 100644 --- a/Marlin/example_configurations/K8200/Configuration_adv.h +++ b/Marlin/example_configurations/K8200/Configuration_adv.h @@ -659,6 +659,38 @@ const unsigned int dropsegments = 2; //everything with less than this number of #endif +/** + * TWI/I2C BUS + * + * This feature is an EXPERIMENTAL feature so it shall not be used on production + * machines. Enabling this will allow you to send and receive I2C data from slave + * devices on the bus. + * + * ; Example #1 + * ; This macro send the string "Marlin" to the slave device with address 0x63 + * ; It uses multiple M155 commands with one B arg + * M155 A63 ; Target slave address + * M155 B77 ; M + * M155 B97 ; a + * M155 B114 ; r + * M155 B108 ; l + * M155 B105 ; i + * M155 B110 ; n + * M155 S1 ; Send the current buffer + * + * ; Example #2 + * ; Request 6 bytes from slave device with address 0x63 + * M156 A63 B5 + * + * ; Example #3 + * ; Example serial output of a M156 request + * echo:i2c-reply: from:63 bytes:5 data:hello + */ + +// @section i2cbus + +//#define EXPERIMENTAL_I2CBUS + #include "Conditionals.h" #include "SanityCheck.h" diff --git a/Marlin/example_configurations/RigidBot/Configuration_adv.h b/Marlin/example_configurations/RigidBot/Configuration_adv.h index 17e19b0839..6985ddbe4f 100644 --- a/Marlin/example_configurations/RigidBot/Configuration_adv.h +++ b/Marlin/example_configurations/RigidBot/Configuration_adv.h @@ -653,6 +653,38 @@ const unsigned int dropsegments = 5; //everything with less than this number of #endif +/** + * TWI/I2C BUS + * + * This feature is an EXPERIMENTAL feature so it shall not be used on production + * machines. Enabling this will allow you to send and receive I2C data from slave + * devices on the bus. + * + * ; Example #1 + * ; This macro send the string "Marlin" to the slave device with address 0x63 + * ; It uses multiple M155 commands with one B arg + * M155 A63 ; Target slave address + * M155 B77 ; M + * M155 B97 ; a + * M155 B114 ; r + * M155 B108 ; l + * M155 B105 ; i + * M155 B110 ; n + * M155 S1 ; Send the current buffer + * + * ; Example #2 + * ; Request 6 bytes from slave device with address 0x63 + * M156 A63 B5 + * + * ; Example #3 + * ; Example serial output of a M156 request + * echo:i2c-reply: from:63 bytes:5 data:hello + */ + +// @section i2cbus + +//#define EXPERIMENTAL_I2CBUS + #include "Conditionals.h" #include "SanityCheck.h" diff --git a/Marlin/example_configurations/SCARA/Configuration_adv.h b/Marlin/example_configurations/SCARA/Configuration_adv.h index 1b09057ed8..7af0110991 100644 --- a/Marlin/example_configurations/SCARA/Configuration_adv.h +++ b/Marlin/example_configurations/SCARA/Configuration_adv.h @@ -653,6 +653,38 @@ const unsigned int dropsegments = 5; //everything with less than this number of #endif +/** + * TWI/I2C BUS + * + * This feature is an EXPERIMENTAL feature so it shall not be used on production + * machines. Enabling this will allow you to send and receive I2C data from slave + * devices on the bus. + * + * ; Example #1 + * ; This macro send the string "Marlin" to the slave device with address 0x63 + * ; It uses multiple M155 commands with one B arg + * M155 A63 ; Target slave address + * M155 B77 ; M + * M155 B97 ; a + * M155 B114 ; r + * M155 B108 ; l + * M155 B105 ; i + * M155 B110 ; n + * M155 S1 ; Send the current buffer + * + * ; Example #2 + * ; Request 6 bytes from slave device with address 0x63 + * M156 A63 B5 + * + * ; Example #3 + * ; Example serial output of a M156 request + * echo:i2c-reply: from:63 bytes:5 data:hello + */ + +// @section i2cbus + +//#define EXPERIMENTAL_I2CBUS + #include "Conditionals.h" #include "SanityCheck.h" diff --git a/Marlin/example_configurations/TAZ4/Configuration_adv.h b/Marlin/example_configurations/TAZ4/Configuration_adv.h index 62dde979c8..f96f20236b 100644 --- a/Marlin/example_configurations/TAZ4/Configuration_adv.h +++ b/Marlin/example_configurations/TAZ4/Configuration_adv.h @@ -661,6 +661,38 @@ const unsigned int dropsegments = 5; //everything with less than this number of #endif +/** + * TWI/I2C BUS + * + * This feature is an EXPERIMENTAL feature so it shall not be used on production + * machines. Enabling this will allow you to send and receive I2C data from slave + * devices on the bus. + * + * ; Example #1 + * ; This macro send the string "Marlin" to the slave device with address 0x63 + * ; It uses multiple M155 commands with one B arg + * M155 A63 ; Target slave address + * M155 B77 ; M + * M155 B97 ; a + * M155 B114 ; r + * M155 B108 ; l + * M155 B105 ; i + * M155 B110 ; n + * M155 S1 ; Send the current buffer + * + * ; Example #2 + * ; Request 6 bytes from slave device with address 0x63 + * M156 A63 B5 + * + * ; Example #3 + * ; Example serial output of a M156 request + * echo:i2c-reply: from:63 bytes:5 data:hello + */ + +// @section i2cbus + +//#define EXPERIMENTAL_I2CBUS + #include "Conditionals.h" #include "SanityCheck.h" diff --git a/Marlin/example_configurations/WITBOX/Configuration_adv.h b/Marlin/example_configurations/WITBOX/Configuration_adv.h index b92a737983..ab8000a88b 100644 --- a/Marlin/example_configurations/WITBOX/Configuration_adv.h +++ b/Marlin/example_configurations/WITBOX/Configuration_adv.h @@ -653,6 +653,38 @@ const unsigned int dropsegments = 5; //everything with less than this number of #endif +/** + * TWI/I2C BUS + * + * This feature is an EXPERIMENTAL feature so it shall not be used on production + * machines. Enabling this will allow you to send and receive I2C data from slave + * devices on the bus. + * + * ; Example #1 + * ; This macro send the string "Marlin" to the slave device with address 0x63 + * ; It uses multiple M155 commands with one B arg + * M155 A63 ; Target slave address + * M155 B77 ; M + * M155 B97 ; a + * M155 B114 ; r + * M155 B108 ; l + * M155 B105 ; i + * M155 B110 ; n + * M155 S1 ; Send the current buffer + * + * ; Example #2 + * ; Request 6 bytes from slave device with address 0x63 + * M156 A63 B5 + * + * ; Example #3 + * ; Example serial output of a M156 request + * echo:i2c-reply: from:63 bytes:5 data:hello + */ + +// @section i2cbus + +//#define EXPERIMENTAL_I2CBUS + #include "Conditionals.h" #include "SanityCheck.h" diff --git a/Marlin/example_configurations/delta/biv2.5/Configuration_adv.h b/Marlin/example_configurations/delta/biv2.5/Configuration_adv.h index 491cf38f33..da192eb81a 100644 --- a/Marlin/example_configurations/delta/biv2.5/Configuration_adv.h +++ b/Marlin/example_configurations/delta/biv2.5/Configuration_adv.h @@ -655,6 +655,38 @@ const unsigned int dropsegments = 5; //everything with less than this number of #endif +/** + * TWI/I2C BUS + * + * This feature is an EXPERIMENTAL feature so it shall not be used on production + * machines. Enabling this will allow you to send and receive I2C data from slave + * devices on the bus. + * + * ; Example #1 + * ; This macro send the string "Marlin" to the slave device with address 0x63 + * ; It uses multiple M155 commands with one B arg + * M155 A63 ; Target slave address + * M155 B77 ; M + * M155 B97 ; a + * M155 B114 ; r + * M155 B108 ; l + * M155 B105 ; i + * M155 B110 ; n + * M155 S1 ; Send the current buffer + * + * ; Example #2 + * ; Request 6 bytes from slave device with address 0x63 + * M156 A63 B5 + * + * ; Example #3 + * ; Example serial output of a M156 request + * echo:i2c-reply: from:63 bytes:5 data:hello + */ + +// @section i2cbus + +//#define EXPERIMENTAL_I2CBUS + #include "Conditionals.h" #include "SanityCheck.h" diff --git a/Marlin/example_configurations/delta/generic/Configuration_adv.h b/Marlin/example_configurations/delta/generic/Configuration_adv.h index 414d4de32d..b2bf328571 100644 --- a/Marlin/example_configurations/delta/generic/Configuration_adv.h +++ b/Marlin/example_configurations/delta/generic/Configuration_adv.h @@ -655,6 +655,38 @@ const unsigned int dropsegments = 5; //everything with less than this number of #endif +/** + * TWI/I2C BUS + * + * This feature is an EXPERIMENTAL feature so it shall not be used on production + * machines. Enabling this will allow you to send and receive I2C data from slave + * devices on the bus. + * + * ; Example #1 + * ; This macro send the string "Marlin" to the slave device with address 0x63 + * ; It uses multiple M155 commands with one B arg + * M155 A63 ; Target slave address + * M155 B77 ; M + * M155 B97 ; a + * M155 B114 ; r + * M155 B108 ; l + * M155 B105 ; i + * M155 B110 ; n + * M155 S1 ; Send the current buffer + * + * ; Example #2 + * ; Request 6 bytes from slave device with address 0x63 + * M156 A63 B5 + * + * ; Example #3 + * ; Example serial output of a M156 request + * echo:i2c-reply: from:63 bytes:5 data:hello + */ + +// @section i2cbus + +//#define EXPERIMENTAL_I2CBUS + #include "Conditionals.h" #include "SanityCheck.h" diff --git a/Marlin/example_configurations/delta/kossel_mini/Configuration_adv.h b/Marlin/example_configurations/delta/kossel_mini/Configuration_adv.h index a9de9f43aa..fa0da7cdd3 100644 --- a/Marlin/example_configurations/delta/kossel_mini/Configuration_adv.h +++ b/Marlin/example_configurations/delta/kossel_mini/Configuration_adv.h @@ -654,6 +654,38 @@ const unsigned int dropsegments = 5; //everything with less than this number of #endif +/** + * TWI/I2C BUS + * + * This feature is an EXPERIMENTAL feature so it shall not be used on production + * machines. Enabling this will allow you to send and receive I2C data from slave + * devices on the bus. + * + * ; Example #1 + * ; This macro send the string "Marlin" to the slave device with address 0x63 + * ; It uses multiple M155 commands with one B arg + * M155 A63 ; Target slave address + * M155 B77 ; M + * M155 B97 ; a + * M155 B114 ; r + * M155 B108 ; l + * M155 B105 ; i + * M155 B110 ; n + * M155 S1 ; Send the current buffer + * + * ; Example #2 + * ; Request 6 bytes from slave device with address 0x63 + * M156 A63 B5 + * + * ; Example #3 + * ; Example serial output of a M156 request + * echo:i2c-reply: from:63 bytes:5 data:hello + */ + +// @section i2cbus + +//#define EXPERIMENTAL_I2CBUS + #include "Conditionals.h" #include "SanityCheck.h" diff --git a/Marlin/example_configurations/delta/kossel_pro/Configuration_adv.h b/Marlin/example_configurations/delta/kossel_pro/Configuration_adv.h index 29d9607ac1..6ace77f421 100644 --- a/Marlin/example_configurations/delta/kossel_pro/Configuration_adv.h +++ b/Marlin/example_configurations/delta/kossel_pro/Configuration_adv.h @@ -659,6 +659,38 @@ const unsigned int dropsegments = 5; //everything with less than this number of #endif +/** + * TWI/I2C BUS + * + * This feature is an EXPERIMENTAL feature so it shall not be used on production + * machines. Enabling this will allow you to send and receive I2C data from slave + * devices on the bus. + * + * ; Example #1 + * ; This macro send the string "Marlin" to the slave device with address 0x63 + * ; It uses multiple M155 commands with one B arg + * M155 A63 ; Target slave address + * M155 B77 ; M + * M155 B97 ; a + * M155 B114 ; r + * M155 B108 ; l + * M155 B105 ; i + * M155 B110 ; n + * M155 S1 ; Send the current buffer + * + * ; Example #2 + * ; Request 6 bytes from slave device with address 0x63 + * M156 A63 B5 + * + * ; Example #3 + * ; Example serial output of a M156 request + * echo:i2c-reply: from:63 bytes:5 data:hello + */ + +// @section i2cbus + +//#define EXPERIMENTAL_I2CBUS + #include "Conditionals.h" #include "SanityCheck.h" diff --git a/Marlin/example_configurations/delta/kossel_xl/Configuration_adv.h b/Marlin/example_configurations/delta/kossel_xl/Configuration_adv.h index 23829cbbc9..f42f877014 100644 --- a/Marlin/example_configurations/delta/kossel_xl/Configuration_adv.h +++ b/Marlin/example_configurations/delta/kossel_xl/Configuration_adv.h @@ -653,6 +653,38 @@ const unsigned int dropsegments = 5; //everything with less than this number of #endif +/** + * TWI/I2C BUS + * + * This feature is an EXPERIMENTAL feature so it shall not be used on production + * machines. Enabling this will allow you to send and receive I2C data from slave + * devices on the bus. + * + * ; Example #1 + * ; This macro send the string "Marlin" to the slave device with address 0x63 + * ; It uses multiple M155 commands with one B arg + * M155 A63 ; Target slave address + * M155 B77 ; M + * M155 B97 ; a + * M155 B114 ; r + * M155 B108 ; l + * M155 B105 ; i + * M155 B110 ; n + * M155 S1 ; Send the current buffer + * + * ; Example #2 + * ; Request 6 bytes from slave device with address 0x63 + * M156 A63 B5 + * + * ; Example #3 + * ; Example serial output of a M156 request + * echo:i2c-reply: from:63 bytes:5 data:hello + */ + +// @section i2cbus + +//#define EXPERIMENTAL_I2CBUS + #include "Conditionals.h" #include "SanityCheck.h" diff --git a/Marlin/example_configurations/makibox/Configuration_adv.h b/Marlin/example_configurations/makibox/Configuration_adv.h index 301f362b67..16f00bbf9b 100644 --- a/Marlin/example_configurations/makibox/Configuration_adv.h +++ b/Marlin/example_configurations/makibox/Configuration_adv.h @@ -653,6 +653,38 @@ const unsigned int dropsegments = 5; //everything with less than this number of #endif +/** + * TWI/I2C BUS + * + * This feature is an EXPERIMENTAL feature so it shall not be used on production + * machines. Enabling this will allow you to send and receive I2C data from slave + * devices on the bus. + * + * ; Example #1 + * ; This macro send the string "Marlin" to the slave device with address 0x63 + * ; It uses multiple M155 commands with one B arg + * M155 A63 ; Target slave address + * M155 B77 ; M + * M155 B97 ; a + * M155 B114 ; r + * M155 B108 ; l + * M155 B105 ; i + * M155 B110 ; n + * M155 S1 ; Send the current buffer + * + * ; Example #2 + * ; Request 6 bytes from slave device with address 0x63 + * M156 A63 B5 + * + * ; Example #3 + * ; Example serial output of a M156 request + * echo:i2c-reply: from:63 bytes:5 data:hello + */ + +// @section i2cbus + +//#define EXPERIMENTAL_I2CBUS + #include "Conditionals.h" #include "SanityCheck.h" diff --git a/Marlin/example_configurations/tvrrug/Round2/Configuration_adv.h b/Marlin/example_configurations/tvrrug/Round2/Configuration_adv.h index 0c62e79118..c8ddbd603c 100644 --- a/Marlin/example_configurations/tvrrug/Round2/Configuration_adv.h +++ b/Marlin/example_configurations/tvrrug/Round2/Configuration_adv.h @@ -653,6 +653,38 @@ const unsigned int dropsegments = 5; //everything with less than this number of #endif +/** + * TWI/I2C BUS + * + * This feature is an EXPERIMENTAL feature so it shall not be used on production + * machines. Enabling this will allow you to send and receive I2C data from slave + * devices on the bus. + * + * ; Example #1 + * ; This macro send the string "Marlin" to the slave device with address 0x63 + * ; It uses multiple M155 commands with one B arg + * M155 A63 ; Target slave address + * M155 B77 ; M + * M155 B97 ; a + * M155 B114 ; r + * M155 B108 ; l + * M155 B105 ; i + * M155 B110 ; n + * M155 S1 ; Send the current buffer + * + * ; Example #2 + * ; Request 6 bytes from slave device with address 0x63 + * M156 A63 B5 + * + * ; Example #3 + * ; Example serial output of a M156 request + * echo:i2c-reply: from:63 bytes:5 data:hello + */ + +// @section i2cbus + +//#define EXPERIMENTAL_I2CBUS + #include "Conditionals.h" #include "SanityCheck.h" diff --git a/Marlin/twibus.cpp b/Marlin/twibus.cpp new file mode 100644 index 0000000000..3131060848 --- /dev/null +++ b/Marlin/twibus.cpp @@ -0,0 +1,104 @@ +/* + * Marlin 3D Printer Firmware + * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "Marlin.h" + +#if ENABLED(EXPERIMENTAL_I2CBUS) + +#include "twibus.h" + +#include + +TWIBus::twibus() { + Wire.begin(); // We use no address so we will join the BUS as the master + this->reset(); +} + +void TWIBus::reset() { + this->addr = 0; + this->buffer_s = 0; + this->buffer[0] = 0x00; +} + +void TWIBus::address(uint8_t addr) { + this->addr = addr; + + if (DEBUGGING(INFO)) { + SERIAL_ECHOPAIR("TWIBus::sendto: ", this->addr); + SERIAL_EOL; + } +} + +void TWIBus::addbyte(char c) { + if (buffer_s >= sizeof(this->buffer)) return; + this->buffer[this->buffer_s++] = c; + + if (DEBUGGING(INFO)) { + SERIAL_ECHOPAIR("TWIBus::addbyte: ", this->buffer[this->buffer_s -1]); + SERIAL_EOL; + } +} + +void TWIBus::send() { + if (!this->addr) return; + if (DEBUGGING(INFO)) SERIAL_ECHOLNPGM("TWIBus::send()"); + + Wire.beginTransmission(this->addr); + Wire.write(this->buffer, this->buffer_s); + Wire.endTransmission(); + + // Reset the buffer after sending the data + this->reset(); +} + +void TWIBus::reqbytes(uint8_t bytes) { + if (!this->addr) return; + if (DEBUGGING(INFO)) { + SERIAL_ECHOPAIR("TWIBus::reqbytes(): ", bytes); + SERIAL_EOL; + } + + millis_t t = millis(); + Wire.requestFrom(this->addr, bytes); + + // requestFrom() is a blocking function + while (Wire.available() < bytes) { + if (millis() - t >= this->timeout) break; + else continue; + } + + SERIAL_ECHO_START; + SERIAL_ECHOPAIR("i2c-reply: from:", this->addr); + SERIAL_ECHOPAIR(" bytes:", Wire.available()); + 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()); + SERIAL_EOL; + + // Reset the buffer after sending the data + this->reset(); +} + +#endif //EXPERIMENTAL_I2CBUS diff --git a/Marlin/twibus.h b/Marlin/twibus.h new file mode 100644 index 0000000000..5ab725777b --- /dev/null +++ b/Marlin/twibus.h @@ -0,0 +1,122 @@ +/* + * Marlin 3D Printer Firmware + * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef TWIBUS_H +#define TWIBUS_H + +/** + * TWIBUS class + * + * This class implements a wrapper around the two wire (I2C) bus, it allows + * Marlin to send and request data from any slave device on the bus. This is + * an experimental feature and it's inner workings as well as public facing + * interface are prune to change in the future. + * + * The two main consumers of this class are M155 and M156, where M155 allows + * Marlin to send a I2C packet to a device (please be aware that no repeated + * starts are possible), this can be done in caching method by calling multiple + * times M155 B or a one liner M155, have a look at + * the gcode_M155() function for more information. M156 allows Marlin to + * request data from a device, the received data is then relayed into the serial + * line for host interpretation. + * + */ +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. + */ + 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. + */ + 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. + */ + uint8_t buffer_s = 0; + + /** + * @brief Internal buffer + * @details This is a fixed buffer, TWI command cannot be longer than this + */ + char buffer[30]; + + + public: + /** + * @brief Class constructor + * @details Initialized the TWI bus and clears the buffer + */ + TWIBus(); + + /** + * @brief Reset the buffer + * @details Brings the internal 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. + */ + 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. + * + * @param c a data byte + */ + void addbyte(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. + * + * @param addr 7-bit integer address + */ + void address(uint8_t addr); + + /** + * @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. + * + * @param bytes the number of bytes to request + */ + void reqbytes(uint8_t bytes); +}; + +#endif //TWIBUS_H