Low level module to address the DAC:
Code: Select all
MODULE DAC2378;
IMPORT SYSTEM, LPC := LPC2378;
CONST
BiasBit = 16; (* = 010000H *)
VAR
UseBias : BOOLEAN;
PROCEDURE SetBias*(CONST v : BOOLEAN);
BEGIN
UseBias := v
END SetBias;
PROCEDURE GetBias*(): BOOLEAN;
BEGIN
RETURN UseBias
END GetBias;
(****************************************************************************
** Description: initialize DAC channel
*****************************************************************************)
PROCEDURE Init*;
(* PCLSKSEL0 {23:22} = Peripheral Clock selection for DAC, default 00 = 72Mhz/4=18Mhz *)
(* PINMODE1 P0.26, {21:20} default after reset =00=> on-chip pullup resistor enabled
01-> reserved, do not use
10-> no pull-up/down resistor enabled
11-> pull-down resistor enabled *)
(* PINSEL1 P0.26, {21:20} = {1:0} enables DAC = AOUT *)
VAR
bits : SET;
BEGIN
(* Clock: reset to CCLK/4 *)
SYSTEM.GET(LPC.PCLKSEL0, bits);
SYSTEM.PUT(LPC.PCLKSEL0, bits - {22,23});
(* setup the related pins to DAC output *)
SYSTEM.GET(LPC.PINSEL1, bits);
SYSTEM.PUT(LPC.PINSEL1, bits + {21} - {20}); (*/* set p0.26 to DAC output *)
(* setup pin modes *)
SYSTEM.GET(LPC.PINMODE1, bits);
SYSTEM.PUT(LPC.PINMODE1, bits +{21} - {20}); (* no pull-up/down resistor enabled *)
END Init;
(* Place a value (0..1023) into the DAC register and bring it out *)
PROCEDURE* Convert*( CONST v : INTEGER);
VAR
bits : INTEGER;
BEGIN
bits := LSL(v MOD 1024, 6);
IF UseBias THEN bits := SYSTEM.VAL(INTEGER, SYSTEM.VAL(SET, bits) + {BiasBit}) END;
SYSTEM.PUT(LPC.DACR, bits)
END Convert;
END DAC2378.
Code: Select all
MODULE DACWave;
IMPORT Timer, DAC := DAC2378, Math0;
(* Max resolution = 10 bit = value 1023. Min value = 0 = silence.
a beep of 1000 hz should be given with 2000 samples/sec, so for a max of 4 khz, we
should use sample delivery of about 8khz = is one sample every 125 usecs. *)
CONST
SampleTime = 125; (* microseconds for each sample *)
VAR
(* This array limits our frequency spectrum from 40Hz to 4Khz *)
ampl : ARRAY 200 OF INTEGER; (* unpacked values, not efficient using 32 bits for each 10bit value *)
(* to produce a tone of 1khz we need 8 samples *)
(* limiting Lower Range to 40Hz, means we need store 0,025 secs of 10-bit values for a waveform
PROCEDURE Test1k;
CONST
ofs = 512;
VAR
a : ARRAY 8 OF INTEGER;
i, v : INTEGER;
BEGIN
a[0] := 0; a[1] := 282; a[2] := 400; a[3] := 282;
a[4] := 0; a[5] := -282; a[6] := -400; a[7] := -282;
FOR i := 0 TO 7 DO
v := ofs + a[i];
DAC.Convert(v);
Timer.uSecDelay(SampleTime);
END
END Test1k;
*)
PROCEDURE NoOfSamples(CONST f : INTEGER) : INTEGER;
VAR
SampleTimeFloat, ff : REAL;
BEGIN
SampleTimeFloat := FLT(SampleTime) / 1000000.0; ff := FLT(f);
RETURN FLOOR((1.0 / ff / SampleTimeFloat) + 0.5)
END NoOfSamples;
PROCEDURE CalcAmplitudes(ns : INTEGER);
CONST
maxv = 400.0;
VAR
delta : REAL;
idx : INTEGER;
BEGIN
delta := 360.0 / FLT(ns);
ampl[0] := 0;
FOR idx := 1 TO ns-1 DO
ampl[idx] := FLOOR(maxv * Math0.DegSin(delta * FLT(idx)));
END;
END CalcAmplitudes;
(* For debugging the values
PROCEDURE DisplayAmplitudes(ns : INTEGER);
VAR
idx : INTEGER;
BEGIN
CalcAmplitudes(ns);
FOR idx := 0 TO ns - 1 DO
Out.Int(ampl[idx],0); Out.Char(' ')
END;
Out.Ln;
END DisplayAmplitudes;
*)
(* Calculate the number of iterations we need to replay the ampl-buffer
to let it sound for -duration- OF milliseconds *)
PROCEDURE CalcIterations(CONST freq, duration: INTEGER) : INTEGER;
VAR
st, numiter : INTEGER;
BEGIN
st := 10000 DIV freq; (* duration of 1 full wave sample of -freq- Hz. in ms*)
IF duration < st THEN
numiter := 1
ELSE
numiter := duration DIV st
END
RETURN numiter
END CalcIterations;
(* play a tone of -freq- herz, and repeat that during -duration- of milliseconds
A tone will be played at least one full sample *)
PROCEDURE Tone*(CONST freq, duration : INTEGER);
CONST
ofs = 512; (* Use this as the center-amplitude value *)
VAR
idx, jdx, ns, iter, f : INTEGER;
BEGIN
IF freq < 40 THEN f := 40
ELSIF freq > 4000 THEN f := 4000
ELSE f := freq END;
ns := NoOfSamples(f);
iter := CalcIterations(f, duration);
CalcAmplitudes(ns);
FOR jdx := 1 TO iter DO
FOR idx := 0 TO ns-1 DO (* playing a full wave sample *)
DAC.Convert(ofs + ampl[idx]);
Timer.uSecDelay(SampleTime)
END
END
END Tone;
(* play a tone of -freq- herz, and repeat that - iterations- times.
Remember that a 40Hz tone will take 25 ms so to iterate that 40 times takes 1 second.
A Tone of 1200 hz iterating 40 times will take 33ms *)
PROCEDURE Beep*(CONST freq, iterations : INTEGER);
CONST
ofs = 512; (* Use this as the center-amplitude value *)
VAR
idx, jdx, ns, f : INTEGER;
BEGIN
IF freq < 40 THEN f := 40
ELSIF freq > 4000 THEN f := 4000
ELSE f := freq END;
ns := NoOfSamples(f);
CalcAmplitudes(ns);
FOR jdx := 1 TO iterations DO
FOR idx := 0 TO ns-1 DO (* playing a full wave sample *)
DAC.Convert(ofs + ampl[idx]);
Timer.uSecDelay(SampleTime)
END
END
END Beep;
PROCEDURE Init*;
BEGIN
DAC.Init;
Timer.Init(Timer.uSecs);
END Init;
END DACWave.
Code: Select all
MODULE Sound;
IMPORT Timer, DACWave;
(**********************************************************************************************\
* Geef een geluidssignaal met toonhoogte van 'frequentie' in Herz en tijdsduur 'duration'
* in milliseconden.
* LET OP: toonhoogte is slechts een grove indicatie. Deze routine is bedoeld als signaalfunctie
* en is niet bruikbaar voor toepassingen waar de toonhoogte zuiver/exact moet zijn.
* Routine wordt verlaten na beeindiging van de pieptoon.
\*********************************************************************************************)
(* LPC2378 has monaural headphone-jack, so connect your speaker & enjoy ;-) .. *)
PROCEDURE Alarm*(CONST Variant, Duration: INTEGER);
VAR
x, y, v, n : INTEGER;
BEGIN
IF Duration < 1 THEN n :=1 ELSE n := Duration END;
v := Variant MOD 8;
CASE v OF
0 : DACWave.Beep(2000, 20*n);
| 1 : (* four beeps *)
FOR y := 1 TO n DO
DACWave.Beep(3000, 30); Timer.uSecDelay(100000);
DACWave.Beep(3000, 30); Timer.uSecDelay(100000);
DACWave.Beep(3000, 30); Timer.uSecDelay(100000);
DACWave.Beep(3000, 30); Timer.uSecDelay(1000000)
END
| 2 : (* whoop up *)
FOR y := 1 TO Duration DO
FOR x := 1 TO 50 DO
DACWave.Beep(250*x DIV 4, 20)
END
END
| 3 : (* whoop down *)
FOR y := 1 TO n DO
FOR x := 50 TO 1 BY -1 DO
DACWave.Beep(250*x DIV 4, 20)
END
END
| 4 : (* S.O.S. *)
FOR y := 1 TO n DO
DACWave.Beep(1200, 50); Timer.uSecDelay(100000);
DACWave.Beep(1200, 50); Timer.uSecDelay(100000);
DACWave.Beep(1200, 50); Timer.uSecDelay(200000);
DACWave.Beep(1200, 300); Timer.uSecDelay(100000);
DACWave.Beep(1200, 300); Timer.uSecDelay(100000);
DACWave.Beep(1200, 300); Timer.uSecDelay(200000);
DACWave.Beep(1200, 50); Timer.uSecDelay(100000);
DACWave.Beep(1200, 50); Timer.uSecDelay(100000);
DACWave.Beep(1200, 50);
IF y > 1 THEN Timer.uSecDelay(500000) END (* NOT n *)
END
| 5 : (* ding-dong *)
FOR x := 0 TO n DO
IF x > 0 THEN Timer.uSecDelay(2000000) END;
DACWave.Beep(1500, 500); DACWave.Beep(1200, 500)
END
| 6: (* phone ring *)
FOR x := 0 TO 15*n DO
DACWave.Beep(1000, 40); DACWave.Beep(750, 40)
END
| 7: (* boot *)
DACWave.Beep(1500, 100); DACWave.Beep(1000, 100)
END (* CASE *)
END Alarm;
BEGIN
DACWave.Init;
END Sound.
Code: Select all
MODULE TestDAC;
IMPORT Main, Timer, Sound;
PROCEDURE MakeAllNoises;
VAR
idx : INTEGER;
BEGIN
REPEAT
FOR idx := 0 TO 7 DO
Sound.Alarm(idx, 5); (* make the sound *)
Timer.uSecDelay(1000000); (* just a sec of silence *)
END
UNTIL FALSE
END MakeAllNoises;
BEGIN
MakeAllNoises
END TestDAC.