From e0f8a879fee88fb88b989d501a86607f16499c67 Mon Sep 17 00:00:00 2001 From: Gustavo Casanova Date: Fri, 8 May 2020 07:33:32 -0300 Subject: [PATCH] Arrange folders and release v1.4 --- .gitignore | 2 +- LICENSE | 2 +- README.md | 49 +++---- apps/README.md | 8 +- nb-libs/README.md | 12 +- nb-libs/cmd/library.json | 11 ++ nb-libs/twim/NbMicro/NbMicro.cpp | 132 ++---------------- nb-libs/twim/NbMicro/NbMicro.h | 35 +---- nb-libs/twim/NbMicro/libconfig.h | 36 ++--- nb-libs/twim/NbMicro/library.json | 20 +++ nb-libs/twim/TimonelTwiM/TimonelTwiM.cpp | 42 +++--- nb-libs/twim/TimonelTwiM/TimonelTwiM.h | 8 +- nb-libs/twim/TimonelTwiM/libconfig.h | 90 ++++++------ nb-libs/twim/TimonelTwiM/library.json | 15 ++ nb-libs/twim/TwiBus/TwiBus.cpp | 122 ++++++++++++++++ nb-libs/twim/TwiBus/TwiBus.h | 42 ++++++ nb-libs/twim/TwiBus/libconfig.h | 29 ++++ nb-libs/twim/TwiBus/library.json | 15 ++ nb-libs/twis/interrupt-based/nb-usitwisl.c | 2 +- nb-libs/twis/interrupt-based/nb-usitwisl.h | 2 +- nb-libs/twis/interrupt-free/nb-usitwisl-if.c | 2 +- nb-libs/twis/interrupt-free/nb-usitwisl-if.h | 2 +- timonel-bootloader/README.md | 85 +++++------ timonel-bootloader/timonel.c | 2 +- timonel-bootloader/timonel.h | 2 +- timonel-hexparser/README.md | 7 +- timonel-hexparser/tml-hexparser.c | 6 +- timonel-twim-ms/README.md | 9 +- timonel-twim-ms/get-github-lib.py | 25 ++++ timonel-twim-ms/platformio.ini | 13 +- .../{project_name.py => set-bin-name.py} | 0 .../src/{main.cpp => timonel-twim-ms.cpp} | 14 +- timonel-twim-ss/.gitignore | 1 + timonel-twim-ss/README.md | 12 +- timonel-twim-ss/get-github-lib.py | 25 ++++ timonel-twim-ss/platformio.ini | 17 ++- .../{project_name.py => set-bin-name.py} | 0 .../src/{main.cpp => timonel-twim-ss.cpp} | 51 ++++--- timonel-updater/README.md | 10 +- tools/README.md | 4 +- 40 files changed, 553 insertions(+), 408 deletions(-) create mode 100644 nb-libs/cmd/library.json create mode 100644 nb-libs/twim/NbMicro/library.json create mode 100644 nb-libs/twim/TimonelTwiM/library.json create mode 100644 nb-libs/twim/TwiBus/TwiBus.cpp create mode 100644 nb-libs/twim/TwiBus/TwiBus.h create mode 100644 nb-libs/twim/TwiBus/libconfig.h create mode 100644 nb-libs/twim/TwiBus/library.json create mode 100644 timonel-twim-ms/get-github-lib.py rename timonel-twim-ms/{project_name.py => set-bin-name.py} (100%) rename timonel-twim-ms/src/{main.cpp => timonel-twim-ms.cpp} (97%) create mode 100644 timonel-twim-ss/get-github-lib.py rename timonel-twim-ss/{project_name.py => set-bin-name.py} (100%) rename timonel-twim-ss/src/{main.cpp => timonel-twim-ss.cpp} (95%) diff --git a/.gitignore b/.gitignore index 8796b487..b30f2424 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -# v1.3 +# v1.4 # Prerequisites *.d diff --git a/LICENSE b/LICENSE index f8addfa6..c98a9cec 100644 --- a/LICENSE +++ b/LICENSE @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 53692d94..992d074c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -Timonel - ATtiny85 I2C Bootloader -================================= +![timonel-bootloader](https://github.com/casanovg/timonel/blob/media/timonel-github-wh.jpg) +## ATtiny85 I2C Bootloader Timonel is an I2C bootloader for ATtiny85/45/25 microcontrollers. The aim is to enable AVR firmware updates in scenarios where there is a more powerful MCU (ESP8266, Arduino, RPi, BeagleBone, etc.) acting as I2C master and one or more Tiny85 as I2C slave performing peripheral functions. @@ -10,46 +10,47 @@ Some possible cases: * etc ... In these situations, it's handy to be able to update the AVRs firmware straight from the I2C master. But, so far (mid-2018), I haven't found an I2C bootloader that fits directly the TinyX5 family, addressing its several limitations: + * It doesn't have dedicated hardware to handle I2C, only the USI (Universal Serial Interface). * It lacks a protected memory area for the bootloader. * It is not possible to redirect the interruption vectors to the bootloader. That's why I started writing this one. -Usage: ------- +## Usage: + * [Install](/timonel-bootloader/README.md#Installation) "timonel.hex" on a Tiny85 (bare chips or Digisparks). -* Compile your [application program](/apps) and convert the generated ".hex" into an array of bytes to be included in "timonel-twim-ss" or "timonel-twim-ms" (e.g. uint8_t payload[size] = { 0xaa, 0xbb, ...}; ). Use ["tml-hexparser"](/timonel-hexparser) for helping to create the array (payload). -* Use [VS Code](http://code.visualstudio.com) + [PlatformIO](http://platformio.org) to compile and install "timonel-twim-ss.bin" or "timonel-twim-ms.bin" (containing the payload) in an arduino-compatible MCU. It has been tested with ESP8266 ESP01 and NodeMCU. __Note:__ the ".bin" file provided contains a small payload demo that sends an SOS by blinking PB1. -* Connect both chips by __I2C__ (SDA, SCL and ground). +* Compile your [application program](/apps) and convert the generated ".hex" into an array of bytes to be included in "timonel-twim-ss" or "timonel-twim-ms" (e.g. uint8\_t payload[size] = { 0xaa, 0xbb, ...}; ). Use "[tml-hexparser](/timonel-hexparser)" for helping to create the array (payload). +* Use [VS Code](http://code.visualstudio.com) + [PlatformIO](http://platformio.org) to compile and install "[timonel-twim-ss.bin](/timonel-twim-ss)" or "[timonel-twim-ms.bin](/timonel-twim-ms)" (containing the payload) in an arduino-compatible MCU. It has been tested with ESP8266 ESP01 and NodeMCU. **Note:** the ".bin" file provided contains a small payload demo that sends an SOS by blinking PB1. +* Connect both chips by **I2C** (SDA, SCL and ground). * Open an asynchronous terminal (e.g. [MobaXterm](http://mobaxterm.mobatek.net)) connected to the serial port of the I2C master (9600 N 8 1). * Run the commands shown on screen for erasing and flashing new firmware on the Tiny85. -* It is also possible to update the bootloader itself by using ["timonel-updater"](/timonel-updater) (based on the micronucleus upgrade program). +* It is also possible to update the bootloader itself by using "[timonel-updater](/timonel-updater)" (based on the micronucleus upgrade program). + +## Contributing: -Contributing: -------------- Contributions are welcome! If you want to add a new feature, please feel free to create a pull request or open an issue :o) -Version History: ----------------- -__v1.4__ - 2019-10-29: Functional Release: Significant memory saving by inlining the TWI driver functions, now the smaller version "tml-t85-small" occupies ~1Kb, leaving 7Kb available for user applications. Transmission speed improvement by adjusting the code to transmit and receive 32-byte packets (half memory-page on an ATtiny85). User-application autorun is now optional. Internal clock configuration support improved. +## Version History: + +**v1.4** \- 2019\-10\-29: Functional Release: Significant memory saving by inlining the TWI driver functions\, now the smaller version "tml\-t85\-small" occupies less than 1 kB\, leaving 7 kB available for user applications\. Speed improvement through a code tuning to transmit 32\-byte packets \(half a page of memory in a Tiny85\)\. User\-application "**autorun**" is now optional. Internal clock configuration support improved. [Interactive master](/timonel-twim-ss) test program improved with streamlined libs (see it [working](http://youtu.be/-7GOMToGvzI)). [Multi-slave master](/timonel-twim-ms) test program added (see it [working](http://youtu.be/PM9X1thrdOY)). + +**v1.3** \- 2019\-06\-06: Functional Release: Bootloader inline functions \(smaller code\) and low fuse auto clock tweaking\. Support for 1\, 2\, 8 and 16 MHz clock speed in user\-application mode\. TWI master UploadApplication refactoring\, now supports both types of page address calculation and both modes of **APP\_USE\_TPL\_PG**. Several bug fixes. -__v1.3__ - 2019-06-06: Functional Release: Bootloader inline functions (smaller code) and low fuse auto clock tweaking. TWI master UploadApplication refactoring, now supports both types of page address calculation and both modes of APP_USE_TPL_PG. Several bug fixes. +**v1.2** \- 2019\-05\-15: Functional Release: "Good\-neighbor" behavior fixes data dump operation interferences among Timonel devices in multi\-device bus setups\. The TWI master functionality has been packed in a couple of Arduino libraries to ease the handling of the several configuration options\. Timonel\-master\-ss firmware shows its usage\. The TWI master code was moved to PlatformIO\. -__v1.2__ - 2019-05-15: Functional Release: "Good-neighbor" behavior fixes data dump operation interferences among Timonel devices in multi-device bus setups. The TWI master functionality has been packed in a couple of Arduino libraries to ease the handling of the several configuration options. Timonel-master-ss firmware shows its usage. The TWI master code was moved to PlatformIO. +**v1.1** \- 2018\-10\-29: Functional Release: Optional ReadFlash command added\. Minor tweaks for running Timonel @ 8 MHz\. -__v1.1__ - 2018-10-29: Functional Release: Optional ReadFlash command added. Minor tweaks for running Timonel @ 8 MHz. +**v1.0** \- 2018\-10\-05: Functional Release: Optional features implemented\. -__v1.0__ - 2018-10-05: Functional Release: Optional features implemented. See it [working](https://youtu.be/-7GOMToGvzI). +**v0.9** \- 2018\-09\-29: Functional pre\-release: Temporary page buffer and other minor issues solved\. -__v0.9__ - 2018-09-29: Functional pre-release: Temporary page buffer and other minor issues solved. +**v0.8** \- 2018\-09\-16: First functional pre\-release\. -__v0.8__ - 2018-09-16: First functional pre-release. +**v0.7** \- 2018\-09\-07: Non\-functional\. -__v0.7__ - 2018-09-07: Non-functional. +**v0.4** \- 2018\-08\-10: Non\-functional\. -__v0.4__ - 2018-08-10: Non-functional. +## Credits: -Credits: --------- -I would like to thank the guys @ [AVRFreaks.net](http://www.avrfreaks.net), specially joeymorin and clawson) for sharing their vast knowledge and technical advice in general. Many thanks also to Donald Papp @ [Hackaday](http://hackaday.com) for [posting about this](https://hackaday.com/2018/10/20/i2c-bootloader-for-attiny85-lets-other-micros-push-firmware-updates). +I would like to thank the guys @ [AVRFreaks.net](http://www.avrfreaks.net), specially joeymorin and clawson) for sharing their vast knowledge and technical advice in general. Many thanks also to Donald Papp @ Hackaday for [posting about this](https://hackaday.com/2018/10/20/i2c-bootloader-for-attiny85-lets-other-micros-push-firmware-updates). diff --git a/apps/README.md b/apps/README.md index a58639ec..62a5084b 100644 --- a/apps/README.md +++ b/apps/README.md @@ -1,11 +1,9 @@ -# Test Apps v1.4 # +# Test Apps v1.4 This folder contains simple apps that can be used to test the bootloader functionality. -Choose any of then and compile it. The resulting ".hex" file has to be converted into a byte-array by using "timonel-hexparser". After that, the "payload.h" file obtained has to be included in the "/data/payloads" folder of "timonel-twim-ss" or "timonel-twim-ss" to be able to flash it into the T85. +Choose any of then and compile it. The resulting ".hex" file has to be converted into a byte-array by using "[timonel-hexparser](/timonel-hexparser)". After that, the "payload.h" file obtained has to be included in the "/data/payloads" folder of "[timonel-twim-ss](/timonel-twim-ss/data/payloads)" or "[timonel-twim-ms](/timonel-twim-ms/data/payloads)" to be able to flash it into the T85. * avr-blink-twis: Simple led blink demo with I2C controllable through a serial console. - * avr-native-blink: Simple AVR blink. - -* bare-t85-blink-io: Simple blink compiled with platformio. +* bare-t85-blink-io: Simple blink compiled with platformio. \ No newline at end of file diff --git a/nb-libs/README.md b/nb-libs/README.md index 693c6ee7..53b0af70 100644 --- a/nb-libs/README.md +++ b/nb-libs/README.md @@ -1,4 +1,4 @@ -# NB Libraries v1.4 # +# NB Libraries v0.9 # ## cmd folder: ## It contains the definition of the NB command set, common for the slave and master TWI (I2C) devices. Note that any change in the "nb-twi-cmd.h" file implies the need to recompile both firmware. If only one of the parties is compiled with a new revision, the communication will surely fail. This is especially important when sending a bootloader update to a slave device. @@ -18,13 +18,15 @@ The correct sequence for those cases is: If all went well, now both TWI devices share the new command set, the communication is reestablished. ## twim folder: ## -It has two Arduino-compatible TWI (I2C) master libraries: "NbMicro" and "TimonelTWIM". +It has three Arduino-compatible TWI (I2C) master libraries: "NbMicro", "TimonelTWIM" and "TwiBus". -The NbMicro library handles base communication with slave devices that implement the NB command set over TWI (I2C). The NbMicro class should be inherited by any higher level application (as the Timonel bootloader TWI master side app). +The NbMicro library handles TWI (I2C) communications with slave microcontrollers that implement the NB command set. The NbMicro class should be inherited by any high-level application (as the Timonel bootloader TWI master side app) that needs to build over the NB command set. -The TimonelTWIM library inherits from NbMicro and implements functions to control a TWI slave device that runs Timonel bootloader. +The TimonelTWIM library inherits from NbMicro and implements functions to control a TWI slave device that runs the Timonel bootloader. -Both libraries consist of a C++ source, a header file and a configuration file that allow some degree of customization. Mainly the TimonelTWIM library, to match enabled features in the bootloader. +The TwiBus class has methods to scan the bus in search of connected devices addresses and data. + +The libraries consist of a C++ source, a header file and a configuration file that allow some degree of customization. Mainly the TimonelTWIM library, to match enabled features in the bootloader. ## twis folder: ## TWI slave driver libraries: "nb-usitwisl" is a USI-based I2C driver for AVR devices which uses hardware interrupts for better precision working. It derives from Atmel AVR312 application note. diff --git a/nb-libs/cmd/library.json b/nb-libs/cmd/library.json new file mode 100644 index 00000000..3af5f44b --- /dev/null +++ b/nb-libs/cmd/library.json @@ -0,0 +1,11 @@ +{ + "name": "nb-twi-cmd", + "keywords": "nb-twi-cmd, i2c, twi, communications, arduino", + "description": "NB TWI command set. Defines the comm protocol over TWI (I2C).", + "repository": { + "type": "git", + "url": "https://github.com/casanovg/timonel.git" + }, + "include": "nb-libs/cmd", + "version": "0.5.0" +} \ No newline at end of file diff --git a/nb-libs/twim/NbMicro/NbMicro.cpp b/nb-libs/twim/NbMicro/NbMicro.cpp index 665277c4..568949f8 100644 --- a/nb-libs/twim/NbMicro/NbMicro.cpp +++ b/nb-libs/twim/NbMicro/NbMicro.cpp @@ -4,19 +4,15 @@ * ........................................... * File: NbMicro.cpp (Library) * ........................................... - * Version: 1.4 / 2019-08-09 + * Version: 0.9.0 / 2020-04-29 * gustavo.casanova@nicebots.com * ........................................... * This TWI (I2C) master library handles the communication protocol * with slave devices that implement the NB command set over a TWI - * bus. In addition, the TwiBus class has methods to scan the bus in - * search of the existing slave devices addresses. For single-slave - * setups or those where all addresses are known in advance, this - * last one could be dropped to save memory. + * bus. */ #include "NbMicro.h" -#include "TimonelTwiM.h" ///////////////////////////////////////////////////////////////////////////// //////////// NBMICRO CLASS //////////// @@ -123,8 +119,10 @@ byte NbMicro::TwiCmdXmit(byte twi_cmd_arr[], byte cmd_size, byte twi_reply, byte } // TWI command reply (one byte expected) if (reply_size == 0) { - Wire.requestFrom(addr_, ++reply_size, STOP_ON_REQ); /* True: releases the bus with a stop after a master request. */ - byte reply = Wire.read(); /* False: sends a restart, not releasing the bus. */ + reply_size++; + //Wire.requestFrom(addr_, ++reply_size, STOP_ON_REQ); /* True: releases the bus with a stop after a master request. */ + Wire.requestFrom(addr_, ++reply_size); /* True: releases the bus with a stop after a master request. */ + byte reply = Wire.read(); /* False: sends a restart, not releasing the bus. */ if (reply == twi_reply) { #if ((defined DEBUG_LEVEL) && (DEBUG_LEVEL >= 2)) USE_SERIAL.printf_P("[%s] > Command 0x%02X parsed OK <<< 0x%02X (single byte reply)\n\r", __func__, twi_cmd_arr[0], reply); @@ -139,8 +137,9 @@ byte NbMicro::TwiCmdXmit(byte twi_cmd_arr[], byte cmd_size, byte twi_reply, byte } // TWI command reply (multiple bytes expected) else { - byte reply_length = Wire.requestFrom(addr_, reply_size, STOP_ON_REQ); /* True: releases the bus with a stop after a master request. */ - for (int i = 0; i < reply_size; i++) { /* False: sends a restart, not releasing the bus. */ + //byte reply_length = Wire.requestFrom(addr_, reply_size, STOP_ON_REQ); /* True: releases the bus with a stop after a master request. */ + byte reply_length = Wire.requestFrom(addr_, reply_size); /* True: releases the bus with a stop after a master request. */ + for (int i = 0; i < reply_size; i++) { /* False: sends a restart, not releasing the bus. */ twi_reply_arr[i] = Wire.read(); } if ((twi_reply_arr[0] == twi_reply) && (reply_length == reply_size)) { @@ -176,116 +175,3 @@ byte NbMicro::InitMicro(void) { #endif /* DEBUG_LEVEL */ return (TwiCmdXmit(INITSOFT, ACKINITS)); } - -#if ((defined MULTI_DEVICE) && (MULTI_DEVICE == true)) -#pragma GCC warning "TwiBus device discovery functions code included in TWI master!" -///////////////////////////////////////////////////////////////////////////// -//////////// TWIBUS CLASS //////////// -///////////////////////////////////////////////////////////////////////////// - -// Class constructor -TwiBus::TwiBus(byte sda, byte scl) : sda_(sda), scl_(scl) { - if (!((sda == 0) && (scl == 0))) { -#if ((defined DEBUG_LEVEL) && (DEBUG_LEVEL >= 1)) - USE_SERIAL.printf_P("[%s] Creating a new I2C connection\n\r", __func__); -#endif /* DEBUG_LEVEL */ - Wire.begin(sda, scl); /* Init I2C sda:GPIO0, scl:GPIO2 (ESP-01) / sda:D3, scl:D4 (NodeMCU) */ - reusing_twi_connection_ = false; - } else { -#if ((defined DEBUG_LEVEL) && (DEBUG_LEVEL >= 1)) - USE_SERIAL.printf_P("[%s] Reusing I2C connection\n\r", __func__); -#endif /* DEBUG_LEVEL */ - reusing_twi_connection_ = true; - } -} - -// Class destructor -TwiBus::~TwiBus() { - // Destructor -} - -/* _________________________ - | | - | ScanBus A | - |_________________________| -*/ -// ScanBus (Overload A: Return the address and mode of the first TWI device found on the bus) -byte TwiBus::ScanBus(bool *p_app_mode) { - // Address 08 to 35: Timonel bootloader (app mode = false) - // Address 36 to 63: Application firmware (app mode = true) -#if ((defined DEBUG_LEVEL) && (DEBUG_LEVEL >= 1)) - USE_SERIAL.printf_P("\n\r[%s] Scanning TWI bus, looking for the first device (lowest address) ...\n\r", __func__); -#endif /* DEBUG_LEVEL */ - byte twi_addr = LOW_TWI_ADDR; - while (twi_addr < HIG_TWI_ADDR) { - Wire.beginTransmission(twi_addr); - if (Wire.endTransmission() == 0) { - if (p_app_mode != nullptr) { - if (twi_addr < (((HIG_TWI_ADDR + 1 - LOW_TWI_ADDR) / 2) + LOW_TWI_ADDR)) { - #if ((defined DEBUG_LEVEL) && (DEBUG_LEVEL >= 1)) - USE_SERIAL.printf_P("[%s] Timonel bootloader found at address: %d (0x%X)\n\r", __func__, twi_addr, twi_addr); - #endif /* DEBUG_LEVEL */ - *p_app_mode = false; - } else { - #if ((defined DEBUG_LEVEL) && (DEBUG_LEVEL >= 1)) - USE_SERIAL.printf_P("[%s] Application firmware found at address: %d (0x%X)\n\r", __func__, twi_addr, twi_addr); - #endif /* DEBUG_LEVEL */ - *p_app_mode = true; - } - } - return twi_addr; - } - delay(DLY_SCAN_BUS); - twi_addr++; - } - return OK; -} - -/* _________________________ - | | - | ScanBus B | - |_________________________| -*/ -// ScanBus (Overload B: Fills an array with the address, firmware and version of all devices connected to the bus) -byte TwiBus::ScanBus(DeviceInfo dev_info_arr[], byte arr_size, byte start_twi_addr) { - // Address 08 to 35: Timonel bootloader - // Address 36 to 63: Application firmware - // Each I2C slave must have a unique bootloader address that corresponds - // to a defined application address, as shown in this table: - // T: |08|09|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35| - // A: |36|37|38|39|40|41|42|43|44|45|46|47|48|49|50|51|52|53|54|55|56|57|58|59|60|61|62|63| -#if ((defined DEBUG_LEVEL) && (DEBUG_LEVEL >= 1)) - USE_SERIAL.printf_P("\n\r[%s] Scanning TWI bus, searching all the connected devices, please wait ...\n\r", __func__); -#endif /* DEBUG_LEVEL */ - byte found_devices = 0; - byte twi_addr = LOW_TWI_ADDR; - while (twi_addr <= HIG_TWI_ADDR) { - Wire.beginTransmission(twi_addr); - if (Wire.endTransmission() == 0) { - if (twi_addr < (((HIG_TWI_ADDR + 1 - LOW_TWI_ADDR) / 2) + LOW_TWI_ADDR)) { - Timonel tml(twi_addr); - Timonel::Status sts = tml.GetStatus(); - dev_info_arr[found_devices].addr = twi_addr; - if (sts.signature == T_SIGNATURE) { - dev_info_arr[found_devices].firmware = L_TIMONEL; - } else { - dev_info_arr[found_devices].firmware = L_UNKNOWN; - } - dev_info_arr[found_devices].version_major = sts.version_major; - dev_info_arr[found_devices].version_minor = sts.version_minor; - } else { - dev_info_arr[found_devices].addr = twi_addr; - dev_info_arr[found_devices].firmware = L_APP; - dev_info_arr[found_devices].version_major = 0; - dev_info_arr[found_devices].version_minor = 0; - } - found_devices++; - } - //delay(DLY_SCAN_BUS); - twi_addr++; - } - return OK; -} -#else -#pragma GCC warning "TwiBus device discovery functions code included in TWI master!" -#endif /* MULTI_DEVICE */ \ No newline at end of file diff --git a/nb-libs/twim/NbMicro/NbMicro.h b/nb-libs/twim/NbMicro/NbMicro.h index b0781271..b19610f6 100644 --- a/nb-libs/twim/NbMicro/NbMicro.h +++ b/nb-libs/twim/NbMicro/NbMicro.h @@ -4,26 +4,24 @@ * ........................................... * File: NbMicro.h (Header) * ........................................... - * Version: 1.4 / 2019-08-09 + * Version: 0.9.0 / 2020-04-29 * gustavo.casanova@nicebots.com * ........................................... * This TWI (I2C) master library handles the communication protocol * with slave devices that implement the NB command set over a TWI - * bus. In addition, the TwiBus class has methods to scan the bus in - * search of the existing slave devices addresses. For single-slave - * setups or those where all addresses are known in advance, this - * last one could be dropped to save memory. + * bus. */ #ifndef _NBMICRO_H_ #define _NBMICRO_H_ +#include + #include -#include "../../cmd/nb-twi-cmd.h" + #include "Arduino.h" #include "Wire.h" #include "libconfig.h" -#include "stdbool.h" typedef uint8_t byte; @@ -55,27 +53,4 @@ class NbMicro { private: }; -#if ((defined MULTI_DEVICE) && (MULTI_DEVICE == true)) -// Class TwiBus: Represents a Two Wire Interfase (I2C) bus -class TwiBus { - public: - typedef struct device_info_ { - byte addr = 0; - String firmware = ""; - byte version_major = 0; - byte version_minor = 0; - } DeviceInfo; - TwiBus(byte sda = 0, byte scl = 0); - ~TwiBus(); - byte ScanBus(bool *p_app_mode = nullptr); - byte ScanBus(DeviceInfo dev_info_arr[], - byte arr_size = HIG_TWI_ADDR + 1, - byte start_twi_addr = LOW_TWI_ADDR); - - private: - byte sda_ = 0, scl_ = 0; - bool reusing_twi_connection_ = true; -}; -#endif /* MULTI_DEVICE */ - #endif /* _NBMICRO_H_ */ diff --git a/nb-libs/twim/NbMicro/libconfig.h b/nb-libs/twim/NbMicro/libconfig.h index 22284682..cf21017d 100644 --- a/nb-libs/twim/NbMicro/libconfig.h +++ b/nb-libs/twim/NbMicro/libconfig.h @@ -1,9 +1,9 @@ /* libconfig.h ================================= - NbMicro & TwiBus configuration + NbMicro configuration --------------------------------- - Version: 1.4 2019-08-09 + Version: 0.9.0 2020-04-29 gustavo.casanova@nicebots.com --------------------------------- */ @@ -12,42 +12,30 @@ #define _NBMICRO_CONFIG_H_ ///////////////////////////////////////////////////////////////////////////// -//////////// NbMicro & TwiBus settings //////////// +//////////// NbMicro settings //////////// ///////////////////////////////////////////////////////////////////////////// // General defs -//#define DEBUG_LEVEL 0 /* Level 0: No debug info over serial terminal */ -//#define USE_SERIAL Serial /* Console output */ -#define MULTI_DEVICE true /* Enable multi device discovery code */ -#define LOW_TWI_ADDR 8 /* Lowest allowed TWI address on slave devices */ -#define HIG_TWI_ADDR 63 /* Highest allowed TWI address on slave devices */ -#define OK 0 /* No error in function execution */ -#define T_SIGNATURE 84 /* Timonel signature "T" */ +#define LOW_TWI_ADDR 8 /* Lowest allowed TWI address on slave devices */ +#define HIG_TWI_ADDR 63 /* Highest allowed TWI address on slave devices */ +//#define OK 0 /* No error in function execution */ +//#define T_SIGNATURE 84 /* Timonel signature "T" */ // End General defs // NbMicro::constructor defs -#define DLY_NBMICRO 500 /* Delay before canceling NbMiccro object creation (ms) */ +#define DLY_NBMICRO 500 /* Delay before canceling NbMiccro object creation (ms) */ // End NbMicro::constructor defs // NbMicro::SetTwiAddress defs -#define ERR_ADDR_IN_USE 1 /* Error: The TWI address is already taken */ +#define ERR_ADDR_IN_USE 1 /* Error: The TWI address is already taken */ // End NbMicro::SetTwiAddress defs // NbMicro::TwiCmdXmit defs -#define STOP_ON_REQ true /* Config: true=master releases the bus with "stop" after a request, false=sends restart */ -#define ERR_CMD_PARSE_S 1 /* Error: reply doesn't match command (single byte) */ -#define ERR_CMD_PARSE_M 2 /* Error: reply doesn't match command (multi byte) */ +#define STOP_ON_REQ true /* Config: true=master releases the bus with "stop" after a request, false=sends restart */ +#define ERR_CMD_PARSE_S 1 /* Error: reply doesn't match command (single byte) */ +#define ERR_CMD_PARSE_M 2 /* Error: reply doesn't match command (multi byte) */ // End NbMicro::TwiCmdXmit defs -// TwiBus::ScanBus defs -#define DLY_SCAN_BUS 1 /* TWI scanner pass delay */ -#define L_TIMONEL "Timonel" /* Literal: Timonel */ -#define L_UNKNOWN "Unknown" /* Literal: Unknown */ -#define L_APP "Application" /* Literal: Application */ -// End TwiBus::ScanBus defs - - - ///////////////////////////////////////////////////////////////////////////// //////////// End settings //////////// ///////////////////////////////////////////////////////////////////////////// diff --git a/nb-libs/twim/NbMicro/library.json b/nb-libs/twim/NbMicro/library.json new file mode 100644 index 00000000..a4e33d7e --- /dev/null +++ b/nb-libs/twim/NbMicro/library.json @@ -0,0 +1,20 @@ +{ + "name": "NbMicro", + "keywords": "nbmicro, i2c, twi, master, communications, arduino", + "description": "This TWI (I2C) master library handles the communication protocol with slave devices that implement the NB command set over a TWI bus", + "repository": { + "type": "git", + "url": "https://github.com/casanovg/timonel.git" + }, + "include": "nb-libs/twim/NbMicro", + "version": "0.9.0", + "frameworks": "arduino", + "dependencies": [ + { + "name": "Wire" + }, + { + "name": "nb-twi-cmd" + } + ] +} \ No newline at end of file diff --git a/nb-libs/twim/TimonelTwiM/TimonelTwiM.cpp b/nb-libs/twim/TimonelTwiM/TimonelTwiM.cpp index ef1d98a8..12016ff2 100644 --- a/nb-libs/twim/TimonelTwiM/TimonelTwiM.cpp +++ b/nb-libs/twim/TimonelTwiM/TimonelTwiM.cpp @@ -4,7 +4,7 @@ * ........................................... * File: TimonelTwiM.cpp (Library) * ........................................... - * Version: 1.4 / 2019-08-09 + * Version: 0.9.0 / 2020-04-29 * gustavo.casanova@nicebots.com * ........................................... * This TWI (I2C) master library interacts with a microcontroller @@ -99,7 +99,7 @@ byte Timonel::DeleteApplication(void) { USE_SERIAL.printf_P("\n\r[%s] Delete Flash Memory >>> 0x%02X\r\n", __func__, DELFLASH); #endif /* DEBUG_LEVEL */ byte twi_errors = TwiCmdXmit(DELFLASH, ACKDELFL); - delay(DLY_DEL_INIT); /* Long delay (~750 ms) to allow complete erasing before trying to initialize */ + delay(DLY_DEL_INIT); /* Long delay (~750 ms) to allow complete erasing before trying to initialize */ twi_errors += BootloaderInit(); #if ((defined DEBUG_LEVEL) && (DEBUG_LEVEL >= 1)) if (twi_errors > 0) { @@ -133,7 +133,7 @@ byte Timonel::UploadApplication(byte payload[], int payload_size, const int star USE_SERIAL.printf_P("\n\r"); #endif /* DEBUG_LEVEL */ #if (!((defined FEATURES_CODE) && ((FEATURES_CODE >> F_AUTO_PAGE_ADDR) & true))) -#pragma GCC warning "Address handling code included in Timonel::UploadApplication!" + //#pragma GCC warning "Address handling code included in Timonel::UploadApplication!" if (!((status_.features_code >> F_AUTO_PAGE_ADDR) & true)) { // ............................................................................. // If AUTO_PAGE_ADDR is disabled, the TWI master calculates the pages addresses @@ -167,7 +167,7 @@ byte Timonel::UploadApplication(byte payload[], int payload_size, const int star // If the user application fits in memory (can use also the trampoline page) #if ((defined DEBUG_LEVEL) && (DEBUG_LEVEL >= 1)) USE_SERIAL.printf_P("[%s] Payload (%d bytes) fits in AVR memory (trampoline page available), uploading ...\n\r", __func__, payload_size); -#endif /* DEBUG_LEVEL */ +#endif /* DEBUG_LEVEL */ twi_errors += FillSpecialPage(TPL_PAGE, payload[1], payload[0]); /* Calculate and fill trampoline page */ twi_errors += SetPageAddress(start_address); } else { @@ -186,13 +186,13 @@ byte Timonel::UploadApplication(byte payload[], int payload_size, const int star // ............................................................................. } else { #else - if (!((status_.features_code >> F_AUTO_PAGE_ADDR) & true)) { + if (!((status_.features_code >> F_AUTO_PAGE_ADDR) & true)) { #if ((defined DEBUG_LEVEL) && (DEBUG_LEVEL >= 1)) - USE_SERIAL.printf_P("[%s] WARNING! AUTO_PAGE_ADDR is disabled in Timonel, please setup TWI master to support it!\n\n\r", __func__); -#endif /* DEBUG_LEVEL */ - return ERR_AUTO_CALC; - } -#endif /* FEATURES_CODE >> !(F_AUTO_PAGE_ADDR) */ + USE_SERIAL.printf_P("[%s] WARNING! AUTO_PAGE_ADDR is disabled in Timonel, please setup TWI master to support it!\n\n\r", __func__); +#endif /* DEBUG_LEVEL */ + return ERR_AUTO_CALC; + } +#endif /* FEATURES_CODE >> !(F_AUTO_PAGE_ADDR) */ // ............................................................................. // If AUTO_PAGE_ADDR is enabled, the bootloader calculates the pages addresses // ............................................................................. @@ -210,7 +210,7 @@ byte Timonel::UploadApplication(byte payload[], int payload_size, const int star } else { #if ((defined DEBUG_LEVEL) && (DEBUG_LEVEL >= 1)) USE_SERIAL.printf_P("[%s] Warning! Payload (%d bytes) doesn't fit in AVR flash memory with current Timonel setup ...\n\r", __func__, payload_size); - USE_SERIAL.printf_P("[%s] Trampoline page is available for the application.\n\r", __func__); + USE_SERIAL.printf_P("[%s] Trampoline page is available for the application.\n\r", __func__); USE_SERIAL.printf_P("[%s] Trampoline: %d (Timonel start: %d)\n\r", __func__, status_.bootloader_start - TRAMPOLINE_LEN, status_.bootloader_start); USE_SERIAL.printf_P("[%s] App size: %d\n\r", __func__, payload_size); USE_SERIAL.printf_P("[%s] --------------------------------------\n\r", __func__); @@ -229,18 +229,18 @@ byte Timonel::UploadApplication(byte payload[], int payload_size, const int star } else { #if ((defined DEBUG_LEVEL) && (DEBUG_LEVEL >= 1)) USE_SERIAL.printf_P("[%s] Warning! Payload (%d bytes) doesn't fit in AVR flash memory with current Timonel setup ...\n\r", __func__, payload_size); - USE_SERIAL.printf_P("[%s] Trampoline page is NOT available for the application.\n\r", __func__); + USE_SERIAL.printf_P("[%s] Trampoline page is NOT available for the application.\n\r", __func__); USE_SERIAL.printf_P("[%s] Trampoline: %d (Timonel start: %d)\n\r", __func__, status_.bootloader_start - TRAMPOLINE_LEN, status_.bootloader_start); USE_SERIAL.printf_P("[%s] App size: %d\n\r", __func__, payload_size); USE_SERIAL.printf_P("[%s] --------------------------------------\n\r", __func__); USE_SERIAL.printf_P("[%s] Overflow: %d bytes\n\n\r", __func__, (payload_size - (status_.bootloader_start - SPM_PAGESIZE))); #endif /* DEBUG_LEVEL */ return ERR_APP_OVF_MC; - } + } #if ((defined FEATURES_CODE) && ((FEATURES_CODE >> F_APP_USE_TPL_PG) & true)) } -#endif /* FEATURES_CODE >> F_APP_USE_TPL_PG */ - // ............................................................................. +#endif /* FEATURES_CODE >> F_APP_USE_TPL_PG */ + // ............................................................................. #if (!((defined FEATURES_CODE) && ((FEATURES_CODE >> F_AUTO_PAGE_ADDR) & true))) } #endif /* FEATURES_CODE >> !(F_AUTO_PAGE_ADDR) */ @@ -252,14 +252,14 @@ byte Timonel::UploadApplication(byte payload[], int payload_size, const int star } // ..................................... // ...... Application upload loop ...... - // ..................................... + // ..................................... for (int i = 0; i < payload_size; i++) { if (i < (payload_size - padding)) { // If there are payload unsent data, place them in a data packet data_packet[packet_ix] = payload[i]; } else { // If there is no more payload data and the last a data packet - // is incomplete, add padding data at the end of it (0xFF) + // is incomplete, add padding data at the end of it (0xFF) data_packet[packet_ix] = 0xFF; } if (packet_ix++ == (MST_PACKET_SIZE - 1)) { @@ -313,7 +313,7 @@ byte Timonel::UploadApplication(byte payload[], int payload_size, const int star } // ..................................... // .......... Upload loop end .......... - // ..................................... + // ..................................... if (twi_errors == 0) { #if ((defined DEBUG_LEVEL) && (DEBUG_LEVEL >= 1)) USE_SERIAL.printf_P("\n\r[%s] Application was successfully uploaded to AVR flash memory ...\n\n\r", __func__); @@ -334,7 +334,7 @@ byte Timonel::UploadApplication(byte payload[], int payload_size, const int star */ // Display the microcontroller's entire flash memory contents over a serial connection #if ((defined FEATURES_CODE) && ((FEATURES_CODE >> F_CMD_READFLASH) & true)) -#pragma GCC warning "Timonel::DumpMemory function code included in TWI master!" +//#pragma GCC warning "Timonel::DumpMemory function code included in TWI master!" byte Timonel::DumpMemory(const word flash_size, const byte rx_packet_size, const byte values_per_line) { if (!((status_.features_code >> F_CMD_READFLASH) & true)) { USE_SERIAL.printf_P("\n\r[%s] Function not supported by current Timonel (TWI %d) features ...\r\n", __func__, addr_); @@ -413,7 +413,7 @@ byte Timonel::BootloaderInit(void) { // Timonel initialization: STEP 1 twi_errors += QueryStatus(); #if ((defined FEATURES_CODE) && ((FEATURES_CODE >> F_TWO_STEP_INIT) & true)) -#pragma GCC warning "Two-step initialization code included in Timonel::BootloaderInit!" + //#pragma GCC warning "Two-step initialization code included in Timonel::BootloaderInit!" // If TWO_STEP_INIT feature is enabled in Timonel device if ((status_.features_code >> F_TWO_STEP_INIT) & true) { #if ((defined DEBUG_LEVEL) && (DEBUG_LEVEL >= 1)) @@ -496,7 +496,7 @@ byte Timonel::SendDataPacket(const byte data_packet[]) { // Function SetPageAddres (Sets the start address of a flash memory page) #if (!((defined FEATURES_CODE) && ((FEATURES_CODE >> F_AUTO_PAGE_ADDR) & true))) -#pragma GCC warning "Timonel::SetPageAddress, FillSpecialPage and CalculateTrampoline functions code included in TWI master!" +//#pragma GCC warning "Timonel::SetPageAddress, FillSpecialPage and CalculateTrampoline functions code included in TWI master!" byte Timonel::SetPageAddress(const word page_addr) { const byte cmd_size = 4; const byte reply_size = 2; diff --git a/nb-libs/twim/TimonelTwiM/TimonelTwiM.h b/nb-libs/twim/TimonelTwiM/TimonelTwiM.h index 4c530f63..0d48b99c 100644 --- a/nb-libs/twim/TimonelTwiM/TimonelTwiM.h +++ b/nb-libs/twim/TimonelTwiM/TimonelTwiM.h @@ -4,7 +4,7 @@ * ........................................... * File: TimonelTwiM.h (Header) * ........................................... - * Version: 1.4 / 2019-08-09 + * Version: 0.9.0 / 2020-04-29 * gustavo.casanova@nicebots.com * ........................................... * This TWI (I2C) master library interacts with a microcontroller @@ -16,11 +16,9 @@ #ifndef _TIMONELTWIM_H_ #define _TIMONELTWIM_H_ -#include "../../cmd/nb-twi-cmd.h" -#include "NbMicro.h" -#include "Wire.h" +#include + #include "libconfig.h" -#include "stdbool.h" // Class Timonel: Represents an ATTiny85/45/25 microcontroller running the Timonel bootloader class Timonel : public NbMicro { diff --git a/nb-libs/twim/TimonelTwiM/libconfig.h b/nb-libs/twim/TimonelTwiM/libconfig.h index cfa9d686..bd00d96f 100644 --- a/nb-libs/twim/TimonelTwiM/libconfig.h +++ b/nb-libs/twim/TimonelTwiM/libconfig.h @@ -3,7 +3,7 @@ ================================= Timonel TWI Master configuration --------------------------------- - Version: 1.4 2019-08-09 + Version: 0.9.0 2020-04-29 gustavo.casanova@nicebots.com --------------------------------- */ @@ -16,43 +16,43 @@ ///////////////////////////////////////////////////////////////////////////// // General defs -#define DEBUG_LEVEL 0 /* Debug level: 0 = No debug info over serial terminal, 1+ = Progressively increasing verbosity */ -#define USE_SERIAL Serial /* Console output */ -#define FEATURES_CODE 253 /* Enabled features (NOTE: This must match the bootloader, If you aren't sure, use 253 (default) */ -#define EXT_FEATURES 15 /* Enabled extended features (NOTE: This must match the bootloader, If you aren't sure, use 15 */ -#define LOW_TML_ADDR 8 /* Lowest allowed TWI address for Timonel devices */ -#define HIG_TML_ADDR 35 /* Highest allowed TWI address for Timonel devices */ -#define T_SIGNATURE 84 /* Timonel signature "T" (Uppercase means clock tweaking made at compile time*/ -#define MST_PACKET_SIZE 32 /* Master-to-Slave Xmit data block size: always even values, min = 2, max = 32 */ -#define SLV_PACKET_SIZE 32 /* Slave-to-Master Xmit data block size: always even values, min = 2, max = 32 */ -#define SPM_PAGESIZE 64 /* Tiny85 flash page buffer size */ -#define OK 0 /* No error in function execution */ +#define DEBUG_LEVEL 0 /* Debug level: 0 = No debug info over serial terminal, 1+ = Progressively increasing verbosity */ +#define USE_SERIAL Serial /* Console output */ +#define FEATURES_CODE 253 /* Enabled features (NOTE: This must match the bootloader, If you aren't sure, use 253 (default) */ +#define EXT_FEATURES 15 /* Enabled extended features (NOTE: This must match the bootloader, If you aren't sure, use 15 */ +#define LOW_TML_ADDR 8 /* Lowest allowed TWI address for Timonel devices */ +#define HIG_TML_ADDR 35 /* Highest allowed TWI address for Timonel devices */ +#define T_SIGNATURE 84 /* Timonel signature "T" (Uppercase means clock tweaking made at compile time*/ +#define MST_PACKET_SIZE 32 /* Master-to-Slave Xmit data block size: always even values, min = 2, max = 32 */ +#define SLV_PACKET_SIZE 32 /* Slave-to-Master Xmit data block size: always even values, min = 2, max = 32 */ +#define SPM_PAGESIZE 64 /* Tiny85 flash page buffer size */ +#define OK 0 /* No error in function execution */ // End General defs // Timonel::QueryStatus defs -#define CMD_ACK_POS 0 /* Command acknowledge reply position */ +#define CMD_ACK_POS 0 /* Command acknowledge reply position */ // *** Status reply (10 bytes) -#define S_REPLY_LENGTH 12 /* Timonel status reply lenght (1 bit ACK + 8 status bytes + 1 checksum byte) */ -#define S_SIGNATURE 1 /* Status: signature byte position */ -#define S_MAJOR 2 /* Status: major number byte position */ -#define S_MINOR 3 /* Status: minor number byte position */ -#define S_FEATURES 4 /* Status: available features code byte position */ -#define S_EXT_FEATURES 5 /* Status: available features code byte position */ -#define S_BOOT_ADDR_MSB 6 /* Status: Timonel start address MSB position */ -#define S_BOOT_ADDR_LSB 7 /* Status: Timonel start address LSB position */ -#define S_APPL_ADDR_MSB 8 /* Status: Application address MSB position */ -#define S_APPL_ADDR_LSB 9 /* Status: Application address LSB position */ -#define S_LOW_FUSE 10 /* Status: Low fuse setting */ -#define S_OSCCAL 11 /* Status: AVR low fuse value byte position */ +#define S_REPLY_LENGTH 12 /* Timonel status reply lenght (1 bit ACK + 8 status bytes + 1 checksum byte) */ +#define S_SIGNATURE 1 /* Status: signature byte position */ +#define S_MAJOR 2 /* Status: major number byte position */ +#define S_MINOR 3 /* Status: minor number byte position */ +#define S_FEATURES 4 /* Status: available features code byte position */ +#define S_EXT_FEATURES 5 /* Status: available features code byte position */ +#define S_BOOT_ADDR_MSB 6 /* Status: Timonel start address MSB position */ +#define S_BOOT_ADDR_LSB 7 /* Status: Timonel start address LSB position */ +#define S_APPL_ADDR_MSB 8 /* Status: Application address MSB position */ +#define S_APPL_ADDR_LSB 9 /* Status: Application address LSB position */ +#define S_LOW_FUSE 10 /* Status: Low fuse setting */ +#define S_OSCCAL 11 /* Status: AVR low fuse value byte position */ // *** Features byte (8 bits) -#define F_ENABLE_LED_UI 0 /* Features 1 (1) : LED UI enabled */ -#define F_AUTO_PAGE_ADDR 1 /* Features 2 (2) : Automatic trampoline and addr handling */ -#define F_APP_USE_TPL_PG 2 /* Features 3 (4) : Application can use trampoline page */ -#define F_CMD_SETPGADDR 3 /* Features 4 (8) : Set page address command enabled */ -#define F_TWO_STEP_INIT 4 /* Features 5 (16) : Two-step initialization required */ -#define F_USE_WDT_RESET 5 /* Features 6 (32) : Reset by watchdog timer enabled */ -#define F_TIMEOUT_EXIT 6 /* Features 7 (64) : If not initialized, exit to app after timeout */ -#define F_CMD_READFLASH 7 /* Features 8 (128): Read flash command enabled */ +#define F_ENABLE_LED_UI 0 /* Features 1 (1) : LED UI enabled */ +#define F_AUTO_PAGE_ADDR 1 /* Features 2 (2) : Automatic trampoline and addr handling */ +#define F_APP_USE_TPL_PG 2 /* Features 3 (4) : Application can use trampoline page */ +#define F_CMD_SETPGADDR 3 /* Features 4 (8) : Set page address command enabled */ +#define F_TWO_STEP_INIT 4 /* Features 5 (16) : Two-step initialization required */ +#define F_USE_WDT_RESET 5 /* Features 6 (32) : Reset by watchdog timer enabled */ +#define F_TIMEOUT_EXIT 6 /* Features 7 (64) : If not initialized, exit to app after timeout */ +#define F_CMD_READFLASH 7 /* Features 8 (128): Read flash command enabled */ // *** Extended features byte (8 bits) #define F_AUTO_CLK_TWEAK 0 /* Ext features 1 (1) : Auto clock tweaking by reading low fuse */ #define F_FORCE_ERASE_PG 1 /* Ext features 2 (2) : Erase each page before writing new data */ @@ -62,10 +62,10 @@ // End Timonel::QueryStatus defs // Timonel::FillSpecialPage defs -#define RST_PAGE 1 /* Config: 1=Reset page (addr: 0) */ -#define TPL_PAGE 2 /* Config: 2=Trampoline page (addr: TIMONEL_START - 64) */ -#define DLY_SET_ADDR 100 /* Delay after setting a memory address */ -#define DLY_RETURN 100 /* Delay before return control to caller */ +#define RST_PAGE 1 /* Config: 1=Reset page (addr: 0) */ +#define TPL_PAGE 2 /* Config: 2=Trampoline page (addr: TIMONEL_START - 64) */ +#define DLY_SET_ADDR 100 /* Delay after setting a memory address */ +#define DLY_RETURN 100 /* Delay before return control to caller */ // End Timonel::FillSpecialPage defs // Timonel::DumpMemory defs @@ -87,17 +87,17 @@ // End Timonel::SendDataPacket defs // Timonel::UploadApplication defs -#define DLY_PKT_SEND 10 /* Delay after sending a data packet */ -#define DLY_FLASH_PG 100 /* Delay to allow memory page flashing */ -#define TRAMPOLINE_LEN 2 /* Trampoline length: two-byte address to jump to the app */ -#define ERR_SETADDRESS 1 /* Error: AUTO_PAGE_ADDR and CMD_SETPGADDR are disabled, can't set page addresses */ -#define ERR_APP_OVF_AU 2 /* Error: the payload doesn't fit in AVR memory (auto page addr calculation) */ -#define ERR_APP_OVF_MC 3 /* Error: the payload doesn't fit in AVR memory (page addr calculated by TWI master) */ -#define ERR_AUTO_CALC 4 /* Error: AUTO_PAGE_ADDR is disabled and the addr handling cade is not included in TWI master */ +#define DLY_PKT_SEND 10 /* Delay after sending a data packet */ +#define DLY_FLASH_PG 100 /* Delay to allow memory page flashing */ +#define TRAMPOLINE_LEN 2 /* Trampoline length: two-byte address to jump to the app */ +#define ERR_SETADDRESS 1 /* Error: AUTO_PAGE_ADDR and CMD_SETPGADDR are disabled, can't set page addresses */ +#define ERR_APP_OVF_AU 2 /* Error: the payload doesn't fit in AVR memory (auto page addr calculation) */ +#define ERR_APP_OVF_MC 3 /* Error: the payload doesn't fit in AVR memory (page addr calculated by TWI master) */ +#define ERR_AUTO_CALC 4 /* Error: AUTO_PAGE_ADDR is disabled and the addr handling cade is not included in TWI master */ // End Timonel::UploadApplication defs // Timonel::DeleteApplication defs -#define DLY_DEL_INIT 750 /* Delay to allow deleting the app before initializing Timonel */ +#define DLY_DEL_INIT 750 /* Delay to allow deleting the app before initializing Timonel */ // End Timonel::DeleteApplication defs ///////////////////////////////////////////////////////////////////////////// diff --git a/nb-libs/twim/TimonelTwiM/library.json b/nb-libs/twim/TimonelTwiM/library.json new file mode 100644 index 00000000..035cc8f6 --- /dev/null +++ b/nb-libs/twim/TimonelTwiM/library.json @@ -0,0 +1,15 @@ +{ + "name": "TimonelTwiM", + "keywords": "timoneltwim, i2c, twi, master, communications, bootloader, arduino", + "description": "This TWI (I2C) master library interacts with a slave microcontroller running Timonel bootloader. It inherits from the NbMicro class, which handles the actual communication over the TWI bus using the NB command set.", + "repository": { + "type": "git", + "url": "https://github.com/casanovg/timonel.git" + }, + "include": "nb-libs/twim/TimonelTwiM", + "version": "0.9.0", + "frameworks": "arduino", + "dependencies": { + "name": "NbMicro" + } +} \ No newline at end of file diff --git a/nb-libs/twim/TwiBus/TwiBus.cpp b/nb-libs/twim/TwiBus/TwiBus.cpp new file mode 100644 index 00000000..10c7333c --- /dev/null +++ b/nb-libs/twim/TwiBus/TwiBus.cpp @@ -0,0 +1,122 @@ +/* + * TWI Bus Master Library + * Author: Gustavo Casanova + * ........................................... + * File: TwiBus.cpp (Library) + * ........................................... + * Version: 0.9.0 / 2020-04-29 + * gustavo.casanova@nicebots.com + * ........................................... + * The TwiBus class has methods to scan the bus in + * search of the existing slave devices addresses. + */ + +#include "TwiBus.h" + +///////////////////////////////////////////////////////////////////////////// +//////////// TWIBUS CLASS //////////// +///////////////////////////////////////////////////////////////////////////// + +// Class constructor +TwiBus::TwiBus(byte sda, byte scl) : sda_(sda), scl_(scl) { + if (!((sda == 0) && (scl == 0))) { +#if ((defined DEBUG_LEVEL) && (DEBUG_LEVEL >= 1)) + USE_SERIAL.printf_P("[%s] Creating a new I2C connection\n\r", __func__); +#endif /* DEBUG_LEVEL */ + Wire.begin(sda, scl); /* Init I2C sda:GPIO0, scl:GPIO2 (ESP-01) / sda:D3, scl:D4 (NodeMCU) */ + reusing_twi_connection_ = false; + } else { +#if ((defined DEBUG_LEVEL) && (DEBUG_LEVEL >= 1)) + USE_SERIAL.printf_P("[%s] Reusing I2C connection\n\r", __func__); +#endif /* DEBUG_LEVEL */ + reusing_twi_connection_ = true; + } +} + +// Class destructor +TwiBus::~TwiBus() { + // Destructor +} + +/* _________________________ + | | + | ScanBus A | + |_________________________| +*/ +// ScanBus (Overload A: Return the address and mode of the first TWI device found on the bus) +byte TwiBus::ScanBus(bool *p_app_mode) { + // Address 08 to 35: Timonel bootloader (app mode = false) + // Address 36 to 63: Application firmware (app mode = true) +#if ((defined DEBUG_LEVEL) && (DEBUG_LEVEL >= 1)) + USE_SERIAL.printf_P("\n\r[%s] Scanning TWI bus, looking for the first device (lowest address) ...\n\r", __func__); +#endif /* DEBUG_LEVEL */ + byte twi_addr = LOW_TWI_ADDR; + while (twi_addr < HIG_TWI_ADDR) { + Wire.beginTransmission(twi_addr); + if (Wire.endTransmission() == 0) { + if (p_app_mode != nullptr) { + if (twi_addr < (((HIG_TWI_ADDR + 1 - LOW_TWI_ADDR) / 2) + LOW_TWI_ADDR)) { +#if ((defined DEBUG_LEVEL) && (DEBUG_LEVEL >= 1)) + USE_SERIAL.printf_P("[%s] Timonel bootloader found at address: %d (0x%X)\n\r", __func__, twi_addr, twi_addr); +#endif /* DEBUG_LEVEL */ + *p_app_mode = false; + } else { +#if ((defined DEBUG_LEVEL) && (DEBUG_LEVEL >= 1)) + USE_SERIAL.printf_P("[%s] Application firmware found at address: %d (0x%X)\n\r", __func__, twi_addr, twi_addr); +#endif /* DEBUG_LEVEL */ + *p_app_mode = true; + } + } + return twi_addr; + } + delay(DLY_SCAN_BUS); + twi_addr++; + } + return OK; +} + +/* _________________________ + | | + | ScanBus B | + |_________________________| +*/ +// ScanBus (Overload B: Fills an array with the address, firmware and version of all devices connected to the bus) +byte TwiBus::ScanBus(DeviceInfo dev_info_arr[], byte arr_size, byte start_twi_addr) { + // Address 08 to 35: Timonel bootloader + // Address 36 to 63: Application firmware + // Each I2C slave must have a unique bootloader address that corresponds + // to a defined application address, as shown in this table: + // T: |08|09|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35| + // A: |36|37|38|39|40|41|42|43|44|45|46|47|48|49|50|51|52|53|54|55|56|57|58|59|60|61|62|63| +#if ((defined DEBUG_LEVEL) && (DEBUG_LEVEL >= 1)) + USE_SERIAL.printf_P("\n\r[%s] Scanning TWI bus, searching all the connected devices, please wait ...\n\r", __func__); +#endif /* DEBUG_LEVEL */ + byte found_devices = 0; + byte twi_addr = LOW_TWI_ADDR; + while (twi_addr <= HIG_TWI_ADDR) { + Wire.beginTransmission(twi_addr); + if (Wire.endTransmission() == 0) { + if (twi_addr < (((HIG_TWI_ADDR + 1 - LOW_TWI_ADDR) / 2) + LOW_TWI_ADDR)) { + Timonel tml(twi_addr); + Timonel::Status sts = tml.GetStatus(); + dev_info_arr[found_devices].addr = twi_addr; + if (sts.signature == T_SIGNATURE) { + dev_info_arr[found_devices].firmware = L_TIMONEL; + } else { + dev_info_arr[found_devices].firmware = L_UNKNOWN; + } + dev_info_arr[found_devices].version_major = sts.version_major; + dev_info_arr[found_devices].version_minor = sts.version_minor; + } else { + dev_info_arr[found_devices].addr = twi_addr; + dev_info_arr[found_devices].firmware = L_APP; + dev_info_arr[found_devices].version_major = 0; + dev_info_arr[found_devices].version_minor = 0; + } + found_devices++; + } + //delay(DLY_SCAN_BUS); + twi_addr++; + } + return OK; +} diff --git a/nb-libs/twim/TwiBus/TwiBus.h b/nb-libs/twim/TwiBus/TwiBus.h new file mode 100644 index 00000000..5d125b96 --- /dev/null +++ b/nb-libs/twim/TwiBus/TwiBus.h @@ -0,0 +1,42 @@ +/* + * TWI Bus Master Library + * Author: Gustavo Casanova + * ........................................... + * File: TwiBus.h (Header) + * ........................................... + * Version: 0.9.0 / 2020-04-29 + * gustavo.casanova@nicebots.com + * ........................................... + * The TwiBus class has methods to scan the bus in + * search of the existing slave devices addresses. + */ + +#ifndef _TWIBUS_H_ +#define _TWIBUS_H_ + +#include + +#include "libconfig.h" + +// Class TwiBus: Represents a Two Wire Interfase (I2C) bus +class TwiBus { + public: + typedef struct device_info_ { + byte addr = 0; + String firmware = ""; + byte version_major = 0; + byte version_minor = 0; + } DeviceInfo; + TwiBus(byte sda = 0, byte scl = 0); + ~TwiBus(); + byte ScanBus(bool *p_app_mode = nullptr); + byte ScanBus(DeviceInfo dev_info_arr[], + byte arr_size = HIG_TWI_ADDR + 1, + byte start_twi_addr = LOW_TWI_ADDR); + + private: + byte sda_ = 0, scl_ = 0; + bool reusing_twi_connection_ = true; +}; + +#endif /* _TWIBUS_H_ */ diff --git a/nb-libs/twim/TwiBus/libconfig.h b/nb-libs/twim/TwiBus/libconfig.h new file mode 100644 index 00000000..07225132 --- /dev/null +++ b/nb-libs/twim/TwiBus/libconfig.h @@ -0,0 +1,29 @@ +/* + libconfig.h + ================================= + TwiBus configuration + --------------------------------- + Version: 0.9.0 2020-04-29 + gustavo.casanova@nicebots.com + --------------------------------- +*/ + +#ifndef _TWIBUS_CONFIG_H_ +#define _TWIBUS_CONFIG_H_ + +///////////////////////////////////////////////////////////////////////////// +//////////// TwiBus settings //////////// +///////////////////////////////////////////////////////////////////////////// + +// TwiBus::ScanBus defs +#define DLY_SCAN_BUS 1 /* TWI scanner pass delay */ +#define L_TIMONEL "Timonel" /* Literal: Timonel */ +#define L_UNKNOWN "Unknown" /* Literal: Unknown */ +#define L_APP "Application" /* Literal: Application */ +// End TwiBus::ScanBus defs + +///////////////////////////////////////////////////////////////////////////// +//////////// End settings //////////// +///////////////////////////////////////////////////////////////////////////// + +#endif /* _TWIBUS_CONFIG_H_ */ \ No newline at end of file diff --git a/nb-libs/twim/TwiBus/library.json b/nb-libs/twim/TwiBus/library.json new file mode 100644 index 00000000..3bb95ee4 --- /dev/null +++ b/nb-libs/twim/TwiBus/library.json @@ -0,0 +1,15 @@ +{ + "name": "TwiBus", + "keywords": "twibus, i2c, twi, master, communications, arduino", + "description": "The TwiBus class has methods to scan the bus in search of the existing slave devices addresses.", + "repository": { + "type": "git", + "url": "https://github.com/casanovg/timonel.git" + }, + "include": "nb-libs/twim/TwiBus", + "version": "0.9.0", + "frameworks": "arduino", + "dependencies": { + "name": "TimonelTwiM" + } +} \ No newline at end of file diff --git a/nb-libs/twis/interrupt-based/nb-usitwisl.c b/nb-libs/twis/interrupt-based/nb-usitwisl.c index 4fd9ee39..42ca0211 100644 --- a/nb-libs/twis/interrupt-based/nb-usitwisl.c +++ b/nb-libs/twis/interrupt-based/nb-usitwisl.c @@ -4,7 +4,7 @@ * ............................................. * File: nb-usitwisl.c (Slave driver library) * ............................................. - * Version: 1.4 / 2019-08-09 + * Version: 0.9.0 / 2019-08-09 * gustavo.casanova@nicebots.com * ............................................. * Based on work by Atmel (AVR312) et others diff --git a/nb-libs/twis/interrupt-based/nb-usitwisl.h b/nb-libs/twis/interrupt-based/nb-usitwisl.h index bea62a02..4ed38f8b 100644 --- a/nb-libs/twis/interrupt-based/nb-usitwisl.h +++ b/nb-libs/twis/interrupt-based/nb-usitwisl.h @@ -4,7 +4,7 @@ * ............................................. * File: nb-usitwisl.h (Slave driver headers) * ............................................. - * Version: 1.4 / 2019-08-09 + * Version: 0.9.0 / 2019-08-09 * gustavo.casanova@nicebots.com * ............................................. * Based on work by Atmel (AVR312) et others diff --git a/nb-libs/twis/interrupt-free/nb-usitwisl-if.c b/nb-libs/twis/interrupt-free/nb-usitwisl-if.c index e0c38aa5..aa5a01bd 100644 --- a/nb-libs/twis/interrupt-free/nb-usitwisl-if.c +++ b/nb-libs/twis/interrupt-free/nb-usitwisl-if.c @@ -4,7 +4,7 @@ * ............................................. * File: nb-usitwisl-if.c (Slave driver library) * ............................................. - * Version: 1.4 / 2019-08-09 + * Version: 0.9.0 / 2019-08-09 * gustavo.casanova@nicebots.com * ............................................. * Based on work by Atmel (AVR312) et others diff --git a/nb-libs/twis/interrupt-free/nb-usitwisl-if.h b/nb-libs/twis/interrupt-free/nb-usitwisl-if.h index 8f33b3a4..f3e66cfb 100644 --- a/nb-libs/twis/interrupt-free/nb-usitwisl-if.h +++ b/nb-libs/twis/interrupt-free/nb-usitwisl-if.h @@ -4,7 +4,7 @@ * ............................................. * File: nb-usitwisl-if.h (Slave driver headers) * ............................................. - * Version: 1.4 / 2019-08-09 + * Version: 0.9.0 / 2019-08-09 * gustavo.casanova@nicebots.com * ............................................. * Based on work by Atmel (AVR312) et others diff --git a/timonel-bootloader/README.md b/timonel-bootloader/README.md index 1ea455ce..644b261b 100644 --- a/timonel-bootloader/README.md +++ b/timonel-bootloader/README.md @@ -1,66 +1,55 @@ -# Timonel Bootloader v1.4 # +# Timonel Bootloader v1.4 -This bootloader version has several improvements: +This version has several improvements: -* __Significant memory savings:__ by inlining the TWI (I2C) driver functions' implementation inside the bootloader source code, now the smaller version "tml-t85-small" occupies ~ 1K byte, leaving 7K bytes available for user applications. +* **Significant memory savings:** by inlining the TWI (I2C) driver functions' implementation inside the bootloader source code, now the smaller version "tml-t85-small" occupies \~ 1K byte, leaving 7K bytes available for user applications. +* **Transmission speed improvement:** the code was adjusted to allow the bootloader to transmit and receive 32-byte packets (Half memory-page on an ATtiny85). This produces a significant performance increase to the user application upload and flash memory reading functions. +* **User application autorun is now optional:** implemented by adding a TIMEOUT\_EXIT feature to allow selecting whether the user application will run automatically after a timeout when the bootloader is not initialized, or, it will only be run controlled by the TWI master. The CHECK\_EMPTY\_FL optional feature was deprecated since the READFLSH command can be used for the same purpose. Improved command reply switch-case. +* **Different internal-clock configurations support improved:** now the bootloader adapts its clock speed by modifying the OSCCAL register to compensate fuse configurations in 1, 2 and 8 MHz (At 16 Mhz it works without any type of compensation). This can be done in two ways: + 1. The compensation is configured at the time of bootloader compilation by setting the LOW\_FUSE variable. + 2. It adapts at runtime by directly reading the value of the low fuse. This last mode is selected by enabling "AUTO\_CLK\_TWEAK". It allows the bootloader to continue working without recompiling despite changing the fuses settings, but it takes a little more memory. In both cases, the bootloader restores the original configuration after its execution so that the application can function at the speed for which it was designed. -* __Transmission speed improvement:__ the code was adjusted to allow the bootloader to transmit and receive 32-byte packets (Half memory-page on an ATtiny85). This produces a significant performance increase to the user application upload and flash memory reading functions. +## Compilation -* __User application autorun is now optional:__ implemented by adding a TIMEOUT_EXIT feature to allow selecting whether the user application will run automatically after a timeout when the bootloader is not initialized, or, it will only be run controlled by the TWI master. The CHECK_EMPTY_FL optional feature was deprecated since the READFLSH command can be used for the same purpose. Improved command reply switch-case. +The **"make-timonel.sh"** script allows launching "[make](http://www.gnu.org/software/make)" with different configurations. It has several arguments, including **"--all"**, which compiles all the preconfigured options found in the **"configs"** directory. The flashable **".hex"** binary files are saved in the **"releases"** directory. -* __Different internal-clock configurations support improved:__ now the bootloader adapts its clock speed by modifying the OSCCAL register to compensate fuse configurations in 1, 2 and 8 MHz (At 16 Mhz it works without any type of compensation). This can be done in two ways: - 1. The compensation is configured at the time of bootloader compilation by setting the LOW_FUSE variable. - - 2. It adapts at runtime by directly reading the value of the low fuse. This last mode is selected by enabling "AUTO_CLK_TWEAK". It allows the bootloader to continue working without recompiling despite changing the fuses settings, but it takes a little more memory. In both cases, the bootloader restores the original configuration after its execution so that the application can function at the speed for which it was designed. +E.g: `./make-timonel.sh tml-t85-small timonel 13 1B80 1 false;` -## Compilation ## -The __"make-timonel.sh"__ script allows launching ["make"](http://www.gnu.org/software/make) with different configurations. It has several arguments, including __"--all"__, which compiles all the preconfigured options found in the __"configs"__ directory. The flashable __".hex"__ binary files are saved in the __"releases"__ directory. +* Generates a **"timonel.hex"** binary file based on **"tml-t85-small"** config. +* Assigns the TWI address **13** to the device in bootloader mode. +* Sets **0x1B80** as the bootloader start memory position. +* Sets the device low fuse to operate at **1 MHz** in user-application mode. +* **Disables** automatic clock tweaking. -E.g: __`./make-timonel.sh tml-t85-small timonel 13 1B80 1 false;`__ +**Note:** This bootloader version has been compiled with the **"avr-gcc 8.3.0 64-bit"** toolchain downloaded from [this site](http://blog.zakkemble.net/avr-gcc-builds)., it's also included under the "[avr-toolchains](http://github.com/casanovg/avr-toolchains)" repository. The scripts are included mainly to ease to repetitive work of flashing several devices but, of course, the bootloader can be compiled and flashed using avr-gcc and avrdude directly. - * Generates a __\"timonel.hex\"__ binary file based on __\"tml-t85-small\"__ config. - * Assigns the TWI address __17__ to the device. - * Sets __0x1B00__ as the bootloader start memory position. - * Sets the device low fuse to operate at __8 MHz__. - * __Disables__ automatic clock tweaking. +## Flashing Timonel on the device -__Note:__ This bootloader version has been compiled with the __"avr-gcc 8.3.0 64-bit"__ toolchain downloaded from [this site](http://blog.zakkemble.net/avr-gcc-builds)., it's also included under the [\"avr-toolchains\"](http://github.com/casanovg/avr-toolchains) repository. The scripts are included mainly to ease to repetitive work of flashing several devices but, of course, the bootloader can be compiled and flashed using avr-gcc and avrdude directly. +The **"flash-timonel-bootloader.sh"** script allows flashing Timonel on the device by using the "[avrdude](http://savannah.nongnu.org/projects/avrdude)" utility with an [AVR programmer](http://www.fischl.de/usbasp). The supported arguments are: -## Flashing Timonel on the device ## -The script __"flash-timonel-bootloader.sh"__ allows flashing Timonel on the device by using the ["avrdude"](http://savannah.nongnu.org/projects/avrdude) utility with an [AVR programmer](http://www.fischl.de/usbasp). The supported arguments are: 1. Binary file name (without ".hex" extension), located under "releases" directory. - 2. Clock speed in MHz: 16, 8, 2, 1. The bootloader can be flashed to bare ATtiny85/45/25 chips, Digispark boards and other Tiny85-compatible devices using an AVR programmer (e.g. USBasp). -E.g: __`./flash-timonel-bootloader.sh timonel 1;`__ - - * Flashes __\"timonel.hex\"__ binary file on the device with avrdude. - * Sets the device's low fuse to run at __1 MHz__ (possible values are 1, 2, 8 and 16). - -## Setting optional features ## -The bootloader has several optional features that allow finding the right balance between characteristics, flash memory usage, and performance. They're enabled from the configuration file __"tml-config.mak"__ placed inside specific configuration folders (e.g. "tml-t85-cfg", the default one). It's a makefile include that adds or removes sections of the source code that will be part of the ".hex" binary file when compiling it. As a general rule of thumb, more enabled features = bigger bootloader size = less space for user applications. The available options are briefly described below: - -* __ENABLE_LED_UI__: If this is enabled, the GPIO ping defined by LED_UI_PIN is used to display Timonel activity when certain functions are run. This is useful mainly for debugging. PLEASE DISABLE THIS FOR PRODUCTION! IT COULD ACTIVATE SOMETHING CONNECTED TO A POWER SOURCE BY ACCIDENT! (Default: false). - -* __AUTO_PAGE_ADDR__: Automatic page and trampoline address calculation. If this option is enabled, the bootloader will auto-increase the uploaded data pages addresses when receiving an application from the TWI (I2C) master and it will calculate the trampoline needed to jump to the application on exit. On the other hand, when this is disabled the bootloader becomes smaller but this task is transferred to the TWI master, so this one has to calculate the page addresses and the trampoline. With this option disabled, enabling CMD_SETPGADDR becomes mandatory, otherwise, the TWI master won't be able to set the pages addresses, the application upload wouldn't be possible. (Default: true). - -* __APP_USE_TPL_PG__: This option enables the user application to use the trampoline page when AUTO_PAGE_ADDR is enabled. This is more a kind of safety measure than a true memory stretching since enabling this takes 2 extra memory pages. In the end, disabling this allows 1 extra page. If AUTO_PAGE_ADDR is disabled, this option is irrelevant since the trampoline page writing duty is transferred to the I2C master. (Default: false). - -* __CMD_SETPGADDR__: When this is enabled, the TWI master can define the starting address of every application memory page being uploaded. If it's disabled, enabling AUTO_PAGE_ADDR becomes mandatory. In such cases, applications can only be flashed starting from page 0 since the page address auto-increase works that way. This is OK for most applications. (Default: false). - -* __TWO_STEP_INIT__: If this is enabled, Timonel expects a two-step initialization from an I2C master before running the exit, memory erase and write commands. This is a safety measure to avoid bootloader initialization, which enables memory functions, due to noise. When it's disabled, only a single-step initialization is required. (Default: false). - -* __USE_WDT_RESET__: If this is enabled, the bootloader uses the watchdog timer for resetting instead of jumping to TIMONEL_START. This reset is more similar to a power-on reset. It could be useful to start the user application from a "cleanest" state if required. (Default: true). - -* __CHECK_EMPTY_FL__: If this is enabled, when running GETTMNLV command, the bootloader will read the first 100 flash memory positions to check if there is an application (or some other data) loaded in flash memory. The true/false outcome is informed as part of the GETTMNLV command reply packet. (Default: false). +E.g: `./flash-timonel-bootloader.sh timonel 1;` -* __CMD_READFLASH__: This option enables the READFLSH command, which is used by the TWI master for dumping the device's whole memory contents for debugging purposes. It can also be useful for backing up the flash memory before flashing a new firmware. (Default: false). +* Flashes **"timonel.hex"** binary file on the device with avrdude. +* Sets the device's low fuse to run at **1 MHz** (possible values are 1, 2, 8 and 16). -* __AUTO_CLK_TWEAK__: When this feature is enabled, the clock speed adjustment is made at run time based on the low fuse setup. It works only for internal CPU clock configurations: RC oscillator or HF PLL. (Default: false). +## Setting optional features -* __FORCE_ERASE_PG__: If this option is enabled, each flash memory page is erased before writing new data. Normally, it shouldn't be necessary to enable it. (Default: false). +The bootloader has several optional features that allow finding the right balance between characteristics, flash memory usage, and performance. They're enabled from the configuration file **"tml-config.mak"** placed inside specific configuration folders (e.g. "tml-t85-cfg", the default one). It's a makefile include that adds or removes sections of the source code that will be part of the ".hex" binary file when compiling it. As a general rule of thumb, more enabled features = bigger bootloader size = less space for user applications. The available options are briefly described below: -* __CLEAR_BIT_7_R31__: This is to avoid that the first bootloader instruction is skipped after restarting without an user application in memory. See: http://www.avrfreaks.net/comment/2561866#comment-2561866. (Default: false). - -* __CHECK_PAGE_IX__: If this option is enabled, the page index size is checked to ensure that isn't bigger than SPM_PAGESIZE (64 bytes in an ATtiny85). This keeps the app data integrity in case the master sends wrong page sizes. (Default: false). +* **ENABLE\_LED\_UI**: If this is enabled, the GPIO pin defined by LED\_UI\_PIN is used to display Timonel activity when certain functions are run. This is useful mainly for debugging. PLEASE DISABLE THIS FOR PRODUCTION! IT COULD ACTIVATE SOMETHING CONNECTED TO A POWER SOURCE BY ACCIDENT! (Default: false). +* **AUTO\_PAGE\_ADDR**: Automatic page and trampoline address calculation. If this option is enabled, the bootloader will auto-increase the uploaded data pages addresses when receiving an application from the TWI (I2C) master and it will calculate the trampoline needed to jump to the application on exit. On the other hand, when this is disabled the bootloader becomes smaller but this task is transferred to the TWI master, so this one has to calculate the page addresses and the trampoline. With this option disabled, enabling CMD\_SETPGADDR becomes mandatory, otherwise, the TWI master won't be able to set the pages addresses, the application upload wouldn't be possible. (Default: true). +* **APP\_USE\_TPL\_PG**: This option enables the user application to use the trampoline page when AUTO\_PAGE\_ADDR is enabled. This is more a kind of safety measure than a true memory stretching since enabling this takes 2 extra memory pages. In the end, disabling this allows 1 extra page. If AUTO\_PAGE\_ADDR is disabled, this option is irrelevant since the trampoline page writing duty is transferred to the I2C master. (Default: false). +* **CMD\_SETPGADDR**: When this is enabled, the TWI master can define the starting address of every application memory page being uploaded. If it's disabled, enabling AUTO\_PAGE\_ADDR becomes mandatory. In such cases, applications can only be flashed starting from page 0 since the page address auto-increase works that way. This is OK for most applications. (Default: false). +* **TWO\_STEP\_INIT**: If this is enabled, Timonel expects a two-step initialization from an I2C master before running the exit, memory erase and write commands. This is a safety measure to avoid an unexpected bootloader initialization, which enables memory functions, due to bus noise. When it's disabled, only a single-step initialization is required. (Default: false). +* **USE\_WDT\_RESET**: If this is enabled, the bootloader uses the watchdog timer for resetting instead of jumping to TIMONEL\_START. This reset is more similar to a power-on reset. It could be useful to start the user application from a "cleanest" state if required. (Default: true). +* ~~**CHECK\_EMPTY\_FL**: If this is enabled, when running GETTMNLV command, the bootloader will read the first 100 flash memory positions to check if there is an application (or some other data) loaded in flash memory. The true/false outcome is informed as part of the GETTMNLV command reply packet. (Default: false)~~. **Deprecated in v1.4!** +* **TIMEOUT_EXIT**: If this option is set to true, the user application loaded will **NOT** start automatically after a timeout when the bootloader is not initialized. It always has to be launched by the TWI master (Default: false). +* **CMD\_READFLASH**: This option enables the READFLSH command, which is used by the TWI master for dumping the device's whole memory contents for debugging purposes. It can also be useful for backing up the flash memory before flashing a new firmware. (Default: false). +* **AUTO\_CLK\_TWEAK**: When this feature is enabled, the clock speed adjustment is made at run time based on the low fuse setup. It works only for internal CPU clock configurations: RC oscillator or HF PLL. (Default: false). +* **FORCE\_ERASE\_PG**: If this option is enabled, each flash memory page is erased before writing new data. Normally, it shouldn't be necessary to enable it. (Default: false). +* **CLEAR\_BIT\_7\_R31**: This is to avoid that the first bootloader instruction is skipped after restarting without an user application in memory. See: http://www.avrfreaks.net/comment/2561866#comment-2561866. (Default: false). +* **CHECK\_PAGE\_IX**: If this option is enabled, the page index size is checked to ensure that isn't bigger than SPM\_PAGESIZE (64 bytes in an ATtiny85). This keeps the app data integrity in case the master sends wrong page sizes. (Default: false). diff --git a/timonel-bootloader/timonel.c b/timonel-bootloader/timonel.c index 81df3e3d..d5d9229b 100644 --- a/timonel-bootloader/timonel.c +++ b/timonel-bootloader/timonel.c @@ -8,7 +8,7 @@ * Timonel - TWI Bootloader for TinyX5 MCUs * Author: Gustavo Casanova * ........................................... - * Version: 1.4 "Sandra" / 2019-04-07 (Cati) + * Version: 1.4 "Sandra" / 2019-10-29 * gustavo.casanova@nicebots.com */ diff --git a/timonel-bootloader/timonel.h b/timonel-bootloader/timonel.h index 309879cb..61a18495 100644 --- a/timonel-bootloader/timonel.h +++ b/timonel-bootloader/timonel.h @@ -4,7 +4,7 @@ * ........................................... * File: timonel.h (Main bootloader headers) * ........................................... - * Version: 1.4 "Sandra" / 2019-08-09 (BENI) + * Version: 1.4 "Sandra" / 2019-10-29 * gustavo.casanova@nicebots.com * ........................................... */ diff --git a/timonel-hexparser/README.md b/timonel-hexparser/README.md index 03ff20b2..5a9b19f7 100644 --- a/timonel-hexparser/README.md +++ b/timonel-hexparser/README.md @@ -1,7 +1,6 @@ -Timonel Hexparser -================= +# Timonel Hexparser -This utility converts a ".hex" binary file into a ".h" file which contains a byte array to be included in "timonel-twim-ss". +This utility converts a ".hex" binary file into a ".h" file which contains a byte array to be included in "timonel-twim-ss" or "timonel-twim-ms". The AVR binary files should be placed into the "appl-flashable" folder. They can be generated using any editor + the avr-gcc toolchain, Atmel Studio 7 or the Arduino IDE. If you use Arduino IDE, the compiled .hex files are a bit hard to find, use these instructions to find them: "https://arduino.stackexchange.com/questions/48431/how-to-get-the-firmware-hex-file-from-a-ino-file-containing-the-code". @@ -11,4 +10,4 @@ Once that you have the desired .hex in the "appl-flashable" folder, just run The script leaves a ".h" file with the same name of the ATtiny firmware file into the "appl-payload" and "timonel-twim-ss/data/payloads" folders. -The "timonel-twim-ss" application must be recompiled and flashed to the master device before being able to flash the payload to the AVR device running Timonel. +The "timonel-twim-ss" application must be recompiled and flashed to the master device before being able to flash the payload to the AVR device running Timonel. \ No newline at end of file diff --git a/timonel-hexparser/tml-hexparser.c b/timonel-hexparser/tml-hexparser.c index c8db7420..771c160f 100644 --- a/timonel-hexparser/tml-hexparser.c +++ b/timonel-hexparser/tml-hexparser.c @@ -1,16 +1,16 @@ /* ******************************************************* * Timonel Intel Hex Parser * - * Version: 0.3 | For Unix & Windows * + * Version: 0.3 "Cati" | For Unix & Windows * * ................................................... * - * 2018-07-14 gustavo.casanova@nicebots.com * + * 2018-04-07 gustavo.casanova@nicebots.com * * ................................................... * * Based on code from BootloadHID project * * ................................................... * * NOTE: * * ----- * * To compile on Windows, you need to install "MinGW" * - * with, at least the "mingw32-base" package from * + * with, at least, the "mingw32-base" package from * * the installation manager. You also have to verify * * that your path variable includes "C:\MinGW\bin". * ******************************************************* diff --git a/timonel-twim-ms/README.md b/timonel-twim-ms/README.md index 3d67451b..88035965 100644 --- a/timonel-twim-ms/README.md +++ b/timonel-twim-ms/README.md @@ -1,8 +1,7 @@ -Timonel TWI master - Multi slave -================================ +# Timonel TWI master - Multi slave -This test application [shows](https://youtu.be/PM9X1thrdOY) the usage of TWI master libraries. +This ESP8266/Arduino test application [shows](https://youtu.be/PM9X1thrdOY) the usage of TWI master libraries. -It is a serial console-based application, Arduino-compatible, that runs a 3-time loop that flashes, deletes and runs a user application on three Tiny85's (two bare chips and a Digispark). +It is a serial console-based application that runs a 3-time loop that flashes, deletes and runs a user application on three Tiny85's (two bare chips and a Digispark). -The application has been tested on ESP-01 and NodeMCU modules. It is compiled and flashed to the device using __PlatformIO__ over __VS Code__. +The application has been tested on ESP-01 and NodeMCU modules. It is compiled and flashed to the device using [PlatformIO](http://platformio.org) over [VS Code](http://code.visualstudio.com). \ No newline at end of file diff --git a/timonel-twim-ms/get-github-lib.py b/timonel-twim-ms/get-github-lib.py new file mode 100644 index 00000000..7718a511 --- /dev/null +++ b/timonel-twim-ms/get-github-lib.py @@ -0,0 +1,25 @@ +import os + +Import("env") + +PR_LIB_DIR = "." +GITHUB_USR = "casanovg" +GITHUB_REP = "timonel" +GITHUB_BRN = "master" +GITHUB_TAG = "v1.4" +NBLIBS_DIR = env.subst("$PROJECT_DIR/" + PR_LIB_DIR) + +LIB_DEPS = "nb-libs/cmd " +LIB_DEPS += "nb-libs/twim " + +if not os.path.exists(NBLIBS_DIR + "/.git"): + print ("Getting " + GITHUB_REP + " repository libraries into this project ... ") + env.Execute("git init " + PR_LIB_DIR) + os.chdir(PR_LIB_DIR) + env.Execute("git remote add -t " + GITHUB_BRN + " -f origin https://github.com/" + GITHUB_USR + "/" + GITHUB_REP + ".git") + env.Execute("git sparse-checkout init") + env.Execute("git sparse-checkout set " + LIB_DEPS) + env.Execute("git checkout -f tags/" + GITHUB_TAG) +else: + print ("Checking " + GITHUB_REP + " repository updates ... ") + env.Execute("git --work-tree=$PROJECT_DIR/" + PR_LIB_DIR + " --git-dir=$PROJECT_DIR/" + PR_LIB_DIR + "/.git checkout -f tags/" + GITHUB_TAG) diff --git a/timonel-twim-ms/platformio.ini b/timonel-twim-ms/platformio.ini index 115477ae..84f18c5a 100644 --- a/timonel-twim-ms/platformio.ini +++ b/timonel-twim-ms/platformio.ini @@ -14,11 +14,16 @@ platform = espressif8266 board = nodemcuv2 ;board = esp01_1m framework = arduino -lib_deps_builtin = Wire -lib_extra_dirs = ../nb-libs -lib_extra_dirs = ../nb-libs/twim + +lib_extra_dirs = + nb-libs/twim + nb-libs + build_flags = -I data/payloads -D PROJECT_NAME=timonel-twim-ms -fexceptions -extra_scripts = pre:project_name.py + +extra_scripts = + pre:set-bin-name.py + pre:get-github-lib.py diff --git a/timonel-twim-ms/project_name.py b/timonel-twim-ms/set-bin-name.py similarity index 100% rename from timonel-twim-ms/project_name.py rename to timonel-twim-ms/set-bin-name.py diff --git a/timonel-twim-ms/src/main.cpp b/timonel-twim-ms/src/timonel-twim-ms.cpp similarity index 97% rename from timonel-twim-ms/src/main.cpp rename to timonel-twim-ms/src/timonel-twim-ms.cpp index 99765eba..dccb802f 100644 --- a/timonel-twim-ms/src/main.cpp +++ b/timonel-twim-ms/src/timonel-twim-ms.cpp @@ -1,7 +1,7 @@ /* main.cpp (timonel-twim-ms) ========================== - Timonel library test program (Multi Slave) v1.4 "Beni" + Timonel library test program (Multi Slave) v1.4 ---------------------------------------------------------------------------- This demo shows how to control and update several Tiny85 microcontrollers running the Timonel bootloader from an ESP8266 master. @@ -23,10 +23,10 @@ 7) Repeats the routine 3 times. */ -//#include -//#include -#include "NbMicro.h" -#include "TimonelTwiM.h" +#include +#include +#include + #include "payload.h" #define USE_SERIAL Serial @@ -115,7 +115,7 @@ void setup() { if (errors == 0) { USE_SERIAL.printf_P("OK!\n\r"); } else { - USE_SERIAL.printf_P("Error!\n\r", errors); + USE_SERIAL.printf_P("Error! (%d)\n\r", errors); } delay(1000); USE_SERIAL.printf_P("\n\rGetting status of device %d\n\r", dev_info_arr[i].addr); @@ -133,7 +133,7 @@ void setup() { if (errors == 0) { USE_SERIAL.printf_P("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b successful! \n\r"); } else { - USE_SERIAL.printf_P("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b error! \n\r", errors); + USE_SERIAL.printf_P("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b error! (%d) \n\r", errors); } delay(10); USE_SERIAL.printf_P("\n\rGetting status of device %d\n\r", dev_info_arr[i].addr); diff --git a/timonel-twim-ss/.gitignore b/timonel-twim-ss/.gitignore index 0e3b4677..4808399d 100644 --- a/timonel-twim-ss/.gitignore +++ b/timonel-twim-ss/.gitignore @@ -4,3 +4,4 @@ .piolibdeps .clang_complete .gcc-flags.json +nb-lib/ diff --git a/timonel-twim-ss/README.md b/timonel-twim-ss/README.md index eb4a7b9d..3e38d36b 100644 --- a/timonel-twim-ss/README.md +++ b/timonel-twim-ss/README.md @@ -1,16 +1,12 @@ -Timonel TWI master - Single slave -================================= +# Timonel TWI master - Single slave -This test application [shows](http://youtu.be/-7GOMToGvzI) the usage of TWI master libraries. +This ESP8266/Arduino test application [shows](http://youtu.be/-7GOMToGvzI) the usage of TWI master libraries. -It is a serial console-based application, Arduino-compatible, that allows sending commands to a device that runs the Timonel bootloader. Its main functions are: +It is a serial console-based application that allows sending commands to a device that runs the Timonel bootloader. Its main functions are: * Searches a device running Timonel bootloader on the TWI bus and initializes it. - * Uploads an application to the device. The application to send to the AVR bootloader (payload) is compiled as part of this TWI master application. The utility "timonel-hexparser" is used to convert an AVR application into a TWI master payload. - * Deletes the application from the AVR device memory. - * Optionally, it makes an on-screen dump of all the device's memory for debugging. -The application has been tested on ESP-01 and NodeMCU modules. It is compiled and flashed to the device using __PlatformIO__ over __VS Code__. +The application has been tested on ESP-01 and NodeMCU modules. It is compiled and flashed to the device using [PlatformIO](http://platformio.org) over [VS Code](http://code.visualstudio.com). \ No newline at end of file diff --git a/timonel-twim-ss/get-github-lib.py b/timonel-twim-ss/get-github-lib.py new file mode 100644 index 00000000..7718a511 --- /dev/null +++ b/timonel-twim-ss/get-github-lib.py @@ -0,0 +1,25 @@ +import os + +Import("env") + +PR_LIB_DIR = "." +GITHUB_USR = "casanovg" +GITHUB_REP = "timonel" +GITHUB_BRN = "master" +GITHUB_TAG = "v1.4" +NBLIBS_DIR = env.subst("$PROJECT_DIR/" + PR_LIB_DIR) + +LIB_DEPS = "nb-libs/cmd " +LIB_DEPS += "nb-libs/twim " + +if not os.path.exists(NBLIBS_DIR + "/.git"): + print ("Getting " + GITHUB_REP + " repository libraries into this project ... ") + env.Execute("git init " + PR_LIB_DIR) + os.chdir(PR_LIB_DIR) + env.Execute("git remote add -t " + GITHUB_BRN + " -f origin https://github.com/" + GITHUB_USR + "/" + GITHUB_REP + ".git") + env.Execute("git sparse-checkout init") + env.Execute("git sparse-checkout set " + LIB_DEPS) + env.Execute("git checkout -f tags/" + GITHUB_TAG) +else: + print ("Checking " + GITHUB_REP + " repository updates ... ") + env.Execute("git --work-tree=$PROJECT_DIR/" + PR_LIB_DIR + " --git-dir=$PROJECT_DIR/" + PR_LIB_DIR + "/.git checkout -f tags/" + GITHUB_TAG) diff --git a/timonel-twim-ss/platformio.ini b/timonel-twim-ss/platformio.ini index 34d4d597..7794f586 100644 --- a/timonel-twim-ss/platformio.ini +++ b/timonel-twim-ss/platformio.ini @@ -9,16 +9,21 @@ ; https://docs.platformio.org/page/projectconf.html [env:nodemcuv2] -board = nodemcuv2 ;[env:esp01_1m] -;board = esp01_1m platform = espressif8266 +board = nodemcuv2 +;board = esp01_1m framework = arduino -;lib_deps_builtin = Wire -lib_extra_dirs = ../nb-libs -lib_extra_dirs = ../nb-libs/twim + +lib_extra_dirs = + nb-libs/twim + nb-libs + build_flags = -I data/payloads -D PROJECT_NAME=timonel-twim-ss -fexceptions -extra_scripts = pre:project_name.py + +extra_scripts = + pre:set-bin-name.py + pre:get-github-lib.py diff --git a/timonel-twim-ss/project_name.py b/timonel-twim-ss/set-bin-name.py similarity index 100% rename from timonel-twim-ss/project_name.py rename to timonel-twim-ss/set-bin-name.py diff --git a/timonel-twim-ss/src/main.cpp b/timonel-twim-ss/src/timonel-twim-ss.cpp similarity index 95% rename from timonel-twim-ss/src/main.cpp rename to timonel-twim-ss/src/timonel-twim-ss.cpp index 615c3447..a2ad0c77 100644 --- a/timonel-twim-ss/src/main.cpp +++ b/timonel-twim-ss/src/timonel-twim-ss.cpp @@ -1,25 +1,25 @@ /* - main.cpp (timonel-twim-ss) - ========================== - Timonel library test program (Single Slave) v1.4 "Valen" + timonel-twim-ss.cpp + =================== + Timonel library test program (Single Slave) v1.4 ---------------------------------------------------------------------------- This demo implements an I2C serial commander to control interactively a Tiny85 microcontroller running the Timonel bootloader from an ESP8266 master. It uses a serial console configured at 9600 N 8 1 for feedback. ---------------------------------------------------------------------------- - 2019-03-19 Gustavo Casanova + 2020-04-29 Gustavo Casanova ---------------------------------------------------------------------------- -*/ - -//#include -//#include -#include "NbMicro.h" -#include "TimonelTwiM.h" +*/ + +#include +#include +#include + #include "payload.h" #define USE_SERIAL Serial -#define SDA 0 /* I2C SDA pin */ -#define SCL 2 /* I2C SCL pin */ +#define SDA 0 /* I2C SDA pin */ +#define SCL 2 /* I2C SCL pin */ // Prototypes void setup(void); @@ -41,7 +41,7 @@ byte block_rx_size = 0; bool new_key = false; bool new_byte = false; bool new_word = false; -bool app_mode = false; /* This holds the slave device running mode info: bootloader or application */ +bool app_mode = false; /* This holds the slave device running mode info: bootloader or application */ char key = '\0'; word flash_page_addr = 0x0; word timonel_start = 0xFFFF; /* Timonel start address, 0xFFFF means 'not set' */ @@ -51,7 +51,7 @@ Timonel tml; /* From now on, we'll keep a Timonel instance active */ // Setup block void setup() { bool *p_app_mode = &app_mode; /* This is to take different actions depending on whether the bootloader or the application is active */ - USE_SERIAL.begin(9600); /* Initialize the serial port for debugging */ + USE_SERIAL.begin(9600); /* Initialize the serial port for debugging */ //Wire.begin(SDA, SCL); ClrScr(); delay(150); @@ -96,11 +96,11 @@ void loop() { USE_SERIAL.printf_P("\n .\n\r . .\n\r. . .\n\n\r"); Wire.begin(SDA, SCL); delay(500); -// #if ESP8266 -// ESP.restart(); -// #else -// resetFunc(); -// #endif /* ESP8266 */ + // #if ESP8266 + // ESP.restart(); + // #else + // resetFunc(); + // #endif /* ESP8266 */ break; } // ****************** @@ -153,8 +153,7 @@ void loop() { USE_SERIAL.printf_P("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); if (cmd_errors == 0) { USE_SERIAL.printf_P(" successful "); - } - else { + } else { USE_SERIAL.printf_P(" [ command error! %d ]", cmd_errors); } USE_SERIAL.printf_P("\n\n\r"); @@ -199,17 +198,16 @@ void loop() { case 'W': { USE_SERIAL.printf_P("\n\rBootloader Cmd >>> Upload app firmware to flash memory, \x1b[5mPLEASE WAIT\x1b[0m ..."); byte cmd_errors = tml.UploadApplication(payload, sizeof(payload), flash_page_addr); - USE_SERIAL.printf_P("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + USE_SERIAL.printf_P("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); if (cmd_errors == 0) { USE_SERIAL.printf_P(" successful "); - } - else { + } else { USE_SERIAL.printf_P(" [ command error! %d ]", cmd_errors); } USE_SERIAL.printf_P("\n\n\r"); break; } -#if ((defined FEATURES_CODE) && ((FEATURES_CODE >> F_CMD_READFLASH) & true)) +#if ((defined FEATURES_CODE) && ((FEATURES_CODE >> F_CMD_READFLASH) & true)) // ******************************** // * Timonel ::: READFLSH command * // ******************************** @@ -334,7 +332,7 @@ void PrintStatus(Timonel timonel) { } USE_SERIAL.printf_P("\n\r Timonel v%d.%d %s ", version_major, version_minor, version_mj_nick.c_str()); USE_SERIAL.printf_P("(TWI: %02d)\n\r", twi_address); - USE_SERIAL.printf_P(" ====================================\n\r"); + USE_SERIAL.printf_P(" ====================================\n\r"); USE_SERIAL.printf_P(" Bootloader address: 0x%X\n\r", tml_status.bootloader_start); word app_start = tml_status.application_start; if (app_start != 0xFFFF) { @@ -410,4 +408,3 @@ void ListTwiDevices(byte sda, byte scl) { } USE_SERIAL.printf_P("...........................................................\n\n\r"); } - diff --git a/timonel-updater/README.md b/timonel-updater/README.md index a3b08c05..7b40f5d5 100644 --- a/timonel-updater/README.md +++ b/timonel-updater/README.md @@ -1,11 +1,10 @@ -Timonel Updater -=============== +# Timonel Updater -__NOTE:__ This bootloader updater has been included from the micronucleus project: github.com/micronucleus +__NOTE:__ This bootloader updater has been included from the [micronucleus](github.com/micronucleus) project. Usage: ------ -To simplify the step necesary to generate a bootloader update payload, use the __make-updater.sh__ script. If the script is run without arguments, it will generate a default-configuration based bootloader payload. The supported arguments are positional, as follows: +To simplify the steps necesary to generate a bootloader update payload, use the __make-updater.sh__ script. If the script is run without arguments, it will generate a default-configuration based bootloader payload. The supported arguments are positional, as follows: * __CONFIG__: Timonel configuration option to use. (Def=tml-t85-std). @@ -85,3 +84,6 @@ Taking inspiration from computer viruses, when upgrade runs it goes through this forwarding any requests to the new bootloader's interrupt vector table. At this point the viral upgrader has completed it's life cycle and has disabled itself. It should never run again, booting directly in to the bootloader instead. + diff --git a/tools/README.md b/tools/README.md index 7d19cd46..ffb28b4e 100644 --- a/tools/README.md +++ b/tools/README.md @@ -1,5 +1,5 @@ -Tools -===== +# Tools + Here there are several worksheets for bootloader parameters calculations. The release v1.4 has been compiled with avr-gcc 8.3.0 64-bit located [here](https://github.com/casanovg/avr-toolchains) ...