STM32Butterfly2: obsługa akcelerometru LIS35D

W ostatnim czasie bardzo dużą popularność zdobyły układy MEMS. Szczególnie widoczne są one w postaci akcelerometrów montowanych w telefonach komórkowych, umożliwiając automatyczną zmianę orientacji, obrazu i wykrywanie gestów w sterowaniu aplikacjami. Układy te można także zastosować we własnych aplikacjach.

Poniższy projekt przedstawia obsługę akcelerometru LIS35DE, jest on dostępny także w postaci modułu KAmodMEMS2 (fotografia 1). Działanie aplikacji polega na pomiarze pozycji w osiach X, Y i Z oraz prezentacji jej na wyświetlaczu pochodzącego z telefonu Nokia 3310 (w tym przypadku moduł KAmodLCD1). Komunikacja z układem LIS35DE może być realizowana przez magistrale I2C lub SPI, w przedstawionej aplikacji została wykorzystana ta pierwsza.

 

Fot. 1. Wygląd modułu KAmodMEMS2

Fot. 1. Wygląd modułu KAmodMEMS2

 

Rys. 2. Schemat elektryczny modułu KAmodMEMS2

Rys. 2. Schemat elektryczny modułu KAmodMEMS2

 

Projekt został przygotowany dla zestawu STM32Butterfly2 oraz STM32Butterfly. W obu przypadkach używane elementy są w identycznej konfiguracji, w związku z tym aplikacja nie wymaga wprowadzania dodatkowych zmian przy przejściu na drugą platformę. Projekt do poprawnego działania wymaga modułów: KAmodeMEMS2 i KAmodLCD1. Połączenie ich do zestawu ewaluacyjnego zostało przedstawione na rysunku 3. Układ LIS35D wymaga zasilania z zakresu 2,16V do 3,6V, w związku z tym zasilanie modułu nie powinno być pobierane ze złącza magistrali I2C, tylko ze złącza z wyprowadzonymi liniami portów.

 

Rys. 3. Zalecany sposób podłączenia modułu KAmodMEMS2 (z układem LIS35D) do STM32Butterfly2

Rys. 3. Zalecany sposób podłączenia modułu KAmodMEMS2 (z układem LIS35D) do STM32Butterfly2

 

Poniżej przedstawiono program główny aplikacji prezentującej pozycję modułu KAmodMEMS2.

 

W pierwszym kroku wywoływana jest funkcja time_init(), która inicjalizuje licznik SysTick. Licznik ten używany jest w celu generowania dokładnych opóźnień. Działanie funkcji polega na skonfigurowaniu częstotliwości występowania przerwania generowanego przez przepełnienie się licznika, ustawienie priorytetu generowanego przerwania oraz włączenie go.

Następnie wywoływana jest funkcja nlcd_init(), która przygotowuje do pracy wyświetlacz LCD, pochodzący z telefonu Nokia 3310. W ramach działania włączane są zegary używanych portów GPIO i kontrolera SPI oraz realizowana jest konfiguracja linii GPIO i kontrolera SPI. Po zakończeniu konfiguracji przeprowadzana jest inicjalizacja wyświetlacza, która polega na wysłaniu odpowiednich komend do niego.

W kolejnym kroku wywoływana jest funkcja i2cm_init, która odpowiada za konfigurację kontrolera I2C. Funkcja ta jako parametr przyjmuje częstotliwość z jaką wysyłane będą dane. Poniżej przedstawiono jej listing.

 

Na początku swojego działania funkcja włącza zegary dla portu GPIO oraz kontrolera I2C. Następnym działaniem jest konfiguracja używanych linii. Do przeprowadzenia konfiguracji stosowana jest funkcja io_config, która wymaga podania czterech parametrów. Pierwszy z nich określa port, do którego podłączone są linie. Drugi parametr definiuje konfigurowaną linię. Trzeci i czwarty parametr określają tryb działania linii, w tym przypadku działanie obu linii jest konfigurowane jako alternatywne. Dodatkowo w ramach konfiguracji linii realizowane jest podciągnięcie ich do VCC. Realizowane jest to przez ustawienie stanu wysokiego na linii przy użyciu funkcji io_set, która przyjmuje dwa parametry określające port oraz linie.

Następnym działaniem jest włączenie kontrolera I2C, jest to realizowane przez ustawienie odpowiedniego bitu w rejestrze CR1 używanego kontrolera I2C. Po włączeniu następuje programowe zresetowanie kontrolera. Działanie to polega na ustawieniu, a następnie wyzerowaniu bitu SWRST rejestru konfiguracyjnego. Kolejnym działaniem jest ustawienie częstotliwości z jaką taktowany jest kontroler, informacja ta zapisana jest w sześciu najmłodszych bitach rejestru CR2 kontrolera I2C. W celu zachowania niezmienionej wartości pozostałych bitów proces ten realizowany jest poprzez skopiowanie zawartości rejestru do zmiennej pomocniczej, a następnie wyzerowanie bitów odpowiedzialnych za wybór częstotliwości i ustawienie pożądanej wartości. Tak zmieniona wartość zmiennej pomocniczej jest zapisywana do rejestru CR2.

