5.4.1 The bit composer's playground
In the source code eight registers are used to compose the serial bits for
the 4094s. Those are named rT0 to rT7 and located in R0 to R7.
rTn is responsible for the bits in 4094-n.
Those registers normally are composed when one second is over. Depending from
all bits in the eight registers are either set to ones or to zeroes. If only
one of the two constants is one, one's are the choice. This does the macro
- the cUln2001 state (reversed signal polarity through ULN driver), and
- the cSink state (reversed LEDs through sink mode)
5.4.2 Setting/Clearing one bit in the playground
Very often in the different subroutines one of the 60 time bits has to be
set or cleared, depending from the polarity (see above). The macro SetBit
does this. The bit to be set has to be in register rmp and between 0 and
59 (seconds and minutes directly). In case of hours: if larger than 11 subtract
12, then multiply by five and enter SetBit.
Firstly, the four extra LEDs have to be jumped over by increasing rmp, if
certain values are exceeded. Then the rmp, now between 0 and 63, is
converted into a 16-bit-address (through dividing by 8) in register pair Z. The
bit position is calculated by shifting a one to the left for the remaining division
Depending from the the macro parameter @0, which can either be 1 or 0, and depending
from the polarity, the bit, that is now in rShft, is either set or cleared:
This macro parameter @0 enables it to definitely set or clear the bit for the display
of seconds, if @0 is one. When displaying hours or minutes, the EOR just reverses the
state of the LED, so that, in case minutes and hours are on the same LED, the LED is
turned on/off in the one and two second blinking rhythm mode of minutes and hours.
- Parameter @0 = 0: bit is reversed with EORing rmp with rShft,
- Parameter @0 = 1: if bits are
- not reversed (cUln2001 == cSource): bit is set by ORing rmp with
- reversed (cUln2001 <> cSource): bit is cleared by ANDing rmp
with the inverted rShft.
5.4.3 The other four LEDs
While the AM/PM LEDs are activated during normal mode, by either setting or
clearing (depending from the polarity) bit 7 of rT6 (AM) or of rT0
(PM). In normal mode those two LEDs are not blinking.
This changes in adjustment mode. Here the AM/PM as well as the yellow Adjust-LED
and the red Alarm-LED (if active) blink. See the adjustment section below on the
5.4.4 Transmitting the LED bits in the playgound to the 4094
Transmitting the bits to the 4094s goes as follows:
Note that the data sheets by Texas Instruments are faulty: their truth table says
that clocking and strobing is only active if OUTPUT ENABLE is high. Their diagrams
show that the OUTPUT ENABLE influences only the output pins, but have no connection
to the shift registers and CLOCK or STROBE.
- Placing of the first eight data bits for the LEDs to the output port D. Bit
PD0 is for 4094-1, bit PD1 is for 4094-2, etc.
- Pulsing the CLOCK input of all 4094 to high for at least 1µs long,
which shifts the data bits to the shift register. This is done with the macro
PulseClock, which does
- wait for at least one µs, then
- either sets PC2 high (cUln2001 = 0) or low (cUln2001 = 1),
- wait for at least one µs, then
- either clears PC2 (cUln2001 = 0) or sets it high (cUln2001
- Placing the second, third, etc. data bits to port D and clocking those into
the 4094s's shift registers.
- By pulsing the STROBE inputs of all 4094s for at least 1µs the content
of the shiftregisters is latched into the flip-flop-latches of the 4094s (macro
- By setting the OUTPUT ENABLE pin high, the latch content appears on the
eight output pins.
The complete interrupt service routine with the increase of the seconds, composing
the next playground and transmitting it to the 4094s needs roughly 10 milli-seconds
execution time. With that, the controller is busy for 1% of its time at 32kHz clock.
This also speaks for a low clock rate of 32kHz: with more MHz the controller would
only wait an extended time for the next execution event, nothing else useful to do
5.4.5 The default LED association to the output pins of the 4094s
The LED rows in the hardware schematic are not simply straight-forward, but have
a special structure. The 64 different bits in the eight rTn registers are not
simply to be transmitted in a straight way, because L1 is not necessarily Q1 of the
4094-1, and L8 not always Q8 of the 4094-1. Depending from PCB design decisions the
outputs of the 4094s are driving different LEDs. The following depicts the first 4094,
that drives the first seven 3mm digits L1 to L7 plus the 5mm LED L8.
This design, used in the here published PCB version above, associates Q1 of the
4094 (pin 4 of the DIL package) with L4. This and the other seven associations
are listed in the first two lines of the table. The third row of the table shows
how the eight bits of the registers rTn are organized: bit 1 or B1 is
responsible for L1 and the least significant bit.
Note that the bit names in rTn are the original bit numbers that were at that
place of the byte before transmission started. Shifting and swapping moves those
original bits during transmission.
The first bit to be send is that for the final output Q8, because the shift register
4094 shifts the bits to the left (from the data input to bit 1, from bit 1 to bit 2,
etc.), so that the first transmitted bit should be that for Q8. But Q8 is pin 11 of
the 4094 and this is connected to L5. So the first bit to be transmitted is bit B5
of rTn. To get B5 either to the right or to the left corner of the byte (to
allow shifting bits to carry with LSR or LSL) in rTn, we can SWAP the
register. Swapping exchanges the upper and lower nibble of the byte, and bit B5 is
now the lowest bit on the right side of rTn. Of course, we have to SWAP all
registers rTn in the same manner. A SWAP has to exchange nibbles in all eight
rTn registers, so needs eight clock cycles. These are 244µs at 32.768kHz
clock, not a very long time if it is only executed once per second.
An LSR-instruction shifts this bit B5 now into the carry bit of SREG, by that
shifting B6 as the next lowest bit. The carry bit is then rotated left into the
After four LSR+ROL instructions, B5 to B8 have been transmitted to the 4094. Now B1
is the lowest bit in rTn. And the next four bits are in the correct row to be
send. So, one initial SWAP and 8 LSRs and ROLs transfer the eight bits for the 4094
in the correct row. Of course, the other seven rTns are to be shifted and
rotated simultanously to get eight data bits together and to shift eight bits
per clock to all eight 4094s.
Several alternative PCB designs are possible. Here are three alternatives.
5.4.6 Alternative design: the upper nibble on the outside
In this PCB design, the upper four bits are not routed inside the DIL but outside.
This also changes the LED row: now the upper bits Q5 to Q8 of the 4094 are responsible
for L5 to L8 of the LEDs,in the correct row. Only the lower nibble is still reversed:
L1 is on Q4, etc..
Now the four upper bits of rTn are already in the correct row: they can
be shifted out of rTn when an LSL instruction is used, followed by a ROL to
the transmit register.
But when four shifts have been made, B4 is now the most significant bit. The row
has to be reversed then, because Q4 is connected with L1, so we have to send B1
as the fifth bit. This is done with a swap after four shifts: now B1 is the least
significant bit and can be shifted to carry with LSR. This is repeated threetimes,
and all bits in the correct row are written to the 4094s.
5.4.7 Alternative design: all pins in a correct row
This puts the pins into a correct row: here, L1 to L4 are routed on the inside of the
DIL package and L5 to L8 on the outside. So the association is linear: Output Q1 is
LED L1, Q2 is L2, etc.
This simplifies transmission a lot: no swapping or other tricks, just LSL on the
rTn and ROL of the transmitter register. And that eight times until all bits
are shifted into the 4094s.
5.4.8 Alternative design: the 4094 turned around
We could change the direction in which the 4094s are mounted, by 180 degrees. That
has the following advantages:
The angled mounting of the 4094 changes the associations as can be seen in the table:
Q1 of the 4094 is now L8, Q2 is L7, etc. The upper nibble of the 4094 has Q5 on
L1, Q6 on L2, etc.
- The STROBE, DATA, CLOCK and OUTPUT ENABLE pins of the 4094 are now in direction
to the inside of the circle and (except for the DATA) could be connected by conductor
pathes for all eight 4094s.
- All positive supply plus pins point to the inside of the circle, caps can be
placed in a simpler way.
- Only the GND pin is a little bit longer.
- Conductor pathes to the LEDs are shorter.
As Q8 is now B1 of the rTn, we first have to SWAP the register. Now B4 is the
most significant bit and can be shifted to carry with the LSL instruction. After the
first four bits are transmitted, we have to change the row again, to have B5 as the
least significant bit. The second row is transmitted with LSR and ROL.
Typical for that is that SWAP appears twice. But remember: a SWAP needs eight clock
cycles (one for each rTn) or 244µs at 32.768kHz, so both add
488µs or less than a Millisecond.
5.4.9 Alternative design: the 4094 turned around and the lower nibble on the inside
Here, for completeness, the fourth alternative. In that case SWAP is once at the beginning,
then followed by eight LSLs and ROLs.
5.4.10 Alternative design: the 4094 turned around and straight and upper nibble on the inside
Now here is another alternative: the 4094 reversed, placing the lower nibble on the
outside and the upper nibble on the outside, and all that with a straight design. In that
case transmitting is not that simple: a swap, four LSL, another swapand four LSR.
You see, anything goes if your software is in assembler and uses such nice instructions
like LSL and LSR together with ROL, as well as SWAP. Try this in another language, the
swaps and rotates will turn your hair grayer and grayer. Anything simple and straight
here, no bracket orgy to get confused.
5.5 The bits of the playground in the adjust mode
While time display is, more or less, straight forward, the adjust mode changes a lot.
In adjust mode the ADC determines the rhythm. Adjust mode always needs the potentiometer
to adjust hours, minutes, seconds and the melodies. The ADC measures the voltages of
the potentiometer continously and sums up the 8-bit values 256 times.
The 8-bit MSB result of the sum is then multiplied:
The MSB of the multiplication is stored in SRAM, so that any key interrupts find the
correct selection there and can either continuing or copy all three selected values
over to the time or the alarm time registers.
- hours: by 24,
- minutes, seconds: by 60,
- melodies: by the number of melodies stored.
Another counter counts the completion of the 256 average conversions. As this depends
from the clock rate, the AD-prescaler and this counter are used to come to roughly
210 milliseconds repeat time. See the sheet adc in the LibreOffice
calculation file for more timing details.
If the downcounter reaches zero, the respective LED with the original value is set.
If the number of display events is odd, the adjusted value (hour, minute, second or
melody number) is also displayed and therefore blinks. If it is even, the yellow
adjustment LED is activated by setting/clearing bit 7 of rT4 and, if the
alarm is active, the alarm LED is setting/clearing bit 7 of rT2.
5.6 How it works: Key processing
Key processing goes via PCINTs. Any change of the ALARM switch is immediately copied
to the bAlrm flag using the PCINT0. The two other keys work different.
If key1 is pressed (PCINT10), then it is decided between the following:
If key2is pressed (PCINT9), then it is decided between the following:
- If adjustment mode is inactive (flag bAdj = 0), the adjustment mode
flag as well as the hours and minute adjust flags (bAdjHr, bAdjMin)
are set and the ADC is started.
- If adjustment mode is already active, it is decided whether hour adjustment
is active (bAdjHr = 1). If that is the case, the adjustment flag is cleared
and the ADC is stopped. If hour adjustmentis inactive and the minute adjustment
flag bAdjMin is active, the hour adjustment flag bAdjHr is set.
If bAdjMin is clear then this flag is set.
- If not in adjustment mode and flag bAlrm is set, then the alarm time
is increased by five minutes.
- If in adjustment mode and
- the adjust hour bit is one, the hour is stored in SRAM and the adjust hour
bit is cleared,
- if the adjust hour bit is clear, it is checked whether the adjust minute
is set or clear, and
- if set, the minute is stored in SRAM and the minute flag is cleared,
- if not set, then
and the adjustment bit is cleared.
- if bAlrm is zero, the stored hours, minutes and seconds overwrite
the time registers,
- if bAlrm is one, the stored hours, minutes and melody number
overwrites the alarm time registers,
5.7 How it works: Music and melodies
5.7.1 Music notes
With crystals above 1 MHz up to 63 music notes are available as constants. With
the default 32.768kHz clock only the first 45 musical notes are available,
because of to the limited capabilities to generate higher-frequency tones.
The names of those tones start with n for notes, followed by the
note's octal name with one character (A, H, C, D, E, F, G) and the octave,
ranging from 0 to 9 (32.768kHz: 0 to 6).
The note cPause or zero switches the output off, when played. It can be used
to generate silent pauses, with an inactive speaker output. The output pin is then
cleared instead of toggling. The note 255 or 0xFF switches signals the end of the
melody: the output pin is put low, the timer TC2 and its interrupt on compare match
A are disabled and so ends the music output.
The LibreOffice sheet "music notes" provides a calculation sheet that has
all those notes, their frequencies, the optimal setting of the prescaler and of the
compare match value of 16-bit timer TC1. It provides two lists that can be copied
from the LibreOffice sheet to the assembler source code:
Note that the table NotesTable: also includes the d value, which is the delta
of the tone generated by the TC as compared to the desired frequency. The delta is in
percent. Note also, that with the low frequency crystal the higher tones of octave 5
differ by more than 2% from the desired value. That is why the low-frequency tones
are limited to octave 6, with the highest tone +4.5% too high.
- Notes: defines all musical notes as constants, so that melodies can be written
with those constants,
- NotesTable: defines the CTC values for compare match A in the CTC mode
of TC1 and the duration of that tone, which is equal to the compare matches for
one second duration of that tone multiplied by two.
- The constant nPresc8, which is defined on top of NotesTable:,
says from which of the tones the prescaler of TC1 has to be one, tones below
have a prescaler of eight. Crystals with or below 3.579545MHz do not need
prescaler values other than 1.
By default the source code includes eight melodies. See the melody section of the
source code to understand how these are programmed.
Each tone consists of two bytes: the first byte is the note's number (nTN,
the second byte is the duration of the tone. The duration is encoded as multiples
of 1/16th. The standard pause of 4/16th of a second needs a 4, a tone duration of
one second needs 16. The maximum duration is 27 for the highest tone G9
or 127 for G6, which corresponds to a maximum tone duration of 1.7 resp.
10 seconds. The lower the tone the higher can be the durations. As the duration
factor is 8 bit in size a maximum of 16 seconds is possible for lower frequency
The following pause's duration is encoded in the same way, with 1/16th of a second
An example "melody" would be for example:
The first line encodes the notes C2, D2, E2,
F2 and G2. The duration of those tones is 1/16th, 2/16th,
4/16th, 8/16th and 16/th in the first row.
.db nC2,1,nD2,2,nE2,4,nF2,8,nG2,16 ; Without pauses in between notes
.db nC3,1,0,4,nD3,2,0,4,nE3,4,0,4,nF3,8,0,4,nG3,8,0,4 ; With standard pauses
.db 0xFF,0xFF ; End of the melody
The second row inserts pauses of 4/16th of a second (250 ms) between all
the notes, their frequency is one octave higher (C3 etc.). Please
note that the G3 is of a length of 8/16th, so equals F3
Of course, line 3 has the end-of-the-melody encoding.
To add further melodies you'll have to write a table with the notes and pauses to
be played and ending with 0xFF and 0xFF and name it Melody8:. All other
settings are automated, so you do not have to care (as long as Melody15:
is not exceeded).
5.7.3 Music play software
The software to play those tunes works as follows.
The Timer/Counter TC1 does all the hardware processing. If the tone is on, it toggles
the OC1A output pin, if the tone is off (note = 0) it clears OC1A. To play a certain
frequency, the TC1 is in CTC mode, with Compare A as frequency control. The compare
match A interrupt is executed.
Each tone to be played, that has an entry in the Notes: list, also has an entry
in the table named NotesTable:. The two words per tone consist of the following:
Music output is started with the macro StartMelody. This macro
- The first word is the CTC value, already decreased by one and can be directly
written to the compare match A registers of TC1 (OCR1AH:OCR1AL).
- The second word gives the number of OCR1A interrupts for the duration of this
tone for one second, which is two times the frequency's tone. This number is
used to calculate the tone duration, the time over which this tone is to be
Further processing is done in the interrupt service routine for TC1's compare match
A interrupt. This routine reads the next byte from the address in Y. If that is 0xFF,
the routine checks if the adjust mode bAdj is active and the bHr as
well as bMin are clear. In that case the melody play is restarted, if not then
TC1 and its interrupt enable bit is switched off.
- reads the melody to be played, identifies the melody's address and sets the
register pair YH:YL to its address,
- sets the TC1 to count and to interrupt on compare match A.
If it is not a 0xFF, it is checked whether it is zero. If so, the OC1A pin is set to
clear on compare match, otherwise it is set to toggle the pin OC1A, by that turning
the tone on.
The note is then re-read. If the note is smaller than nPresc8, the prescaler
of TC1 is set to 8, if not it is set to 1. The note is again re-read, together with
the the duration multiplier that follows. The note is then multiplied by four and
added to the doubled NotesTable: start address. The first two bytes are read and
written as new CTC value to the compare register A of TC1.
The next two bytes of the NotesTable: are written to XH:XL. This is first
divided by 16, because this is the base length with which the duration multiplier
has to be multiplied. To avoid rounding errors when dividing by 16, an additional
byte is used to shift the bits bits to, which is register rmp.
The result of the division by 16 is copied to ZH:ZL and rmp is copied to
rShft. Then the multiplicator is decreased. If it isn't zero, the registers
rShft and rmp are added, and ZH:ZL as well as the carry bit from the
previous addition are added to XH:XL. The XH:XL registers after that hold the number
of TC2 compare match interrupts over which the tone is to be played.
These two pictures simulate tone generation with the OC1A output pin. The above
listed melody is played.
The 131.072 Hz in the left diagram of the first tone is very close to the
C2's 130.8175 Hz. The difference is caused by integer math: if we want
the tone to be more correct, we would have to pick a 20MHz crystal, which
would fit more precisely to the tones. But a usual listener wouldn't hear the
To the right, the tone D2 follows with a frequency of 146.286 Hz,
which should rather be 146.8325. Also a difference for a tone specialist's ear.
The duration now is twice as long, the 1 plus 2 sixteenth sum up to 187.5 ms.
The same exact timing is going on when E2 and F2 follow for
4 and 8/16th of a second.
Here, the fifth tone, a G2 follows.
Then the pause-separated tones with one octave higher frequencies start. To the left,
the C3 has been issued, to the right the next tone starts after a 250 ms
The next two tones follow, after a standard pause of 1/4th of a second.
The last tone, a G3, follows with a duration of 8/16th of a second.
Now, all tones of the above "melody" have been played. The last pause follows,
then the transmitter is switched off.
©2021/22 by http://www.avr-asm-tutorial.net