Zpět

Knihovna pre LCD TFT displej

Martin Šerík

Obsah

Popis displeja

Na demonštračnom kitu slúži na zobrazovanie mimo iného aj 3.2" LCD TFT dotykový displej s rozlíšením 320x240 pixelov. Ide o displej z Číny - odkaz. My sme si zadovážili jeho lacnejší variant cez eBay. Jedná sa o model YX32B, ktorý neobsahuje SD kartu a miesto 40 pinov má vyvedených pinov 32. Jeho cena vyšla po prepočte na necelých 350 Kč.

Displej je riadený čipom SSD1289. Jedná sa o radič s RAM, silovými obvodmi, hradlovými a emitorovými budičmi integrovanými na jednom čipe. Dokáže zobraziť až 262k farieb (my budeme používať 65k farieb) na TFT displeji s maximálnym rozlíšením 320x240. Na čipe sa nachádza 172 800 bytov GDDRAM (Graphic Display Data RAM, slúži na ukladanie farby pixelu). Vďaka tomu je kompatibilný s 8/9/16-18-bit 6800 alebo 8080 sériovými rozhraniami. Displej obsahuje softvérovo nastaviteľný obvod na kontrolu gamma krivky, vďaka čomu si môžeme nastaviť optimálnu kvalitu zobrazovania.

Ako sme už uviedli z displeja je vyvedených 32 pinov. DB0 až DB15 slúžia na dátovú komunikáciu, RESET slúži na reset čipu (aktívny v logickej nule). WR (WRite) je aktívny na nulovej úrovni a signalizuje sa pomocou neho zápis dát do pamäte radiča. Pin RD (ReaD) je aktívny v logickej 1. Keď je aktívny, tak je možné čítať obsah registrov radiča. Na pin CS (Chip Select) má byť pri komunikácii privedená nulová úroveň. Na displeji nájdeme ešte pin označený RS. Tu je trochu zmätok, pretože v datasheete je uvedený pod označením DC (Data or Command). Keď je v logickej 1 tak sa jedná o zápis, resp. čítanie dát (data), v logickej 0 potom o zápis príkazov (command). Pomocou PWM signálu privedenému na pin BL_CNT môžeme kontrolovať intenzitu podsvietenia displeja. Displej je napájaný 3.3 V.

Knihovna

LCD displej je riadený z vývojového kitu STM32F4-Discovery. Na kitu je osadený procesor STM32F407VGT6. Tento procesor obsahuje perifériu, ktorá poskytuje rozhranie pre prístup k synchrónnym a asynchrónnym pamätiam a 16-bitovým PC pamäťovým kartám. Volá sa FSMC (Flexible Static Memory Controller). Pri správnom nastavení umožňuje zápis do RAM displeja.

Ako prepojiť jednotlivé kontakty STM32F4-Discovery s LCD modulom nájdeme v hlavičkovom súbore LCD_STM32F4.h. Na inicializáciu pinov mikroprocesoru používame funkciu
  Init_GPIO();
  
V nej sa nastavia všetky piny okrem resetu do alternatívnej funkcie, tak aby sa dali použiť s FSMC. V ďalšej funkcii
  Init_FSMC();
  
sa inicializuje FSMC. Podla datasheetu sme ju nastavili tak, aby bola kompatibilná s 16 bitovým 8080 rozhraním. Na zápis do SRAM sa používa banka 1. Tá je ďalej rozdelená na 4 x 64 MB NOR/PSRAM regióny. Pri nastavovaní FSMC sme vybrali banku 1 a región 1 (FSMC_Bank1_NORSRAM1). Nastavenie časovania jednotlivých signálov (setup time, access time, hold time, ...) sme museli v konečnom dôsledku nastaviť experimentálne, keďže na celkom dlhých vodičoch, ktorými je prepojený displej s kitom, dochádza k rôznym rušeniam. Kritické je nastavenie parametru
  timing.FSMC_DataSetupTime=0x0A;
  
, ktorý bude pravdepodobne potrebné pri inom zapojení (napríklad na DPS) zmeniť. Ešte uvediem, že všetky časy sa udávajú v násobku hodinového taktu. Banka 1 začína na adrese 6000 0000h a končí na 6FFF FFFFh. Ďalej je rozdelená na tri sekcie, a to na dátovú sekciu (data section: 6000 0000h - 6000 FFFFh), príkazovú sekciu (command sectio: 6001 0000h - 6001 FFFFh) a adresnú sekciu (address section: 6002 0000h - 6003 FFFFh). Pri zapisovaní do RAM displeja využívame nasledujúcu konštrukciu:
typedef struct
{
  /* LCD Index Write       Address offset 0x00 */
  __IO uint16_t Register;  
  /* LCD Data Write        Address offset 0x02 */
  __IO uint16_t Data;      
}LCD_TypeDef;

#define LCD_BASE ((uint32_t) (0x60000000 | 0x0001FFFE))
#define LCD      ((LCD_TypeDef *) LCD_BASE)
Na samotné posielanie dát slúži:
  LCD->Register = reg;
  LCD->Data = data;
  
