Unified interface for selecting different implementations for communicating with a TM1637 LED controller chip on Arduino platforms

AceTMI

Validation

Unified interface for communicating with a TM1637 LED controller chip on Arduino platforms. The code was initially part of the AceSegment library, but was extracted into a separate library for consistency with the AceWire and AceSPI libraries. It provides the following implementations:

  • SimpleTmiInterface
    • Implements the TM1637 protocol using digitalWrite().
  • SimpleTmiFastInterface
    • Implements the TM1637 protocol using digitalWriteFast().
    • Consumes 4X less flash memory than SimpleTmiInterface (182 bytes versus 744 bytes).
    • Over 9X faster than SimpleTmiInterface (386 kbps versus 41 kbps).

The "TMI" acronym was invented by this library to name the protocol used by the TM1637 chip. It stands for "Titan Micro Interface", named after Titan Micro Electronics which manufactures the TM1637 chip. The TM1637 protocol is electrically very similar to I2C, but different enough that we cannot use the <Wire.h> I2C library.

The protocol implemented by this library works only for the TM1637 chip as far as I know. Most people will want to use the Tm1637Module class in the AceSegment library instead of using this lower-level library.

The library uses C++ templates to achieve minimal runtime overhead. In more technical terms, the library provides compile-time polymorphism instead of runtime polymorphism to avoid the overhead of the virtual keyword.

Version: 0.3 (2021-08-17)

Changelog: CHANGELOG.md

See Also:

Table of Contents

Installation

The latest stable release is available in the Arduino IDE Library Manager. Search for "AceTMI". Click install.

The development version can be installed by cloning the GitHub repository, checking out the default develop branch, then manually copying over to or symlinking from the ./libraries directory used by the Arduino IDE. (The result is a directory or link named ./libraries/AceTMI.)

The master branch contains the stable releases.

Source Code

The source files are organized as follows:

  • src/AceTMI.h - main header file
  • src/ace_tmi/ - implementation files
  • docs/ - contains the doxygen docs and additional manual docs

Dependencies

The main AceTMI.h does not depend any external libraries.

The "Fast" version (SimpleTmiFastInterface.h) depends on one of the digitalWriteFast libraries, for example:

Documentation

Usage

Include Header and Namespace

In many cases, only a single header file AceTMI.h is required to use this library. To prevent name clashes with other libraries that the calling code may use, all classes are defined in the ace_tmi namespace. To use the code without prepending the ace_tmi:: prefix, use the using directive:

#include <Arduino.h>
#include <AceTMI.h>
using ace_tmi::SimpleTmiInterface;

The "Fast" versions are not included automatically by AceTMI.h because they work only on AVR processors and they depend on a <digitalWriteFast.h> library. To use the "Fast" versions, use something like the following:'

#include <Arduino.h>
#include <AceTMI.h>

#if defined(ARDUINO_ARCH_AVR)
  #include <digitalWriteFast.h>
  #include <ace_tmi/SimpleTmiFastInterface.h>
  using ace_tmi::SimpleTmiFastInterface;
#endif

Unified Interface

The classes in this library provide the following unified interface for handling communication with the TM1637 chip. Downstream classes can code against this generic API using C++ templates so that different implementations can be selected at compile-time.

class XxxInterface {
  public:
    void begin() const;
    void end() const;

    void startCondition() const;
    void stopCondition() const;
    uint8_t write(uint8_t data) const;
};

Notice that the classes in this library do not inherit from a common interface with virtual functions. This saves several hundred bytes of flash memory on 8-bit AVR processors by avoiding the dynamic dispatch, and often allows the compiler to optimize away the overhead of calling the methods in this library so that the function call is made directly to the underlying implementation. The reduction of flash memory consumption is especially large for classes that use the digitalWriteFast libraries which use compile-time constants for pin numbers. The disadvantage is that this library is harder to use because these classes require the downstream classes to be implemented using C++ templates.

