Wpis z mikrobloga

Projekt oscyloskopu cyfrowego. Trochę czasu minęło odkąd wszystko zacząłem, jakiś miesiąc - przez ten czas do ogarnięcia było sporo dużych i drobnych problemów, które potrafiły zająć cały dzień.. Zdecydowanie projektowanie czegoś na FPGA wymaga dużej trzeźwości umysłu. W sumie spędziłem może nad tym projektem z 100 roboczogodzin.

W ostatnim wpisie pokazałem Wam połączony moduł ADC, pamięć RAM i interfejs VGA, wraz z niewielką ilością systemu napisanego w VHDL. Dało to w efekcie prosty oscyloskop z buforem obrazu, który później rozwinąłem o obsługę dwóch enkoderów i przycisków do skalowania/przesuwania w czasie i zdałem jako projekt z elektroniki na zaliczenie na 5.0 ;-)

Projekt pozostawiony na tamtym etapie nie nazwał bym rozwojowym - implementacja kolejnych funkcjonalności nie należała do przyjemnych i zdecydowanie brakowało już na tym etapie architektury mikroprocesora, który zajął by się renderowaniem obrazu. Oczywiście poszedłem w tym kierunku ;-)

Altera dostarcza do swoich układów architekturę procesora zwanego Nios - spędziłem relatywnie mało czasu na pierwszej szybkiej implementacji tego rozwiązania, która dała mi możliwość wykonywania własnego kodu napisanego w C! :-) Do tego w Quartusie dodany jest Eclipse z odpowiednimi pluginami do programowania. To zdecydowanie był krok do przodu, ale pociągnął za sobą horrendalne ilości czasu spędzonego na łączeniu wszystkiego "bez zgrzytów" - o nich później. Ponieważ przy implementacji takiej architektury zaczyna się tu pojawiać multum sygnałów które jakoś trzeba ogarniać i łączyć, Altera wystawiła do tego celu zestaw interfejsów Avalon który określa protokoły komunikacyjne pomiędzy modułami opracowanymi przez ich samych (np. pamięć, ADC, mikroprocesor) oraz narzędzie Qsys - pozwalające na łączenie tego wszystkiego w sposób graficzny. W moim przypadku wygląda to tak:

http://i.imgur.com/HIAxbSz.png

Oczywiście można tworzyć swoje własne moduły, które będzie można dołączyć do tej struktury. Nie skorzystałem jeszcze z takiej opcji aby zmieścić tu to co sam pisałem - obsługę VGA, cały glue-logic itd, ale wygląda to na przyjemne rozwiązanie i w przyszłości może bym z niego skorzystał, zamiast pisać dziesiątki linijek port mapów w VHDL.

To co było dalej, to próba połączenia wszystkiego na nowo. Tutaj sytuacja zaczęła się lekko pieprzyć - nie mogłem i nie mogę dojść do porządku. Z sukcesem wykonałem jeszcze parę zabiegów takich jak:

1) Opracowanie nowego sposobu przechowywania ramki obrazu - teraz nie miałem do dyspozycji wygodnych 3-bitowych komórek pamięci, tylko grube 32-bitowe. Pod każdym adresem kryje się dane 16 pixeli, po 2 bity na kolor. W VHDL wykonanie odczytu konkretnego pixela, po otrzymaniu 32-bitowego ciągu (a także obliczenie która to jest komórka pamięci), jest wykonywane w sumie "w locie" - do takich rzeczy jest stworzone FPGA, natomiast zapisywanie w C pod wskazanymi współrzędnymi pixela to trochę bardziej wymagająca sprawa:

