Digilent Pmod i STM32 (cz. 1) – PmodLED i PmodALS
PmodALS
PmodALS zawiera dwa układy umożliwiające pomiar natężenia światła widzialnego. Pierwszym z nich jest fototranzystor Vishay Semiconductor’s TEMT6000X01 dokonujący konwersji natężenia światła na odpowiednią wartość prądu kolektora (rysunek 6). Fototranzystor działa w zakresie światła widzialnego (440 nm – 800 nm), natomiast maksimum czułości przypada na długość fali wynoszącą 570 nm. Charakterystyka ta odpowiada czułości ludzkiego oka, dlatego czujnik ten dobrze nadaje się na przykład do kontrolowania jasności wyświetlaczy w zależności od poziomu światła otoczenia.
Rysunek 6. Charakterystyka konwersji światło/prąd kolektora fototranzystora w zestawie PmodALS
Drugim układem jest 8-bitowy przetwornik analogowo-cyfrowy Texas Instruments ADC081S021 umożliwiający odczyt napięcia proporcjonalnego do prądu kolektora fototranzystora, które odkłada się na rezystorze R1 (10kΩ). Układ pomiarowy przedstawiono na rysunku 7.
Rysunek 7. Układ do pomiaru natężenia światła za pomocą fototranzystora i przetwornika analogowo-cyfrowego
Obsługa przetwornika ADC
Przetwornik ADC081S021 ma interfejs SPI umożliwiający odczyt mierzonego napięcia. Posiada on dwa tryby działania – normalny (Normal), a także wyłączony (Shutdown). Pierwszy z nich wykonuje ciągłą konwersję bez oczekiwania na inicjalizację urządzenia przed każdym pomiarem. Zmiana sygnału CS# jest jednocześnie początkiem konwersji oraz odczytu danych. Aby urządzenie przełączyło się w tryb normalny lub pozostało w nim po odczycie danych, sygnał CS# musi pozostać w stanie niskim po odczycie 16 bitów danych przez SPI lub zmienić się na stan wysoki – drugi z tych warunków jest spełniony w przypadku zwykłego odczytu danych przez SPI. Urządzenie można wyłączyć zmieniając stan linii CS# na wysoki pomiędzy drugim i dziesiątym opadającym zboczem linii zegara SCL.
Aby odebrać dane z przetwornika należy odczytać 16 bitów danych. 8-bitowy wynik konwersji jest przesunięty o 4 bity w lewo. Należy pamiętać, że odczyt dotyczy zawsze konwersji rozpoczętej przez poprzednią zmianę sygnału CS#, dlatego do odczytania aktualnej wartości napięcia wymagane są dwie transakcje SPI, pomiędzy którymi musi upłynąć czas potrzebny do wykonania kolejnej konwersji (350 ns od trzynastego narastającego i 50 ns od szesnastego opadającego zbocza zegara).
Moduł PmodALS posiada złącze Pmod SPI typu 2 – jego opis znajduje się w tabeli 10. W nawiasach podano piny mikrokontrolera podłączone do poszczególnych sygnałów złącza (linia MISO nie jest używana).
Tabela 10. Interfejs SPI (6 pinów) – Typ 2
Sygnał | Numer pinu |
CS (PB0) | 1 |
MOSI | 2 |
MISO (PE14) | 3 |
SCK (PA1) | 4 |
GND | 5 |
VCC | 6 |
Przykład na mikrokontroler STM32
Obsługę modułu PmodALS w przykładzie dla mikrokontrolera STM32L496ZG, a także zestawu deweloperskiego KAmeleon zakodowano w pliku src/PmodALS.c. Konfiguracja SPI wywoływana jest za pomocą funkcji PmodALS_Config, przedstawionej na listingu 4. Funkcja ta konfiguruje SPI1 w trybie tylko do odczytu (linia MISO) dla danych 16-bitowych. Funkcja biblioteczna HAL_SPI_Init wywołuje natomiast funkcję HAL_SPI_MspInit, gdzie konfigurowane są zegary peryferiów i linie GPIO. Zaprezentowano ją na listingu 5. Linie danych (MISO) i zegara SPI (SCK) są obsługiwane sprzętowo, natomiast linia CS jest sterowana programowo.
Przetwornik ADC081S021 pracuje cały czas w trybie Normal, a odczyt danych zrealizowany jest jako zwykła transakcja SPI zaimplementowana w funkcji PmodALS_GetValue (listing 6.). Dzięki temu sygnał CS jest zmieniany na stan wysoki po zakończeniu odczytu danych i przetwornik nie przechodzi do stanu Shutdown. Odczytana 16-bitowa wartość jest przesuwana w prawo o 4 bity tak, żeby otrzymać poziom natężenia światła z zakresu od 0 do 255.
Kod źródłowy funkcji
Listing 4. Konfiguracja SPI
void PmodALS_Config(void) { // Configure the SPI connected to the Pmod module. Only the MISO line is required. pmodAlsSpi.Instance = SPI1; pmodAlsSpi.Init.Mode = SPI_MODE_MASTER; pmodAlsSpi.Init.Direction = SPI_DIRECTION_2LINES_RXONLY; pmodAlsSpi.Init.DataSize = SPI_DATASIZE_16BIT; pmodAlsSpi.Init.CLKPolarity = SPI_POLARITY_HIGH; pmodAlsSpi.Init.CLKPhase = SPI_PHASE_1EDGE; pmodAlsSpi.Init.NSS = SPI_NSS_SOFT; pmodAlsSpi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64; pmodAlsSpi.Init.FirstBit = SPI_FIRSTBIT_MSB; pmodAlsSpi.Init.TIMode = SPI_TIMODE_DISABLE; pmodAlsSpi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; pmodAlsSpi.Init.NSSPMode = SPI_NSS_PULSE_DISABLE; HAL_SPI_Init(&pmodAlsSpi); }
Listing 5. Konfiguracja zegarów peryferiów i linii GPIO
void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi) { // Initialize GPIO used by the SPI1 peripheral. The CS is controlled by the software (PB0 pin). __HAL_RCC_SPI1_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOE_CLK_ENABLE(); GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLDOWN; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF5_SPI1; GPIO_InitStruct.Pin = GPIO_PIN_1; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_14; HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_PULLDOWN; GPIO_InitStruct.Pin = GPIO_PIN_0; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); }
Listing 6. Fragment funkcji PmodLED_SetLed
uint8_t PmodALS_GetValue(void) { uint16_t value = 0; HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); HAL_SPI_Receive(&pmodAlsSpi, (uint8_t*)&value, 1, 100); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); // The data obtained from the ADC is 16 bit, but the light level value is only 8 bit. // It is shifted left by 4 bits. return (value >> 4); }
W przykładzie dodatkowo konfigurowany jest Timer4 w trybie PWM, którego wyjście podłączone jest do pinu PD12. To wyprowadzenie z kolei steruje niebieską diodą LED-RGB. Wypełnienie sygnału PWM jest zmieniane proporcjonalnie do wartości odczytanej przez przetwornik. Wartość ta jest także wypisywana na port szeregowy LPUART1 podłączony do programatora ST-Link i można ją odczytać po podłączeniu do komputera jako wirtualny port szeregowy. Obsługa PWM, a także portu szeregowego jest zaimplementowana w plikach src/pwm.c i src/serial.c.
Przykład został przygotowany dla środowiska Atollic TrueSTUDIO for STM32 i zestawu deweloperskiego KAmeleon, w oparciu o bibliotekę STM32Cube_FW_L4.