SimpleTmiInterface

The SimpleTmiInterface can be used like this to communicate with a TM1637 controller chip. It looks like this:

class SimpleTmiInterface {
  public:
    explicit SimpleTmiInterface(
        uint8_t dioPin,
        uint8_t clkPin,
        uint8_t delayMicros
    );

    void begin() const;
    void end() const;

    void startCondition() const;
    void stopCondition() const;
    uint8_t write(uint8_t data) const;
};

It is configured and used by the calling code MyClass like this:

#include <Arduino.h>
#include <AceTMI.h>
using ace_tmi::SimpleTmiInterface;

template <typename T_TMII>
class MyClass {
  public:
    explicit MyClass(T_TMII& tmiInterface)
        : mTmiInterface(tmiInterface)
    {...}

    void sendData() {
      // Set addressing mode.
      mTmiInterface.startCondition();
      mTmiInterface.write(addressMode);
      mTmiInterface.stopCondition();

      // Send data bytes.
      mTmiInterface.startCondition();
      mTmiInterface.write(otherCommand);
      [...]
      mTmiInterface.stopCondition();

      // Set brightness.
      mTmiInterface.startCondition();
      mTmiInterface.write(brightness);
      mTmiInterface.stopCondition();
    }

  private:
    T_TMII mTmiInterface; // copied by value
};

const uint8_t CLK_PIN = 8;
const uint8_t DIO_PIN = 9;
const uint8_t DELAY_MICROS = 100;

using TmiInterface = SimpleTmiInterface;
TmiInterface tmiInterface(DIO_PIN, CLK_PIN, DELAY_MICROS);
MyClass<TmiInterface> myClass(tmiInterface);

void setup() {
  tmiInterface.begin();
  ...
}

The using statement is the C++11 version of a typedef that defines TmiInterface. It is not strictly necessary here, but it allows the same pattern to be used for the more complicated examples below.

The T_TMII template parameter contains a T_ prefix to avoid name collisions with too many #define macros defined in the global namespace on Arduino platforms. The double II contains 2 Interface, the first referring to the TM1637 protocol, and the second referring to classes in this library.

SimpleTmiFastInterface

The SimpleTmiFastInterface is identical to SimpleTmiInterface except that it uses digitalWriteFast(). It looks like this:

template <
    uint8_t T_DIO_PIN,
    uint8_t T_CLK_PIN,
    uint8_t T_DELAY_MICROS
>
class SimpleTmiFastInterface {
  public:
    explicit SimpleTmiFastInterface() = default;

    void begin() const;
    void end() const;

    void startCondition() const;
    void stopCondition() const;
    uint8_t write(uint8_t data) const;
};

It is configured and used by the calling code MyClass like this:

#include <Arduino.h>
#include <AceTMI.h>
#if defined(ARDUINO_ARCH_AVR)
  #include <digitalWriteFast.h>
  #include <ace_tmi/SimpleTmiFastInterface.h>
  using ace_tmi::SimpleTmiInterface;
#endif

const uint8_t CLK_PIN = 8;
const uint8_t DIO_PIN = 9;
const uint8_t DELAY_MICROS = 100;

template <typename T_TMII>
class MyClass {
  // Exactly same as above.
};

using TmiInterface = SimpleTmiFastInterface<DIO_PIN, CLK_PIN, DELAY_MICROS>;
TmiInterface tmiInterface;
MyClass<TmiInterface> myClass(tmiInterface);

void setup() {
  tmiInterface.begin();
  ...
}

Storing Interface Objects

In the above examples, the MyClass object holds the T_TMII interface object by value. In other words, the interface object is copied into the MyClass object. This is efficient because interface objects are very small in size, and copying them by-value avoids an extra level of indirection when they are used inside the MyClass object.

The alternative is to save the T_TMII object by reference like this:

