W ostatniej >>części<< zająłem się zbadaniem czasu odświeżania wyświetlacza LCD 16×2 na STM32 za pomocą 4-bitowej magistrali komunikacyjnej oraz z ustalonym odgórnie czasem oczekiwania na przetworzenie dostarczonych danych. Dzisiaj sprawdzę jak na czas odświeżania wpłynie czytanie przez MCU tzw. flagi zajętości. Lecimy!

Magistrala 4-bitowa ze sprawdzaniem flagi zajętości

Aby odczytać busy flag z kontrolera wyświetlacza potrzebuję zmodyfikować schemat połączenia oraz kod. Modyfikacje które wykonałem polegają na:

  1. Pin nr 5 czyli RW będzie tym razem podłączony do STM32, który będzie sterował kierunkiem przepływu danych na magistrali. Dzięki temu możliwe będzie czytanie danych z LCD.
  2. Zmiana kierunku GPIO przeznaczonych do komunikacji z wyświetlaczem “w locie”. Biblioteka ma za zadanie robić to samodzielnie.

Konfigurację GPIO dla pinów LCD_DB4…LCD_DB7 jako Input lub Output wykonam w sposób jaki proponuje SMT32CubeMX. W odpowiedni sposób zmodyfikowałem też funkcje przesyłu i odbioru danych.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
static void LCD_DataOut()
{
GPIO_InitTypeDef GPIO_InitStruct;

GPIO_InitStruct.Pin = LCD_DB4_Pin|LCD_DB5_Pin|LCD_DB6_Pin|LCD_DB7_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &amp;GPIO_InitStruct);
}

static void LCD_DataIn()
{
GPIO_InitTypeDef GPIO_InitStruct;

GPIO_InitStruct.Pin = LCD_DB4_Pin|LCD_DB5_Pin|LCD_DB6_Pin|LCD_DB7_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &amp;GPIO_InitStruct);
}

//
// Write byte to LCD
//
uint8_t LCD_ReadByte(void)
{
uint8_t result = 0;
LCD_DataIn();

SET_LCD_RW;

SET_LCD_E;
result = (LCD_GetDataPort() &lt;&lt; 4);
RESET_LCD_E;

SET_LCD_E;
result |= LCD_GetDataPort();
RESET_LCD_E;

return result;
}

//
// Check Busy Flag
//
uint8_t LCD_CheckBusyFlag()
{
RESET_LCD_RS;
return LCD_ReadByte();
}

//
// Write byte to LCD
//
void LCD_WriteByte(uint8_t data)
{
LCD_DataOut();

RESET_LCD_RW;

SET_LCD_E;
LCD_SetDataPort(data &gt;&gt; 4);
RESET_LCD_E;

SET_LCD_E;
LCD_SetDataPort(data);
RESET_LCD_E;

// HAL_Delay(1);
// Delay_us(120); // Wait for data processing
while((LCD_CheckBusyFlag() &amp; (1&lt;&lt;7))); // Wait for data processing
}

Odpalam kod i… WOW! Mimo, że mikrokontroler robi masę operacji na pinach, to czas odświeżenia ramki wyniósł tylko 2,74 ms! Czy ta prędkość jest warta jeden pin GPIO? Myślę, że w wielu przypadkach zdecydowanie tak.

A może jeszcze uda się coś urwać? Kontroler LCD oferuje maksymalnie 8-bitową szerokość magistrali komunikacyjnej. Sprawdzę czy dwukrotne zwiększenie jednocześnie wysyłanych danych przyśpieszy dwukrotnie czas odświeżenia ramki. W pierwszej kolejności sprawdzę bez czytania flagi zajętości.

Magistrala 8-bitowa bez sprawdzania flagi zajętości

Ze względu na beznadziejnie długi czas odświeżania jaki osiągnąłem korzystając jedynie z wbudowanych w STM32HAL funckji delay, pominę rozważania tego sposobu dla 8-bitów. Pomiary zrealizuję jedynie używając funkcji działającej na timerze.

Zaczynam od podłączenia pozostałych 4 linii, czyli LCD_DB0…LCD_DB3.

Modyfikacja kodu polega na przypisaniu nowych funkcji odpowiednim pinom w STM32CubeMX

…oraz modyfikacji kodu pod szerszą magistralę. Zmianie ulegają funkcje dotyczące ustawienia pinów GPIO, przesłania jednego bajtu danych oraz funkcja inicjalizująca wyświetlacz, która teraz ustawia kontroler LCD w tryb 8-bitowy.