void writePixel(int x, int y, int color) {
int block = y*80 + x / 4;
int data = IORD_8DIRECT(0x0, block);
``` int colorMask = color << ((x % 4)*2);```

``` data &= ~colorMask;```

``` IOWR_8DIRECT(0, block, data);```
}`

2) Organizacja pamięci z podziałem na bufor VGA, próbki ADC, a dopiero na końcu obszar mikroprocesora - ustawienie całego BSP. Trochę zajęło zgranie tego z ustawieniami w Qsysie, bo nagle okazuje się, że nie mogłem zarezerwować całej pamięci układu, bo brakuje jakichś bloków M9K. A przebudowanie wszystkiego z powrotem to kolejne 5 minut... Ostatecznie wyglądało to tak:

http://imgur.com/8u10Znh

3) Implementacja dwuoperacyjnej pamięci RAM. Ponieważ jeden port dwuportowej pamięci RAM użytej w Qsysie jest w całości wykorzystywany przez mikroprocesor, to drugi musi zostać do użytku przez część kodu w VHDL. A ten z kolei musi odczytywać i zapisywać na przemian - a interfejs Avalon-MM daje tylko możliwość zapisu lub odczytu w jednym takcie. Postanowiłem napisać jednostkę, która biorąc co najmniej 3 razy szybszy zegar taktujący niż najwyższa z częstotliwości wykonujących operacje w pamięci. Ma to działać na tej zasadzie, że jednostka na zmianę raz zapisuje.

Niby się udało, w symulatorze działa ok - ale w praktyce dzieją się rzeczy niestworzone i mieszają się adresy zapisywania wraz z adresami odczytywania. Tutaj macie kod jakbyście chcieli przeanalizować, wraz z komentarzami "co autor miał na myśli":

http://pastebin.com/ZmZfj5MQ
(nazwa zmiennej doubleClk powinna być w sumie tripleClk)

Ponieważ moja jednostka nie chce działać jak należy, wszystko dalej się sypie. Ekran miga sobie w dobre, mieszając próbki z ADC wraz z danymi z bufora VGA. Gdy wyłączę zapisywanie próbek z ADC, mam fajną możliwość renderowania obrazu na monitorze, prosto z kodu w C :)

Lekko straciłem siły, przede wszystkim bo sesja, zaliczenia, przeprowadzka. Zobaczymy co dalej, zbiorę się po tym wszystkim i pewnie będę próbował dalej, choć zaczyna to męczyć... Do tego pojawiają się pewnie ograniczenia - Nios2 wcale nie działa tak szybko jak moja szybka implementacja renderowania, nie mogę go taktować z częstotliwościami kilkuset MHz - póki co ograniczam się do 100 MHz. Wydłuża to znacząco czas renderowania, dodatkowo ilość instrukcji ze względu na uP przyrasta znacząco. Nie będzie już na tyle czasu aby renderować obraz w wolnym czasie pomiędzy kolejnymi odświeżeniami obrazu o których pisałem w poprzednim wpisie. Z resztą, jest to słaby pomysł, bo wykorzystywanie 20% obszaru monitora żeby przez pozostały czas renderować obraz.. Bezsensowne.
Rozwiązanie jest, ale wprowadza kolejne ograniczenie - bo rozwiązaniem jest podwójne buforowanie obrazu. A to wymaga pamięci, której mam teraz na styk na te 320x240 px.

Jeżeli ktoś to przeczytał, to podziwiam :P

Spamlista (wołajcie jak chcecie): @syn_admina, @printf, @olewales

#visherdev przede wszystkim - zapraszam
#vga #monitory #fpga #synteza #maximator #vhdl #altera #elektronika
Visher - Projekt oscyloskopu cyfrowego. Trochę czasu minęło odkąd wszystko zacząłem, ...

źródło: comment_yKlgVPc8UOU7D9ZREo85MjJeETRcFpTB.jpg

Pobierz
  • 8
  • Odpowiedz
@Visher: nie doczytałem do końca, ale w normalnych oscyloskopach dane obrabia jedno fpga, a obraz wyświetlany jest za pomocą drugiego. Zaoszczedziloby ci to sporo zasobów.
  • Odpowiedz
@Visher: Fajny projekt, też dłubałem w FPGA jak kupiłem MAX10 ale w Verilogu. Mozesz dać więcej info na temat obsługi wbudowanego ramu? Napisałem sterownik VGA, ale nie miał bufora ramki - strasznie miało informacji było w necie na temat tego fpga.
  • Odpowiedz
@d15ea5e:

Ogółem sprawa jest bardzo prosta. W Quartusie można to zrobić na dwa sposoby: z wykorzystaniem qsysa i bez.

Qsys tak jak we wpisie pisałem to narzędzie które pozwalała łączyć różne IP (w uproszczeniu IP = taki moduł, entity) w przyjemny graficzny sposób. Można w nim dodać moduł "Altera On-Chip RAM" i w zależności od potrzeb go skonfigurować. Ale, i tu jest pierwsza różnica, z jakiejś przyczyny, sposoby konfiguracji są ograniczone.
Visher - @d15ea5e: 

Ogółem sprawa jest bardzo prosta. W Quartusie można to zrobić ...

źródło: comment_9XSZbYt8nTMIWAjydtGlj5Wz6hvWDhUk.jpg

Pobierz
  • Odpowiedz