template <typename T_TMII>
class MyClass {
  public:
    explicit MyClass(T_TMII& tmiInterface)
        : mTmiInterface(tmiInterface)
    {...}

    [...]

  private:
    T_TMII& mTmiInterface; // copied by reference
};

The internal size of the SimpleTmiInterface object is just 3 bytes, and the size of the SimpleTmiFastInterface is even smaller at 0 bytes, so we do not save much memory by storing these by reference. But storing the mTmiInterface as a reference causes an unnecessary extra layer of indirection every time the mTmiInterface object is called. In almost every case, I recommend storing the XxxInterface object by value into the MyClass object.

Resource Consumption

Flash And Static Memory

The Memory benchmark numbers can be seen in examples/MemoryBenchmark. Here are 2 samples:

Arduino Nano

+--------------------------------------------------------------+
| functionality                   |  flash/  ram |       delta |
|---------------------------------+--------------+-------------|
| baseline                        |    456/   11 |     0/    0 |
|---------------------------------+--------------+-------------|
| SimpleTmiInterface              |   1200/   14 |   744/    3 |
| SimpleTmiFastInterface          |    638/   11 |   182/    0 |
+--------------------------------------------------------------+

ESP8266

+--------------------------------------------------------------+
| functionality                   |  flash/  ram |       delta |
|---------------------------------+--------------+-------------|
| baseline                        | 256700/26784 |     0/    0 |
|---------------------------------+--------------+-------------|
| SimpleTmiInterface              | 257588/26796 |   888/   12 |
+--------------------------------------------------------------+

CPU Cycles

The CPU benchmark numbers can be seen in examples/AutoBenchmark. Here are 2 samples:

Arduino Nano

+-----------------------------------------+-------------------+----------+
| Functionality                           |   min/  avg/  max | eff kbps |
|-----------------------------------------+-------------------+----------|
| SimpleTmiInterface,1us                  |   752/  781/  836 |     41.0 |
| SimpleTmiFastInterface,1us              |    76/   83/   84 |    385.5 |
+-----------------------------------------+-------------------+----------+

ESP8266

+-----------------------------------------+-------------------+----------+
| Functionality                           |   min/  avg/  max | eff kbps |
|-----------------------------------------+-------------------+----------|
| SimpleTmiInterface,1us                  |   392/  395/  433 |     81.0 |
+-----------------------------------------+-------------------+----------+

System Requirements

Hardware

This library has Tier 1 support on the following boards:

  • Arduino Nano (16 MHz ATmega328P)
  • SparkFun Pro Micro (16 MHz ATmega32U4)
  • SAMD21 M0 Mini (48 MHz ARM Cortex-M0+)
  • STM32 Blue Pill (STM32F103C8, 72 MHz ARM Cortex-M3)
  • NodeMCU 1.0 (ESP-12E module, 80MHz ESP8266)
  • WeMos D1 Mini (ESP-12E module, 80 MHz ESP8266)
  • ESP32 dev board (ESP-WROOM-32 module, 240 MHz dual core Tensilica LX6)
  • Teensy 3.2 (72 MHz ARM Cortex-M4)

Tier 2 support can be expected on the following boards, mostly because I don't test these as often:

  • ATtiny85 (8 MHz ATtiny85)
  • Arduino Pro Mini (16 MHz ATmega328P)
  • Teensy LC (48 MHz ARM Cortex-M0+)
  • Mini Mega 2560 (Arduino Mega 2560 compatible, 16 MHz ATmega2560)

The following boards are not supported:

Tool Chain

Operating System

I use Ubuntu 20.04 for the vast majority of my development. I expect that the library will work fine under MacOS and Windows, but I have not explicitly tested them.

License

MIT License

Feedback and Support

If you have any questions, comments, or feature requests for this library, please use the GitHub Discussions for this project. If you have bug reports, please file a ticket in GitHub Issues. Feature requests should go into Discussions first because they often have alternative solutions which are useful to remain visible, instead of disappearing from the default view of the Issue tracker after the ticket is closed.

