wersja mobilna | kontakt z nami

NIOS II na maXimatorze, czyli mikroprocesor w układzie FPGA (3). Przerwania, timery i obsługa wyświetlaczy

Numer: Luty/2018

Do tej pory wspólnymi siłami udało nam się wbudować w pełni funkcjonalny system mikroprocesorowy, który odbierał i generował cyfrowe sygnały (powiedzmy dumnie, że przetwarzał sygnały cyfrowe!). Kilkakrotnie wspominałem przy tej okazji, że stosowanie opóźnień jest rozwiązaniem nagannym, jednak dotychczas nie mieliśmy alternatywy - czas ją poznać i wzbogacić system oraz swoją wiedzę o timery i system przerwań.

Pobierz PDFMateriały dodatkowe

Abyśmy mogli przystąpić do nauki, musimy mieć solidną bazę, czyli projekt zawierający porty GPIO (PIO) do sterowania wyświetlaczami 7-segmentowymi oraz mieć informacje na temat metody ich sterowania. Aby zbędnie nie przedłużać tej części (i ufając, że każdy opracował swoje zadanie), przedstawię swoją wersję wymaganego projektu i bardzo krótko ją omówię.

Dodano porty wyjściowe o szerokości odpowiednio 4 i 8 bitów – do sterowania włączaniem odpowiednio kolejnych wyświetlaczy i segmentów (7 oraz kropka). Port sterujący wyświetlaczami został wyposażony w funkcje ustawiania/kasowania pojedynczych bitów.

rys1W programie dodano folder 7SEG na pliki z funkcjami obsługującymi sterowanie wyświetlaczami. Klikamy PPM na nazwę projektu, potem New ’ Folder (rysunek 1).

Dodano pliki 7SEG.c i 7SEG.h w utworzonym folderze. Podobnie jak wcześniej, klikamy PPM na nazwę projektu i potem New ’ File.

Dodano folder 7SEG do ścieżki wyszukiwania plików Include:

- otwieramy Project ’ Properties,
- wybieramy Nios II Application Properties ’ Nios II Application Paths,
- obok okna Application include directories klikamy na Add…,
- w nowym oknie lokalizujemy nasz folder. Wszędzie klikamy OK/Yes (rysunek 2).

Zdefiniowano kombinacje segmentów do zapalenia dla każdej cyfry z systemu heksadecymalnego oraz znaku „–”, funkcję ustawiającą odpowiednią kombinację na wyprowadzeniach połączonych z segmentam oraz funkcję wyłączającą wszystkie wyświetlacze lub włączającą jeden z nich.

Napisano program multipleksujący wyświetlacze (listing 1). Na jego przykładzie powtórzymy też w skrócie ideę multipleksowania wyświetlaczy:

rys2- wyłączamy wszystkie wyświetlacze,
- ustawiamy kombinację segmentów dla kolejnego wyświetlacza,
- włączamy ten wyświetlacz,
- czekamy trochę czasu (tu zaraz pozbędziemy się instrukcji opóźniającej),
- powtarzamy dla kolejnego wyświetlacza.

Uwaga. Często popełnianym błędem jest zapominanie o instrukcji wyłączającej wszystkie wyświetlacze, przed zmianą kombinacji segmentów (a) – powoduje to powstanie bardzo nieestetycznych duchów na wyświetlaczach, jeśli chcecie, możecie to sprawdzić, usuwając tę instrukcję.

Kody źródłowe zadania domowego w mojej interpretacji umieszczone zostały w pliku Tutorial03_start.zip i do nich będę się w dalszym ciągu naszego spotkania odwoływał, jeśli jednak przygotowaliście swoje wersje, to jeśli działają one poprawnie, zachęcam do kontynuowania prac nad nimi. Tak czy inaczej zachęcam do zapoznania się z moją propozycją i porównania swoich autorskich programów.

Timer i przerwania

