LTC-637D1P LED Display : best practice?

Hello,

I like to use LTC-637D1P LED display with arduino
and have some beginner questions.

This display use common Cathode and was used for alarm
clock. It has - that's my challenge - 32 leds but only
4 cathodes and 18 anodes which makes total of 22. (Using
only 4 digits reduces to 2 Cathode and 14 anodes :
total of 16).

LTC-637D1P.pdf (156,8 KB)

What's best practice to get this display function?

IMHO 3 ways :
1.) shift register f.e. 74hc595

  • cheap
  • need 3 of them
  • flickering might occur
  • need resistors for led

2.) port expander f.e. pcf8574

  • need only 2
  • bit more expensive
  • need resistors for led

3.) MAX7219/21

  • designed for led matrix common cathode 8 cathode x 8 anode = 64 led
  • no need for led resistor

My questions?

How was it solved originally? Are there another IC that solves my problem perfectly?

Can I use MAX7219/21 for my 4 cathode x 18 anode = 32 leds and how?

Thanks in advance!

check the HT16K33 (I2C) - it could be used for eight 16 segments, so it might be ok for your "2 common cathode display" also.

curious display.
if you haven't got hundreds of them, I just would use another display...

This is a very strange display!

I have never seen a display wired like this before, or a solution for it.

I don't think so.

74hc595 maybe. You would also need a couple of transistors for the common cathodes.
PCF8574 no, it cannot source enough current to drive a led. It can sink enough current for a led, but with all those anodes you need to source current.
MAX7219 I don't think so, not enough anode driver pins
HT16K33 this feels like the easiest solution (even though much of its capability would be wasted)

Thanks for all answers.

I will give HT16K33 a try.

Shure. This is another way, however I like to get old stuff working.

Look at Weitere Elektronik in Hamburg Stellingen - Eimsbüttel | eBay Kleinanzeigen ist jetzt Kleinanzeigen where shift register were used.

Update:

It took some time to order and receive HT16K33.

I got easily this display working with that chip. However ... even on highest brightness the display is very weak. This is probadly due to multiplexing, since it reduce to 1/8 as I read because there are 8 cathodes. Actually I use only 3 cahtodes.

Are there a way to speed up by multiplexing only 3 cathodes?

Maybe mapping the 8 chip cathodes to 2 display cathodes (1,3,5,7 to 1; 2,4,6,8 to 2)?

