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