هل من الصعب أن تكتب أول برنامج VHDL؟

هل من الصعب أن تكتب أول برنامج VHDL؟ من الصعب القول ، لكن الشيء الرئيسي هنا هو الدافع ...


ربما تمكنت من تأخير هذه اللحظة ، لكن أحد الجيران طلب مني إنشاء مولد نبض مستطيل بحيث يمكن عرضه بوضوح وسيكون من الممكن التحكم في وتيرة ومدة النبضة.

وبدقة 0.1 ميكروثانية ...

ووقع رأيي على وشاح مع CPLD (200 روبل ، نوعا ما) التي كانت هناك مؤشرات وأزرار. بمجرد أن تبدأ العمل مع مثل هذا الشيء ، فكرت ، و ...

لم يكن خيار الكتابة VHDL أو Verilog - على الرغم من أنني أكتب كل شيء في لغة C ، لكنني ما زلت أحب Ada - لذلك VHDL فريدة من نوعها. علاوة على ذلك ، بعد قراءة مقدمة FPGA ، أدركت أنه لن يكون هناك شيء معقد (جيدًا ، على الأقل لمثل هذه المهمة البسيطة).

لذلك ، في البداية كانت الكلمة دعونا نجعل أنفسنا مولدًا. تردد التردد الأصلي هو 50 ميجاهرتز ، أي سنقله إلى 10 ، بحيث يكون تبديل خط الساعة في المنتصف والنهاية. إليك ما حدث.

-- 100 ns signal generator process(clk) variable t:integer range 0 to 5 := 0; begin if rising_edge(clk) then t := t + 1; if t = 5 then t := 0; tact <= not tact; end if; if t = 2 then tact <= not tact; end if; end if; end process; 

ثم تحتاج إلى عرض وإدارة بطريقة أو بأخرى. لدينا قيمتان - طول الفترة وطول الدافع ، بحيث نحدد طول الفترة الزمنية 3 معارف (مع الأخذ في الاعتبار الأعشار) وطول الفترة - 3.

 shared variable period : integer range 0 to 1000 := 500; shared variable duty : integer range 0 to 1000 := 250; shared variable dig1:std_logic_vector(3 downto 0):="0000"; shared variable dig2:std_logic_vector(3 downto 0):="0101"; shared variable dig3:std_logic_vector(3 downto 0):="0010"; shared variable di1:std_logic_vector(3 downto 0):="0000"; shared variable di2:std_logic_vector(3 downto 0):="0000"; shared variable di3:std_logic_vector(3 downto 0):="0101"; 

حسنًا ، للتحكم ، تكون الإشارات الصادرة من الأزرار مناسبة ، والتي تكون مرئية في أسفل اللوحة - هناك 4 منها فقط ،
لذلك دعونا اثنين السيطرة على التغيير في الفترة والزخم ، على التوالي ، واحد يحدد علامة التغيير ، وآخر واحد تشغيل وإيقاف مولد المولد ...

ها هي الإدارة
 process(key1) begin if rising_edge(key1) then ready <= not ready; end if; end process; process(key3) begin if rising_edge(key3) then if key4 = '1' then inc_duty; else dec_duty; end if; end if; end process; process(key2) begin if rising_edge(key2) then if key4 = '1' then inc_period; else dec_period; end if; end if; end process; 


في الإدارة هناك إجراءات inc / dec ، ها هم
 procedure inc_duty is begin if duty < period then duty := duty + 1; if dig1 = "1001" then dig1 := "0000"; if dig2 = "1001" then dig2 := "0000"; if dig3 = "1001" then dig3 := "0000"; else dig3 := dig3 + 1; end if; else dig2 := dig2 + 1; end if; else dig1 := dig1 + 1; end if; end if; end procedure; procedure dec_duty is begin if duty > 1 then duty := duty - 1; if dig1 = "0000" then dig1 := "1001"; if dig2 = "0000" then dig2 := "1001"; dig3 := dig3 - 1; else dig2 := dig2 - 1; end if; else dig1 := dig1 - 1; end if; end if; end procedure; procedure inc_period is begin if period < 1000 then period := period + 1; if di1 = "1001" then di1 := "0000"; if di2 = "1001" then di2 := "0000"; if di3 = "1001" then di3 := "0000"; else di3 := di3 + 1; end if; else di2 := di2 + 1; end if; else di1 := di1 + 1; end if; end if; end procedure; procedure dec_period is begin if period > 1 then period := period - 1; if di1 = "0000" then di1 := "1001"; if di2 = "0000" then di2 := "1001"; if di3 = "0000" then di3 := "1001"; else di3 := di3 - 1; end if; else di2 := di2 - 1; end if; else di1 := di1 - 1; end if; end if; end procedure; 


إنه طويل ومعقد بعض الشيء (لهذا السبب يتم تصغيره) ، لكنه مفهوم تمامًا.

حسنًا ، نحتاج إلى عرضه بطريقة أو بأخرى - لدينا مؤشر من سبعة أجزاء ، وهناك 6 منها (في الواقع 8). سنعرض الوقت ، وحتى لا نعاني من نقطة ما ، في أعشار ميكروثانية.

