ISIX-RTOS – przykład 3 – obsługa przerwań na przykładzie zegara RTC z magistralą I2C

Zadeklarowanie przyjaźni funkcji umożliwia wywoływanie dowolnych metod chronionych klasy z funkcji zaprzyjaźnionej, co zostało wykorzystane do wywołania metody isr() stanowiącej wektor obsługi przerwania. Do synchronizacji wątku z procedurą obsługi przerwania wykorzystano semafor sem_irq, natomiast semafor sem_lock jest wykorzystywany do blokowania sterownika w przypadku, gdy jest on zajęty jest obsługą magistrali I2C.
Konstruktor klasy obiektu i2c_host przyjmuje dwa argumenty: adres wybranego kontrolera I2C (np. I2C1, I2C2) oraz szybkość taktowania magistrali I2C wyrażoną w hercach, której domyślna wartość wynosi 100000. Zadaniem konstruktora jest inicjalizacja kontrolera sprzętowego I2C, uruchomienie przerwań oraz przypisanie wskaźnika this utworzonego obiektu do wskaźnika wykorzystywanego przez procedurę obsługi przerwania.

List. 3.

Na początku sprawdzany jest numer kontrolera I2C (obecnie zaimplementowana jest tylko obsługa kontrolera I2C1), następnie konfigurowane są porty GPIO, tak aby pełniły funkcję wyjścia układu peryferyjnego. Następnie konfigurowany jest sprzętowy kontroler I2C, tak aby pełnił rolę sterownika master z 7-bitowym adresowaniem. Do wskaźnika na obiekt wykorzystanego przez procedurę obsługi przerwania przypisywany jest wskaźnik this aktualnie tworzonego obiektu. Przyjęto założenie że istnieje tylko jedna instancja klasy i2c_host, ponieważ do danego kontrolera magistrali może być przypisany tylko jeden sterownik. Klasę można rozbudować w taki sposób, aby w przypadku próby utworzenia kolejnej instancji klasy rzucany był wyjątek. Na zakończenie włączane są przerwania w kontrolerze I2C oraz konfigurowane są przerwania w kontrolerze NVIC.
Jedyną metodą interfejsu użytkownika klasy sterownika I2C jest metoda i2c_transfer_7bit umożliwiająca przeprowadzenie transakcji I2C na magistrali.

List. 4.

Jako parametry przyjmuje ona kolejno adres sprzętowy układu I2C, z którym chcemy przeprowadzić transakcję, wskaźnik do bufora z danymi oraz długość bufora, z którego dane chcemy przesłać magistralą I2C. Następnie przekazujemy wskaźnik do bufora gdzie będą przesłane dane odebrane z magistrali I2C oraz liczba danych jaką chcemy odczytać. Jeśli chcemy wykonać tylko pojedynczy zapis danych lub odczyt, do nieużywanego wskaźnika na bufor należy przypisać wartość NULL. Metoda blokuje wykonanie bieżącego wątku do chwili zakończenia transakcji I2C oraz w przypadku powodzenia zwraca wartość ERR_OK. Na początku funkcji wywoływana jest metoda wait() na głównym semaforze blokującym, w wyniku czego proces może zostać zablokowany, jeżeli sterownik jest zajęty przez inny proces. Do zmiennych klasy przypisywane są wskaźniki do buforów oraz wielkości tych buforów oraz jest generowana sekwencja start. Następnie oczekujemy na semaforze sygnalizującym zakończenie pracy przez procedurę obsługi przerwania. Cała obsługa cyklu magistrali wykonywana jest w przerwaniu. Oczekiwanie na semafor kończy się w momencie sygnalizacji przez procedurę obsługi przerwania lub w wyniku przekroczenia czasu oczekiwania, co informuje nas o wystąpieniu błędu. W przypadku powodzenia zwracany jest status ERR_OK oraz podnoszony jest semafor blokujący sem_lock za pomocą wywołania metody sem_lock.signal(). Generacja bitu startu powoduje rozpoczęcie działania kontrolera I2C. W wyniku wystąpienia poszczególnych zdarzeń zgłaszane jest przerwanie, którego obsługa realizowana jest przez procedurę i2c1_ev_isr_vector (list. 5).

List. 5. Procedura obsługi przerwania

Funkcja ta jest zaprzyjaźniona z klasą i2c_host. Na rzecz obiektu klasyi2c_host jest wywoływana funkcja isr(), która jest właściwą procedurą obsługi przerwania (list. 6).

List. 6. Funkcja isr() jest procedurą obsługi przerwania

Do pobrania

O autorze