Sterowanie PWM diodą LED - VHDL

Zadanie: Zaprojektować układ sterujący poziomem jasności świecenia diody LED na płytce prototypowej (np., LD0 na płytce Nexys) sygnałem PWM (Pulse Width Modulation) o wypełnieniu regulowanym przyciskami. 

Jak ma działać układ:

  • Zapewnić wypełnienie przebiegu wyjściowego od 0% do 100% z krokiem co 10%.
  • Zmianę wypełnienia realizujemy za pomocą dwóch przycisków: UP i DOWN. Po naciśnięciu przycisku UP zwiększamy jasność świecenia diody LED (+10%), po naciśnięciu DOWN - zmniejszamy (-10%). Po osiągnięciu 100%, dalsze naciskanie UP nie powoduje żadnej zmiany, a również po osiągnięciu 0% dalsze naciskanie DOWN nie powoduje żadnej zmiany. 
  • Należy zabezpieczyć się przed drganiami przycisków (tzw. debouncer) oraz zastosować układ, który reaguje tylko na naciśnięcie przycisku, a nie jego przytrzymywanie (tzw. leading edge detector)
  • Na wyświetlaczu 7-segmentowym LED wyświetlany jest aktualny poziom jasności w procentach (0-100), należy wygasić nie wykorzystywane cyfry wyświetlacza LED.

Wymagania dotyczące projektu:

  • Wszystkie bloki powinny mieć reset asynchroniczny (patrz szablony kodu HDL). W czasie resetu wszystkie segmenty wyświetlacza powinny się zapalać, a po resecie poziom jasności PWM powinien się ustawiać na 100%.
  • Podzielić projekt na bloki, np.: dzielnik częstotliwości, eliminator drgań (debouncer), detektor zbocza przycisku, sterownik wyświetlacza 7-segmentowego. Każdy blok powinien być w osobnym pliku HDL. Nazwa pliku powinna być taka sama jak nazwa bloku (plus odpowiednie rozszerzenie).
  • Do odczytywania przycisków (debouncer) i sterowania wyświetlaczem LED (multipleksacja) zaleca się stosować zegar o częstotliwości rzędu 1kHz, natomiast do sygnału PWM: np. 100kHz. 
  • Napisać osobny moduł testbench generujący wszystkie sygnały i służący do symulacji układu. Moduł testbench może być oczywiście niesyntezowalny.

Co należy przedstawić do oceny:

  • Symulację funkcjonalną, pokazującą działanie wszystkich funkcji układu.
  • Demonstrację działania układu, włącznie z działaniem resetu.

Wirtualnymi przyciskami steruje się poprzez emulator przycisków fpga_remote_lab - patrz instrukcja.

Więcej szczegółów, schematy itp. znajdziesz w instrukcji obsługi płytki Nexys A7, na stronach 13 i 22.

Plik "constraints" w formacie XDC do zadania, płytka Digilent Nexys A7, układ Artix-7 XC7A100T-1CSG324C (obudowa: CSG324, speed grade:-1):

#########################################################################################
# CLOCK:
set_property -dict { PACKAGE_PIN E3 IOSTANDARD LVCMOS33 } [get_ports {clk_i} ];
create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports {clk_i}];
#########################################################################################
# Virtual RESET (BTN3):
set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports {rst_i} ]; #virtual BTN3
#########################################################################################
# Virtual BUTTONS:
set_property -dict { PACKAGE_PIN C17 IOSTANDARD LVCMOS33 } [get_ports { btn_dn_i }];  #virtual BTN0
set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports { btn_up_i }];  #virtual BTN1
#########################################################################################
set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { pwm_o }]; # LD0
#########################################################################################
# LED 7-SEGMENT DISPLAY:
set_property -dict { PACKAGE_PIN T10 IOSTANDARD LVCMOS33 } [get_ports { led_seg_o[7] }];
set_property -dict { PACKAGE_PIN R10 IOSTANDARD LVCMOS33 } [get_ports { led_seg_o[6] }];
set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { led_seg_o[5] }];
set_property -dict { PACKAGE_PIN K13 IOSTANDARD LVCMOS33 } [get_ports { led_seg_o[4] }];
set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33 } [get_ports { led_seg_o[3] }];
set_property -dict { PACKAGE_PIN T11 IOSTANDARD LVCMOS33 } [get_ports { led_seg_o[2] }];
set_property -dict { PACKAGE_PIN L18 IOSTANDARD LVCMOS33 } [get_ports { led_seg_o[1] }];
set_property -dict { PACKAGE_PIN H15 IOSTANDARD LVCMOS33 } [get_ports { led_seg_o[0] }];

set_property -dict { PACKAGE_PIN J17 IOSTANDARD LVCMOS33 } [get_ports { led_an_o[0] }];
set_property -dict { PACKAGE_PIN J18 IOSTANDARD LVCMOS33 } [get_ports { led_an_o[1] }];
set_property -dict { PACKAGE_PIN T9 IOSTANDARD LVCMOS33 }  [get_ports { led_an_o[2] }];
set_property -dict { PACKAGE_PIN J14 IOSTANDARD LVCMOS33 } [get_ports { led_an_o[3] }];

set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { led_an_o[4] }];
set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { led_an_o[5] }];
set_property -dict { PACKAGE_PIN K2  IOSTANDARD LVCMOS33 } [get_ports { led_an_o[6] }];
set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { led_an_o[7] }];
#########################################################################################