[TWI][I2C] Biblioteka oparta o przerwanie.

Tu możesz pisać o swoich problemach z pisaniem programów w języku C dla AVR.
Awatar użytkownika
Antystatyczny
Geek
Geek
Posty: 1168
Rejestracja: czwartek 03 wrz 2015, 22:02

[TWI][I2C] Biblioteka oparta o przerwanie.

Postautor: Antystatyczny » niedziela 31 lip 2016, 04:50

Witam serdecznie.

Po pięciu weekendach walk z modułem I2C w mikrokontrolerze STM32 postanowiłem odrobinę odpocząć od tej zakały i zająć się czymkolwiek innym. Niestety, jako że nie potrafię odpoczywać biernie, bezmyślnie lub, jak kto woli, nic nie robiąc, przypomniała mi się pewna idea, która zrodziła się w mojej głowie kilka lat temu. Początki programowania bywały trudne i do dziś pamiętam chwile bezsilności, gdy napisany przez mnie program zawieszał się z niewiadomych przyczyn, a w kodzie niby wszystko było w porządku. Tak, na taki stres się narażałem... Przyczyną tego stresu był mój błąd w ustaleniu prawidłowego adresu układu na szynie I2C (TWI). Szczęśliwie udało mi się ów błąd zlokalizować, ale nie byłem zadowolony z funkcji, które wówczas obsługiwały moduł TWI w mikrokontrolerze ATmega 32.

Dzisiaj chciałbym zaprezentować mój własny zestaw funkcji do obsługi modułu TWI w mikrokontrolerach ATmega. Od razu pragnę podziękować Protonowi za krytyczne spojrzenie na konstrukcję kodu oraz Woodpakerowi za pomoc przy angielskich komentarzach. Podstawowe cechy tej biblioteczki:

  • Praca w oparciu o sprzętowe przerwanie.
  • Nadawanie oraz odbiór danych w sposób nieblokujący pętli głównej programu.
  • Nadawanie oraz odbiór danych w sposób blokujący pętlę główną programu.
  • Możliwość inicjowania transmisji wewnątrz podprogramów obsługi przerwań sprzętowych.
  • Możliwość sprawdzenia, czy zlecona transmisja nieblokująca dobiegła końca.
  • Możliwość przetestowania obecności układu slave na szynie I2C bez wysyłania danych do tego układu.
  • Brak efektu zamrożenia całego programu w przypadku awarii układu slave na szynie I2C (dotyczy funkcji nieblokujących i blokujących).
  • Wykrywanie podstawowych błędów transmisji (SLAVE_ERROR, BUS_ERROR)

Niniejszy zestaw funkcji wyczerpuje możliwości modułu TWI w zakresie pracy jako pojedynczy układ nadrzędny, czyli MASTER bez MULTIMASTERINGU. Niemniej jednak błąd utraty arbitrażu jest obsługiwany i możliwe, że multimastering będzie działał poprawnie, bo moduł TWI, w przypadku wykrycia utraty arbitrażu, czeka grzecznie na sekwencję stop na szynie, by następnie przystąpić do działania. Niestety na obecną chwilę nie mam technicznej możliwości przetestowania tego scenariusza.

Na potrzeby tej prezentacji przygotowałem prosty układ składający się z mikrokontrolera ATmega32 oraz bardzo popularnego zegara czasu rzeczywistego PCF8583 firmy NXP.

Schemat.JPG


Od strony programowej mamy do dyspozycji następujące funkcje kontrolne:

Kod: Zaznacz cały

void I2C_Init(uint32_t speed);
int I2C_CheckSlave(uint8_t slave);
int I2C_CheckLastTransmission(void);


Nieblokujące funkcje do obsługi transmisji:

Kod: Zaznacz cały

int I2C_WriteRandom(uint8_t slave, uint8_t wordAddr, uint8_t *msg, size_t msgLength);
int I2C_ReadRandom(uint8_t slave, uint8_t wordAddr, uint8_t *buf, size_t bufLength);
int I2C_ReadCurrent(uint8_t slave, uint8_t *buf, size_t bufLength);


Oraz blokujące funkcje do obsługi transmisji:

Kod: Zaznacz cały

int I2C_WriteRandomWait(uint8_t slave, uint8_t wordAddr, uint8_t *msg, size_t msgLength);
int I2C_ReadRandomWait(uint8_t slave, uint8_t wordAddr, uint8_t *buf, size_t bufLength);
int I2C_ReadCurrentWait(uint8_t slave, uint8_t *buf, size_t bufLength);


