By exploiting these ideas I hacked a Kitvision digital picture frame to make it into a Daylight Clock.
By showing a pre-existing map image and cutting the RGB signal at the right moments (using code derived from Peter Duffett-Smith’s Practical Astronomy with your Calculator) you get the following (which looks better than in the photograph) :
The trick is to do the calculation during the flyback period, and use interrupts to do the time critical cutting of the picture. In addition to the Digital Picture Frame, the project uses just two ICs : an ATMega328 clocked at 16MHz (mainly needing the 32k of program space for the calculation of the sunset/terminator line) and a video switch chip (analog multiplexer) 74HC4053. The AT Mega has no trouble keeping up – the quantisation of the jagged terminator line is however due to the timing fidelity driven by the clock.
The result can be compared with an online solution. Note that the time shown in the picture was added by the camera and is BST (GMT+1).
Essentially the Photo Frame shows a map of the world and the ATMega decides which parts should be dark and light and controls the analog multiplexer to switch between the frame’s picture and black. Serendipitous stray coupling between the signals gives the ‘moonlight’ effect of the dark!
The frame used was a Kitvision. Models DPF7SIK or DPF7BKK (respectively Silver and Black) are 7 inch digital photograph frames with 480 x 234 pixel displays. Depending on the model they can access 8MB or 20MB files, with SD/MMC/MS CARD and USB interfaces.
Although all sharing the above model numbers, the internal components differ. Notably certain models (all of those operating at 5V that I have bought) have convenient pads on the circuit boards allowing video signals to be extracted. The one model with a 12V supply was entirely different internally, with no easy access to the signals. Externally the 12V model is distinguished by 4 buttons on the back, rather than 6 buttons on the top and is also the only model to allow the 20MB files.
In addition to convenient access, 5V is of course also convenient to link to TTL logic and to provide power for a microcontroller. Although the three 5V DPF7xxK that I have bought all have different display models, the circuit board is common. Although one of the three also had a different display ribbon connector (while the other two were physically and electrically interchangeable), the circuit board is common – with solder pads for either ribbon, the other being left unconnected. The circuit board from the rear looks like:
All pads are visible, although the +5V supply label is just out of shot – the pad is to the top left of the ribbon connector. Those of interest are :
|VR||Red||Red||Analog RGB – RED|
|VG||Green||Green||Analog RGB – GREEN|
|VB||Blue||Blue||Analog RGB – BLUE|
|VCOM||RGB common||Brown||Square wave to provide common level for RGB signals (presumably zero DC offset)|
|CLK||Clock||Grey||Pixel clock ~10MHz square wave|
|STV||Start Vertical||Orange||Pulses before 1st display line, at about 55Hz|
|CKV||Vertical clock||Yellow||Pulse at new horizontal line, about 15.6kHz|
|OEV or STH?||Output enable vertical||White||Returns screen to default in interval – allows DC to stabilise.|
The image below shows the connections to the pads on the rear (left hand side) and the front (right hand side). On the front, the RGB connections are made to one end of a SMD capacitor’s pad after the capacitor was removed (achieved by snipping with pliers). The whole is later held in place with epoxy. Effectively the 4053 switch replaces the capacitor.
By using an ATMega328, one can connect the STV pulse direct to the INT0 input (PD2) which will trigger an interrupt routine whenever the display is about to refresh (rising pulse). As can be seen, the routine can set the display row number to zero, and also rely on the signal to increment an accurate clock (JulianFract is a time variable which runs from 0.0 to 1.0 over 24 hours). STVHZ is about 60Hz. This means there is ~17ms for all horizontal lines to be painted – which would allow 262 lines at 64μs per line (see below). The display has only 232 lines allowing some spare time (~2ms).
STV pulse width (while high) is measured at ~6.4μs; the manual seems to have 64μs. Curious.
AVR C Interrupt code for the vertical pulse is:
ISR(INT0_vect) // Highest priority. Used for STV - Vertical start pulse
// STV measured at ~6.4 us width high pulse approx every 17ms i.e. 60Hz
// STV line is ORANGE and connected to INT0 - PD2 on Atmega8/328
row=0; // Measured at 1.75us at 16MHz
The CKV pulse can be connected to INT1 and will trigger whenever a new row is about to start. The CKV signal looks like :
CKV is low for about 52μs, during which there are 480 pixels of about 94ns each (48μs total). CKV is high for ~12μs, during which there is ‘flyback’. Hence the period is about 64μs, i.e. 15,625Hz.
The signal can be used to control what we display. In this example the idea is that any given row will display either some day, followed by night, followed by day – or the reverse (Night-Day-Night); with special cases all day or all night.
We have previously (outside the interrupt) calculated two array of values, two values for each row. One signifies the point at which darkness should start, and the other the point at which the day should start. Whichever is smaller dictates the starting point – i.e. to draw day-night-day specify the -night-day part which implies the initial day- part.
VCOM looks like this (the even square wave) and switches polarity at every STH pulse (i.e. for alternate rows) as shown.
The AVR C code for processing rows is:
ISR(INT1_vect) // Second priority. Used for CKV - New row
// CKV measured as 3V p2p. Square wave with approx 1:4 mark to space
// Measured 12us mark; 52 us space, 64us period = 15.6kHz
// CKV line is YELLOW and connected to INT1 - PD1 on Atmega8/328
// Original picture shows when PORTC 0..2 are HIGH
// Note that it is quicker to use PORTC = 0x07 and PORT C = 0;
// than PORTC |= (0x07) and PORT C &= ~(0x07)
// Logical to do this because we know we're not using the rest of PORT C
// and timing is crucial
t1=t1s[row]; // Copy to fixed variable to avoid repeating row index
t2=t2s[row]; // calculation – consistent speed
// Use -Os for this speed
if (t1 < t2) // Day-Night-Day
if ((t1+1) == t2) // Immediate Day
PORTC = RGB;
PORTC = RGB;
t3 = t2 - t1;
for (i=1;i<t1;i++) __asm("nop"); // Delay
PORTC = BLACK;
for (i=1;i<t3;i++) __asm("nop"); // Delay
PORTC = RGB;
[Similar code for Night-Day-Night]
I also got the extra code to display eclipse shadow calculations working on a PC but was having trouble shoe-horning that into the AT Mega’s 32k code limit, so that remains a work in progress.