as a LED Module with 8 digits isn't "weak", I doubt that reducing the scanning to 3 digits hasn't a big impact (and that isn't possible anyway imho).

I suspect your setup, wiring, power source or your code.

When you need support, provide

  • wiring diagram
  • real pictures where we can check each and every wire
  • the code including links to external libraries (if any)

It could be that the display is a very old design or manufacture. The unusual wiring seems to confirm that. Modern displays tend to have a very consistent and similar wiring scheme. Older displays, even if they have never been used, are made with led segments which are much less efficient at turning current into light.

Reducing the multiplexing ratio will help to some degree. Unfortunately I don't know if the ht16k33 has that feature. Max7219 does allow the multiplex radio to be reduced, but max7219 does not have enough anode pins, otherwise I would have suggested it.

Maybe, but don't try it before researching the idea thoroughly. Depending on the design on the cathode pins, damage could occur if they are connected together.

Checking the equivalent circuits for the display driver pins:


There would be no problem connecting COM4-7 together I think, because they are "open drain". But COM0-3 have "push-pull" design, so there is a danger of damage...

Thanks for your answers.

Hope the fritzing is understandable


and the reality is:

The sketch uses Strandtest 7 Segment from Noiasca HT16K33 library (great work) for testing. It works. However pretty weak.

Yes, problem of current flowback when output are wired together came to my mind as well. Thanks for that precise description. Can't I put a diode after output preventing current flow back.

How can turn on only specific anodes/cathodes from ht16k33, say only A2 and C1? Are there low level commands?

Regards!

  
    /** 
      \brief write to I2C
      
      I2C lowLevel write of a bitmask to the IC to a specific position
      \param position digit to be written to
      \param bitmask the bits/segments to be activated as bitmask
    */ 
    void writeLowLevel(uint8_t position, uint16_t bitmask);
display.writeLowLevel(0, 0xFFFF); // switch on all segments on pos 0

P.S.: There should be a docs/html folder in the library which lists all member functions

Well I succeeded to make it brighter by using all 8 cathodes. In order to avoid current flowback to cathodes, diodes were used.

By using this sketch (GitHub - bxparks/AceSegment: A library for rendering seven segment LED modules using the TM1637, TM1638, MAX7219, HT16K33, or 74HC595 controller chip.)

/*
 * Write digits 0-3 into an 4-digit LED module using the HT16K33 ship, set the
 * brightness, then render it by flushing the data bits to the HT16K33
 * controller over I2C using the TwoWireInterface class from the AceWire
 * library.
 */

#include <Arduino.h>
#include <Wire.h> // TwoWire, Wire
#include <AceWire.h> // TwoWireInterface
#include <AceSegment.h> // Ht16k33Module

using ace_wire::TwoWireInterface;
using ace_segment::LedModule;
using ace_segment::Ht16k33Module;

// Replace these with the PIN numbers of your dev board.
const uint8_t SDA_PIN = SDA;
const uint8_t SCL_PIN = SCL;
const uint8_t HT16K33_I2C_ADDRESS = 0x70;
const uint8_t NUM_DIGITS = 4;

using WireInterface = TwoWireInterface<TwoWire>;
WireInterface wireInterface(Wire);
Ht16k33Module<WireInterface, NUM_DIGITS> ledModule(
    wireInterface, HT16K33_I2C_ADDRESS);

void setup() {
  delay(1000);

  Wire.begin();
  wireInterface.begin();
  ledModule.begin();
  
  uint8_t at = 0;
  uint8_t pattern = 0b00000111;
  ledModule.setPatternAt(at, pattern);

  ledModule.setBrightness(15);

  ledModule.flush();
}

void loop() {}

and mapping sketch params "at" and "pattern" to display segments results in

------------+  +------------+           +------------+
|   aaaa     |  |   aaaa     |           |   aaaa     |
|  f    b    |  |  f    b    |           |  f    b    |
|  f    b    |  |  f    b    |           |  f    b    |
|   gggg     |  |   gggg     |  *  *  *  |   gggg     |
|  e    c    |  |  e    c    |           |  e    c    |
|  e    c    |  |  e    c    |           |  e    c    |
|   dddd     |  |   dddd     |           |   dddd     |
+------------+  +------------+           +------------+
  Digit 0         Digit 1                 Digit {N-1}


at	pattern 	Digit 	Segment
0	0b10000000	-	-
1	0b10000000	-	-
2	0b10000000	-	-
3	0b10000000	-	-

0	0b01000000	2	g
1	0b01000000	2	b & 3 f
2	0b01000000	2	b & 3 f
3	0b01000000	2	g

0	0b00100000	3	b
1	0b00100000	3	g
2	0b00100000	3	g
3	0b00100000	3	b

0	0b00010000	3	c
1	0b00010000	3	d
2	0b00010000	3	d
3	0b00010000	3	c

0	0b00001000	4	e
1	0b00001000	3	c
2	0b00001000	3	c
3	0b00001000	4	e

0	0b00000100	4	g
1	0b00000100	4	b
2	0b00000100	4	b
3	0b00000100	4	g

0	0b00000010	4	d
1	0b00000010	4	c
2	0b00000010	4	c
3	0b00000010	4	d

0	0b00000001	4	b
1	0b00000001	4	a
2	0b00000001	4	a
3	0b00000001	4	b

It can be seen that f.e. segment b from digit 4 results from 4 different combination. Putting these 4 combination on resuts in brighter segment.

Problem is that not all segments can be activated. I will check writeLowLevel. Thanks for that hint.

I'm running out of time and will show pictures later.

Final!y I managed to use all segments of that old display. Brighness was fine as well.

Thanks to all for comments and advices.

/*******************************************************************************
  Noiasca HT16K33

https://werner.rothschopf.net/201909_arduino_ht16k33.htm

  Sketch for mapping
 *******************************************************************************/
#include <Wire.h>            // HT16K33 uses I2C, include the Wire Library
#include "NoiascaHt16k33.h"  // include the noiasca HT16K33 library - download from //http://werner.rothschopf.net/

const uint8_t i2cAddress = 0x70;  // the I2C address of the first module
const uint8_t numOfDevices = 1;   // how many modules have you installed on the I2C Bus
const uint16_t wait = 500;        // wait milliseconds between demos

Noiasca_ht16k33_hw_14 display;

uint16_t bitmask  = (1<<14);


void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  Wire.begin();                             // start the I2C interface
  display.begin(i2cAddress, numOfDevices);  // I2C address of first display, total number of devices

  display.setBrightness(15);
  display.clear();
  // display.writeLowLevel(position, bitmask);
}