V prvom príkaze zapisujeme do príkazovej sekcie (reg sa posiela na adresu 6001 FFFEh, DC sa nastaví do 0 - prebieha výber registru SSD1289, do ktorého sa bude zapisovať) a v druhom do adresnej sekcie (data sa posiela na adresu 6001 FFFEh + 2h = 6002 0000h, DC sa nastaví na 1 - prebieha zápis do naposledy vybraného registru). Knihovna obsahuje v aktuálnej verzii nasledujúce funkcie:
void Clear_Screen(uint16_t color);
void Set_Cursor(uint16_t x, uint16_t y);
void Draw_Pixel(uint16_t x, uint16_t y, uint16_t color);
void Draw_Line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);
void Draw_Rect(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);
void Draw_Full_Rect(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);
void Draw_Circle(uint16_t x, uint16_t y, uint16_t r, uint16_t color);
void Draw_Full_Circle(uint16_t x, uint16_t y, uint16_t r, uint16_t color);
void Draw_Char(uint16_t x, uint16_t y, const uint16_t *c, uint16_t color);
void Display_Char(uint16_t x, uint16_t y, uint8_t c, uint16_t color);
void Display_String(uint16_t x, uint16_t y, uint8_t *ptr, uint16_t color);
void Set_Font(sFONT *fonts);
void Draw_Image(uint16_t x, uint16_t y, uint16_t x_res, uint16_t y_res,const uint16_t *ptr_image);
Mylsím, že z názvov je jasné, čo ktorá funkcia robí. Bližší popis môžete nájsť v LCD_STM32F4.c. Pristavil by som sa pri funkcii na vykresľovanie obrázkov:
/*
 * Draw an image in format GRB565.
 * x, y - position, where to start displaying.
 * x_res, y_res - resolution in pixels.
 * *ptr_image - pointer to image array.
 */

void Draw_Image(uint16_t x, uint16_t y, uint16_t x_res, uint16_t y_res,const uint16_t *ptr_image)
{
  uint16_t i = 0, j = 0;

  for(i = 0; i < x_res; i++)
  {
    Set_Cursor((x+i), y);
    Write_GDDRAM_Prepare();

    for(j = 0; j < y_res; j++)
    {
      Write_Data(*(ptr_image++));
    }
  }
}
Vstupom funkcie je, okrem pozície (x, y) a rozlíšenia (x_res, y_res) obrázku, ukazovateľ na pole celých čísel, ktoré reprezentujú farbu jednotlivých pixelov obrázku vo formáte RGB-565 (čísla 5, 6 a 5 reprezentujú počet bitov postupne pre každú farebnú zložku, čiže zo 16 bitov je prvých 5 zľava červená, ďalších 6 zelená a posledných 5 bitov je modrá zložka). Na prevod tzv. True-Color obrázku (napr. .jpg alebo .png) s 24 bitovou hĺbkou do nami požadovaného formátu sme vytvorili v Matlabe malý skript (rgb565.m), ktorého výstupom je hlavičkový súbor s polom celých čísel reprezentujúcich obrázok a ďalšími potrebnými náležitosťami (správny formát, deklarácia typu pola, ...).
clc;
clear all;

nazov = 'mandelbrot4';

a = imread('mandelbrot4.jpg');

r = a(:, :, 1); g = a(:, :, 2); b = a(:, :, 3);

r_565 = bitshift(uint16(r/(255/31)),11);
g_565 = bitshift(uint16(g/(255/63)),5);
b_565 = uint16(b/(255/31));

rgb_565 = bitor(bitor(r_565,g_565),b_565);

rgb_565_reshape = reshape(rgb_565', [], 1);

filename = [nazov '.h'];
h = fopen(filename, 'w');

fprintf(h,'#include \n\nconst static uint16_t %s[] = {\n',nazov);


for k=1:length(rgb_565_reshape)
    fprintf(h,'0x%s',dec2hex(rgb_565_reshape(k)));
    
    if (k < length(rgb_565_reshape))
        fprintf(h,', ');
    end
    
    if (mod(k,9) == 0)  % jump to new line every 9 numbers
        fprintf(h,'\n');
    end
end

fprintf(h, '};');

fclose(h);
Na začiatku programu nastavíme do premennej nazov ľubovoľný názov. Priamo tento názov budeme potom zadávať vo funkcii Draw_Image() ako posledný parameter (ukazovateľ na prvý prvok pola, *ptr_image). Do funkcie imread() napíšeme názov súboru s obrázkom (v našom prípade mandelbrot4.jpg), ktorý by mal byť uložený v tom istom adresári ako skript. Samotná funkcia skriptu potom pozostáva z rozdelenia obrázku na jednotlivé farebné zložky (r, g, b), ich škálovania a bitového posunu na pozície zodpovedajúcim jednotlivým farbám v 16 bitovom čísle (r_565, g_565, b_565). Po spojení do jednej premennej (rgb_565) a preorganizovaní matice do jednorozmerného pola (rgb_565_reshape) je toto pole pri výpise do textového súboru prevedené do šestnástkového tvaru (pomocou funkcie dec2hex). Výsledkom je súbor "nazov.h" (v našom prípade mandelbrot4.h). Ten je potrebné vložiť do LCD_STM32F4.h pomocou direktívy #include. Takto je to napríklad v demo projekte na videu dole:
/* Includes ******************************************************************/

#include "stm32f4xx.h"
#include "stm32f4xx_it.h"
#include "fonts.h"

/* Header files with pictures as integer arrays in RGB565 format */
#include "logo_urel.h"
#include "wave.h"
#include "image_to_RGB565/mandelbrot1.h"
#include "image_to_RGB565/mandelbrot2.h"
#include "image_to_RGB565/mandelbrot3.h"
#include "image_to_RGB565/mandelbrot4.h"

Demonstrace

Na nasledujúcom videu je demonštrované využitie knihovny pre LCD displej.

Download

Archiv s projektem projekt.zip