TM1637 LED Driver

Coding and general discussion relating to the compiler

Moderators: David Barker, Jerry Messina

Jon Chandler
Registered User
Registered User
Posts: 185
Joined: Mon Mar 10, 2008 8:20 am
Location: Seattle, WA USA
Contact:

TM1637 LED Driver

Post by Jon Chandler » Thu Dec 22, 2022 10:40 pm

I'm trying to wrap my head around the best way to control a TM1637 6-Digit LED Driver. Four and six digit display assemblies can be had for next to nothing from the usual sources. Has anybody developed code for these guys? Note the TM1638 from the same company uses a standard I2C interface while the TM1637 does not.

The interface is a mixed up, totally different version of I2C. Bits sent in the reverse order, different start and stop commands, etc. I think I can use the shift module to send each byte, with start and stop commands added as needed.

[start], Shift[byte], [stop]

It might be easier to bit bang everything, but I'm not space nor speed limited.

Suggestions appreciated.
Jon

Check out the TAP-28 PIC Application board at http://www.clever4hire.com/throwawaypic/

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: TM1637 LED Driver

Post by Jerry Messina » Thu Dec 22, 2022 11:49 pm

That looks like normal I2C to me, just with no address byte, so I2C.Start, Stop, WriteByte, etc should work.

Since there's no addressing you'd have to have a bus dedicated to it with SDA and SCL pullups as usual. 100KHz speed should work.

Am I missing something?

Jon Chandler
Registered User
Registered User
Posts: 185
Joined: Mon Mar 10, 2008 8:20 am
Location: Seattle, WA USA
Contact:

Re: TM1637 LED Driver

Post by Jon Chandler » Fri Dec 23, 2022 12:33 am

One major thing you're missing - the bits are sent LSB first instead of MSB first. I suppose you could just invert the data to be sent. There are only a few commands and you just reverse the order of the LED segments to be sent.

This page provides some more details of the interface

Thanks Jerry.
Jon

Check out the TAP-28 PIC Application board at http://www.clever4hire.com/throwawaypic/

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: TM1637 LED Driver

Post by Jerry Messina » Fri Dec 23, 2022 1:02 pm

The ref code in that link looks a little dodgy to me... it never sets the DIO pin to input mode.

Here's a port of that reference C code with the CLK and DIO pins used as open-drain like I2C.
I added an option for the CLK pin so it can be used in push-pull mode w/out a pullup, but DIO requires one

Code: Select all

// TM1637 driver ref code from http://www.microcontroller.it/english/Tutorials/Elettronica/componenti/TM1637.htm
//  Copyright: Shenzhen Tian Microelectronics
//  File name: TM1637
//  Current Version: 1.0
module TM1637

// CLK and DIO pins
#option TM1637_CLK = PORTB.0        // pullup optional (see below)
#option TM1637_DIO = PORTB.1        // requires a pullup

// set CLK pin mode
//   true = open-drain (requires pullup), false = push-pull
// TM1637 does not drive the CLK, so it can be push-pull
#option TM1637_OD_CLK = false

dim clk as TM1637_CLK.TM1637_CLK@,
    dio as TM1637_DIO.TM1637_DIO@

// assumes open-drain mode with pullups on CLK and DIO pins
inline sub CLK_HIGH()
  #if (TM1637_OD_CLK)
    input(clk)
  #else     // push-pull
    high(clk)
  #endif    
end sub

inline sub CLK_LOW()
    low(clk)
end sub

inline sub DIO_HIGH()
    input(dio)
end sub

inline sub DIO_LOW()
    low(dio)
end sub

// 1637 start
public sub Start()
    CLK_HIGH()      // clk = 1
    DIO_HIGH()      // dio = 1
    delayus(2)
    DIO_LOW()       // dio = 0
end sub

// 1637 Answer
public sub Ask()
    CLK_LOW()       // clk = 0
    DIO_HIGH()      // sets dio to input
    delayus(5)      // After the falling edge of the eighth clock delay 5us, ACK signals the beginning of judgment
    while (dio = 1)
    end while
    CLK_HIGH()      // clk = 1
    delayus(2)
    CLK_LOW()       // clk = 0
end sub

// 1637 Stop
public sub Stop()
    CLK_LOW()       // clk = 0
    delayus(2)
    DIO_LOW()       // dio = 0
    delayus(2)
    CLK_HIGH()      // clk = 1
    delayus(2)
    DIO_HIGH()      // dio = 1
end sub

// write a byte
public sub WriteByte(b as byte)
    dim i as byte

    for i = 0 to 7
        CLK_LOW()                   // clk = 0
        if (b.bits(0) = 1) then
            DIO_HIGH()              // dio = 1
        else
            DIO_LOW()               // dio = 0
        endif
        delayus(3)
        b = b >> 1
        CLK_HIGH()                  // clk = 1
        delayus(3)
    next
    DIO_HIGH()                      // set dio to OD mode