void loop() {
  display.writeLowLevel(0, bitmask);
  display.writeLowLevel(2, bitmask);
  display.writeLowLevel(4, bitmask);
  display.writeLowLevel(6, bitmask);
 
  delay(1000);
  display.clear();
 
  display.writeLowLevel(1, bitmask);
  display.writeLowLevel(3, bitmask);
  display.writeLowLevel(5, bitmask);
  display.writeLowLevel(7, bitmask);
  
  delay(2000);
  display.clear();
}

I can't test with that specific hardware.
But this is something I copy/pasted and it gives "somehow" output on my display

The idea is following:
the font from the libray is just used to get the needed segments.
based on your anode variables we split into two 16bit bitmaps. and activate the bitmaps for the two cathodes per digit.

so the change is a custom class with a very specific write function.

/*******************************************************************************
  Prototype for LTC-637D1P display with custom wiring to a HT16K33
  Noiasca HT16K33

  by noiasca
  Sketch Version 2023-02-10

  On startup you should see some text on your display
  In the loop all printable Characters will be shown.

 *******************************************************************************/

#include <NoiascaHt16k33.h>                                          // include the noiasca HT16K33 library - download from http://werner.rothschopf.net/

//Noiasca_ht16k33_hw_14 display = Noiasca_ht16k33_hw_14();           // object for 14 segments - 8 digits

//create your own class from the library internal abstract class
class Custom_ht16k33 : public Noiasca_ht16k33 {
  protected:
    uint8_t _lastBitmap;                                   // last written bitmap (if we have to reprint for the decimal point)