Kolejnym krokiem jest skonfigurowanie częstotliwości z jaką będą wysyłane dane przez kontroler. Odpowiada za to funkcja i2cm_set_speed, która jako parametr przyjmuje właśnie pożądaną częstotliwość. Ze względu na złożoność, wynikającą z zależności od innych wartości, proces ten realizowany jest w odrębnej funkcji. Kolejnym realizowanym zadaniem jest ustawienie trybu działania kontrolera I2C, operacja ta jest wykonywana analogicznie jak przy konfiguracji częstotliwości taktowania kontrolera (działanie na kopii rejestru konfiguracyjnego).

Po zakończeniu konfiguracji trybu działania ustawiany jest adres urządzenia oraz zerowane są oba rejestry stanu działania. Na koniec działania funkcji konfiguracyjnej realizowane jest ustawienie priorytetu przerwania pochodzących od kontrolera I2C oraz następuje ich włączenie. W ramach obsługi obu przerwań realizowane jest wysyłanie oraz odbiór danych.

Przeprowadzenie konfiguracji kontrolera I2C umożliwia wykonanie inicjalizacji układu LIS35DE. Jest ona przeprowadzana w ramach funkcji lis35_init(), której listing przedstawiono poniżej.

 

Funkcja inicjalizująca akcelerometr w pierwszej kolejności definiuje dwuelementową tablicę. Pierwszy element tablicy służy do ustawienia adresu, do którego zostanie zapisany drugi element tablicy. Zaś drugi element, poprzez ustawienie odpowiednich bitów, włącza wszystkie detektory wszystkich trzech osi oraz włącza wykonywanie pomiarów. Tak stworzona tablica jest wysyłana przy użyciu funkcji i2cm_transfer_7bit. Funkcja ta wymaga podania pięciu parametrów. Pierwszy z nich określa adres układu, z którym odbywać się będzie transmisja, drugi parametr wskazuje bufor danych do wysłania, trzeci jest liczbą ilości danych do wysłania, czwarty parametr wskazuje bufor dla odbieranych danych, a ostatni parametr określa ilość danych do odebrania. W przypadku braku danych do wysłania lub odebrania w miejsce tych parametrów wpisuje się NULL (dla bufora) i 0 (dla ilości danych).

W ramach działania funkcja wysyłająca i odbierająca dane zwraca rezultat działania. Zwrócona wartość równa 0 informuje o udanym przeprowadzeniu działania, zaś wartość poniżej zera oznacza wystąpienie błędu. W przypadku wystąpienia błędu na wyświetlaczu pojawi się odpowiedni komunikat wraz z kodem błędu, a program zostanie wprowadzony do nieskończonej pętli blokując dalsze działanie. Jeśli inicjalizacja została przeprowadzona bez błędu na wyświetlaczu pojawia się komunikat powitalny a program przechodzi do nieskończonej pętli.

W ramach nieskończonej pętli aktualizuje wartości wychylenia akcelerometru w każdej z trzech osi oraz przedstawia je na wyświetlaczu. Wartości są zapisywane do zmiennych utworzonych w ramach deklaracji nieskończonej pętli. Sam proces aktualizacji wychylenia realizowany jest przez funkcję lis35_get(&x,&y,&z), której listing przedstawiono poniżej.

 

W pierwszym kroku definiowany jest zmienna przechowująca adres rejestru, od którego będzie odbywał się odczyt. Dodatkowo ustawiany jest bit wymuszający automatyczną inkrementację po każdym odczycie rejestru. Drugą zdefiniowaną zmienną jest pięcioelementowa tablica służąca jako bufor odczytywanych danych. Tablica jest pięciowymiarowa ze względu na dodatkowe rejestry pomiędzy tymi, które przechowują informacje o wychyleniu. Odczyt wartości odbywa się przy użyciu wcześniej opisanej funkcji do transmisji z wykorzystaniem magistrali I2C – i2cm_transfer_7bit. Jeśli transmisja odbyła się bezbłędnie otrzymane dane są przetwarzane poprzez zapis uzyskanych wartości do zmiennych prezentujących wychylenie osi w odpowiednim kierunku.

Natomiast sama prezentacja wychylenia prezentowana jest przez funkcję print_value(x,y,z). Jej listing przedstawiono poniżej.

 

Jak można zauważyć w pierwszym kroku tworzony jest bufor danych, a następnie wywoływana jest funkcja tiny_snprintf, która odpowiada za odpowiednie sformatowanie wartości liczbowej do postaci ciągu znaków. Tak uzyskany ciąg znaków wyświetlany jest na wyświetlaczu przy użyciu funkcji nlcd_put_string. Operacja ta jest wykonywana trzykrotnie, dla każdej z osi oddzielnie.

Należy zauważyć, iż w programie głównym nie ma kodu odpowiedzialnego za konfigurację między innymi układu RCC. Proces ten jest realizowany w ramach przerwania reset_handler, wywoływanego w momencie uruchomienia mikrokontrolera. W ramach działania powyższego przerwania realizowane jest między innymi kopiowanie danych z pamięci Flash do SRAM, wyzerowanie segmentu bss, konfiguracja wspomnianego układu RCC oraz wywołanie programu głównego main().

Autor projektu: Lucjan Bryndza
Redakcja i przygotowanie: Mariusz Dziębowski

Do pobrania

Autor: