STM32Butterfly2: obsługa wyświetlacza z Nokii 3310
Na początku określany jest priorytet przerwania pochodzącego od licznika SysTick. W kolejnym kroku do rejestru SysTick->LOAD zapisywana jest wartość, która określa z jaką częstotliwością będzie wywoływane przerwanie. Kolejne polecenia włącza generowanie przerwania, ostanie uruchamia licznik.
Kolejnym poleceniem w programie głównym jest funkcja nlcd_init(). Odpowiada ona za inicjalizację podłączonego wyświetlacza, bazującego na sterowniku PCD8544. Inicjalizacja polega na skonfigurowaniu linii GPIO podłączonych do wyświetlacza i SPI oraz wysłaniu danych inicjalizujących. Opis zostanie ograniczony do tych najważniejszych elementów, czyli funkcji konfigurującej linii GPIO i SPI oraz funkcji wysyłania danych przez SPI.
Poniżej przedstawiono listing funkcji odpowiedzialnej za konfigurację komunikacji z wyświetlaczem.
static void hw_init(void) { RCC->APB2ENR |= RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOD | RCC_APB2Periph_SPI1; //SPI MISO (Input) //io_config(SPI_PORT,MISO_BIT,GPIO_MODE_50MHZ,GPIO_CNF_ALT_PP); //SPI MOSI (Output) io_config(SPI_PORT,MOSI_BIT,GPIO_MODE_50MHZ,GPIO_CNF_ALT_PP); //SPI SCK (Output) io_config(SPI_PORT,SCK_BIT,GPIO_MODE_50MHZ,GPIO_CNF_ALT_PP); //SSEL io_config(SPI_PORT,SSEL_BIT,GPIO_MODE_50MHZ,GPIO_CNF_GPIO_PP); //Control lines directions io_config(CTRL_PORT,DC_BIT,GPIO_MODE_50MHZ,GPIO_CNF_GPIO_PP); io_config(CTRL_PORT,RES_BIT,GPIO_MODE_50MHZ,GPIO_CNF_GPIO_PP); //Linia DC stan 1 dc_pin(1); //Linia SEL stan 1 sel_pin(1); //Linia RES stan 1 res_pin(1); SPI1->CR1 = SPI_Direction_1Line_Tx | SPI_Mode_Master | SPI_DataSize_8b | SPI_CPOL_Low | SPI_CPHA_1Edge |SPI_BaudRatePrescaler_16| SPI_FirstBit_MSB |SPI_NSS_Soft; // Enable SPI1 SPI1->CR1 |= CR1_SPE_Set; }
Pierwsze polecenie odpowiada za włączenie zegarów dla używanych GPIO oraz SPI1. W kolejnym kroku realizowana jest konfiguracja linii GPIO, ustawiane są one do pracy alternatywnej jako linie magistrali SPI. Funkcje dc_pin(), sel_pin() oraz res_pin() odpowiadają za ustawianie odpowiedniego stanu na liniach D/C, SCE oraz RES.
Konfiguracja magistrali SPI sprowadza się do ustawienia odpowiednich bitów w rejestrze SPI1->CR1. W przypadku przedstawionego projektu ustawiane są bity:
- SPI_Direction_1Line_Tx – transmisja z wykorzystaniem tylko jednej linii nadającej sygnał (ustawiane są dwa bity),
- SPI_Mode_Master – działanie w trybie Master,
- SPI_DataSize_8b – ramka długości 8 bitów,
- SPI_CPOL_Low i SPI_CPHA_1Edge – ustawienie konkretnego trybu działania magistrali SPI,
- SPI_BaudRatePrescaler_16 – dzielnik zegara ustawiony na 16 (ustawiane są trzy bity),
- SPI_FirstBit_MSB – pierwszy transmitowany jest najbardziej znaczący bit,
- SPI_NSS_Soft – linia NSS kontrolowana jest programowo.
Ustawienie bitu CR1_SPE_Set w rejestrze SPI1->CR1 powoduje uruchomienie magistrali SPI. Wysyłanie sprowadza się do zapisania danych do rejestru SPI1->DR, jednak podczas przeprowadzania tej operacji należy pamiętać o sprawdzeniu dwóch flag informujących o działaniu magistrali SPI. Pierwszą flagą jaka jest sprawdzane przed zapisem danych jest flaga TXE, informuje ona czy aktualnie bufor jest wolny. Natomiast druga flaga – BSY – informuje o aktualnie przeprowadzanym wysyłaniu danych bądź zajętości SPI. Listing funkcji wysyłającej dane do wyświetlacza przedstawiono poniżej.
static void hw_spi_write(unsigned char byte) { while(!(SPI1->SR & SPI_I2S_FLAG_TXE)); SPI1->DR = byte; while(SPI1->SR & SPI_I2S_FLAG_BSY); // Wait until sending is over }
Po przeprowadzeniu inicjalizacji kolejną czynnością wykonywaną w programie głównym jest wyświetlenie wiadomości powitalnej na wyświetlaczu. Realizuje to funkcja , która przyjmuje trzy parametry: pierwszym jest ciąg tekstu do wyświetlenia, drugi i trzeci parametr określa położenie tekstu na wyświetlaczu.
Po wyświetleniu komunikatu program przechodzi do nieskończonej pętli, w czasie której pobierany jest stan pozycji joysticka. Odczyt wykonywany jest dwukrotnie z pewnym opóźnieniem które służy eliminacji drgań styków. W przypadku jednakowego odczytu na wyświetlaczu prezentowana jest informacja o położeniu joysticka.
Odczyt położenia joysticka realizowany jest przez funkcję joy_keys(), Listing jej został przedstawiony poniżej.
static inline int joy_keys(void) { return (~io_get_mask(JOY_PORT, JOY_BITS) & JOY_BITS) >> JOY_PIN_OK; }
Funkcja ogranicza się do odczytania stanu linii przy wykorzystaniu funkcji io_get_mask, która jako pierwszy parametr przyjmuje nazwę portu, natomiast jako drugi maskę ograniczającą odczyt do wskazanych linii. Zwracana wartość jest odpowiednio przetwarzana tak aby zmiana położenia joysticka powodowała ustawienie odpowiedniego bitu.