W wyżej przedstawionym programie znalazła się instrukcja, o której stosowaniu (a raczej prawie zakazie jej stosowania) już wspominałem. Chodzi o instrukcję generującą opóźnienie. Ta, której używaliśmy dotychczas, bazuje na fakcie wykonywania „pustych” instrukcji na rdzeniu procesora (instrukcje NOP). Takie rozwiązanie ma dwie wady. Pierwszą z nich jest to, że dokładne wygenerowanie opóźnienia jest dosyć kłopotliwe. Z jednej strony umieszczenie odpowiedniej liczby operacji NOP da dokładne opóźnienie, ale kosztem dużej zajętości pamięci (np. 1 ms przy zegarze 50 MHz to 50 tysięcy operacji, zakładając, że jedna operacja wykonuje się w jednym cyklu zegarowym). Z drugiej strony, zwykle instrukcje niskiego poziomu używane przy tworzeniu pętli nie mają jednoznacznie określonego czasu wykonywania (np. instrukcja porównania z zerem na pewnych procesorach może wykonać się w 1 lub 2 taktach, w zależności od tego, czy warunek jest spełniony, czy też nie). Druga poważna wada to fakt, że w czasie odmierzania opóźnienia procesor nie może robić nic innego i po prostu marnuje czas. Wyobraźmy sobie, że nasz system ma nie tylko wyświetlać dane na wyświetlaczu, ale jednocześnie np. zliczać impulsy, obsługiwać prostą klawiaturę i jakieś menu użytkownika… Już niejeden raz widziałem „arcydzieła” mogące konkurować z obrazami mistrza Picasso zawierające setki instrukcji warunkowych poprzeplatanych z maleńkimi kwantami opóźnień…

rys3My jednak pozostaniemy z daleka od takich artystycznych rozwiązań i postaramy się wykonać zadanie możliwie zgodnie ze sztuką. Zatem zacznijmy od przedstawienia głównego bohatera naszego spotkania, czyli timera (licznika). Jak sama nazwa wskazuje, układ ten liczy impulsy, w naszym przypadku będą to impulsy sygnału zegarowego. Otwórzmy teraz nasz projekt Qsys i wyszukajmy Interval timer, a następnie rozpocznijmy proces dodawania go do naszego systemu (rysunek 3).

Timer Licznik dostarczony nam przez producenta ma możliwość zliczania tylko w dół, czyli jego wartość zmniejsza się, aż do osiągnięcia zera. W tym momencie nasz timer może wygenerować sygnał dla procesora (o czym powiemy za chwilę) i zatrzymać się lub przyjąć określoną wartość i znów rozpocząć zliczanie do zera, w zależności od ustawienia.

Omówmy teraz w skrócie parametry, jakie możemy ustawić z poziomu Qsys:

Timeout Period: Period, Units – definiujemy tu wartość, jaka ma być ładowania do timera po zakończeniu odliczania, oraz jednostki, w jakich jest ona wyrażona (jeśli wszystko wykonujemy poprawnie, Qsys wie, jaka jest częstotliwość zegara i jest w stanie przeliczyć czas na liczbę cykli zegara – to bardzo wygodne). W skrócie definiujemy tu okres, z jakim licznik będzie nas powiadamiał o zakończeniu odmierzania czasu.

Counter Size – tu definiowana jest liczba bitów, jaką miał będzie nasz licznik. Jak nietrudno zauważyć, zależy od niej maksymalny czas, jaki możemy odmierzyć. Oczywiście w danej liczbie bitów musi zmieścić się liczba cykli zegara potrzebna do odmierzenia danego czasu, a nie tenże czas podany np. w sekundach.

No Start/Stop control bits – opcja ta pozwala na pozbawienie naszego licznika możliwości uruchamiania go i zatrzymywania z poziomu programu (napisanego na procesor NIOS II).

Fixed period – to ustawienie pozwala z kolei na pozbawienie licznika możliwości zmiany jego okresu (patrz punkt 1) z poziomu programu.

Readable snapshot – zaznaczenie tej opcji pozwala na odczyt stanu licznika (aktualnej wartości) w dowolnym momencie z poziomu programu.

