circuitcellar.com
Magazine Support   Digital Library   Products & Services   Suppliers Directory 
 
 





 

June 2000, Issue 119

The Chips are Alive with the Sound of Music
Imitatiing the Dead Melody IC


by Jeff Bachiochi

FIRST COMPARISON

Both chips execute an instruction in 1 µs. Although Microchip’s instruction set is simpler, many operations require multiple instructions because data must move through the W register. One of Microchip’s 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 1—The 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)
//Atmel’s 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 2—Here’s 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 note’s 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.

Here’s 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 note’s 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 you’ve 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 doesn’t need to know how to produce the note, just where it’s 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 don’t 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 you’re ready to begin.

The frequency output continues for the note’s 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.