  public:
    // custom write method for 7 segment
    size_t write(uint8_t value) {
      // define segments
      //const uint16_t bitmask_0_DP = 1 << 15; // Doppelpunkt
      //const uint16_t bitmask_1_AL = 1 << 15; // Punkt rechts unten
      //const uint16_t bitmask_0_pm = 1 << 14; // Punkt links oben
      //const uint16_t bitmask_1_am = 1 << 14; // Punkt links unten
      // const uint16_t bitmask_0_ = 1 << 13; // noch frei
      const uint16_t bitmask_1_1b = 1 << 13;
      const uint16_t bitmask_0_1a = 1 << 12;
      const uint16_t bitmask_1_1g = 1 << 12;
      const uint16_t bitmask_0_1d = 1 << 11;
      const uint16_t bitmask_1_1e = 1 << 11;
      const uint16_t bitmask_0_2e = 1 << 10;
      const uint16_t bitmask_1_1c = 1 << 10;
      const uint16_t bitmask_0_2d = 1 << 9;
      const uint16_t bitmask_1_2c = 1 << 9;
      const uint16_t bitmask_0_2f = 1 << 8;
      const uint16_t bitmask_1_2a = 1 << 8;
      const uint16_t bitmask_0_2g = 1 << 7;
      const uint16_t bitmask_1_2b = 1 << 7;
      const uint16_t bitmask_0_3a = 1 << 6;
      const uint16_t bitmask_1_3f = 1 << 6;
      const uint16_t bitmask_0_3b = 1 << 5;
      const uint16_t bitmask_1_3g = 1 << 5;
      const uint16_t bitmask_0_3c = 1 << 4;
      const uint16_t bitmask_1_3d = 1 << 4;
      const uint16_t bitmask_0_4e = 1 << 3;
      const uint16_t bitmask_1_3e = 1 << 3;
      const uint16_t bitmask_0_4g = 1 << 2;
      const uint16_t bitmask_1_4b = 1 << 2;
      const uint16_t bitmask_0_4d = 1 << 1;
      const uint16_t bitmask_1_4c = 1 << 1;
      const uint16_t bitmask_0_4f = 1 << 0;
      const uint16_t bitmask_1_4a = 1 << 0;

      // no separate dot handling - deleted
    
      if (value > 31 && value < 128)                                // write printable ASCII characters to display
      {
        uint8_t cathodeA = 0;  // the real segments are distributed to two cathodes
        uint8_t cathodeB = 0;
        uint16_t bitmapA = 0;   // each cathode drives it's own bitmap with segments
        uint16_t bitmapB = 0;

        // now read the logical segments from the internal font as 8bit byte, 
        uint8_t segments = pgm_read_byte_near(charTable + value - 32);          // the table starts with the first printable character at 32

        // now distribute the 8bit segment to two 16bit segments
        for (int i = 0; i < 8; i++)
        {
          uint8_t segment = segments & (1 << i); // the actual segment
          // MISSING: ... byte 0 mit BV=1 muss auf segment a finden
          switch (_currentPosition) {
            case 0:
              switch (segment) {
                case _BV(0): bitmapB |= bitmask_0_1a; break;  //  "S1a",  // should be S0a as we start counting with 0 in c++
                case _BV(1): bitmapB |= bitmask_1_1b; break;  //  "S1b",
                case _BV(2): bitmapB |= bitmask_1_1c; break;  //  "S1c",
                case _BV(3): break; // ???
                case _BV(4): bitmapB |= bitmask_1_1e; break;  //  "S1e",  // ???
                case _BV(5): bitmapA |= bitmask_0_1d; break;  //  "S1f",  // ???
                case _BV(6): bitmapB |= bitmask_1_1g; break;  //  "S1g",
              }
              break;
            case 1:
              switch (segment) {
                case _BV(0): bitmapB |= bitmask_1_2a; break;  //  "S2a",
                case _BV(1): bitmapB |= bitmask_1_2b; break;  //  "S2b",
                case _BV(2): bitmapB |= bitmask_1_2c; break;  //  "S2c",
                case _BV(3): bitmapA |= bitmask_0_2d; break;  //  "S2d",
                case _BV(4): bitmapA |= bitmask_0_2e; break;  //  "S2e",
                case _BV(5): bitmapA |= bitmask_0_2f; break;  //  "S2f",
                case _BV(6): bitmapA |= bitmask_0_2g; break;  //  "S2g",
              }
              break;
            case 2:
              switch (segment) {
                case _BV(0): bitmapA |= bitmask_0_3a; break; //  "S3a",
                case _BV(1): bitmapA |= bitmask_0_3b; break; //  "S3b",
                case _BV(2): bitmapA |= bitmask_0_3c; break; //  "S3c",
                case _BV(3): bitmapB |= bitmask_1_3d; break; //  "S3d",
                case _BV(4): bitmapB |= bitmask_1_3e; break;  //  "S3e",
                case _BV(5): bitmapB |= bitmask_1_3f; break;  //  "S3f",
                case _BV(6): bitmapB |= bitmask_1_3g; break;  //  "S3g",
              }
              break;
            case 3:
              switch (segment) {
                case _BV(0): bitmapB |= bitmask_1_4a; break; //  "S4a",
                case _BV(1): bitmapB |= bitmask_1_4b; break; //  "S4b",
                case _BV(2): bitmapB |= bitmask_1_4c; break; //  "S4c",
                case _BV(3): bitmapA |= bitmask_0_4d; break; //  "S4d",
                case _BV(4): bitmapA |= bitmask_0_4e; break; //  "S4e",
                case _BV(5): bitmapA |= bitmask_0_4f; break; //  "S4f",
                case _BV(6): bitmapA |= bitmask_0_4g; break; //  "S4g",
              }
              break;
          }
        }
        // get the two cathodes for each position
        switch (_currentPosition) {
          case 0: cathodeA = 0; cathodeB = 1; break;
          case 1: cathodeA = 2; cathodeB = 3; break;
          case 2: cathodeA = 4; cathodeB = 5; break;
          case 3: cathodeA = 6; cathodeB = 7; break;
        }
        //finally output to display:
        writeLowLevel(cathodeA, bitmapA);
        writeLowLevel(cathodeB, bitmapB);
        _lastPosition = _currentPosition;  // tbc: not needed as we do not have a dot/comma handling in this write
        _currentPosition++;
        if (_currentPosition >= _numDigits * _numDevices) _currentPosition = 0;
        // MISSING: handling of two _lastBitmap to care about the state of the 4 dots
      }
      return 1; // assume sucess
    }
};
Custom_ht16k33 display;