Uzyskany czas jest bez szału. W zasadzie prawie nic się nie skróciło porównując z wersją 4-bit. Cała ramka przesłała się w 7,11 ms.

 

Magistrala 8-bitowa ze sprawdzaniem flagi zajętości

Dla trybu 4-bitowego zamiana delay’ów na czytanie zajętości LCD wyszło rewelacyjnie – czas skrócił się znacząco. Sprawdzę czy dla 8-bitów wynik będzie równie spektakularny.

Przerabiam kod i… szczerze mówiąc spodziewałem się czegoś lepszego 🙁 Uzyskałem w ten sposób 2.74 ms, czyli wynik dokładnie taki sam, jak przy wykorzystaniu trybu 4-bitowego.

Dalsza optymalizacja?

Można jeszcze zamienić HALowe funkcje do sterowania GPIO na bezpośrednie działania na rejestrach. Czy warto iść dalej tą droga? Chyba nie. Powinno dać się jeszcze urwać może 0,2 ms ponieważ czas ustawiania GPIO niestety ma znikomy wpływ – czas oczekiwania na kontroler LCD jest zdecydowanie większy, a tego nie skrócę.

Patrząc na przebiegi można  też wywnioskować całkiem ciekawą rzecz. Otóż 1,5 ms na początku przesyłania trwa kasowanie wyswietlacza. Przy sterowaniu z obsługą busy flag jest to ponad połowa czasu potrzebnego na wyświetlenie dwóch pełnych wierszy! Może by tutaj spróbować ugryźć? Np. zamiast wysyłać komendę kasującą wpisać same spacje, hmm? Albo wysyłać wcześniej przygotowany kompletny bufor z pamięci RAM mikrokotrolera? Sposobów na buforowanie jest wiele i w przyszłości na pewno pojawi się na blogu wątek dotyczący tego tematu.

Podsumowanie

Dotarłem do końca 🙂 Zbadałem wszystkie 4 możliwe sposoby komunikacji z popularnym wyświetlaczem LCD z kontrolerem zgodnym z HD44780 wykorzystując mikrokontroler STM32F401RE. Wyniki badań przedstawia poniższa tabela.

TrybCzas
4-bit HAL_Delay
67,29 ms
4-bit bez BF
7,14 ms
4-bit z BF
2,74 ms
8-bit bez BF
7,11 ms
8-bit z BF
2,74 ms

Z którego trybu korzystać? Z miejsca można odrzucić sposób z wykorzystaniem wbudowanego HAL_Delay. Czas ten jest zdecydowanie nieakceptowalny! Szkoda życia, nie polecam.

Porównując dwa tryby 4-bitowe widać jak duży wpływ ma czytanie flagi zajętości. Nie trzeba zgadywać, kiedy kontroler jest gotowy na przyjęcie danych, wydłużając całą procedurę. Skrócenie czasu ponad 2.5x kosztuje jedynie jeden pin GPIO. Ten czas może być bardzo cenny w bardziej skomplikowanym projekcie.

A co z 8-bitami? Pic na wodę. Wyniki są prawie identyczne jak przy dwa razy węższej szynie danych. Co to oznacza? Zupełnie można pominąć ten tryb używając wyświetlaczy alfanumerycznych. Wchodzenie w tryb 8-bitowy jest marnowaniem czterech cennych pinów mikrokontrolera.

Kod testowy wraz z biblioteką znajdziesz na moim GitHUB’ie: link

Na koniec zachęcam do dyskusji w komentarzach na temat obsługi wyświetlacza LCD na STM32. Uważasz, że popełniłem gdzieś błąd? Masz jakiś ciekawy pomysł co można ulepszyć? Podziel się tym w komentarzu! Pamiętaj, że dyskusja ma być kulturalna i zgodna z zasadami języka polskiego.


Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

Serwis wykorzystuje pliki cookies. Korzystając ze strony wyrażasz zgodę na wykorzystywanie plików cookies. więcej informacji

Wrażenie zgody na pliki Cookies jest konieczne, aby uzyskać najlepsze wrażenia z przeglądania strony. Jeżeli nadal nie wyraziłeś zgody na używanie plików Cookies, zaakceptuj poniżej klikając w przycisk "Akceptuj" na banerze.

Close