June
2000, Issue 119
The
Chips are Alive with the Sound of Music
Imitatiing
the Dead Melody IC
FIRST COMPARISON
Both
chips execute an instruction in 1 µs. Although Microchips
instruction set is simpler, many operations require
multiple instructions because data must move through
the W register. One of Microchips powerful instructions
is the decfsz command,
which decrements, tests for zero, and determines a branch
in a single instruction and one instruction cycle (see
Listing 1). It takes two cycles if it must change the
program counter.
| Listing
1The decfsz command
determines a branch in a single instruction and
one instruction cycle. |
NOTDONE:
DECFSZ TEMP ; 1, 2ifz - decrement and skip
if zero
GOTO NOTDONE ; 2
DONE: (minimum of two execution cycles)
//Atmels equivalent code requires three instructions,
dec, tst, and breq and four to five instruction
cycles.
NOTDONE: DEC TEMP ; 1
TST TEMP ; 1
BREQ DONE ; 1, 2ifz - branch if zero
RJMP NOTDONE ; 2
DONE: (minimum of four execution cycles)
//Of course, you would likely use the opposite branch
instruction and save a cycle.
NOTDONE: DEC TEMP ; 1
TST TEMP ; 1
BRNE NOTDONE ; 1,2if<>z - branch if not zero
DONE: (minimum of 3 execution cycles)
//If you had a spare register that was cleared,
you could use this (TEMPZ) register to save another
cycle.
NOTDONE: DEC TEMP ; 1
CPSE TEMP,TEMPZ ; 1 - compare and skip if equal
RJMP NOTDONE ; 2
DONE: (minimum of two execution cycles) |
| Listing
2Heres the bit information arrangement. |
1xxxxxxx = Last note in list
0xxxxxxx = More notes in list
x1xxxxxx = Disable the frequency output (rest)
x0xxxxxx = Enable the frequency output (note)
xx11xxxx = Duration eight half beats (whole note)
xx10xxxx = Duration four half beats (half note)
xx01xxxx = Duration two half beats (quarter note)
xx00xxxx = Duration one half beats (eighth note)
xxxx0000 = Note table offset zero (note G)
xxxx1111 = Note table offset 15 (note F)
|
My
interrupt timer routines require the same number of
maximum instruction cycles for either processor. Frequency-generated
notes are based on the 64-µs timer interrupt routine.
Each notes duration is based on a tic or beat
of 1000h interrupts (~0.25 s). The rest of the code
is a small loop and two main lookup tables. The first
lookup table is an 8-bit code containing note, duration,
enable, and EOF information. See Listing 2 for the bit
information arrangement.
Heres
how it begins. After initial housekeeping, Table1offset
is cleared,
and the first value of Table 1 is read. If the MSB is
a one, you are at the last note in the tune, and the
Table1offset is cleared, allowing
the tune to repeat. Otherwise, Table1offset
is incremented for the next table1 read. Now,you have
the data indicating which note will be played and its
duration.
Next, Note1duration is initialized to one, and if the LSB duration is one,
Note1duration
is shifted left. If the MSB duration is also one, Note1
duration is shifted left twice. This shifting sets the
duration to one, two, four, or eight. This is used to
count off the notes beats. Remember the second
(16-bit) counter in the interrupt routine? That counter
is responsible for the beat timing (of an eighth note).
In this case, the beat is arbitrarily set to ~0.25 s
(64 µs × 1000h). Now youve set up the number of
tics the note should last, one for 0.25 s (the shortest
note), two for 0.50 s, four for 1 s, or eight for ~2
s (the longest note).
The note number
(LS4B) of the first table read is used as an offset
in a second table. This table holds the Note1reload value.
The first table doesnt need to know how to produce
the note, just where its located in the second
table. Thus, the second table can be transposed easily
without worrying about the duration of the note. In
fact, the notes dont have to be in a particular
order and can span octaves.
Note1reload
has a count that produces periods where an output bit
is complemented every time the count reaches zero, which
is the frequency output of your note. Note1duration has a
count that counts off 0.25-s beats, which is the duration
of your note. When the counters are set, the interrupt
is enabled, and youre ready to begin.
The frequency
output continues for the notes duration. When
Note1 duration is zero (by 0.25-s tics), execution goes
back to reading another table entry. The loop continues
reading table entries until it finds an entry containing
the MSB set, when it clears Table1offset and starts the tune again. Bit 6 (enable) indicates a noteless
duration interval, called a rest. A one in this bit
location disables the frequency output for the duration
period.