end sub

// read buttons
public function ScanKey() as byte
    dim rekey, i as byte
    
    Start()
    WriteByte($42)      // read command buttons
    Ask()
    DIO_HIGH()          // dio = 1, read keys before data lines pulled
    for i = 0 to 7      // start reading from the low
        CLK_LOW()               // clk = 0
        rekey = rekey >> 1
        delayus(30)
        CLK_HIGH()              // clk = 1
        if (dio = 1) then
            rekey.bits(7) = 1
        endif
        delayus(30)
    next
    Ask()
    Stop()
    result = rekey
end function

// Write display register
public sub SmgDisplay()
    dim i as byte

    Start()
    WriteByte($40)  //40H address is automatically incremented by 1 mode, 44H fixed address mode
    Ask()
    Stop()
    
    Start()
    WriteByte($C0)  // Set the first address
    Ask()
    for i = 0 to 5      // Addresses from Canada, do not always write address (???)
        WriteByte($FF)  // Send data
        Ask()
    next
    Stop()

    Start()
    WriteByte($8F)  // Open display, maximum brightness
    Ask()
    Stop()
end sub

// Initialization routine
// CLK and DIO are open-drain pins with pullups
public sub Init()
    CLK_HIGH()
    DIO_HIGH()
end sub

// startup code
Init()

end module

Another option would be to start with the library module SI2C.bas and change the byte in/byte out routines to do LSB first...

Code: Select all

{
****************************************************************************
* Name    : ShiftOut (PRIVATE)                                             *
* Purpose : Shift out a byte value, LSB first                              *
****************************************************************************
}
sub ShiftOut(pData as byte)
    dim count as byte

    count = 8
    repeat
        SDA = pData.bits(0)
        DATA_SETUP_DELAY()
        ToggleClock()
        pData = pData >> 1
        dec(count)
    until (count = 0)
    ClrWDT()
end sub

{
****************************************************************************
* Name    : ShiftIn (PRIVATE)                                              *
* Purpose : Shift in a byte value, LSB first, sample before clock          *
****************************************************************************
}
function ShiftIn() as byte
    dim count as byte

    input(SDA)
    count = 8
    result = 0
    repeat
        result = result >> 1
        result.bits(7) = SDA
        ToggleClock()
        dec(count)
    until (count = 0)
    output(SDA)
    ClrWDT()
end function

Jon Chandler
Registered User
Registered User
Posts: 185
Joined: Mon Mar 10, 2008 8:20 am
Location: Seattle, WA USA
Contact:

Re: TM1637 LED Driver

Post by Jon Chandler » Sat Dec 31, 2022 9:13 pm

I am not making much progress on this....or I have IR 7-segment displays! :?

I'm using the module translated from the example code.

#option statements before the include statements to set the port pins I'm using for clock and data.

In my program, I think all I should need to do is this:

Code: Select all


TM1637.Init
 While 1 = 1
 	SmgDisplay()
 
 	DelayMS(1000)
 	Toggle(LED1)
 Wend


This should light up all the segments as is hardcoded in the module.

The LED is flashing as expected.

Am I missing obvious somewhere?

The TM1637 has built-in pullup resistors.
Jon

Check out the TAP-28 PIC Application board at http://www.clever4hire.com/throwawaypic/

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: TM1637 LED Driver

Post by Jerry Messina » Sat Dec 31, 2022 9:55 pm

Jon -

try getting rid of that last DIO_HIGH at the end of the WriteByte() sub

Code: Select all

    next
    //DIO_HIGH()                      // set dio to OD mode
end sub

Jon Chandler
Registered User
Registered User
Posts: 185
Joined: Mon Mar 10, 2008 8:20 am
Location: Seattle, WA USA
Contact:

Re: TM1637 LED Driver

Post by Jon Chandler » Sun Jan 01, 2023 1:15 am

That didn't change anything.

Just to verify my thoughts - the TM1637 module takes care of setting input/output state, so I don't need to do anything in the main program.

I don't see any problems, it looks like the right commands are all being sent.

Here's another reference and sample code which seems to agree with the first.

Jon
Jon

Check out the TAP-28 PIC Application board at http://www.clever4hire.com/throwawaypic/

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: TM1637 LED Driver

Post by Jerry Messina » Sun Jan 01, 2023 8:18 pm

I found the arduino code that last link used, and adapted it. That looks to be a bit better than the first.
The TM1637.bas module is in the zip file, along with the following test program.
See if this works out any better...

Code: Select all

// TM1637 test
device = 18F26K22
clock = 64