Cała obsługa sprowadza się do wywołania funkcji inicjalizującej moduł TWI:

Kod: Zaznacz cały

I2C_Init(100000UL);


Oraz włączenia przerwań:

Kod: Zaznacz cały

sei();


Od tej chwili można korzystać z TWI.

Tutaj przykładowy programik wykorzystujący kilka z opisywanych funkcji:

Ukryta zawartość
To forum wymaga zarejestrowania i zalogowania się, aby zobaczyć ukrytą zawartość.


Program inicjalizuje moduł TWI, UART oraz przerwanie z zewnętrznego źródła, włącza przerwania, a następnie sprawdza, czy PCF8583 jest obecny. Rezultat sprawdzenia wysłany zostanie przez UART do terminala. Następnie co sekundę będzie odczytywał 3 bajty danych z układu PCF8583, począwszy od rejestru o adresie 0x02. Odczytane dane wysyłane są w niezmienionej postaci do terminala. Celowo użyłem nieblokującej funkcji, by wskazać różnicę pomiędzy moim rozwiązaniem, a rozwiązaniem masowo spotykanym w sieci. Sam odczyt danych z układu PCF8583 zlecam już w podprogramie obsługi przerwania z zewnętrznego źródła. Transmisja rozpocznie się jednak dopiero po wyjściu z tego podprogramu. W pętli głównej sprawdzam, czy transmisja dobiegła końca. W zasadzie czekam, aż ona dobiegnie końca, bo program jest tak malutki, że nie mam czym zająć mikrokontrolera w czasie odczytu tych danych. W każdym razie można zlecić odczyt, a następnie zająć się czymś innym, a po jakiejś tam chwili skorzystać z odczytanych danych. Proponuję poćwiczyć we własnych programach, wypróbować wszystkie funkcje. Na koniec jeszcze wersja z wykorzystaniem funkcji blokujących. W tym przypadku nie mogę skorzystać z funkcji wewnątrz podprogramu obsługi przerwania, bo zamroziłoby to program. Funkcja oczekiwałaby na zakończenie transmisji, a ta rozpocznie się przecież dopiero po wyjściu z podprogramu obsługi przerwania...

Ukryta zawartość
To forum wymaga zarejestrowania i zalogowania się, aby zobaczyć ukrytą zawartość.



A tutaj kompletny projekt dla środowiska Eclipse:
Ukryta zawartość
To forum wymaga zarejestrowania i zalogowania się, aby zobaczyć ukrytą zawartość.



W razie pytań chętnie odpowiem.

Pozdrawiam!
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
"The true sign of intelligence is not knowledge but imagination" Albert Einstein.

Awatar użytkownika
Antystatyczny
Geek
Geek
Posty: 1168
Rejestracja: czwartek 03 wrz 2015, 22:02

Re: [TWI][I2C] Biblioteka oparta o przerwanie.

Postautor: Antystatyczny » piątek 18 sie 2017, 18:13

Mała poprawka.

Wykryłem błąd w funkcji I2C_CheckSlave(), który powodował zwracanie I2C_RESULT_OK nawet wtedy, gdy układ "slave" nie był obecny na szynie I2C. Cały kompletny projekt zawierający poprawkę znajduje się w pierwszym poście. Przy okazji nowych testów napisałem na szybko wykrywacz urządzeń na szynie I2C. Jego działanie jest banalnie proste i polega na wysyłaniu kolejnych adresów (parzystych) na szynę oraz oczekiwaniu na odpowiedź. Każda odpowiedź jest rejestrowana w oknie terminala (w moim przypadku Terminal by Br@y) wraz ze znalezionym adresem układu. Tylko tyle i aż tyle... Cały program jest króciutki i przejrzysty:

Ukryta zawartość
To forum wymaga zarejestrowania i zalogowania się, aby zobaczyć ukrytą zawartość.


Efekt działania programu:

Zrzut ekranu 2017-08-17 23.06.41.png


A tutaj cały projekt do pobrania:

Ukryta zawartość
To forum wymaga zarejestrowania i zalogowania się, aby zobaczyć ukrytą zawartość.
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
"The true sign of intelligence is not knowledge but imagination" Albert Einstein.


Wróć do „Programowanie AVR w C”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 1 gość