Thursday, March 6, 2014

Arduino library for TM1637 Display Module

Update: A new version has been released, includes control of the colon/decimal points.

I needed a small numerical display for a project I'm working on. I found this one on Dealextream. It looks great - a 4 digit module, with a driver and a serial interface - perfect match for my requirements. The product page mentioned that it is driven by a chip called TM1637. A quick search at Google lead me to an Arduino library, made by SeeedStudio that is capable of communicating with the module.

Three weeks later, I have the module at hand. I'm connecting it to an Arduino board, installing the library and uploading one of the example files. Nothing. Total blackness. On the hardware side, with only two digital pins, it's pretty hard to mess things up, so the suspicion falls on the software. The next step is trying to get the datasheet of the TM1637. The chip is made by a company called Titan Microelectronics, which holds a product page for it. Sadly, the link to the datasheet is broken. Searching again, filtering all the "" etc., I find this datasheet, in plain Chinese. With the help of Google Translate, and SeeedStudio's library, the communication protocol gets revealed. The chip uses the I2C protocol, and the sequence required to write display data is as follows (ST - start condition; SP - stop condition):

  • ST - COMM1 (0x40) - SP
  • ST - COMM2 (0xC0) + the first digit to be written
  • digit1 - digit2 - ... - digit4 - SP
  • ST - COMM3 (0x80) + the display brightness - SP

Having all that at hand, I wrote a new library, implementing this protocol. The library is available at GITHUB, including a sample sketch demonstrating its capabilities. The repository also includes a README file explaining how the library should be used and how the module should be connected to the Arduino.

Why did SeeedStudio's library fail?

Browsing through SeeedStudio's code, I found two problems that might cause it to malfunction.
The first one is this:

  digitalWrite(Clkpin,LOW); //wait for the ACK  

The digital output pins are bit-banged to create the I2C signal, but there's no delay. This gives a toggling rate much beyond the specified 400KHz. It's possible that Seeed were testing their module with an 8MHz Arduino, while my module was 16MHz, raising the toggle rate even further away from the specification.

The second problem also arises from the code snippet above. I2C is wired-and bus, meaning it should never be driven high.When a logic '1' is desirable, the output of the Arduino should be put in high-impedance state allowing the pull-up resistor to pull the line to its high level. This is unlikely to cause an immediate problem, but in the long term it may cause the reliability of the components to degrade.


  1. It's interesting why do you implement I2C protocol? Most mictocontrollers have hardware I2C support.

  2. That's correct, but the problem is that not all peripherals are perfectly compliant with the standard when it comes to start and stop conditions. In a case such as this, when the exact specification of the chip is not well understood, I prefer to be able to manipulate each bit and to be able to read back the acknowledge.

  3. Interesting find, thanks for sharing! I'm trying to get the SeeedStudio sample code to work on a different processor and have had trouble, so maybe I'll give the I2C route a try. So even though you like to bitbang I2C with unknown ICs, have you tried to go back and use hardware I2C to communicate with the TM1637?

  4. Thanks, Working properly
    Been problem in 4 hours, found this information all solved.

  5. Any chance you might add an option to turn on the colon in your library? When building any type of clock app, the colon is rather important.

  6. If you set your digits with display.setSegments then you can set the colon with the 8. bit. From the TM1637Display.cpp from the library:
    const uint8_t digitToSegment[] = {
    0b00111111, // 0
    0b00000110, // 1
    0b01011011, // 2...
    the bit X is the decimal Point or the colon at your display.

    Small example without clock funktion, only blink function of the colon:

    // Module connection pins (Digital Pins)
    #define CLK 2
    #define DIO 3

    TM1637Display display(CLK, DIO);

    unsigned long previousMillis = 0;
    const long interval = 500;
    bool colon = false;
    uint8_t data[] = {
    0b00111111, // 0
    0b00000110, // 1
    0b01011011, // 2
    0b01001111, // 3
    0b01100110, // 4
    0b01101101, // 5
    0b01111101, // 6
    0b00000111, // 7
    0b01111111, // 8
    0b01101111, // 9
    uint8_t dataWithColon[] = {
    0b10111111, // 0
    0b10000110, // 1
    0b11011011, // 2
    0b11001111, // 3
    0b11100110, // 4
    0b11101101, // 5
    0b11111101, // 6
    0b10000111, // 7
    0b11111111, // 8
    0b11101111, // 9

    void setup()

    void loop()
    if(millis() - previousMillis >= interval) {
    previousMillis = millis();
    colon = !colon;
    if (colon == true){
    display.setSegments(data + 1, 1, 0); // Shows on digit 0 the number 1
    display.setSegments(dataWithColon + 4, 1, 1); // Shows on digit 1 the number 4 with colon activated
    display.setSegments(data + 3, 1, 2); // Shows on digit 2 the number 3
    display.setSegments(data + 6, 1, 3); // Shows on digit 3 the number 6
    display.setSegments(data + 1, 1, 0); // Shows on digit 0 the number 1
    display.setSegments(data + 4, 1, 1); // Shows on digit 1 the number 4 with colon deactivated
    display.setSegments(data + 3, 1, 2); // Shows on digit 2 the number 3
    display.setSegments(data + 6, 1, 3); // Shows on digit 3 the number 6

  7. the blog has a problem with single << or >> the first to lines of the example should include


  8. Titan Mec has an English version of the datasheet; possibly added later. Find it here:

  9. If the chip uses the I2C protocol, why then cannot we use SDA and SCL (I tried it with the I2C-scanner program, but no address is returned). I would like to have the two extra pins liberated.