Skip to content

Commit

Permalink
Arrange folders and release v1.4
Browse files Browse the repository at this point in the history
  • Loading branch information
Gustavo Casanova committed May 8, 2020
1 parent 1978445 commit e0f8a87
Show file tree
Hide file tree
Showing 40 changed files with 553 additions and 408 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# v1.3
# v1.4
# Prerequisites
*.d

Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -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.
49 changes: 25 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.

Expand All @@ -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).
8 changes: 3 additions & 5 deletions apps/README.md
Original file line number Diff line number Diff line change
@@ -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.
12 changes: 7 additions & 5 deletions nb-libs/README.md
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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.
Expand Down
11 changes: 11 additions & 0 deletions nb-libs/cmd/library.json
Original file line number Diff line number Diff line change
@@ -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"
}
132 changes: 9 additions & 123 deletions nb-libs/twim/NbMicro/NbMicro.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,15 @@
* ...........................................
* File: NbMicro.cpp (Library)
* ...........................................
* Version: 1.4 / 2019-08-09
* Version: 0.9.0 / 2020-04-29
* [email protected]
* ...........................................
* 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 ////////////
Expand Down Expand Up @@ -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);
Expand All @@ -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)) {
Expand Down Expand Up @@ -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 */
Loading

0 comments on commit e0f8a87

Please sign in to comment.