System reset on timeout (Watchdog) – dodaje do naszego timera wyjście sygnału resetującego, którym możemy zresetować cały system po zliczeniu do 0. Dzięki temu możemy stworzyć, jak sama nazwa wskazuje, układ Watchdog, czyli nadzorujący pracę układu i mogący zrestartować go w wypadku błędu (normalnie program powinien okresowo zerować układ Watchdog, jeśli do takiego resetu nie dojdzie to wtedy układ resetuje cały system).

Timeout pulse – dodaje dodatkowe wyjście z timera, które generuje impuls po zliczeniu do 0. Możemy ten sygnał wykorzystać w dowolny sposób.

Na razie zostawmy domyślne ustawienia, dzięki czemu dostępne będziemy mieli prawie wszystkie (poza dwoma ostatnimi) opcje timera. Chciałbym tu jednak zwrócić uwagę na ważną rzecz – mianowicie optymalizację. Na etapie budowania systemu powinniśmy znać już założenia i wymagania stawiane przez oprogramowanie. I tak na przykład do prostego multipleksowania wyświetlaczy powinniśmy usunąć opcje zatrzymywania i uruchamiania timera, zmiany jego okresu czy odczytu jego wartości. Dzięki temu zaoszczędzimy cenne elementy logiczne w układzie.

rys4Teraz doprowadzimy sygnał zegarowy, tak jak poprzednio (wyjście z pętli PLL), sygnał zerowania (reset), magistralę Avalon do Data Master naszego CPU oraz tworzymy połączenie od irq. Wybierzmy jeszcze, mimo braku błędów, ale dla nabrania dobrych nawyków System ’ Assign Base Addresses. Warto zmienić nazwę nowo dodanego komponentu na np. TIMER0.

System (po zwinięciu mniej istotnych teraz elementów) powinien wyglądać jak na rysunku 4.

Przerwania Właśnie podłączyliśmy z naszego timera sygnał przerwania, jestem jednak w tym momencie winny kilka wyjaśnień, czym tak naprawdę są przerwania i jakie mamy możliwości ich konfiguracji w Qsys.

Normalnie program w naszym procesorze jest wykonywany krok po kroku, a instrukcje są realizowane po kolei (za wyjątkiem skoków związanych np. z pętlami czy instrukcjami warunkowymi). Czasem jednak jest wymagane obsłużenie nagłego zdarzenia (np. wciśnięcie przycisku bezpieczeństwa, odebranie danych przesłanych jakimś interfejsem). W tym właśnie celu używa się przerwań, które w określonej sytuacji powodują przerwanie (jak sama nazwa wskazuje) wykonywania głównego programu i wykonanie innych, „priorytetowych” zadań. Po tym wszystkim zwykle następuje powrót do wykonywania głównego programu od miejsca, w którym został on przerwany. Przedstawia to schematycznie rysunek 5.

rys5A w naszym wypadku? Co da nam przerwanie? Odpowiedź na te pytania powoli nasuwa się sama. Jeśli procedura odświeżania naszego wyświetlacza ma być wykonywana co 1 ms, wstępnie ustawiliśmy timer na odmierzanie czasu właśnie 1 ms, to wystarczy umieścić instrukcje odpowiedzialne za multipleksowanie w przerwaniu i… W zasadzie zapominamy o tym, że musimy multipleksować wyświetlacz! A to dopiero początek możliwości, jakie otwiera przed nami użycie timerów i przerwań.

Konfigurowanie przerwań Przerwania musimy przede wszystkim skonfigurować w Qsys. I tak, patrząc na rysunek 4, widzimy kolumnę IRQ, w której są widoczne poł?czenia linii przerwa?, kt?re s??zdublowane w?kolumnie ączenia linii przerwań, które są zdublowane w kolumnie Connections wraz z zaznaczonymi numerami przerwań (0 dla JTAG_UART oraz 1 dla nowo dodanego TIMER0). W rdzeniu Nios II Economy mamy możliwość dodania 32 źródeł przerwania, z których każde musi mieć unikalny numer. W wypadku konfliktów możemy ręcznie zmienić numery przerwań lub posłużyć się opcją System à Assign Interrupt Numbers. Jeśli nasz system nie ma żadnych błędów, co sprawdzamy w panelu Messages, możemy kliknąć Finish i w dalszych krokach odpowiedzieć twierdząco na pytanie o ponowne wygenerowanie systemu. Następnie przeprowadzamy kompilowanie projektu.

