TM1637 Board Arduino Example

The TM1637 is a 8 segments led controller which can control up to 6 displays and key scan of 16 inputs.
There are multiple boards but the most common is using 4 displays with two dots in the middle so can be used as a timer display.
TM1637 Board

The protocol is similar to I2C but is simpler as there is no need of device address.
So the protocol is the following:

  • Start Signal
  • Command Data Byte
  • Optional Data Byte(s)
  • End Signal

Example of protocol

Start Signal

  • CLK must be HIGH
  • DIO must transition from HIGH to LOW

End Signal

  • CLK must be HIGH
  • DIO must transition from LOW to HIGH

Sending Data

  • DIO must be set to value when CLK is low
  • Send 8 bits, each clock cycle can be at most 2us (maximum speed of 500Khz)
  • After 8 bits the 9th clock cycle the chip will send an ACK setting DIO to LOW

There are 3 types of commands:

  • Data command (write to displays or read key scan)
  • Address command (which display to use, it can be up to 6 displays, but the board only contain 4)
  • Display, set displays ON/OFF and set brightness (8 possible levels)

The Data command allows to send a specific address or auto-increment (the most common scenario) so after setting the initial address it can be sent all the data to write in the displays without need to keep setting the address after each command.

The examples in the datasheet shows that Display commands are sent at the end; but there is no need for that, it can be sent before any Data command to set the configuration; after set, there is no need to be changed (except for some reason the display is reset)

The displays in the board are 8 Segments Displays
8 Segments Display
Actually are 7 Segments Displays as there is no dot and the two dots in the middle are handled by the second display.
The byte order is: Xgfedcba where X is the dot or DP

Arduino Code

To make work in Arduino, you need 2 pin inputs and three functions:

  • Start Transfer
  • End Transfer
  • Byte Write
void dataTransferStart() {
  // according to doc, start must be
  // a transition of DIO from LOW to HIGH
  // when a CLK clock is HIGH
  digitalWrite(PIN_DIO, HIGH);
  digitalWrite(PIN_CLK, HIGH);
  delayClock();
  digitalWrite(PIN_DIO, LOW);
  delayClock();
  digitalWrite(PIN_CLK, LOW);
  delayClock();
}

void dataTransferEnd() {
  // according to doc, end must be
  // a transition of DIO from HIGH to LOW
  // when a CLK clock is HIGH
  digitalWrite(PIN_DIO, LOW);
  digitalWrite(PIN_CLK, HIGH);
  delayClock();
  digitalWrite(PIN_DIO, HIGH);
  digitalWrite(PIN_CLK, LOW);
  delayClock();
}

unsigned char writeByte(unsigned char data) {
  // clock is assumed to be low, but just in case
  digitalWrite(PIN_CLK, LOW);

  for (unsigned char i = 0; i < 8; i++) {
    digitalWrite(PIN_DIO, (data & 0x1) ? HIGH : LOW);
    data = data >> 1;

    // run a clock cycle
    delayClock();
    digitalWrite(PIN_CLK, HIGH);
    delayClock();
    digitalWrite(PIN_CLK, LOW);
  }

  // here the chip does an ACK for one cycle
  pinMode(PIN_DIO, INPUT);
  delayClock();
  unsigned char ack = digitalRead(PIN_DIO);

  // finish clock cycle
  digitalWrite(PIN_CLK, HIGH);
  delayClock();
  digitalWrite(PIN_CLK, LOW);
  pinMode(PIN_DIO, OUTPUT);

  return ack;
}

The commands are very simple, the two MSB bits define the type of command:

  • 01 Data
  • 10 Display
  • 11 Address

The most simple is the display:

void setBrightness(unsigned char brightness) {
  // display settings
  dataTransferStart();
  // this will be 0b10_00_1_XXX
  writeByte(CMD_DISPLAY | CMD_DISPLAY_ON | (brightness & 0x7));
  dataTransferEnd();
}

So the 0b10_00_1_XXX means: 10 is the Display command, the 00 are “irrelevant” items in the datasheet, 1 is to enable the display and XXX is the level of the brightness.

The full code and example is here: https://github.com/danguer/arduino-examples/tree/main/tm1637

Links

Leave a Reply