LedClock is clock which shows the time based on the outer glow of a circular led strip. I’m creating this with the WS2812B ledstrip a MSP430G2553 as the controller.
This project is an attempt to replecate the following clock:
- DS1307 RTC
- WS2812B Led strip
- PIR sensor
To control the WS2812 I’m using the SPI bus. I’m using the mechanism described below but instead of 3 or 4 bit encoding I’m using 8 bit encoding at the moment. This will be optimized to 3 or 4 in the near future.
For energy saving and optimum usage of the ledstrips the strips brightness is controlled based on an LDR (Light Dependent Resistor). This ensures the same brightness during the day. The PIR sensor (passive infrared sensor) is used to only turn on the leds when a person is in the room.
Testing PIR logic
Real time clock
At the start I was using the internal oscillator of the MSP430 and a timer running at 1Hz to get the clock going. But the internal oscillator is not precise enough so after 6 hours I had 14 minutes of drift on my clock. So instead I’m going to use a DS1307 RTC to keep the drift on a minimum. The external 1Hz clock output will be used to get the clock going instead of the internal oscillator and the RTC’s eeprom will be used to keep the time settings in case of a power outage because it has a backup battery.
Two protocols on same I/O
Because I’m using the MSP430G2553 I have to switch between SPI and I2C to control the RTC and the Ledstrips. This can be done simultaneously. Because I2C operates at 100 kHz and SPI at 5.3 mHz.
Besides the frequency difference I’m not using the clock when using SPI to control the ledstrips so this won’t interfere with I2C.
Programming DIP after placement
Because I want to use the same chip as is currently in my development board I was looking for a way to program a dip without removing it or adding additional programming headers. I’ve ordered a DIP clamp. These can be found on ebay or aliexpress for about 7 bucks.
I’m going to hookup the DIP clamp according to this schematic:
From design to prototype
After designing the clock in FreeCAD I exported the parts to a .dxf format. To see if the design will work out I decided to cut a sheet of paper as a first try:
After being happy with the result I turned to 5 mm multiplex. The clock has a thickness of 21mm. The top and bottom plates are 3 mm thick this leaves 15mm for the inner ring. I’ve chosen too cut it 3 times out of 5mm mutliplex because of the ease. Here is the result:
PCB prototyping and verification
Ledclock 3D modeling
After a lot of hassle with the CNC I finally cut the ledclock base out of MDF.
After 2.5 hours of CNC-ing I’m left with a raw MDF cut. Dubble sided ducktape wasn’t the best solution to hold it down. A slight sift of about half a mm had happend so it’s a little rough around the edges on the top.
Possible Bug and Fix
If you have a module like this…and it is unreliable or not working at all, here is a possible fix.
– Remove battery
– Remove D1, R6 and R4
– Solder jumper wire in place of R6
– Inspect crystal soldering – fix if necessary
– Replace battery
The module should now work properly. It requires 5V power, but will work with 3.3V logic.
The DS1307 can be replaced with the newer pin compatible DS1338 for operation from 1.8V to 5V, or the TI BQ32000 for 3.3V (only) operation.
Why this is so
The battery backup circuit on these modules is of poor design. D1 and R5 provide a charging current to the CR2032 coin cell. Lithium primary cells such as the CRxxxx series should not be (re)charged. Removing D1 fixes this. R4 & R6 create a voltage divider between the battery and the DS1307. This raises the source impedance (spec sheet warns against this) and increases the current draw from the battery. The voltage divider was necessary because the battery voltage would float at about 4.2V volts due to the D1/R5 circuit! That would keep the DS1307 disabled if present on the Vbat pin. Replacing R6 with a jumper allows the full battery voltage to Vbat.
This information is copied from here:forum.43oh.com/topic/4131-ds1307-rtc-eeprom-from-ebay-possible-unreliable-operation/
and full credit goes to it’s author. I’m writing this guide to hopefully save someone the 3+ hours it took me to learn this.
/* ****************** * 3-bit encoding * ****************** * * 8 bits from LED color stream encoded in 3 byte for transport stream (SPI TX) * or: 1 bit from LED color stream encoded in 3 bit for transport stream * * _ * ZERO: 100 |__ * __ * ONE : 110 |_ * * the bti in the middle defines the value * * data stream: 0x23 0 0 1 0 0 0 1 1 * encoding: 1x01x01x01x01x01x01x01x0 * transport stream: 100100110100100100110110 * * initial mask: 0x92 0x49 0x24 100100100100100100100100 * * sourcebit : 7 6 5 4 3 2 1 0 * encoding : 1x01x01x01x01x01x01x01x0 * targetbit : 6 3 0 5 2 7 4 1 * targetbyte: | 0 | 1 | 2 | * * sourcebit -> (targetbit,targetbyte) * 7->(6,0) * 6->(3,0) * 5->(0,0) * 4->(5,1) * 3->(2,1) * 2->(7,2) * 1->(4,2) * 0->(1,2) */ /* ****************** * 4-bit encoding * ****************** * * 2 bits from LED color stream encoded in 1 byte for transport stream (SPI TX) * or: 1 bit from LED color stream encoded in 4 bit for transport stream * * _ * ZERO: 1000 = 0x8 |___ * ___ * ONE : 1110 = 0xE |_ * * SPI Clock around 3.2MHz (e.g. 6.7MHz/2 = 3.35MHz) * */ #define ZEROPATTERN 0x8 // 4-bit #define ONEPATTERN 0xE // 4-bit // _ _ #define ZEROZEROPATTERN ((ZEROPATTERN<<4) | ZEROPATTERN) // 10001000 |___| |___ // _ ___ #define ZEROONEPATTERN ((ZEROPATTERN<<4) | ONEPATTERN) // 10001110 |___| |_ // ___ _ #define ONEZEROPATTERN (( ONEPATTERN<<4) | ZEROPATTERN) // 11101000 |_| |___ // ___ ___ #define ONEONEPATTERN (( ONEPATTERN<<4) | ONEPATTERN) // 11101110 |_| |_ */