Sari la conținut
ELFORUM - Forumul electronistilor

Placă de dezvoltare FPGA, dintr-un panou de imprimantă


Vizitator

Postări Recomandate

  • Răspunsuri 20
  • Creat
  • Ultimul Răspuns

Top autori în acest subiect

  • soulraven

    2

  • vasile eugen

    2

  • danzup

    1

  • A_L_E_X

    1

Top autori în acest subiect

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. :nebunrau: 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

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ă :bataie.

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!

:rade:

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

Posted Image

 

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

Posted Image

 

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

Posted Image

 

 

 

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. :nebunrau:

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
  • 1 lună mai târziu...

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? :rade:
Link spre comentariu
  • 2 săptămâni mai târziu...

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 cont

Autentificare

Ai deja un cont? Autentifică-te aici.

Autentifică-te acum



×
×
  • Creează nouă...

Informații Importante

Am plasat cookie-uri pe dispozitivul tău pentru a îmbunătății navigarea pe acest site. Poți modifica setările cookie, altfel considerăm că ești de acord să continui.Termeni de Utilizare si Ghidări