const uint8_t i2cAddress = 0x76;                                     // the I2C address of the first module (from 0x70 to 0x77)
const uint8_t numOfDevices = 2;                                      // how many modules have you installed on the I2C Bus
const uint16_t wait = 1000;                                           // wait milliseconds between demo

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println(F("\nstrandtest 14 segment "));
  Wire.begin();                                                       // start the I2C interface
  display.begin(i2cAddress, numOfDevices);                            // I2C adress of first display, total number of devices

  Serial.println(F("ON Test"));
  display.clear();                     // clear display
  display.print(F("ALFABETADELT"));    // if the text is to long or your display (chain) you will only see the last letters
  delay(1000);
}

void test1() {
  display.clear();         // weil vorher etwas mit "print" geschrieben wurde --> löscht
  display.writeLowLevel(0, 0xFFFF);
  display.writeLowLevel(2, 0xFFFF);
  display.writeLowLevel(4, 0xFFFF);
  display.writeLowLevel(6, 0xFFFF);

  delay(wait);
  display.clear();         // löscht 100%ig die mit "writeLowLevel" geschriebenen Sachen
  display.writeLowLevel(1, 0xFFFF);
  display.writeLowLevel(3, 0xFFFF);
  display.writeLowLevel(5, 0xFFFF);
  display.writeLowLevel(7, 0xFFFF);

  delay(wait);
  display.writeLowLevel(1, 0);  // löscht klarerweise auch
  display.writeLowLevel(3, 0);
  display.writeLowLevel(5, 0);
  display.writeLowLevel(7, 0);
}


void test() {
  // put your main code here, to run repeatedly:
  Serial.println(F("Printable characters"));
  for (uint8_t counter = 32; counter < 128; counter++) {
    display.clear();
    display.print(counter);            // print the numerical ANSI code of the character
    display.write(counter);            // print the character for the ANSI code
    delay(wait);
  }
}

void loop() {
  test();
}

I assume a lot to adopt/debug for your ^^

the four dots will need some work, but first, the digits should show correct characters...

I have a clock using a similar display. It is driven by a TMS3450NL from Texas Instruments. The data sheet is at https://e2e.ti.com/cfs-file/__key/communityserver-discussions-components-files/48/0825.TMS3450NL-sxas015-_2800_1_2900_.pdf.
The chip in my clock has died, so I am considering using two 8 bit shift registers to drive the anodes. I may need to have high side drivers to source the current. For the cathodes, one more pin and an inverter driving an XOR circuit so only only one cathode can be enabled at a time. The decoding logic for the digits will be fun with the two phase output.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.