// intosc
include "intosc.bas"

// digital/analog mode
#option DIGITALIO_INIT = true   // automatically call setalldigital at startup
include "setdigitalio.bas"

// TM1637
#option TM1637_CLK = PORTB.0
#option TM1637_DIO = PORTB.1
#option TM1637_BIT_DELAY = 5
'#option TM1637_OD_CLK = false   // true=OD mode, false=push-pull(no pullup reqd)
include "TM1637.bas"

// segment data for 4 displays
dim seg(4) as byte

const SEG_DONE() as byte = 
(
    SEG_B + SEG_C + SEG_D + SEG_E + SEG_G,           // d
    SEG_A + SEG_B + SEG_C + SEG_D + SEG_E + SEG_F,   // O
    SEG_C + SEG_E + SEG_G,                           // n
    SEG_A + SEG_D + SEG_E + SEG_F + SEG_G            // E
)

dim i, k as byte

main:
// this is redundant since option DIGITALIO_INIT=true already took care of it,
// so it's just here as a reminder
SetAllDigital()

// init pins (this is also optional... done at module startup)
TM1637.init()

// all segments on
seg(0) = $FF
seg(1) = $FF
seg(2) = $FF
seg(3) = $FF
TM1637.setSegments(seg)

// turn on display (full on)
TM1637.displayCmd(7, 1)

// brightness test
for k = 0 to 7
    TM1637.displayCmd(k, 1)
    delayms(1000)
next

// on/off test
for k = 1 to 10
    TM1637.displayCmd(7, 0)
    delayms(500)
    TM1637.displayCmd(7, 1)
    delayms(500)
next

// wait 5 secs and clear
delayms(5000)
TM1637.clearDisplay()

// Run through all the dots
for i = 0 to 3
    k = 1
    repeat
        seg(i) = k    
        TM1637.setSegments(seg)
        k = k << 1
    until (k = $80)
next

// Done!
seg = SEG_DONE
TM1637.setSegments(seg)

while (true)
end while
Attachments
TM1637.zip
(2.37 KiB) Downloaded 174 times

Jon Chandler
Registered User
Registered User
Posts: 185
Joined: Mon Mar 10, 2008 8:20 am
Location: Seattle, WA USA
Contact:

Re: TM1637 LED Driver

Post by Jon Chandler » Sun Jan 01, 2023 8:42 pm

I rolled up my sleeves, engaged my brain, and started from the data sheet. Progress is being made...I can at least see where it's hanging up.

I flash LEDs for START, ACK and STOP. The unlined events occur and the program hangs.
tm1637 time diagram.jpg
tm1637 time diagram.jpg (97.4 KiB) Viewed 7248 times
The send subroutine is this. I inserted a number of uS delays thinking this might help. Thanks for the help - it got me moving in the right direction!

Code: Select all

Sub TM1637Display(Level As Byte)
'Digit data stored in DigitData array prior to calling
'Brightness set by constant array - TM1637Brightness
    Dim I As Byte
    TM1637Start
    ShiftOut($40) ' sequential addressing
    TM1637Ack
    DelayUS(2)
    TM1637Stop
    DelayUS(5)
    TM1637Start
    ShiftOut($C0) 'set first address
    TM1637Ack
    DelayUS(2)
    For I = 0 To 5      'shift out digit data
        ShiftOut(DigitData(I))
        TM1637Ack
        DelayUS(2)
    Next 
    
    TM1637Start
    ShiftOut(TM1637Brightness(Level))
    TM1637Ack
    DelayUS(2)
    TM1637Stop
    
End Sub
Jon

Check out the TAP-28 PIC Application board at http://www.clever4hire.com/throwawaypic/

Jon Chandler
Registered User
Registered User
Posts: 185
Joined: Mon Mar 10, 2008 8:20 am
Location: Seattle, WA USA
Contact:

Re: TM1637 LED Driver

Post by Jon Chandler » Sun Jan 01, 2023 10:34 pm

Thanks Jerry,

I missed your post when I made my last post. Appreciate all the help for something that shouldn't be that difficult!

I'll let you know how it goes.

Happy new year. Let's hope it's a great one!

Jon
Jon

Check out the TAP-28 PIC Application board at http://www.clever4hire.com/throwawaypic/

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: TM1637 LED Driver

Post by Jerry Messina » Mon Jan 02, 2023 12:22 pm

Thanks Jon. Happy New Year to you too.

Since I don't have any display hdw, if you could try out the code in that zip file to see if it works that'd be great.
I modified it a bit from that arduino code so we'll have to see.

Using ShiftOut might not be the best of implementations since it actively drives both the clk and data lines, and that could cause a problem during the ack cycle.