Wracamy do programowania

Teraz możemy spokojnie uruchomić środowisko Eclipse, aby zacząć modyfikowanie naszego oprogramowania. W pierwszej kolejności oczywiście generujemy nowe BSP (dokładnie jak poprzednio). I zabieramy się do dzieła. Jednak pewnie zaraz padnie pytanie – gdzie najlepiej szukać informacji na temat obsługi poszczególnych komponentów? Odpowiem tak, jak zwykle w tej chwili odpowiadam – w dokumentacji dostarczonej przez producenta, czyli Intel FPGA (dawniej Altera). Padnie tu też zachęta do nauki języka angielskiego, którą możemy czasem „wspomóc” (oczywiście z rozwagą i pewną dozą nieufności) za pomocą dostępnych online narzędzi tłumaczących. Dlaczego tak? Po pierwsze warto jak najwcześniej przyzwyczajać się do czytania tego typu dokumentacji, po drugie znajdziemy tam zawsze informacje z pierwszej ręki i aktualne, po trzecie omówienie wszystkich komponentów systemu wraz z przykładami i przetłumaczenie całej dokumentacji na język polski byłoby zadaniem karkołomnym. Co można też skwitować powiedzeniem, że „lepiej nauczyć kogoś łowić ryby i dać mu wędkę, niż dać mu kilka ryb”.

W naszym konkretnym przypadku informacji szukać należy (na chwilę pisania tego tekstu) na stronie https://goo.gl/7M2Jg3 (Documentation: Nios II Procesor, rysunek 6).

rys6W chwili obecnej interesować będą nas najbardziej dokumenty:

Software Developer’s Handbook, który zawiera opis wszelkich funkcji wyższego poziomu przygotowanych przez producenta do obsługi rdzenia i innych modułów (tzw. warstwa HAL – Hardware Abstraction Layer – warstwa abstrakcji sprzętu, dzięki której nie musimy „znać rejestrów procesora”, aby coś zrobić, np. wysłać tekst przez nasz JTAG do konsoli na komputerze). Tu znajdziemy m.in. informacje o funkcjach ułatwiających obsługę i kontrolę przerwań.

Embedded Peripherials IP User Guide, który zawiera opis dostarczonych przez producenta modułów i opcji ich konfiguracji, a także ich rejestrów.

Modyfikujemy nasz program

Na samym początku w pliku 7SEG.c utwórzmy funkcję, odpowiedzialną za pojedynczy cykl odświeżania wyświetlacza, oraz dodamy odpowiednią deklarację do pliku nagłówkowego (listing 2). Funkcja ta to w pewnym sensie „rozwinięta” pętla for z pierwotnego programu. Kluczową rolę odgrywa tutaj słowo static, które powoduje, że zmienna disp zachowuje swoją wartość pomiędzy kolejnymi wywołaniami funkcji.

W pliku głównym, przed funkcją main definiujemy funkcję, która będzie funkcją obsługi przerwania – pokazano ją na listingu 3.

Pierwsza z instrukcji powoduje skasowanie (potwierdzenie) przerwania, w przypadku braku takiego potwierdzenia przerwanie od naszego timera byłoby ciągle aktywne i procesor zawiesiłby się wykonując tylko i wyłącznie instrukcje przypisane do tego przerwania. Informacje o tym znajdujemy oczywiście w… odpowiednim dokumencie, który nawet ostrzej informuje o możliwym nieprzewidywalnym działaniu systemu w takiej sytuacji. Druga instrukcja nie wymaga wyjaśnienia, za to kilku słów wymaga z pewnością sam wygląd funkcji. O ile pierwsze void nas nie dziwi, o tyle argument tejże funkcji może zastanawiać. Spieszę z wyjaśnieniem, że ma on taką postać, aby z jednej strony był ogólny, a z drugiej pozwalał na przekazanie do naszej funkcji dowolnych argumentów. W jakim jednak celu? Choćby po to, aby móc tę samą funkcję wykorzystać do obsługi kilku przerwań, które będą powodowały jej wywołanie z różnymi argumentami. Dzięki temu mamy 1 ciało funkcji, ale dzięki argumentowi mogące rozróżnić, skąd zostało „wezwane do działania”.

Sama instrukcja (a właściwie makro) zapisu wartości 0 do rejestru statusu (bo w ten właśnie sposób jest zdefiniowane potwierdzenie przerwania) jest bliźniaczo podobna do tych, których używaliśmy w przypadku pracy z portami PIO. Wszystkie tego typu makra znajdziemy w pliku altera_avalon_timer_regs.h.

rys7Spójrzmy teraz pokrótce na rejestry dostępne w naszym 32-bitowym timerze (timer 64-bitowy ma dodatkowe rejestry periodsnap). Pokazano je na rysunku 7. Wszystkie nieopisane bity mogą przy odczycie przyjmować niezdefiniowane wartości, a zapisywane powinny być zawsze zerami:

status zawiera bity: RUN (przyjmuje 1, gdy licznik pracuje) oraz TO (przyjmujący 1, gdy sygnalizowane jest przerwanie). Zapis 0 do tego rejestru powoduje skasowanie przerwania.

control zawiera bity STOP START (zapisanie do jednego z nich 1 powoduje uruchomienie licznika, zaś do drugiego – jego zatrzymanie, nie wolno zapisywać 1 do obu tych bitów naraz), CONT (ustawienie na 1 powoduje, że timer działa cyklicznie, zaś 0 skutkuje jednokrotnym odmierzeniem zadanego czasu, po czym konieczny jest ręczny start timera za pomocą bitu START) oraz bit ITO (ustawienie go na 1 pozwala na generowanie przerwania).

periodh/l – w 2 połówkach 32-bitowa wartość okresu timera. Zapis do któregokolwiek z tych rejestrów powoduje zatrzymanie timera.

snaph/l – w 2 połowach aktualna wartość, jaką ma licznik. Aby odczytać wartość, należy najpierw dokonać zapisu dowolnej (ignorowanej) wartości do któregokolwiek z rejestrów, a dopiero potem przeprowadzić odczyt z obu rejestrów.

Jakie są w świetle tych informacji nasze dalsze kroki? Po pierwsze musimy „przypisać” zdefiniowaną wcześniej funkcję do przerwania naszego timera. Robimy to w następujący sposób (pełna dokumentacja w Software Developer’s Handbook):

alt_ic_isr_register(TIMER0_IRQ_INTERRUPT_CONTROLLER_ID, TIMER0_IRQ, timer0Interrupt, NULL, NULL);

Pierwszy argument, który moglibyśmy pominąć, to identyfikator kontrolera przerwań (tylko Nios II Fast ma możliwość podłączania dodatkowych kontrolerów przerwań celem zwiększenia ich liczby ponad 32), jednak dla porządku (a może kiedyś zechcemy przenieść nasz kod na ten lepszy rdzeń?) podajemy tam odpowiednią etykietę, a tych szukamy w pliku system.h, jak podczas „zabawy” z PIO. Kolejny argument to numer przerwania, do którego się odnosimy (pamiętacie, jak mówiłem o tym w czasie projektowania systemu w Qsys?) – i tu znów etykieta zamiast liczby – tak jest bezpieczniej i wygodniej. Wygodniej, bo od razu widzimy co to za przerwania, a bezpieczniej, bo gdy zmienimy coś w Qsys (nawet kliknięcie Assign Interrupt Numbers może czasem coś zamieszać) i zmienią się numery przerwań – nie musimy w programie karkołomnie wyszukiwać wszędzie wystąpienia zera czy jedynki (no, chyba że bliżej nam do mistrza Salvadora Dalego niż dobrego programisty). Dalej? No oczywiście – nazwa naszej funkcji, zaraz po niej miejsce na jej argumenty (tak, tak, to, co tu wpiszemy, zostanie przekazane jako argument funkcji), w naszym wypadu nie przekazujemy nic (podajemy pusty wskaźnik, czyli 0, zapisane tu jako NULL). Ostatni argument naszej funkcji, zgodnie z zaleceniami producenta, ma mieć także wartość NULL.

Co jeszcze pozostało nam zrobić? Jedynie włączyć timer, ustawić go w tryb ciągłej pracy i zezwolić na generowanie przerwania. Realizuje to następujący fragment kodu:

IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER0_BASE, ALTERA_AVALON_TIMER_CONTROL_START_MSK | ALTERA_AVALON_TIMER_CONTROL_CONT_MSK | ALTERA_AVALON_TIMER_CONTROL_ITO_MSK );

Po nim powinna znaleźć się tylko pusta pętla while, bez żadnych dodatkowych instrukcji. Program możemy skompilować i wgrać do procesora, pamiętając, aby wcześniej wgrać odpowiednią konfigurację układu FPGA i dokonać Refresh connections. Voilà! Nasz wyświetlacz działa dokładnie tak, jak poprzednio! Tym razem jednak nasza pętla główna jest pusta, a w programie nie ma ani jednej instrukcji generującej opóźnienie! Czas jednak, aby obsługa naszego wyświetlacza była nieco bardziej praktyczna i abyśmy mieli łatwą kontrolę nad tym, co jest na nim wyświetlane.

Nieco modyfikacji

Aby nasz wyświetlacz mógł zostać praktycznie wykorzystany musimy wprowadzić kilka modyfikacji. Po pierwsze, tworzymy w pliku 7SEG.c tablicę volatile uint8_t displayData[4]={0, 0, 0, 0}; Przechowywać będzie ona kombinacje segmentów do wyświetlenia na kolejnych wyświetlaczach. Słowo poprzedzające typ danych (volatile) informuje kompilator, że dostęp do danych będzie miał miejsce zarówno z przerwań, jak i programu i nie może zostać dokonana optymalizacja dostępu do tych danych. Modyfikujemy także funkcję refreshDisplay, aby korzystała z dopiero utworzonej tablicy, a dane wysyłała bezpośrednio na odpowiedni port:

setDisplay(DSOFF);

IOWR_ALTERA_AVALON_PIO_DATA(SEGMENT_BASE, displayData[disp]);

setDisplay(disp);

Jeszcze pozostało tylko zmodyfikować jedną z funkcji i dodać przykładową funkcję wyświetlającą dane w formacie dziesiętnym na wyświetlaczu jak na listingu 4.

W pierwszej z nich dodano wskazanie pozycji (wyświetlacza), na którym ma zostać ustawiona dana liczba, wraz z kontrolą wartości (jest to ochrona przed tzw. wyciekiem pamięci – czyli zapisem danych w nieznane miejsce, np. jako piąty, nieistniejący, element naszej tablicy; wycieki pamięci to stosunkowo częsty i trudny do wykrycia błąd). Ponadto zapis danych na port zastąpiono zapisem do tablicy, którą wcześniej przygotowaliśmy.

Druga funkcja po prostu rozbija podaną liczbę na poszczególne cyfry w zapisie dziesiętnym i ustawia je na kolejnych wyświetlaczach. Po odpowiednim poprawieniu pliku nagłówkowego, możemy zaraz przed pustą pętlą while w funkcji main dodać in DisplayDec(1234); Po kompilacji programu i jego uruchomieniu powinniśmy zobaczyć prawidłowo wyświetlaną liczbę.

Podsumowanie i zadania

W czasie tego spotkania nasz system wzbogaciliśmy o timer, który może generować przerwania. Dowiedzieliśmy się o jego działaniu a także o działaniu systemu przerwań, po czym uruchomiliśmy odświeżanie wyświetlaczy LED działające właśnie w przerwaniu. Czas teraz na kolejną porcję zadań (programistycznych) do realizacji (bez zmian w Qsys):

Zmieniając okres timera, spowolnić multipleksowanie do tak małej prędkości, aby można było naocznie przekonać się, jak to wszystko działa.

W oparciu o dokładnie ten sam timer przygotować odmierzanie czasu w sekundach i wyświetlanie go na wyświetlaczach (tak, tak, 1 timer możemy wykorzystać do obsługi wielu zadań – dlatego nasza biblioteka 7SEG nie zawiera obsługi timera, a jedynie ma wbudowaną funkcję, którą należy cyklicznie wywoływać).

Napisać dla wprawki funkcje, które mogłyby wyświetlać dane w innych systemach liczbowych (10, 16), prezentować dane dodatnie i ujemne, nie wyświetlać nieznaczących nic zer (np. 0001), umożliwiać zapalenie kropki na wybranym wyświetlaczu (uwaga – NIE używamy zapisu zmiennoprzecinkowego – typu float, double itp. są zakazane!).

Powodzenia! W czasie kolejnego spotkania będziemy kontynuować nasze zmagania z przerwaniami i timerami, m.in. w celu skutecznej programowej eliminacji drgań styków.

Piotr Rzeszut, AGH

Pozostałe artykuły

STM32 - interfejs QuadSPI

Numer: Marzec/2018

Niemal wszystkie nowe modele mikrokontrolerów serii STM32L4 i STM32F4 są wyposażone w interfejs QSPI, przeznaczony do współpracy z szybkimi pamięciami z interfejsem szeregowym. Interfejs QSPI (QuadSPI) stanowi rozwinięcie znanego interfejsu SPI. Główną różnicą pomiędzy SPI i QSPI jest zwiększona liczba i zmodyfikowana funkcjonalność linii danych.

SDC_One - komputer zdefiniowany programowo z klasycznym mikroprocesorem (3). Komputer docelowy

Numer: Marzec/2018

W pierwszym dwóch artykułach serii przedstawiliśmy ogólną koncepcję komputera zdefiniowanego programowo oraz szczegóły implementacji przez mikrokontroler STM32 krytycznych czasowo operacji związanych z realizacją protokołu szyny mikroprocesora. W trzeciej części cyklu, przedstawimy zasoby dostępne dla komputera docelowego - pamięć i wejście-wyjście, zrealizowane przez sprzęt i oprogramowanie mikrokontrolera.

NIOS II na maXimatorze, czyli mikroprocesor w układzie FPGA (4). Nowości i powrót do świata timerów i przerwań

Numer: Marzec/2018

Docierają do nas kolejne nowinki od Intel FPGA - została wydana aktualizacja środowiska Quartus do wersji 17.1, w której będą prowadzone kolejne części niniejszego kursu. Ponadto kontynuować będziemy zgłębianie w praktyczny sposób tematyki timerów oraz innych przerwań w naszym systemie.

Systemy dla Internetu Rzeczy (14). Podglądanie ruchu w sieci radiowej z protokołem IEEE 802.15.4

Numer: Luty/2018

Największym problemem podczas pracy z układami komunikacji radiowej jest brak pewności czy nadajnik wysłał to co trzeba i czy odbiornik odbiera poprawnie. Jedynym sposobem pokonania tych kłopotów jest ?podsłuchiwanie? transmisji radiowej. Stosowane są do tego sniffery, zwane też analizatorami sieciowymi lub analizatorami pakietów. Pozwalają śledzić (?wąchać?, ang. sniffing) pakiety przesyłane przez wybrany interfejs sieciowy. Jednym ...

Amazon Alexa (2). Tworzymy własne umiejętności Skills

Numer: Styczeń/2018

W drugiej części kursu tworzenia umiejętności dla asystentki głosowej Alexa opiszemy sposób wykonania oprogramowania odtwarzania plików audio oraz uruchomimy w konfiguratorze wyświetlanie plansz z grafiką ilustrującą wynik losowania kostką.

Mobilna
Elektronika
Praktyczna

Ze świata  Kobiety w elektronice    ...

Elektronika Praktyczna

Maj 2019

PrenumerataePrenumerataKup w kiosku wysyłkowym

Elektronika Praktyczna Plus

lipiec - grudzień 2012

Kup w kiosku wysyłkowym