اسمح لهم بالتنقل وعرض الرقم الحالي:

 process(tactX) begin case tactX is when"000"=> en_xhdl<="11111110"; when"001"=> en_xhdl<="11111101"; when"010"=> en_xhdl<="11111011"; when"011"=> en_xhdl<="11110111"; when"100"=> en_xhdl<="11101111"; when"101"=> en_xhdl<="11011111"; when"110"=> en_xhdl<="10111111"; when"111"=> en_xhdl<="01111111"; when others => en_xhdl<="01111111"; end case; end process; process(en_xhdl) begin case en_xhdl is when "11111110"=> data4<=dig1; when "11111101"=> data4<=dig2; when "11111011"=> data4<=dig3; when "11110111"=> data4<="1111"; when "11101111"=> data4<=di1; when "11011111"=> data4<=di2; when "10111111"=> data4<=di3; when "01111111"=> data4<="0000"; when others => data4<="1111"; end case; end process; process(data4) begin case data4 is WHEN "0000" => dataout_xhdl1 <= "11000000"; WHEN "0001" => dataout_xhdl1 <= "11111001"; WHEN "0010" => dataout_xhdl1 <= "10100100"; WHEN "0011" => dataout_xhdl1 <= "10110000"; WHEN "0100" => dataout_xhdl1 <= "10011001"; WHEN "0101" => dataout_xhdl1 <= "10010010"; WHEN "0110" => dataout_xhdl1 <= "10000010"; WHEN "0111" => dataout_xhdl1 <= "11111000"; WHEN "1000" => dataout_xhdl1 <= "10000000"; WHEN "1001" => dataout_xhdl1 <= "10010000"; WHEN OTHERS => dataout_xhdl1 <= "11111111"; END CASE; END PROCESS; 

أعترف بصراحة أنني سحبت جزءًا من الشفرة من المصادر التي جاءت مع وشاح - إنه رائع جدًا ومكتوب بوضوح! en_xhdl - سوف تتحكم هذه الإشارة في المؤشر الذي يعمل في دورة التبديل ، dataout_xhdl1 - هذه الإشارة تعمل على مصابيح LED ، حسنًا ، data4 هو سجل مؤقت ويخزن رقمًا.

يبقى أن تكتب القلب الذي ينظر في كل شيء - المولد نفسه. هنا tactX هو مولد العرض ، و cnt هو عداد موضع النبض. حسنا ، لين هي إشارة المولد نفسه.

 process(tact) variable cntX : integer range 0 to 1000 := 0; variable cnt : integer range 0 to 1000 := 0; begin if rising_edge(tact) then if cntX = 0 then tactX <= tactX + 1; end if; cntX := cntX + 1; if cnt > period then cnt := 0; else cnt := cnt + 1; end if; if cnt = 0 then lin <= '0'; elsif cnt = duty then lin <= '1'; end if; end if; end process; 

حسنًا ، يبقى إخراج البيانات - يتم ذلك باستمرار ، لذلك يجب أن يكون موجودًا في كتلة التنفيذ الموازية.

  cat_led <= dataout_xhdl1; en_led <= en_xhdl; led1 <= not ready; out1 <= lin when ready = '1' else '0'; out2 <= not lin when ready = '1' else '0'; 

في النهاية ، أعمى كل العمليات معًا - تم استلام ملف Quarus Prime الناتج بشكل جيد وتجميعه والإبلاغ عنه

 Top-level Entity Name v12 Family MAX II Device EPM240T100C5 Timing Models Final Total logic elements 229 / 240 ( 95 % ) Total pins 29 / 80 ( 36 % ) Total virtual pins 0 UFM blocks 0 / 1 ( 0 % ) 

تبقى المرحلة الأكثر مملة ، على الرغم من أنها رسومية بالكامل - لتعيين دبابيس محددة للإشارات. هذا كل شيء - يبقى ملء كل شيء في الجهاز والتحقق منه! ومن المثير للاهتمام ، أننا تمكنا من الاحتفاظ بداخل 229 خلية ، لذلك لم يتبق منها سوى 11 خلية - ولكن في الواقع ، تم تقريبًا كل شيء تقريبًا عن طريق الواجهة - أزرار وعرض. في الواقع يمكن تكديس المولد في عدة خلايا - لدى Intel مستند حيث يصفون كيفية التكديس في 1 LUT - جيدًا ، بالطبع ، بدون تحكم ...

لذا ، أجب على سؤال العنوان الرئيسي - لا ، ليس من الصعب إذا كنت تعرف C أو Ada وأنت تفهم كيف تعمل الإلكترونيات الرقمية ، ونعم ، سيكون من الصعب إذا لم يكن لديك فكرة عن الأشياء الأساسية ... على الأقل ، استغرق الأمر مني يومًا للكتابة ، وأنا لقد حصلت على الكثير من المتعة من عملية التطوير ومن جهاز يعمل! والجار سعيد :)

Source: https://habr.com/ru/post/ar461621/


All Articles