Da gab es früher doch mal den legendären Dreiklanggong
SAB0600 von Siemens, der allerdings schon lange obsolete ist, und dessen Nachfolger
SAE800 auch nicht mehr produziert wird.
So ein Baustein ist ein schönes Objekt für eine CPLD-Implementierung, weil nur ein paar Zähler und keine allzu komplizierte Ablauflogik nötig sind.
Für den Gong müssen erst mal 3 Frequenzen von "normal" 660Hz, 550Hz und 440Hz erzeugt werden. Nach dem Drücken einer Taste wird zuerst der höchste Ton (660Hz) ausgegeben und dessen Ampiltude über einen 4-Bit-Wandler schrittweise linear von Maximal nach Null reduziert. Nach kurzer Zeit kommt dann der nächst tiefere Ton (550Hz), der ebenfalls linear ausklingt, gefolgt vom tiefsten Ton (440Hz). Für kurze Zeit erklingen alle drei Töne und ergeben einen A-Dur Akkord.
Nach dieser Sequenz kann der Ablauf neu gestartet werden.
Weil einem CPLD alles Analoge fremd ist, wird die unterschiedliche Amplitude statt mit einem 4-Bit-DA-Wandler mit einer 16 stufigen PWM nachgebildet.
Der Mischer am Ausgang ist eine Exclusiv-Veroderung der 3 Signale.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity SAB0600 is
Port ( clk : in STD_LOGIC;
start : in STD_LOGIC;
speaker : out STD_LOGIC := '0');
end SAB0600;
architecture Behavioral of SAB0600 is
constant fclk : integer := 50_000_000;
signal cnt13200 : integer range 0 to fclk/13200 := 0;
signal ena13200 : std_logic := '0';
constant m660 : integer := (13200/660)/2-1;
constant m550 : integer := (13200/550)/2-1;
constant m440 : integer := (13200/440)/2-1;
signal cnt660 : integer range 0 to m660 := 0;
signal cnt550 : integer range 0 to m550 := 0;
signal cnt440 : integer range 0 to m440 := 0;
signal hz660 : std_logic := '0';
signal hz550 : std_logic := '0';
signal hz440 : std_logic := '0';
signal en440 : std_logic := '0';
signal adsrpre : unsigned (6 downto 0) := (others=>'0');
signal adsr660 : integer range 0 to 15 := 15;
signal adsr550 : integer range 0 to 15 := 15;
signal adsr440 : integer range 0 to 15 := 15;
signal pwmpresc: integer range 0 to fclk/500000 := 0; -- pwmfrequenz 500kHz
signal pwmcnt : integer range 0 to 14 := 0;
begin
Vorteiler: process begin
wait until rising_edge(clk);
if cnt13200<fclk/13200 then
cnt13200 <= cnt13200+1;
ena13200 <= '0';
else
cnt13200 <= 0;
ena13200 <= '1';
end if;
end process;
Frequenzen: process begin
wait until rising_edge(clk);
en440 <= '0';
if ena13200='1' then
if cnt660<m660 then
cnt660 <= cnt660+1;
else
cnt660 <= 0;
hz660 <= not hz660;
end if;
if cnt550<m550 then
cnt550 <= cnt550+1;
else
cnt550 <= 0;
hz550 <= not hz550;
end if;
if cnt440<m440 then
cnt440 <= cnt440+1;
else
cnt440 <= 0;
hz440 <= not hz440;
en440 <= '1';
end if;
end if;
end process;
Huellkurve: process begin
-- wait until rising_edge(hz440); -- direkt getaktet: 50 Flipflops
wait until rising_edge(clk);
if en440='1' then -- über Enable: 51 Flipflops
adsrpre <= adsrpre+1;
if to_integer(adsrpre)=0 then
if start='1'
and adsr660=0
and adsr550=0
and adsr440=0 then adsr660 <= 15; end if;
if adsr660>0 then adsr660 <= adsr660-1; end if;
if adsr660=10 then adsr550 <= 15; end if;
if adsr550>0 then adsr550 <= adsr550-1; end if;
if adsr550=10 then adsr440 <= 15; end if;
if adsr440>0 then adsr440 <= adsr440-1; end if;
end if;
end if;
end process;
Mischer: process
variable mix : std_logic;
begin
wait until rising_edge(clk);
if pwmpresc<fclk/500000 then
pwmpresc <= pwmpresc+1;
else
pwmpresc <= 0;
if pwmcnt<14 then
pwmcnt<=pwmcnt+1;
else
pwmcnt<=0;
end if;
end if;
mix := '0';
if adsr660>pwmcnt and hz660= '1' then mix := not mix;
end if;
if adsr550>pwmcnt and hz550= '1' then mix := not mix;
end if;
if adsr440>pwmcnt and hz440= '1' then mix := not mix;
end if;
speaker <= mix;
end process;
end Behavioral;
Der Ressourcenverbrauch hält sich trotz einer Eingangsfrequenz von 50MHz, die auf entsprechende verwendete Frequenzen heruntergeteilt wird, mit 50 Flipflops in Grenzen, so dass das Design problemlos in ein 72er CPLD hineinpasst. Wird die Taktfrequenz auf 500kHz (das ist die verwendetete PWM-Frequenz) reduziert, dann lassen sich schnell noch mindestens 7 Flipflops einsparen.
Um den neueren SAE800 genau nachzubilden, müsste ein nichtlinearer DA-Wandler mit einer nichtlinearen Hüllkurve und einer höher auflösenden PWM nachgebildet werden. Dieser Verlauf ist schön im Datenblatt des Bausteins zu sehen.
Hier ein Link zu einem (nicht meinem) Youtube Video, auf dem der Gong in Aktion zu hören ist:
Youtube-Video SAB0600 im FPGA