22 March 2025
I found a little LED clock display module, driven by the Titan Micro Electronics TM1637 driver chip. I’d like to build a simple LED clock using this display module and a WCH CH32V203C8 RISC-V-based microcontroller.
I already had some of the “Blue Pill” development boards for the -203 chip from WeAct Studio. They are the same footprint as the STM32-based “Blue Pill” development boards, and fit nicely in a solderless breadboard. Another nice thing about these boards is that they already have a 32,768 Hz quartz crystal attached to PC14 and PC15, enabling the on-board real-time clock (RTC) of the -203. This one already had a WCH-LinkE programming cable built for it, a remnant of a previous project. This provides power, programming and serial communication lines from my laptop to the circuit. I added a purple wire for the NRST signal.
To wire up the TM1637 module to the prototype circuit, I will need another short cable. The LED module already has a four pin right-angle header soldered to it. The module needs +5V and ground, as well as digital clock and data lines. You know how I just can’t wait to build yet another custom cable for these projects. I’m getting pretty good at it, too.
I can’t really tell the pin numbering of the little LED module, but the individual signals are clearly marked on the PCB. Here is a description of the interface cable:
Pin Signal Color Description
--- ------ ------ ---------------
1 GND black ground
2 VCC red. +5V
3 DIO green data in and out
4 CLK yellow clock
The little LED module is skittering about on the desk quite a bit. I might have to 3D print a little stand for it. I don’t have a mechanical drawing for this module, but as they are still being sold online, I should be able to find one.
Looking online for some more information about these little LED modules, I see that I have the “v1.0” revision of the board, with a “CATALEX” logo and the date “02/10/2014” on the back. The current crop of boards available online show a “V1.1” revision, as well as square pad on the ground terminal, indicating pin 1. That was my guess, anyway. Sometimes I get lucky.
Note that this is the version of the LED module that has four complete seven segment displays and a center colon, but no decimal points.
The driver ship also supports scanning a small keyboard of up to sixteen (16) individual buttons, but does not support “n-key rollover”, so you can’t press more than one key at once. Well, you can, but the results are not guaranteed. To avail ourselves of this feature, I would have to tack on some wires directly to the chip on the back of the module. As the -203 has many as-yet unused pins that could be used for this function, we’ll keep that trick in our back pocket for now.
Having created a new MounRiver Studio 2 (MRS2) project for the software, named “C8-TM1637-clock”, of course, I can see that the USART serial lines are correctly connected and that the system is running at 96 MHz, which is the MRS2 default for these chips. I bumped that up to 144 MHz, because why not? The Blue Pill board already has a 8 MHz quartz crystal and 10 pF bypass capacitors (0402 packages – almost invisibly small) installed. Once all the “clockwork” of the clock is clocking clockfully, I can probably run the CPU from the internal RC oscillator, as the precision needed for keeping time will be the job of the 32,768 Hz crystal.
The Blue Pill board also has a blue LED mounted in active high configuration to pin PB2, via a 1.5KΩ to limit the current. Let’s blink that LED, just to make sure we can.
First, I create a new function called gpio_init() to set up everything. There, we enable the peripheral clock for GPIOB with this SDK call:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // enable GPIOB peripheral clock
Next, the first three pins of GPIOB are configured as push-pull outputs. I have arbitrarily decided to use PB0 as the clock line and PB1 as the data line for the TM1637 module. The code looks like this:
GPIO_InitTypeDef gpio_init_structure = {
.GPIO_Mode = GPIO_Mode_Out_PP,
.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2,
.GPIO_Speed = GPIO_Speed_2MHz
};
GPIO_Init(GPIOB, &gpio_init_structure);
No high-speed shenanigans are required, so I specified the lowest frequency, 2 MHz. The maximum clock speed for the TM1637 is 250 KHz. 2 MHz is overkill, but it’s the lowest setting available.
Within the main() function’s infinite loop, I put this code to blink the LED:
GPIO_WriteBit(GPIOB, GPIO_Pin_2, Bit_SET); // LED on
Delay_Ms(250); // short delay
GPIO_WriteBit(GPIOB, GPIO_Pin_2, Bit_RESET); // LED off
Delay_Ms(250); // short delay
And sure enough, there’s that blinking LED we all love to see early on in any embedded project. All is well with the world.
Now to set up the real-time clock (RTC) peripheral on this chip. It gets a whole chapter in the Reference Manual, Chapter 6. The manufacturer also supplies a code example called “RTC_Calendar” that demonstrates the RTC being set up and printing the time and date to the serial console, using an interrupt. We can peek at this code to get an idea of what is involved to get it clocking ourselves.
The RTC circuit on this chip is simple in its execution. It’s a 32 bit counter that has a programmable clock prescaler and choice of clock inputs. For time-of-day applications, it’s almost always going to be driven by a dedicated 32,768 Hz quartz crystal attached as the LSE (low speed, external) oscillator, divided down into one second pulses. Oddly, all the access and manipulation registers are only 16 bits wide. With 2^32 seconds of run time before it overflows, which is over 136 years, you’d think we’d be safe. But this is exactly the predicament we find ourselves in with the Unix Epoch, wherein the ancestors started counting seconds on 1 January 1970, thinking that the year 2106 would never come. Well, it will, and it’s only 81 years from the date of this writing. Your Humble Narrator fully intends to be complaining about things such as this well past this milestone in our future.
Since the madness of daylight saving time has yet to be expunged from our civilization, we also have to deal with that nonsense, if we’re going to have a clock that sorta-kinda reflects the societally-agreed-upon time. Leap years, on the other hand, are a completely natural and reasonable thing to handle, as the orbital velocity and rotational velocity of this planet are not (yet) tidally locked. One day, we can hope, it will be. Then peace will guide the planets and love, love will steer the stars. Until then, there’s a surprisingly elegant mathematical solution that should keep us pretty close for many centuries.
Another interesting thing about the RTC is that it is within the “backup power domain” of this chip. There is a separate power input pin on this family of chips for battery power, so that things such as the real-time clock and other critical functions can be preserved even when the flash & bang parts of the chip are powered up and down. There is a recognized division within the chip as far as access from one domain to another goes, in that there is a specific sequence of steps to be taken to reset and configure the RTC, even if the rest of the chip has been power cycled.
The Blue Pill board does not provide a separate battery connection, but instead routes the regulated 3.3V supply, via a Schottky diode, to the VBAT pin. I’m not too awfully worried about it at the moment. The next stage of this project, should it ever transpire, would be to create a bespoke PCB for the components and implement a direct LED drive circuit, obviating the need for the TM1637 circuit entirely. Alternately, a dedicated RTC chip with its own backup battery could be added to even the humblest -003 variant as another approach, using abundantly available modules.
There are three key ingredients to any successful timepiece:
1. Keeping time
2. Telling time
3. Setting the time
Now you can also get fancy and add other functions, such as calendars, alarms, timers, and other really nice features. But the basic requirements of a useful clock must be addressed first. I’ve hinted at my solutions for the first two requirements (1: on-chip RTC, 2: TM1637 LED module) but haven’t talked about how we are going to set the time. The SDK example cheats, and just insists that “the initial time is 13:58:55 on October 8, 2019”, which was not when the software was published, so I assume it has some other significance.
Next steps will be to transfer over the appropriate code to set up the RTC, probably using a fake time as well, then start to get some of the LED segments glowing. The time setting user interface I will leave for last.