Digilent Pmod i STM32 (cz. 9) – PmodNAV, PmodPMON1 i PmodTMP2
W dziewiątym i jednocześnie przedostatnim odcinku cyklu poświęconego modułom Pmod firmy Digilent przedstawione zostaną: PmodNAV z akcelerometrem, magnetometrem, żyroskopem i barometrem, PmodPMON1 służący do monitorowania mocy, a także PmodTMP2 z czujnikiem temperatury. Przykłady przedstawione w niniejszym artykule przygotowano dla środowiska Atollic TrueSTUDIO i zestawu uruchomieniowego KAmeleon (www.kameleonboard.org) z wykorzystaniem biblioteki STM32Cube_FW_L4.
PmodNAV
Moduł PmodNAV umożliwia wykonywanie pomiarów ruchu w dziewięciu osiach (3-osiowy akcelerometr, 3-osiowy żyroskop oraz 3-osiowy magnetometr), a także ciśnienia atmosferycznego. Jego sercem są dwa układy firmy ST: LSM9DS1 i LPS25HB. Zakresy pomiarowe poszczególnych wielkości są konfigurowalne i wynoszą:
- akcelerometr: ±2/±4/±8/±16 g,
- żyroskop: ±245/±500/±2000 dps,
- magnetometr: ±4/±8/±12/±16 gauss,
- barometr: 260-1260 hPa.
Rozdzielczość pomiaru ciśnienia wynosi 4096 LSB/hPa, natomiast dla pozostałych wielkości jest zależna od wybranego zakresu, a jej maksymalna wartość (dla najmniejszego zakresu) wynosi odpowiednio: 0,061 mg/LSB, 8,75 mdps/LSB i 0,14 mgauss/LSB.
Fotografia 1. Moduł PmodNAV
Możliwości czujników wbudowanych w moduł PmodNAV
Układ LSM9DS1 umożliwia generację przerwań po przekroczeniu ustawionych progów mierzonych wielkości na każdej z osi, po wykryciu aktywności, a także wówczas, gdy dostępne są nowe dane pomiarowe. Dodatkowo akcelerometr i żyroskop można skonfigurować w trybie FIFO, w którym dane pomiarowe obu czujników są buforowane w wewnętrznej kolejce. Do jej obsługi można użyć przerwań informujących o przekroczeniu zadanej liczby elementów. Czujnik ciśnienia LPS25HB charakteryzuje się podobną funkcjonalnością, pozwalającą na konfigurację progów do generacji przerwań. Posiada on także wewnętrzną kolejkę FIFO do buforowania danych pomiarowych.
Połączenie z zestawem KAmeleon
Oba układy mogą być obsługiwane za pośrednictwem interfejsów SPI oraz I2C, jednak w module PmodNAV udostępniony jest tylko pierwszy z nich. Znajduje się on na złączu Pmod typu 2A (J1), w którym oprócz linii danych oraz zegara znajdują są także trzy sygnały wybierające urządzenie (akcelerometr/żyroskop, magnetometr, barometr), wspólna linia przerwań i sygnał gotowości danych z magnetometru. Dwa ostatnie sygnały nie są używane w przykładzie, jednak ze względu na rozmieszczenie pozostałych sygnałów na złączu nie jest możliwe podłączenie modułu PmodNAV do złącza Pmod-SPI na płytce KAmeleon. Z tego względu moduł został podłączony do złącza ARDUINO według tabeli 1 i fotografii 2.
Tabela 1. Sygnały PmodNAV oraz odpowiadające im piny złącza ARDUINO i mikrokontrolera; w tabeli pominięto sygnały nieużywane w przykładzie (INT i DRDY) i linie zasilania występujące na złączu Pmod
Sygnał | Numer pinu PmodNAV | Numer pinu KAmeleon ARDUINO CONNECTOR | Pin mikrokontrolera |
CS_A/G | 1 | D10 | PB12 |
MOSI | 2 | D11 | PB15 |
MISO | 3 | D12 | PB14 |
SCLK | 4 | D13 | PB10 |
CS_M | 9 | D9 | PB13 |
CS_ALT | 10 | D8 | PD11 |
Fotografia 2. Moduł PmodNAV przyłączony do zestawu KAmeleon
Kod przykładu
Przykładowy kod do obsługi modułu PmodNAV został umieszczony w plikach PmodNAV.c i PmodNAV.h. Pierwsza z funkcji – PmodNAV_Config, znajdująca się na listingu 1, jest odpowiedzialna za konfigurację interfejsu SPI w trybie 3 (CPOL=1, CPHA=1) z programową kontrolą sygnału CS. Dodatkowo, uruchamia ciągłe pomiary we wszystkich czujnikach:
- akcelerometr: 10 Hz,
- żyroskop: 14,9 Hz,
- magnetometr: 10 Hz (wartość domyślna),
- barometr: 12,5 Hz.
Linie GPIO są ustawiane w funkcji HAL_SPI_MspInit wywoływanej przez bibliotekę STM32Cube wewnątrz funkcji HAL_SPI_Init. Piny podłączone do linii danych (MISO oraz MOSI) i zegara (SCLK) są konfigurowane jako funkcja alternatywna dla SPI2, natomiast wszystkie linie CS są ustawiane jako zwykłe wyjścia i będą kontrolowane programowo. Funkcję tę przedstawiono na listingu 2.
Listing 1. Konfiguracja interfejsu SPI2 i konfiguracja modułu PmodNAV
void PmodNAV_Config(void) { // Configure the SPI connected to the Pmod module. pmodNavSpi.Instance = SPI2; pmodNavSpi.Init.Mode = SPI_MODE_MASTER; pmodNavSpi.Init.Direction = SPI_DIRECTION_2LINES; pmodNavSpi.Init.DataSize = SPI_DATASIZE_8BIT; pmodNavSpi.Init.CLKPolarity = SPI_POLARITY_HIGH; pmodNavSpi.Init.CLKPhase = SPI_PHASE_2EDGE; pmodNavSpi.Init.NSS = SPI_NSS_SOFT; pmodNavSpi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128; pmodNavSpi.Init.FirstBit = SPI_FIRSTBIT_MSB; pmodNavSpi.Init.TIMode = SPI_TIMODE_DISABLE; pmodNavSpi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; pmodNavSpi.Init.NSSPMode = SPI_NSS_PULSE_DISABLE; HAL_SPI_Init(&pmodNavSpi); writeRegisterM(0x22, 0x00); // Enable the continuous conversion mode for the magnetometer. writeRegisterAG(0x10, 0x20); // Enable the gyroscope measurements with the 14.9Hz data rate. writeRegisterAG(0x20, 0x20); // Enable the accelerometer measurements with the 10Hz data rate. writeRegisterALT(0x20, 0xB0); // Enable the pressure measurements with 12.5 Hz data rate. }
Listing 2. Konfiguracja linii GPIO dla modułu PmodNAV
void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi) { // Initialize GPIO used by the SPI2 peripheral. All CS signals are controlled by the software. __HAL_RCC_SPI2_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF5_SPI2; GPIO_InitStruct.Pin = GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; // CS_A/G - PB12 GPIO_InitStruct.Pin = GPIO_PIN_12; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); // CS_M - PB13 GPIO_InitStruct.Pin = GPIO_PIN_13; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_SET); // CS_ALT - PD11 GPIO_InitStruct.Pin = GPIO_PIN_11; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); HAL_GPIO_WritePin(GPIOD, GPIO_PIN_11, GPIO_PIN_SET); }
Komunikacja z czujnikami
Do komunikacji z czujnikami modułu PmodNAV przygotowano dwie funkcje pomocnicze: writeRegister i readRegister, pokazane na listingu 3. Realizują one zapis i odczyt rejestru o podanym adresie. Wszystkie czujniki wymagają podania kierunku transmisji na najstarszym bicie adresu (1– odczyt, 0 – zapis), a każda transakcja musi składać się z co najmniej dwóch bajtów. Opisywane funkcje operują na pojedynczych rejestrach, dlatego zawsze wykorzystują dwa bajty – adres oraz wartość rejestru.
Listing 3. Zapis i odczyt rejestru układów LSM9DS1 i LPS25HB
#define SPI_READ_FLAG 0x80 #define SPI_WRITE_FLAG 0x00 static void writeRegister(uint8_t address, uint8_t data) { // The first byte contains the address with the write flag. uint8_t txbuf[2] = {address | SPI_WRITE_FLAG, data}; HAL_SPI_Transmit(&pmodNavSpi, txbuf, 2, 100); } static uint8_t readRegister(uint8_t address) { // Reading a byte requires the address at the beginning, so the whole SPI transaction // has to be 2 bytes long. uint8_t txbuf[2] = {address | SPI_READ_FLAG, 0x00}; uint8_t rxbuf[2] = {0x00}; HAL_SPI_TransmitReceive(&pmodNavSpi, txbuf, rxbuf, 2, 100); return rxbuf[1]; }
Z powyższych funkcji korzystają inne funkcje, realizujące zapis i odczyt rejestrów. Obsługują one dodatkowo odpowiednie sygnały CS, co przedstawiono na listingu 4. Pozostałe zestawy funkcji obsługujące magnetometr i barometr wyglądają analogicznie.
Listing 4. Zapis i odczyt rejestru akcelerometru i żyroskopu
static void writeRegisterAG(uint8_t address, uint8_t data) { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET); writeRegister(address, data); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); } // Read the Accelerometer/Gyroscope register. static uint8_t readRegisterAG(uint8_t address) { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET); uint8_t data = readRegister(address); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); return data; }
Konwersja danych
Pozostałe funkcje zaimplementowane w pliku PmodNAV.c odpowiadają za konwersję odczytanych wartości z czujników na wartości wyrażone w odpowiednich jednostkach:
- akcelerometr [mg],
- żyroskop [mdps],
- magnetometr [mG],
- barometr [hPa].
Jako przykład, na listingu 5 przedstawiono funkcję konwertującą dane pomiarowe z akcelerometru, w której konwersja jest przeprowadzana dla zakresu ±2 g i rozdzielczości 0.061 mg/LSB. Funkcje obsługujące pozostałe czujniki zaimplementowano w analogiczny sposób.
Listing 5. Konwersja wyników pomiaru z akcelerometru
void PmodNAV_ReadAcc(int32_t* x, int32_t* y, int32_t* z) { // Read the measured values from all three axes. *x = (int16_t)((readRegisterAG(0x29) << 8) | readRegisterAG(0x28)); *y = (int16_t)((readRegisterAG(0x2B) << 8) | readRegisterAG(0x2A)); *z = (int16_t)((readRegisterAG(0x2D) << 8) | readRegisterAG(0x2C)); // Configured range is +/- 2g (default value) with 0.061 mg/LSB resolution. *x = (*x * 1.0) * 0.061; *y = (*y * 1.0) * 0.061; *z = (*z * 1.0) * 0.061; }
Główna funkcja przykładu – main, wykonuje konfigurację modułu PmodNAV, a następnie cyklicznie odczytuje wskazania wszystkich dostępnych czujników. Wyniki są wysyłane na port szeregowy LPUART1, dostępny jako wirtualny port szeregowy po podłączeniu KAmeleona do komputera. Obsługa portu znajduje się w plikach serial.c i serial.h.