Informacje: co to jest UART, jak działa i jakie są jego możliwości – zostały podane w 18 części kursu. Jeżeli jej nie czytałeś, gorąco zachęcam, by zapoznać się z nią przed przystąpieniem do dzisiejszego odcinka.
Trochę teorii
Omówmy najpierw, w jaki sposób funkcjonuje odbiornik UART. Na zielono zaznaczono sygnał na wyjściu odbiornika. W stanie spoczynkowym linia transmisyjna ma stan wysoki.
Transmisja rozpoczyna się bitem startu, który zawsze ma stan niski. Wywołuje on zbocze opadające, a zjawisko takie ma za zadanie poinformować odbiornik, że zaczyna się ramka transmisyjna i za chwilę zostaną przetransmitowane bity danych. Zaznaczono to czerwoną strzałką. W jaki sposób będziemy wykrywać zbocze opadające? Zastosujemy tutaj moduł EdgeDetector, z którego korzystaliśmy już wielokrotnie w poprzednich odcinkach kursu.
Sygnał z wykrywacza zbocza uruchomi moduł StrobeGeneratorTicks, opracowany w poprzednim odcinku na potrzeby nadajnika UART. Jego zadanie polega na okresowym wyznaczaniu impulsów strobe, które powodować będą odczytywanie wejścia linii transmisyjnej. Następnie stan wejścia będzie sukcesywnie zapisywany do stanu rejestru wyjściowego, skąd będzie można odczytać odebrany bajt danych.
Próbkowanie zaznaczono czarnymi strzałkami. W idealnej sytuacji badanie stanu wejścia następuje dokładnie w połowie trwania każdego bitu. Odstęp czasowy pomiędzy pobraniem poszczególnych próbek jest równy czasowi trwania każdego bitu. Jednak odstęp pomiędzy zboczem opadającym na początku bitu startu a pobraniem pierwszej próbki to czas trwania półtora bitu. Zatem proces próbkowania musimy opóźnić o pół bitu. Jak to zrobić?
Możliwe są dwa rozwiązania:
- Po wykryciu zbocza opadającego na linii transmisyjnej uruchamia się jednorazowo pierwszy timer, którego celem jest czekanie przez pół bitu. Następnie uruchamia on drugi timer, który odmierza odstępy czasu równe jednemu bitowi i pracuje do końca ramki transmisyjnej.
- Po wykryciu zbocza opadającego na linii transmisyjnej uruchamia się timer, który pracuje przez cały czas trwania transmisji. Generuje on sygnały co pół bitu, lecz w czasie wysyłania bitów danych co drugi z tych sygnałów jest ignorowany.
W naszym module odbiornika zastosujemy rozwiązanie drugie.
Kiedy już uzbieramy osiem próbek, odpowiadających ośmiu bitom, możemy zakończyć pracę modułu i zgłosić sygnał informujący o tym, że na wyjściu modułu odbiornika znajdują się dane gotowe do odczytania.
A co z bitem stopu? W gruncie rzeczy nie jest on nam do niczego potrzebny. Nie będziemy sprawdzać jego stanu ani go zapisywać (zawsze ma stan wysoki). Interesować nas będzie już tylko wykrycie zbocza opadającego, ponieważ zasygnalizuje ono rozpoczęcie transmisji kolejnej ramki danych.
Bardzo ważne jest, aby zegary nadajnika i odbiornika były dobrze zsynchronizowane. W rezultacie bit czwarty próbkowany jest dwa razy, a bitu siódmego nie odczytujemy wcale. Prowadzi to do odebrania błędnych danych.
Próbkowanie odbywa się zbyt wolno, przez co nadajnik kończy transmisję dużo wcześniej, niż odbiornik kończy odbieranie. W przykładowej sytuacji bit piąty nie jest odczytywany wcale, a bit stopu traktowany jest jako najstarszy bit danych.