Anyway, keep me posted. If that works out there are some more subs in that arduino code to help generate chars that I didn't bother to add yet.

Jon Chandler
Registered User
Registered User
Posts: 185
Joined: Mon Mar 10, 2008 8:20 am
Location: Seattle, WA USA
Contact:

Re: TM1637 LED Driver

Post by Jon Chandler » Mon Jan 02, 2023 6:04 pm

I'm on a cruise and brought minimal stuff to get started on an "easy project"....which is becoming very frustrating!

The version I'm trying to work on is bit-banging the clock and data lines, not using the shift module. I had high hopes when I found a version for Proton Basic that was nearly identical to what I had been doing with a slight rearrangement of commands...and a very interesting note that 2uS delays were not reliable, but 50 or 100uS delays were.

I'm not sure I'm actually generating clock and data pulses, as the PICkit 3 I have with me isn't showing anything using the third input that does not have a pulldown resistor. I'm never before tried the logic analyzer function with the PICkit 3 and stand-alone GUI so I have some doubts it may not work.

The subroutines I'm using to control the clock and DIO lines are below. I believe these should be doing the task.

Code: Select all


Sub TM1637ClockPin(Level As Byte)
    'Clock is pulled high
    If Level = 1 Then
            Input(TM1637Clock)
        Else
            Output(TM1637Clock)
            TM1637clock = 0
    End If    
End Sub

Sub TM1637DIOPin(Level As Byte)          
    'DIO is pulled high
    If Level = 1 Then
            Input(TM1637DIO)
        Else
            Output(TM1637DIO)
            TM1637DIO = 0
    End If    
End Sub

This may have to wait until I get home....
Jon

Check out the TAP-28 PIC Application board at http://www.clever4hire.com/throwawaypic/

Jon Chandler
Registered User
Registered User
Posts: 185
Joined: Mon Mar 10, 2008 8:20 am
Location: Seattle, WA USA
Contact:

Re: TM1637 LED Driver

Post by Jon Chandler » Mon Jan 02, 2023 8:49 pm

One question is answered anyway. The PICkit 3 (at least THIS PICkit 3) channel 3 does not function in the logic analyzer. And channels 1 and 2 are pretty much useless to me for this, as the clock and data line 10k pullup resistors won't have much impact against the 4.7k pulldowns on channels 1 & 2.

Another gotcha to be aware of is the logic analyzer doesn't seem to be happy with external power to the board being tested. PICkit 3 power must be on for the logic analyzer to work.
pickit 3 LA.jpg
pickit 3 LA.jpg (206.71 KiB) Viewed 7239 times
Jon

Check out the TAP-28 PIC Application board at http://www.clever4hire.com/throwawaypic/

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: TM1637 LED Driver

Post by Jerry Messina » Tue Jan 03, 2023 2:07 pm

So much for the PK3 LA function!
The subroutines I'm using to control the clock and DIO lines are below. I believe these should be doing the task.
I don't think it would matter much in this instance, but when you go to enable the output low I'd swap the order just to be safe...

Code: Select all

        Else
            Output(TM1637Clock)        // this clears the TRIS bit making it an output with whatever's currently in the LAT register
            TM1637clock = 0		    // this writes to the LAT register... and now it goes low
Better to do:

Code: Select all

        Else
            TM1637clock = 0		    // this writes to the LAT register...
            Output(TM1637Clock)        // this clears the TRIS bit making it an output low
or just use 'low(TM1637clock)', since that does the same thing.
'Low()' and 'High()' set the LAT register first and then the TRIS so you won't get a glitch in case the LAT was 1

It's interesting you mention 50-100us bit timing. I don't see anything in the datasheet that makes me think it would need to be that slow, but the arduino code I ported has it set for 100us too.

The TM1637.bas module has a setting for that...
#option TM1637_BIT_DELAY = 5 // bit high/low time, in usecs

Jon Chandler
Registered User
Registered User
Posts: 185
Joined: Mon Mar 10, 2008 8:20 am
Location: Seattle, WA USA
Contact:

Re: TM1637 LED Driver

Post by Jon Chandler » Thu Jan 05, 2023 11:31 pm

I'm putting this on hold for now until I get home in a couple weeks. Hard to troubleshoot when you can't see what's happening.

I took a look at the TM6318. It's got a more conventional shift-register type interface. It supports 8 digits instead of 6, and common anode OR cathod digits. Interestingly, it has 10 segment drivers per digit, which can be used for other LEDs. It should be a good fit for my project, at a significant increase in BOM costs....a 25% increase to 25 cents each. Which is just unbelievable!

Thanks for the help with this – I'll get back to it in a couple weeks.
Jon

Check out the TAP-28 PIC Application board at http://www.clever4hire.com/throwawaypic/

Post Reply