mircea888 Postat August 7, 2012 Partajează Postat August 7, 2012 super tare, poate ar trebui pus SI la tutorialeAm putea sa facem asta, eventual las o "umbra" aici.Ce zici George il mutam ? Link spre comentariu
Vizitator Postat August 7, 2012 Partajează Postat August 7, 2012 Mulţumesc pentru aprecieri, dar nu e scris cu scopul de a da lecţii, sunt începător în domeniul FPGA-urilor.Aşa, ca jucărie pusă la DIY, e frumos, dar ca tutorial, mi-ar fi ruşine cu ce-am scris.Dacă vi se pare oarecum educativ, atunci ar fi suficient un link de la secţiunea de tutoriale către DIY, iar discuţia să o lăsăm aici, vă rog.Am nişte planuri pentru tutoriale, dar într-un alt format decât cel de aici. Din păcate, nu stiu dacă voi fi în stare să le scriu vreodată, durează foarte, foarte mult. Trebuie să alegi ce să scrii, să te informezi înainte, ca să nu publici tâmpenii, să scrii, să pui scheme, poze desene, filme, etc., să corectezi greşelile, şi tot aşa, multe amănunte care mănâncă timp.Durează mult mai mult să documentez ce-am lucrat (adică să pun pe forum), decât să lucrez. Practic, de când am început să scriu despre subiectul ăsta, aproape că n-am mai avansat cu ce vroiam să fac (aveam un plan cu placa aia, dar nu prea merge ce vreau eu). Link spre comentariu
Vizitator Postat August 14, 2012 Partajează Postat August 14, 2012 Să mergem mai departe cu proiectul. În primul rând, o errata. Errata, înseamnă o listă cu greşeli. În Fig. 8 am desenat porţi sau în loc de porţi sau-nu. E ciudat că nu a observat nimeni, şi că am scăpat netras de urechi, adică . Probabil că mai sunt şi alte greşeli, sper că nu prea multe. Să continuăm. Teorie muzicală Vreau să spun de la început că la teorie muzicală (nici măcar nu ştiu dacă ăsta este termenul corect) sunt bâtă, niente, nada, zero barat, tufă de Veneţia! Am citit câteva lucruri pe Internet, lucruri de care care vreau să amintesc aici. Mai întâi, ce frecvenţă au notele muzicale? Există mai multe feluri de note muzicale, dar cele pe care le ştie toată lumea, au o formulă care se bazează pe o constatare universal valabilă: simţurile noastre sunt logaritmice. Din cauza asta, formula care descrie frecvenţa notelor este o funcţie exponenţială, şi arată cam aşa: Fn = Fo * a**n (1) unde: n = …-2, -1, 0, 1, 2... Fo = 440 Hz nota LA a = 2**(1/12) Folosind formula (1) se ajunge la următorul tabel cu frecvenţele notelor: Tabel 1 Observăm că, pentru a obţine frecvenţele date plecând de la cei 50 MHz de pe placă, e nevoie de divizoare destul de lungi, de câte 17-18 biţi pentru fiecare notă. Câţi biţi, atâtea bistabile. Cu alte cuvinte, e nevoie de multe resurse hardware. Problemă de optimizare De data asta, ne propunem să facem un generator polifonic, adică avem nevoie de toate notele simultan. Pentru cele 8 note, asta ar însemna 8 divizoare, fiecare de câte 17-18 bistabile lungime. În total, mai bine de 100 bistabile. Destul de multe, ţinând cont că întreg FPGA-ul nostru conţine în total numai 1536 bistabile. Să nu risipim resursele. O metodă de a reduce lungimea divizoarelor, şi implicit numărul de bistabile, ar fi să punem în faţa lor un divizor care să reducă frecvenţa de 50MHz, adică un prescaler. Dar, cu cât punem un prescaler mai mare, cu atât scade precizia pentru frecvenţa fiecărei note. Următoarea problemă de rezolvat este, cât de lung poate fi divizorul astfel încât precizia celor 8 note să fie acceptabilă? Vom rezolva problema plecând de la un hint (o indicaţie venită de la cirip - mulţumesc pentru link-uri), şi anume că urechea simte deviaţii foarte mici de frecvenţă, uneori de până la 1 cent. Deşi se admit de multe ori erori mai mari, de până la 5 cents, am încercat să nu forţez, aşa că am stat cît mai aproape de acel 1 cent, pe care nici cele mai educate urechi nu-l simt. Centul este o altă unitate de măsură, tot logaritmică. Ea împarte (logaritmic) intervalul dintre două note în 100 de părţi. http://en.wikipedia.org/wiki/Cent_(music) În graficul următor, se vede că, pe măsură ce mărim prescalerul şi economisim bistabile, eroarea notelor creşte. Axa X reprezintă lungimea prescalerului (numărul de bistabile). Grafic 1 Din grafic, se vede că numărul de bistabile scade liniar, pe când eroarea creşte exponenţial. Din cauza asta, alegem un compromis între precizia notelor şi economia de bistabile. Luăm un prescaler de 6 biţi, asta înseamnă o economie de aproximativ 30%, fără să afectăm perceptibil sunetul. Fişierul cu care am calculat este ataşat. Fişirul este în format ods, echivalentul lui xls, dar pentru Open Office. Vă recomand să folosiţi cu încredere Open Office. Este gratuit, mai puternic şi compatibil cu Microsoft Office. Pentru cei care nu au Open Office, o poză cu tabelul cu care am făcut optimizarea: Tabel. 2 http://i50.tinypic.com/15yekpx.jpg Pentru restul, vă puteţi juca alegând din drop down menu, diferite cifre în celula portocalie. Schema folosită pentru generarea celor 8 note, este similară (dar nu chiar identică) cu cea desenată în Fig. 10 Fig.10 Mixarea celor opt note Există mai multe modalităţi de mixare, dar într-un mixer audio obişnuit, mixarea se face aditiv. Adică se adună semnalele de la intrare şi rezultatul se scoate la ieşirea mixerului. Necazul este că noi avem semnale digitale, notele sunt trenuri de impulsuri de "0" şi "1", oare putem să le mixăm şi să obţinem tot un rezultat de 1 bit, adică doar "0" sau "1"? Să încercăm diferite metode de mixare: 1. Cu OR logic. Nu sună bine. Seamănă cu sunetele de la melodia din , iar atunci când apăs multe butoane deodată, ieşirea tinde să se satureze cu "1" logic şi sunetul se îneacă: Movie 9 lVeGMpV1Lcc 2. Cu XOR logic. Tot nu sună bine, iar dacă apăs multe butoane simultan, sunetul seamănă cu zgomotul alb: Movie 10 hjtxLiOU1Kg 3. Cu adunare pe 4 biţi urmată de un DAC Sigma-Delta. Sună ceva mai bine, dar tot nu merge când apăs multe butoane: Movie 11 q9rNk1ID0zU Bănuiala mea este că se întâmplă aşa, pentru că difuzorul este comandat de un MOSFET (Schema 1, unde scrie 10.07.2012). Deschiderea se face mai repede, dar blocarea lui durează mult mai mult, pentru că nu are prevăzute circuite care să extragă sarcina stocată în grilă. Conversia Sigma-Delta are proprietatea că "împrăştie cât mai uniform" pulsuri foarte scurte. Asta înseamnă că dacă pulsurile scoase de DAC sunt suficient de apropiate, grila MOSFET-ului se saturează cu sarcini şi MOSFET-ul rămâne deschis în loc să comute în ritmul impulsurilor. De aceea, un DAC cu PWM ar fi mai avantajos, pentru că PWM-ul ţine pulsurile de 1 şi de 0 grupate, nu le împrăştie ca Sigma-Delta. 4. Cu adunare pe 4 biţi urmată de un DAC PWM. Sună cel mai bine din toate, chiar şi cu multe note deodată: Movie 12 bpaHlp6x54E Acum e noapte şi târziu, vin altă dată, şi mai scriu. Aşa că trântesc aici codul care sună ca în Movie 12, fără alte comentarii (am păstrat totul într-un singur fişier, pentru a fi mai uşor de urmărit). Prog. 10 ------------------------------------------------------------------------------------ Company: -- Engineer: -- -- Create Date: 09:14:15 08/12/2012 -- Design Name: -- Module Name: polyphonic - Behavioral -- Project Name: -- Target Devices: -- Tool versions: -- Description: ---- Dependencies: ---- Revision: -- Revision 0.01 - File Created-- Additional Comments: ------------------------------------------------------------------------------------library IEEE;use IEEE.STD_LOGIC_1164.ALL;use IEEE.STD_LOGIC_ARITH.ALL;use IEEE.STD_LOGIC_UNSIGNED.ALL;entity polyphonic is port ( NKBD_D : in std_logic_vector(7 downto 0); NKBD_A : out std_logic_vector(2 downto 0); NSPK_VOL: out std_logic; SPK_BIT: out std_logic; NLED : out std_logic_vector(6 downto 1); CLK : in std_logic );end polyphonic;architecture Behavioral of polyphonic is--*******************************************-- declare architecture constants--******************************************* constant PRE_BITS: natural := 18; -- general prescaler counter length constant VOL_BITS: natural := 8; -- general volume DAC resolution constant SND_BITS: natural := 6; -- audio signal DAC resolution-- !!! MIX_BITS must be less then SND_BITS constant MIX_BITS: natural := 4; -- audio mixer resolution--*******************************************-- declare musical notes constants--*******************************************-- !!! constants calculated for PRE_BITS = 6, otherwise the values must be recalculated constant DO_max_count: natural := 1493 - 1; -- freq. divider for note DO constant RE_max_count: natural := 1330 - 1; -- freq. divider for note RE constant MI_max_count: natural := 1185 - 1; -- freq. divider for note MI constant FA_max_count: natural := 1119 - 1; -- freq. divider for note FA constant SOL_max_count: natural := 997 - 1; -- freq. divider for note SOL constant LA_max_count: natural := 888 - 1; -- freq. divider for note LA = 440 Hz constant SI_max_count: natural := 791 - 1; -- freq. divider for note SI constant DO_up_max_count: natural := 747 - 1; -- freq. divider for note DO up--*******************************************-- prescaler divider length for each clock--******************************************* constant PRE_KBD_BITS: natural := 18;-- keyboard clock constant PRE_GEN_BITS: natural := 6; -- notes generators clock constant PRE_MIX_BITS: natural := 1; -- audio mixer clock constant PRE_SND_BITS: natural := 1; -- audio signal DAC clock constant PRE_VOL_BITS: natural := 6; -- general volume DAC clock--*******************************************-- prescaler specific signals--******************************************* signal pre_cnt: std_logic_vector(PRE_BITS - 1 downto 0);--*******************************************-- keyboard specific signals--******************************************* signal kbd_clk: std_logic; -- for DIV_BITS = 18 and clk = 50 MHz -> ~190 Hz (5.24 ms) signal nkbd_line_scanner: std_logic_vector(2 downto 0) := "110"; -- init. kbd line scanner -- D7, D6, D5, D4, D3, D2, D1, D0 --------------------------------- signal keys_from_line_A0: std_logic_vector(7 downto 0); -- 8, 7, 6, 5, 4, 3, 2, 1 signal keys_from_line_A1: std_logic_vector(7 downto 0); -- BL, P, Y, C, #, 0, *, 9 signal keys_from_line_A2: std_logic_vector(3 downto 0); -- BR, GU, GL, GR -- an easy name for each key signal key_1, key_2, key_3, key_4: std_logic; signal key_5, key_6, key_7, key_8: std_logic; signal key_9, key_asterisk, key_0, key_hash: std_logic; signal key_C, key_yellow, key_pink, key_big_left: std_logic; signal key_grey_right, key_grey_left, key_grey_up, key_big_right: std_logic; --*******************************************-- notes generators specific signals--******************************************* -- declare generators prescaler signal gen_clk: std_logic; -- declare notes dvider counters signal cnt_DO, cnt_RE, cnt_MI, cnt_FA: std_logic_vector(10 downto 0); signal cnt_SOL, cnt_LA, cnt_SI, cnt_DO_up: std_logic_vector(9 downto 0); -- declare notes outputs signal out_DO, out_RE, out_MI, out_FA: std_logic; signal out_SOL, out_LA, out_SI, out_DO_up: std_logic; -- declare notes enable signal en_DO, en_RE, en_MI, en_FA: std_logic; signal en_SOL, en_LA, en_SI, en_DO_up: std_logic;--*******************************************-- audio mixer signals--******************************************* -- declare mixer output signal mix_clk: std_logic; signal out_mix: std_logic_vector(MIX_BITS - 1 downto 0);--*******************************************-- DAC's specific signals--******************************************* -- declare sound signal PWM DAC signal snd_clk: std_logic; signal snd_PWM: std_logic; -- declare general volume PWM DAC signal vol_clk: std_logic; signal vol_lev: std_logic_vector(VOL_BITS - 1 downto 0); signal vol_PWM: std_logic;begin--*******************************************-- prescaler CLK divider--*******************************************prescaler: process(CLK) begin if CLK'event and CLK = '1' then pre_cnt <= pre_cnt + '1'; end if; end process; --*******************************************-- clocks--******************************************* kbd_clk <= pre_cnt(PRE_KBD_BITS - 1); -- keyboard clock gen_clk <= pre_cnt(PRE_GEN_BITS - 1); -- notes generators clock mix_clk <= pre_cnt(PRE_MIX_BITS - 1); -- audio mixer clock snd_clk <= CLK; -- audio signal DAC clock vol_clk <= pre_cnt(PRE_VOL_BITS - 1); -- general volume DAC clock --*******************************************-- keyboard read--*******************************************shift_kbd_address_lines: process(kbd_clk) begin if rising_edge(kbd_clk) then nkbd_line_scanner <= nkbd_line_scanner(1 downto 0) & nkbd_line_scanner(2); end if; end process; nkbd_a <= nkbd_line_scanner; memorize_keys_from_line_A0: process(nkbd_line_scanner(0)) begin if rising_edge(nkbd_line_scanner(0)) then keys_from_line_A0 <= not nkbd_d; end if; end process; memorize_keys_from_line_A1: process(nkbd_line_scanner(1)) begin if rising_edge(nkbd_line_scanner(1)) then keys_from_line_A1 <= not nkbd_d; end if; end process; memorize_keys_from_line_A2: process(nkbd_line_scanner(2)) begin if rising_edge(nkbd_line_scanner(2)) then keys_from_line_A2 <= not nkbd_d(7 downto 4); end if; end process; --*******************************************-- map easy names for buttons --******************************************* key_1 <= keys_from_line_A0(0); key_2 <= keys_from_line_A0(1); key_3 <= keys_from_line_A0(2); key_4 <= keys_from_line_A0(3); key_5 <= keys_from_line_A0(4); key_6 <= keys_from_line_A0(5); key_7 <= keys_from_line_A0(6); key_8 <= keys_from_line_A0(7); key_9 <= keys_from_line_A1(0); key_asterisk <= keys_from_line_A1(1); key_0 <= keys_from_line_A1(2); key_hash <= keys_from_line_A1(3); key_C <= keys_from_line_A1(4); key_yellow <= keys_from_line_A1(5); key_pink <= keys_from_line_A1(6); key_big_left <= keys_from_line_A1(7); key_grey_right <= keys_from_line_A2(0); key_grey_left <= keys_from_line_A2(1); key_grey_up <= keys_from_line_A2(2); key_big_right <= keys_from_line_A2(3);--*******************************************-- notes generators--*******************************************voice_DO: process(gen_clk) begin if rising_edge(gen_clk) then if en_DO = '0' then out_DO <= '0'; --reset the output elsif cnt_DO = 0 then cnt_DO <= conv_std_logic_vector(DO_max_count, cnt_DO'length); out_DO <= not out_DO; -- flip the output else cnt_DO <= cnt_DO - '1'; -- decrement counter end if; end if; end process;voice_RE: process(gen_clk) begin if rising_edge(gen_clk) then if en_RE = '0' then out_RE <= '0'; --reset the output elsif cnt_RE = 0 then cnt_RE <= conv_std_logic_vector(RE_max_count, cnt_RE'length); out_RE <= not out_RE; -- flip the output else cnt_RE <= cnt_RE - '1'; -- decrement counter end if; end if; end process;voice_MI: process(gen_clk) begin if rising_edge(gen_clk) then if en_MI = '0' then out_MI <= '0'; --reset the output elsif cnt_MI = 0 then cnt_MI <= conv_std_logic_vector(MI_max_count, cnt_MI'length); out_MI <= not out_MI; -- flip the output else cnt_MI <= cnt_MI - '1'; -- decrement counter end if; end if; end process;voice_FA: process(gen_clk) begin if rising_edge(gen_clk) then if en_FA = '0' then out_FA <= '0'; --reset the output elsif cnt_FA = 0 then cnt_FA <= conv_std_logic_vector(FA_max_count, cnt_FA'length); out_FA <= not out_FA; -- flip the output else cnt_FA <= cnt_FA - '1'; -- decrement counter end if; end if; end process;voice_SOL: process(gen_clk) begin if rising_edge(gen_clk) then if en_SOL = '0' then out_SOL <= '0'; --reset the output elsif cnt_SOL = 0 then cnt_SOL <= conv_std_logic_vector(SOL_max_count, cnt_SOL'length); out_SOL <= not out_SOL; -- flip the output else cnt_SOL <= cnt_SOL - '1'; -- decrement counter end if; end if; end process;voice_LA: process(gen_clk) begin if rising_edge(gen_clk) then if en_LA = '0' then out_LA <= '0'; --reset the output elsif cnt_LA = 0 then cnt_LA <= conv_std_logic_vector(LA_max_count, cnt_LA'length); out_LA <= not out_LA; -- flip the output else cnt_LA <= cnt_LA - '1'; -- decrement counter end if; end if; end process;voice_SI: process(gen_clk) begin if rising_edge(gen_clk) then if en_SI = '0' then out_SI <= '0'; --reset the output elsif cnt_SI = 0 then cnt_SI <= conv_std_logic_vector(SI_max_count, cnt_SI'length); out_SI <= not out_SI; -- flip the output else cnt_SI <= cnt_SI - '1'; -- decrement counter end if; end if; end process;voice_DO_up: process(gen_clk) begin if rising_edge(gen_clk) then if en_DO_up = '0' then out_DO_up <= '0'; --reset the output elsif cnt_DO_up = 0 then cnt_DO_up <= conv_std_logic_vector(DO_up_max_count, cnt_DO_up'length); out_DO_up <= not out_DO_up; -- flip the output else cnt_DO_up <= cnt_DO_up - '1'; -- decrement counter end if; end if; end process;--*******************************************-- map each key to enable sound output for one note--******************************************* en_DO <= key_1; en_RE <= key_2; en_MI <= key_3; en_FA <= key_4; en_SOL <= key_5; en_LA <= key_6; en_SI <= key_7; en_DO_up <= key_8;--*******************************************-- mix all autputs together--*******************************************mixer: process(CLK) begin if rising_edge(CLK) then out_mix <= conv_std_logic_vector(out_DO, MIX_BITS) + conv_std_logic_vector(out_RE, MIX_BITS) + conv_std_logic_vector(out_MI, MIX_BITS) + conv_std_logic_vector(out_FA, MIX_BITS) + conv_std_logic_vector(out_SOL, MIX_BITS) + conv_std_logic_vector(out_LA, MIX_BITS) + conv_std_logic_vector(out_SI, MIX_BITS) + conv_std_logic_vector(out_DO_up, MIX_BITS); end if; end process; --*******************************************-- audio sound signal DAC--*******************************************sound_PWM_DAC: process(snd_clk) begin if rising_edge(snd_clk) then if pre_cnt(SND_BITS - 1 + 2 downto 2) = (out_mix & '0') then snd_PWM <= '0'; elsif pre_cnt(SND_BITS - 0 + 2 downto 2) = b"00_0000" then snd_PWM <= '1'; end if; end if; end process; SPK_BIT <= snd_PWM; -- sound output--*******************************************-- general volume--*******************************************set_volume_level: process(kbd_clk) begin if rising_edge(kbd_clk) then if key_big_left = '1' and vol_lev /= 255 then vol_lev <= vol_lev + '1'; elsif key_big_right = '1' and vol_lev /= 0 then vol_lev <= vol_lev - '1'; end if; end if; end process; volume_PWM_DAC: process(vol_clk) begin if rising_edge(vol_clk) then if pre_cnt(pre_cnt'length - 1 downto pre_cnt'length - vol_lev'length) = vol_lev then vol_PWM <= '0'; elsif pre_cnt(pre_cnt'length - 1 downto pre_cnt'length - vol_lev'length) = 0 then vol_PWM <= '1'; end if; end if; end process; NSPK_VOL <= vol_pwm; -- general volume -- volume LEDs indicator NLED(5) <= vol_pwm; NLED(6) <= not vol_pwm;--*******************************************-- map LED's to signals--******************************************* NLED(1) <= nq; NLED(2) <= q; NLED(3) <= not snd_PWM; -- ON if any key note pressed NLED(4) <= not (en_DO or en_RE or en_MI or en_FA or en_SOL or en_LA or en_SI or en_DO_up);end Behavioral; Acronime: DAC - Digital to Analog Converter MOSFET - Metal Oxide Semiconductor Field Effect Transistor La final, fişierul ataşat care conţine Tabelul 2, cu tot cu formule: Frecventa note muzicale.zip Link spre comentariu
crispus Postat Octombrie 4, 2012 Partajează Postat Octombrie 4, 2012 Dac ai avea pe cineva pe la remat,ai avea posibilitatea. De la fabrici multe se duc.Acum cinci ani am fost la un remat unde aveam contract pentru reparati si erau aduse aparatura multa de la spital ca exemplu.Offtopic: (dummy question) Unde e REMAT-ul asta? Exista vreo posibilitate de a recupera de la ei (constra cost) diverse parti din electronice? Daca nu ai, nu poti sa-ti faci pe cineva la remat? Link spre comentariu
maxente Postat Octombrie 10, 2012 Partajează Postat Octombrie 10, 2012 Merge cumva implementat in acel FPGA softul pentru calculat hash-uri la bitcoin? Link spre comentariu
em2006 Postat Octombrie 24, 2012 Partajează Postat Octombrie 24, 2012 Interesant topic, l-am descoperit dupa ce am postat aici:viewtopic.php?f=211&t=119787&p=1128709#p1127908Precizarile respective ar fi fost mai potrivite aci.Probabil, si astea:viewtopic.php?f=211&t=119787&p=1128709#p1128709 Link spre comentariu
Postări Recomandate
Creează un cont sau autentifică-te pentru a adăuga comentariu
Trebuie să fi un membru pentru a putea lăsa un comentariu.
Creează un cont
Înregistrează-te pentru un nou cont în comunitatea nostră. Este simplu!
Înregistrează un nou contAutentificare
Ai deja un cont? Autentifică-te aici.
Autentifică-te acum