Oberon/ETH Oberon/speaker

 

Back to: Native Oberon Hardware Compatiblity List &#160;

Speaker support &#160; Summary The PC speaker is a poor man's sound generator capable of no more than producing pitiful beeps and squawks, but it is simple to program in Oberon. However, since the SYSTEM module is used, code is not portable. How to control the speaker by program Assume that a sound of a frequency f should be emitted during a time t. The system Timer 2, one of three timers in the Programmable Interval Timer (PIT), is used to control sound generation, in five sucessive steps. The PIT operates at 1.19318 MHz.


 * compute a 2-byte counter value (1 <= count <= 65'535) corresponding to the specified frequency f - IntFreq. 1'193'180 >= f >= 18.2


 * send a PIT control word to port address 43H - InitTimer


 * send the counter value to port address 42H - SetFreq


 * set "on" the bits 0 and 1 of the control register at port address 61H to switch on the speaker and the amplifier - Tone


 * after a time delay t, set "off" the same bits at port address 61H - Tone

The time delay must be controlled by a background task. Note that once the speaker is "on", the frequency may be changed at will, even set to something inaudible to simulate a silence.

Program snippets CONST TONES = 12; OCTAVES = 10; ON = TRUE;  OFF = FALSE; A4 = 440; (* the latin "la" *) (* Convert the frequency to an "internal" value *) PROCEDURE IntFreq(hz: LONGINT): INTEGER; CONST Rate = 1193180;   (* Timer clock is 1.19318 MHz *) BEGIN RETURN SHORT(Rate DIV hz) END IntFreq; (* Set PIT control word to: Timer 2, 16-bit, mode 3, binary = {01110110} i.e. B6H *) PROCEDURE InitTimer;  (* Timer port address: 43H *) BEGIN SYSTEM.PORTOUT (43H, 0B6H) END InitTimer; (* Set counter value *) PROCEDURE SetFreq(hz: LONGINT); (* Timer 2 port address: 42H *) BEGIN SYSTEM.PORTOUT (42H, CHR(hz MOD 100H)); SYSTEM.PORTOUT (42H, CHR(hz DIV 100H)); Tone(ON) END SetFreq; (* Switch speaker and amplifier on/off *) PROCEDURE Tone(b: BOOLEAN); (* Loudspeaker port address: 61H *) VAR s: SET; BEGIN SYSTEM.PORTIN (61H, SYSTEM.VAL(CHAR, s)); IF b THEN s := s + {0, 1} ELSE s := s - {0, 1} END; SYSTEM.PORTOUT (61H, SYSTEM.VAL(CHAR, s)) END Tone; (* Calculate table of "internal" frequencies for a number of octaves *) PROCEDURE CalcTF; VAR t, oct: INTEGER; f, f0, df: REAL; BEGIN df := Math.exp(Math.ln(2) / TONES); f0 := A4 * df * df * df / 32;  (* = c0 *) FOR oct := 0 TO OCTAVES-1 DO       f := f0; FOR t := 0 TO TONES-1 DO          TF[t, oct] := IntFreq(ENTIER(f)); f := f * df       END; f0 := f0 * 2 END END CalcTF; (* Beep on the speaker: beepFreq during beepLen *) PROCEDURE Beep*; VAR wakeUp: LONGINT; BEGIN IF ~timerActive THEN InitTimer; SetFreq(beepFreq); wakeUp := Input.Time + beepLen * (Input.TimeUnit DIV 1000); REPEAT UNTIL Input.Time - wakeUp >= 0; Tone(OFF); timerActive := FALSE END END Beep; [Top] ''13 Jul 2002 - Copyright &#169; 2002 ETH Z&#252;rich. All rights reserved.''

E-Mail: oberon at lists.inf.ethz.ch

Homepage: http://www.ethoberon.ethz.ch/