Sharp logo
8253 sound functions 
( Part I )  

sound generation by counter #0

The control word at port $E007 of the counter #0 is set to mode 3 to operate this counter as a square wave generator for the sound generation. This takes effect by the value loaded into the control port $E007 during the setup of the 8253.

The input signal SOIN of 1.1088 MHz is connected to the pin CLK0 of the counter and will be divided by a value loaded into the port $E004. The result is a frequency which will be outputted at pin OUT0. The output is the input to an audio amplifier. A loudspeaker ( 8 Ohm/1W ) is connected to this amplifier.

The counter and its output can be started and stopped by port $E008.

The following sections will show:

how the sound generation by the monitor 1Z-013A is done,
how you can program the 8253 for your own purposes and which ports you need to this, and
how the hardware is working.

Note You can download now a programming example written in S-BASIC. It's a MZF-formatted and zipped file (1KB).

Ports of counter #0

This is an overview of the ports related to counter #0:

function IC#
This port is used to set the output frequency by loading a counter value. 8253 programmable interval timer
( PIT )
PT control word set to mode 3
( square wave generator ).
starts / stops the counter and its output by setting / resetting bit D0 of this port. Reading this bit is used to count the cycles of an oscillator 32Hz for tempo control function. LS02 control 6F
LS74 control 7E
LS367 buffer 4C
556 tempo, timer 32Hz BJ