Please refrain from emailing me directly unless the content is sensitive. The problem with email is that I cannot reference the email conversation when other people ask similar questions later.

Authors

Created by Brian T. Park ([email protected]).

Comments
  • merge 0.6 into master

    merge 0.6 into master

    • 0.6 (2022-03-01)
      • Add Tm1638::read() method to read the keypad data from the TM1638 controller.
      • Add Tm1637::read() method to read the keypad data from the TM1637 controller.
      • Potentially Breaking: Change SimpleTmi1638Interface::write() and SimpleTmi1638FastInterface::write() to return void instead of uint8_t since it was hardcoded to return 0.
  • merge v0.5 into master

    merge v0.5 into master

    • 0.5 (2022-02-02)
      • Breaking Change: Rename TM1637 classes for consistency with TM1638 classes.
        • Rename SimpleTmiInterface to SimpleTmi1637Interface.
        • Rename SimpleTmiFastInterface to SimpleTmi1637FastInterface.
  • merge v0.4 into master

    merge v0.4 into master

    • 0.4 (2022-02-01)
      • Add support for the TM1638 controller which uses an SPI-like protocol.
        • Add SimpleTmi1638Interface and SimpleTmi1638FastInterface.
      • Upgrade tool chain and regenerate MemoryBenchmark and AutoBenchmark.
        • Arduino IDE from 1.8.13 to 1.8.19
        • Arduino CLI from 0.14.0 to 0.19.2
        • Arduino AVR Core from 1.8.3 to 1.8.4
        • STM32duino from 2.0.0 to 2.2.0
        • ESP8266 Core from 2.7.4 to 3.0.2
        • ESP32 Core from 1.0.6 to 2.0.2
        • Teensyduino from 1.53 to 1.56
  • merge v0.3 into master

    merge v0.3 into master

    • 0.3 (2021-08-17)
      • Rename sendByte() to write() for consistency with the API of AceWire and TwoWire, since the TM1637 protocol is very similar to I2C.
        • Also avoids confusion with the send8() and send16() methods of AceSPI which include the beginTransaction() and endTransaction().
        • The write() methods do not include the start and stop conditions.
  • merge v0.2 into master

    merge v0.2 into master

    • 0.2 (2021-07-30)
      • Add examples/MemoryBenchmark and examples/AutoBenchmark to calculate memory consumption and CPU speed.
      • Invert return value of writeByte(), returning 1 on success and 0 on failure. Matches the return values of AceWire implementations.
      • Add GitHub workflow validation of examples/*.
      • Rename SoftTmi*Interface to SimpleTmi*Interface.
Related tags
Unified interface for selecting hardware or software SPI implementations on Arduino platforms

AceSPI Unified interface for selecting hardware or software SPI implementations on Arduino platforms. The code was initially part of the AceSegment li

Oct 22, 2021
Arduino library for SPI and I2C access to the PN532 RFID/Near Field Communication chip

Adafruit-PN532 This is a library for the Adafruit PN532 NFC/RFID breakout boards This library works with the Adafruit NFC breakout https://www.adafrui

Dec 23, 2022
MCP2515 CAN Controller Driver for Arduino

MCP2515 CAN Controller Library for Arduino Compatibility with the ACAN library This library is fully compatible with the Teensy 3.x ACAN library https

Dec 13, 2022
Arduino library for the MCP2515 CAN Controller

MCP2515 CAN Controller Library for Arduino Compatibility with the ACAN library This library is fully compatible with the Teensy 3.x ACAN library https

Dec 18, 2022
Arduino CAN driver for MCP2517FD CAN Controller (in CAN 2.0B mode)

MCP2517FD CAN Controller Library for Arduino (in CAN 2.0B mode) Compatibility with the other ACAN libraries This library is fully compatible with the

Dec 22, 2022
Distribution of Arduino driver for MCP2517FD CAN controller (CANFD mode)

MCP2517FD and MCP2518FD CAN Controller Library for Arduino (in CAN FD mode) Compatibility with the other ACAN libraries This library is fully compatib

Dec 21, 2022
Library for auto Light Emitting Diode (LED) control based on the timer function of the ESP8266

Library for auto Light Emitting Diode (LED) control based on the timer function of the ESP8266. The purpose is to have LED running for their own without the need to to such things like blinking on your own.

Jan 18, 2022
Arduino library for providing a convenient C++ interface for accessing UAVCAN.
Arduino library for providing a convenient C++ interface for accessing UAVCAN.

107-Arduino-UAVCAN Arduino library for providing a convenient C++ interface for accessing UAVCAN (v1.0-beta) utilizing libcanard. This library works f

Jan 2, 2023
Arduino-compatible library to interface RC1701HP-OSP/WIZE radio modules.
Arduino-compatible library to interface RC1701HP-OSP/WIZE radio modules.

AllWize Arduino-compatible library to interface RC1701HP-OSP/WIZE radio modules. Compatible radios: RadioCrafts RC1701HP-OSP (Ondeo version) RadioCraf

Aug 3, 2022
Arduino Arduino library for the CloudStorage server project. The library provides easy access to server-stored values and operations.

Arduino-CloudStorage Arduino/ESP8266 library that allows you to easly store and retreive data from a remote (cloud) storage in a key/value fashion. Cl

Jan 30, 2022
Arduino library for making an IHC in or output module using an Arduino

Introduction This is an Arduino library for making an IHC in or output module using an Arduino. (IHC controller is a home automation controller made b

Mar 26, 2020
ArduinoIoTCloud library is the central element of the firmware enabling certain Arduino boards to connect to the Arduino IoT Cloud

ArduinoIoTCloud What? The ArduinoIoTCloud library is the central element of the firmware enabling certain Arduino boards to connect to the Arduino IoT

Dec 16, 2022
Leonardo Modifier Keys Controller
Leonardo Modifier Keys Controller

Leonardo Modifier Keys Controller An Arduino Leonardo powered box that allows you to press the modifier keys of the computer. Description An USB devic

May 23, 2022
ESP8266 MQTT Sharp-fu-y30 air purifier controller
ESP8266 MQTT Sharp-fu-y30 air purifier controller

ESP8266 MQTT Sharp-fu-y30 air purifier controller Disclaimer Note: if you decide to do those changes to your air purifier, you take all the responsibi

Dec 6, 2022
Simple web interface builder for esp8266 and ESP32
Simple web interface builder for esp8266 and ESP32

GyverPortal Простой конструктор веб интерфейса для esp8266 и ESP32 Простой конструктор - делаем страницы без знаний HTML и CSS Библиотека является обё

Jan 8, 2023
Arduino library for controlling the MCP2515 in order to receive/transmit CAN frames.
Arduino library for controlling the MCP2515 in order to receive/transmit CAN frames.

107-Arduino-MCP2515 Arduino library for controlling the MCP2515 in order to receive/transmit CAN frames. This library is prepared to interface easily

Nov 16, 2022
Arduino library for interfacing with any GPS, GLONASS, Galileo or GNSS module and interpreting its NMEA messages.
Arduino library for interfacing with any GPS, GLONASS, Galileo or GNSS module and interpreting its NMEA messages.

107-Arduino-NMEA-Parser Arduino library for interfacing with any GPS, GLONASS, Galileo or GNSS module and interpreting its NMEA messages. This library

Jan 1, 2023
A RESTful environment for Arduino

aREST Overview A simple library that implements a REST API for Arduino & the ESP8266 WiFi chip. It is designed to be universal and currently supports

Dec 29, 2022
Arduino web server library.

aWOT Arduino web server library. Documentation 1. Getting started Hello World Basic routing Application generator Serving static files 2. Guide Routin

Jan 4, 2023