The following table shows all bits of the port $E008 and its functions. I put the table in detail here to complete the information about the 8253 ports but only bit D0 is important for this section ( start / stop counter #0 and tempo control ).

port # bit function
set control counter 0:
Reading this bit will return the value 0 or 1 of the tempo controller part 3 ( see schematic diagram of the 8253 ) used for the time period of a note / rest. You'll read the periods of the tempo controller oscillator with approx. 32Hz.
joystick 1: connector P-13 JA1 ( pin # 3 )
joystick 1: connector P-13 JA2 ( pin # 4 )
joystick 2: connector P-14 JB1 ( pin # 3 )
joystick 2: connector P-14 JB2 ( pin # 4 )

Counter initiation

During monitor's startup the sound generator is set up and turned off by the following monitor instructions ( see the source code of the monitor ). The sound generator counter #0 must be turned off at startup, because the 8253 is in an undefined state after power on. This means, the counter may be in work and e.g. could output a tone to the loudspeaker if not turned off.

See the setup of the counter #0 by the monitor during its startup:

0095 CDBE02	CALL	MLDSP	  ;calls $02BE, melody stop
02BE 3E36	LD	A,$36	  ;counter control word 00110110 
02C0 3207E0	LD	(CONTF),A ;into port $E007 
02C3 AF		XOR	A	  ;accu=0 
02C4 3208E0	LD	(SUNDG),A ;silence (bit D0=0 of port
				  ;$E008 means stop counter #0)
02C7 C9		RET		  ;goback

Please refer to the control word of the 8253.

First $36 ( 00110110 binary ) is loaded by $02C0 into the control word port. This means:
Bits D7 = 0 and D6 = 0 indicates counter 0 will be set up
Bits D5 = 1 and D4 = 1 will load / read least significant byte first and then most significant byte
Bits D3 = 0, D2 = 1, and D1 = 1 indicates mode 3 is to set ( square wave generator )
Bit D0 = 0 indicates count will be in binary

Summary: The counter #0 is initiated to mode 3 to operate as a square wave generator, binary counting down and is to be read / load with the least significant byte first and the most significant byte last. This time the counter value isn't loaded. This will be done by a call of the melody play routine or by a call of the bell routine. I'll explain these routines in detail later.

At last the counter will be stopped by $02C4 ( bit D0 of port $E008 set to 0 ).

Using the counter
Outputting a tone by own routines

You can use the counter to generate any output frequencies within the following borders:

The input to the counter is 1.1088MHz ( signal SOIN at pin CLK0 ). This means the max. output frequency at pin OUT0 will be 1.1088MHz too. For further details how to set the counter refer to the details of mode 3.

The max. frequency will be invoked if you load $0001 into the counter port $E004:
1.1088MHz / 1 = 1.1088MHz.

Note Our ears cannot perceive frequencies about 15KHz / 18KHz but those output can be processed by your own hardware connected / soldered directly to pin OUT0 of the 8253 if needed.

The min. frequency will be invoked if you load $FFFF ( 65,535 decimal ) into the counter port $E004:
1.1088MHZ / 65,535 = 16.9Hz.

The counter starts if you set bit D0 of port $E008 and the counter stops if you reset bit D0 of port $E008.

For example, to output a tone of approximate 10KHz load $006F into the port $E004. Compute the counter value as follows:

1.1088MHz / 10kHz =
1.1088 x 106Hz / 10 x 103Hz = 110.8 decimal or 111 rounded decimal, it's $6F hexadecimal.

B000 116F00 LD	 DE,$006F   ; load count register value
B003 2104E0 LD	 HL,CONT0   ; address to port $E004
B006 73	    LD	 (HL),E	    ; load least significant byte 1st
B007 72	    LD   (HL),D	    ; load last significant byte last
B008 3E01   LD	 A,1	    ; set bit D0
B00A 3208E0 LD	 (SUNDG),A  ; to start the counter output
B00D ; at this point the loudspeaker outputs a tone of 10KHz

To stop the output code this:

B010 3E36   LD	 A,$36	    ; mode set, ctrlword into
B012 3207E0 LD	 (CONTF),A  ; port $E007
B015 AF	    XOR  A	    ; sets accu to 0 (all bits, D0 too)
B016 3208E0 LD	 (SUNDG),A  ; to stop the counter output
			    ; reset bit D0 of port $E008

If your application uses the joystick(s) too, the port $E008 should be read into the register A by LD A,(SUNDG) and then use AND A,$FE to stop the counter. Using XOR A at location $B015 as shown resets all other bits of port $E008 too.

Note Do not invoke a further call to $B000 before stopping the output by $B010 otherwise unpredictable output frequencies can occur.

Outputting a tone by monitor subroutines

You can output a tone by your own routines using the ports as described above or by the following monitor routines:

MSTA at loc. $0044 to start the output over the loudspeaker
MSTP at loc. $0047 to stop the output

Use MSTA to invoke the output and set RATIO at loc. $11A1 / $11A2 to the appropriate value before invoking MSTA. The valid range you can put into RATIO is from $0100 to $FFFF, this means that the frequency range goes from 4,331Hz to 16.9Hz.

Note The highest frequency is checked and suppressed by MSTA if RATIO is lower than $0100. No output will be invoked ( to this see $02AE to $02B0 of the monitor ) if the value stored in RATIO is lower than $0100! The counter value $0100 generates a frequency of 4,331Hz. Use own routines which use the ports as described above to generate frequencies above 4.331KHz.

For example to output a tone of 440Hz by MSTA set RATIO at location $11A1 / $11A2 to $09D8
( 1,1088,000Hz / 440 Hz = 2,560 decimal, it's $09D8 hexadecimal ) and invoke MSTA:

B000 21D809 LD	 HL,$09D8   ; Load count register value to invoke 440Hz
B003 22A111 LD	 (RATIO),HL ; store value to RATIO at $11A1
B006 CD4400 CALL MSTA	    ; Start output by MSTA at $0044
B009 ; at this point the loudspeaker outputs a tone of 440Hz

To stop the output invoke MSTP by a simple CALL only:

B010 CD4700 CALL MSTP       ; stop the output by MSTP at $0047

Note Do not invoke a further call to MSTA before stopping the output by MSTP otherwise unpredictable output frequencies can occur.

Note MSTP resets the joystick ports too.

Outputting a tone by the bell subroutine

If the bell subroutine at loc. $003E is invoked a short tone of 880Hz comes over the loudspeaker ( note +A0 will be played ).

To invoke the bell subroutine by your own program code only:

B000 CD3E00 CALL BELL ; invoke bell at $003E

The beep occurs only once per call.

To get a beep everytime a key is pressed like the monitor command B does, code:

B000 3A9D11 LD   A,(SWRK) ;get beep status (on or off)
B003 EE     XOR  $01	  ;invert beep status/bit 0
B004 329D11 LD   (SWRK),A ;store inverted bit 0
B007 C9     RET		  ;go back to caller

If the routine shown above is invoked again the bell output stops until the routine is invoked again
( flip / flop: on / off / on / and so on ).

Playing specified melodies

You can use the counter to play melodies by using the following monitor routines:

XTEMP at loc. $0041 to set the tempo of the melody that is to be played
MELDY at loc. $0030 to play the defined melody

Before invoking MELDY you have to set the tempo of the melody, you have to define the notes, their time periods and their octaves, and the rests and their time periods, and . Read the following sections which will show you how to do this.

A note has its own pitch ( its frequency ). An octave is a musical definition of a set of 7 notes, each octave having its own frequency range. The time period of a note is the time of a "note's life". The rest is a pause between two notes ( last and next note ) and the time period of a rest is the time of a "rest's life". The tempo is the tempo of the whole melody played.

Setting the tempo of a melody

The tempo will be set by XTEMP. Set the accumulator register A to any value of the valid range from $01 to $07. The meaning of the values is as follows:

slow: $01 ( Lento, Adagio )
medium: $04 ( Moderato ); default value set by monitor during its startup
quick: $07 ( Molto Allegro, Presto )

If you don't use XTEMP to set the tempo before invoking MELDY the default value $04 ( moderato / middle ) is used.

For example, to set the tempo to $07 code the following instructions:

B000 3E07   LD   A,$07 ; load tempo $07
B002 CD4100 CALL XTEMP ; execute tempo set routine
		       ; at location $0041

Note XTEMP sets TEMPW at location $119E but contrary to the values you have to load into the accumulator. This means $01 is quick and $07 is slow if you read TEMPW.

Note TEMPW can be set directly by your own program instead of using XTEMP:

B000 3E07   LD   A,$07     ; load tempo $07
B002 329E11 LD   (TEMPW),A ; into $119E
Defining notes and rests

Before you call MELDY you have to define a character string containing your notes, rests, etc. and the register DE must point to the address of this character string. The character string is to be defined like the definitions of the BASIC command MUSIC and must be terminated by $0D or $C8. On return to the caller the carry flag is set to 0 normally. If the execution of the melody subroutine is terminated by a user BREAK ( SHIFT- / BREAK-keys ) then the carry flag is set to 1 on return to the caller.

Valid notes are C, D, E, F, G, A, B, and additional, a preceding # to play a seminote is valid, for example, #C, #D,
#F, #G, #A. Code R to rest between notes.

one octave

Note Defining #E and / or #B is possible! ( But these are no valid musical notes.. ).
If you code #E then it is no error but the note F will be played as if you'd coded F.
If you code #B then the note +C will be played and if you code #B with a preceding - ( minus sign ) then the note C will be played. If you code +#B then +#B will be played but this is the note C of the octave following the upper octave! Fur further details see the table of the frequencies used by the monitor later in this chapter.

Defining time periods

A numeric suffix from 0 to 9 is valid and specifies the time period of the note / rest to be played. See the following picture for all valid time periods:

time periods of notes and rests

The tempo control part3 is used to wait a computed number of cycles before stopping the note / rest. The number of cycles a note / rest will be played depends on the time period value shown above. The tempo a melody is to play set by XTEMP or set by TEMP directly ( see above ). Further details about the computation etc. follow now.

The tempo control part3 is an oscillator and his output is available if bit D0 of the port $E008 is read. The cycles of this oscillator were counted to compute the time period a note / rest is to play.

Note Don't be confused of bit D0 usage. It can be read to compute the time periods and it can be written to it to
start / stop the output of counter #0.

I assume that the engeneers of the MZ-hardware designed the time period 9 of a whole note / rest to 1s if the tempo is set by XTEMP to $01 ( slow ). This means that the time for a 1/32 note / rest is 1/32 second if the defined time period is 0 ( see the figure above ).

Looking at the schematic diagram of the tempo controller oscillator ( part3 ) to calculate the nominal time period does not help because the capacity C86 with 1F can have a big tolerance which rather influences the output frequency. Calculating the frequency by the electronical parts as designed by an engeneer ( R110, R112, and C86 ) and by the following formula for the timer chip 556 ( astable multivibrator ) results to 38.1Hz:

1.44 / ((R112 + 2 x R110) / C86)

Insert R in Ohms, C in Farad: R112=1.8K, R110=18K, C86=1F

1.44 / ((1.8 x 103 + 2 x 18 x 103) / 1 x 10-6) = 38.095Hz

Note A frequency of 34.5Hz of my MZ-731 could be measured by a frequency counter. If you want to adjust this frequency to 32Hz exactly replace R112 and C86 by R112 = 1.5K and C86 = 1.2F ( try to get a good one or check out C86 for this value by a capacity meter, check R110 = 18K and R112 = 1.5K too by an ohm meter ).

The following table shows all possible, resulting number of cycles and values of time periods. The values enclosed in paranthesis base on 32Hz ( 31.25ms/cycle ) assumed as the correct output frequency of the timer oscillator and they show the timing in ms ( milliseconds ). The cycles are shown in bold digits.

Time period defined by the suffix of a note/rest
Tempo value contained in TEMPW at loc. $119E
5 (156.25)
7 (218.75)
10 (312.5)
12 (375.0)
14 (437.5)
9 (281.25)
12 (375.0)
15 (468.75)
18 (562.5)
21 (656.25)
12 (375.0)
16 (500.0)
20 (625.0)
24 (750.0)
28 (875.0)
12 (375.0)
18 (562.5)
24 (750.0)
30 (937.5)
36 (1125.0)
42 (1312.5)
16 (500.0)
24 (750.0)
32 (1000.0)
40 (1250.0)
48 (1500.0)
56 (1750.0)
12 (375.0)
24 (750.0)
36 (1125.0)
48 (1500.0)
60 (1875.0)
72 (2250.0)
84 (2625.0)
16 (500.0)
32 (1000.0)
48 (1500.0)
64 (2000.0)
80 (2500.0)
96 (3000.0)
112 (3500.0)
24 (750.0)
48 (1500.0)
72 (2250.0)
96 (3000.0)
120 (3750.0)
144 (4500.0)
168 (5250.0)
32 (1000.0)
64 (2000.0)
96 (3000.0)
128 (4000.0)
160 (5000.0)
192 (6000.0)
224 (7000.0)

Note Some combinations of the values of the time period and the tempo have the same number of cycles ( for example compare 9 / $01, 7 / $02, and 5 / $04 and other combinations).

The values are computed by a table in the monitor called OPTBL located at $029C, the defined time period, and the defined tempo. The number of cycles is computed by:

#cycles = table value of the time period TP x tempo value

The table values are:

Defined time period TP
OPTBL values

For example: If you code R9 and a tempo of $04 then a silence rest between two notes of 32 x 4 = 128 cycles will occur. If the frequency of the oscillator is 32Hz then the time of the silence rest between the two notes will be:

t(s) = 1 / frequency(Hz) x # of cycles
1 / 32 x 128 = 4000.0ms = 4 seconds

More details about this when I explain the related monitor subroutines ONPU and RYTHM.

Defining an octave

A preceding - or + specifies the octave. Code - for the lower octave and + for the upper octave. Nothing specified plays the standard / medium octave. $CF specifies the lower octave too. $D7 specifies the upper octave too.

available octaves

Try the following example:

B000 1150B0	LD	DE,$B050	;address to string to be played
B003 F7		RST	6		;execute melody play at $0030
B004 C3AD00	JP	$00AD		;return to monitor

and set the area starting from $B050 to the following values by the "M"-command:

B050 2B 41 33 2B 23 46 31 2B  +A3+#F1+
B058 41 2B 42 33 41 2B 44 2B  A+B3A+D+
B060 23 46 31 41 2B 44 33 41  #F1A+D3A
B068 2B 44 2B 23 46 31 41 2B  +D+#F1A+
B070 44 33 2B 23 46 31 41 2B  D3+#F1A+
B078 44 2B 45 2B 23 46 2B 47  D+E+#F+G
B080 2B 41 33 52 0D	      +A3R.

Now execute the jump command JB000 and Beethoven's sonate D-dur ( opus 25 ) should be played as shown in the following picture. You can set the tempo as described above.

Beethoven's sonate D-dur ( opus25 )
Setting the volume

The volume can be controlled only manually by the volume control ( potentiometer ) at the reverse side of the MZ-700.

Do you need additional information or details to the related monitor subroutines? If so, click here.

Go to the top of this page Home

last updated August 5, 2002