Skip to content

Commit 5c0ddbe

Browse files
committed
LCD TFT generic driver
Support: - STM32 F4/F7 LTDC
1 parent 29ca1f6 commit 5c0ddbe

File tree

6 files changed

+481
-0
lines changed

6 files changed

+481
-0
lines changed

include/unicore-mx/lcd_tft/lcd_tft.h

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
/*
2+
* Copyright (C) 2017 Kuldeep Singh Dhaka <[email protected]>
3+
*
4+
* This library is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU Lesser General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This library is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU Lesser General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Lesser General Public License
15+
* along with this library. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
#ifndef UNICOREMX_LCD_TFT_H
19+
#define UNICOREMX_LCD_TFT_H
20+
21+
#include <unicore-mx/cm3/common.h>
22+
#include <stdint.h>
23+
#include <stdbool.h>
24+
#include <stdlib.h>
25+
26+
BEGIN_DECLS
27+
28+
typedef struct lcd_tft lcd_tft;
29+
typedef struct lcd_tft_backend lcd_tft_backend;
30+
31+
extern const lcd_tft_backend lcd_tft_stm32_ltdc;
32+
33+
/**
34+
* @note Single transparent color supported
35+
*/
36+
#define LCD_TFT_STM32_LTDC (&lcd_tft_stm32_ltdc)
37+
38+
struct lcd_tft_config {
39+
struct {
40+
unsigned vsync, hsync;
41+
unsigned vbp, hbp;
42+
unsigned height, width;
43+
unsigned vfp, hfp;
44+
} timing;
45+
46+
enum {
47+
LCD_TFT_HSYNC_ACTIVE_LOW = 0 << 0,
48+
LCD_TFT_HSYNC_ACTIVE_HIGH = 1 << 0,
49+
LCD_TFT_VSYNC_ACTIVE_LOW = 0 << 1,
50+
LCD_TFT_VSYNC_ACTIVE_HIGH = 1 << 1,
51+
LCD_TFT_DE_ACTIVE_LOW = 0 << 2,
52+
LCD_TFT_DE_ACTIVE_HIGH = 1 << 2,
53+
LCD_TFT_CLK_ACTIVE_LOW = 0 << 3,
54+
LCD_TFT_CLK_ACTIVE_HIGH = 1 << 3,
55+
56+
/* https://en.wikipedia.org/wiki/Dither */
57+
LCD_TFT_DITHER_ENABLE = 1 << 4,
58+
59+
LCD_TFT_HSYNC_ACTIVE_MASK = 1 << 0,
60+
LCD_TFT_VSYNC_ACTIVE_MASK = 1 << 1,
61+
LCD_TFT_DE_ACTIVE_MASK = 1 << 2,
62+
LCD_TFT_CLK_ACTIVE_MASK = 1 << 3,
63+
LCD_TFT_DITHER_MASK = 1 << 4
64+
} features;
65+
66+
/* Number of output lines */
67+
enum {
68+
LCD_TFT_OUTPUT_RGB565, /* 16bit */
69+
LCD_TFT_OUTPUT_RGB666, /* 18bit */
70+
LCD_TFT_OUTPUT_RGB888 /* 24bit */
71+
} output;
72+
73+
/** Background color - all pixel in layer are transparent (Format: RGB888) */
74+
uint32_t background;
75+
};
76+
77+
enum lcd_tft_pixel_format {
78+
LCD_TFT_ARGB8888,
79+
LCD_TFT_RGB888,
80+
LCD_TFT_RGB565,
81+
LCD_TFT_ARGB1555,
82+
LCD_TFT_ARGB4444,
83+
LCD_TFT_L8,
84+
LCD_TFT_AL44,
85+
LCD_TFT_AL88
86+
};
87+
88+
struct lcd_tft_layer {
89+
struct {
90+
unsigned x, y, width, height;
91+
92+
/**
93+
* Note: Pointer should be aligned to
94+
* 32bit if 1 pixel contain 4byte data
95+
* 16bit if 1 pixel contain 2byte data
96+
*/
97+
enum lcd_tft_pixel_format format;
98+
const void *data;
99+
} framebuffer;
100+
101+
/** Color of screen area not covered by layer (Format: ARGB8888).
102+
* This is used outside the layer which is not covered by framebuffer */
103+
uint32_t background;
104+
105+
/**
106+
* Hardware palette or Color Look-Up Table (CLUT).
107+
* Only valid for format = L8, AL44, AL88
108+
* Pass @a data = NULL and @a count = 0 to disable.
109+
* @note @a data format is RGB888
110+
*/
111+
struct {
112+
const uint32_t *data;
113+
size_t count;
114+
} palette;
115+
116+
/**
117+
* These colors are seen as transparent if found in frame buffer.
118+
* Pass @a data = NULL and @a count = 0 to disable.
119+
* @note @a data format is RGB888
120+
*/
121+
struct {
122+
const uint32_t *data;
123+
size_t count;
124+
} transparent;
125+
};
126+
127+
/**
128+
* Initalize LCD TFT
129+
* @param backend LCD TFT backend
130+
* @param config Configuration
131+
* @return lcd_tft LCD TFT object
132+
*/
133+
lcd_tft *lcd_tft_init(const lcd_tft_backend *backend,
134+
const struct lcd_tft_config *config);
135+
136+
/**
137+
* Enable the LCD TFT
138+
* @param backend LCD TFT backend
139+
* @param enable Enable
140+
*/
141+
void lcd_tft_enable(lcd_tft *lt, bool enable);
142+
143+
/**
144+
* Setup a layer for LCD TFT
145+
* @param ldc_tft LCD TFT object
146+
* @param index Layer index (0...N)
147+
* @param layer Layer data
148+
*/
149+
void lcd_tft_layer_set(lcd_tft *lt, unsigned index,
150+
const struct lcd_tft_layer *layer);
151+
152+
/**
153+
* Enable the LCD TFT layer
154+
* @param lt LCD TFT object
155+
* @param index Layer index (0...N)
156+
* @param enable Enable
157+
*/
158+
void lcd_tft_layer_enable(lcd_tft *lt, unsigned index,
159+
bool enable);
160+
161+
END_DECLS
162+
163+
#endif
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
/*
2+
* Copyright (C) 2017 Kuldeep Singh Dhaka <[email protected]>
3+
*
4+
* This library is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU Lesser General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This library is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU Lesser General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Lesser General Public License
15+
* along with this library. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
#include "../lcd_tft_private.h"
19+
#include <unicore-mx/stm32/ltdc.h>
20+
#include <unicore-mx/stm32/rcc.h>
21+
22+
static struct lcd_tft *init(const struct lcd_tft_backend *backend,
23+
const struct lcd_tft_config *config);
24+
static void enable(struct lcd_tft *lt, bool enable);
25+
static void layer_set(struct lcd_tft *lt, unsigned index,
26+
const struct lcd_tft_layer *layer);
27+
static void layer_enable(struct lcd_tft *lt, unsigned index,
28+
bool enable);
29+
30+
const struct lcd_tft_backend lcd_tft_stm32_ltdc = {
31+
.init = init,
32+
.enable = enable,
33+
.layer_set = layer_set,
34+
.layer_enable = layer_enable
35+
};
36+
37+
static const struct lcd_tft _lt = {
38+
.backend = &lcd_tft_stm32_ltdc
39+
};
40+
41+
static void timing(const struct lcd_tft_config *config)
42+
{
43+
uint16_t w, h;
44+
w = config->timing.hsync - 1;
45+
h = config->timing.vsync - 1;
46+
LTDC_SSCR = (w << 16) | (h << 0);
47+
48+
w += config->timing.hbp;
49+
h += config->timing.vbp;
50+
LTDC_BPCR = (w << 16) | (h << 0);
51+
52+
w += config->timing.width;
53+
h += config->timing.height;
54+
LTDC_AWCR = (w << 16) | (h << 0);
55+
56+
w += config->timing.hfp;
57+
h += config->timing.vfp;
58+
LTDC_TWCR = (w << 16) | (h << 0);
59+
}
60+
61+
static void features(const struct lcd_tft_config *config)
62+
{
63+
uint32_t gcr = 0;
64+
65+
if (config->features & LCD_TFT_HSYNC_ACTIVE_MASK) {
66+
gcr |= LTDC_GCR_HSPOL_ACTIVE_HIGH;
67+
}
68+
69+
if (config->features & LCD_TFT_VSYNC_ACTIVE_MASK) {
70+
gcr |= LTDC_GCR_VSPOL_ACTIVE_HIGH;
71+
}
72+
73+
if (config->features & LCD_TFT_DE_ACTIVE_MASK) {
74+
gcr |= LTDC_GCR_DEPOL_ACTIVE_HIGH;
75+
}
76+
77+
if (config->features & LCD_TFT_CLK_ACTIVE_MASK) {
78+
gcr |= LTDC_GCR_PCPOL_ACTIVE_HIGH;
79+
}
80+
81+
if (config->features & LCD_TFT_DITHER_MASK) {
82+
gcr |= LTDC_GCR_DITHER_ENABLE;
83+
}
84+
85+
LTDC_GCR = gcr;
86+
}
87+
88+
static struct lcd_tft *init(const struct lcd_tft_backend *backend,
89+
const struct lcd_tft_config *config)
90+
{
91+
(void) backend;
92+
93+
rcc_periph_clock_enable(RCC_LTDC);
94+
95+
features(config);
96+
timing(config);
97+
98+
LTDC_BCCR = config->background;
99+
LTDC_GCR |= LTDC_GCR_LTDC_ENABLE;
100+
101+
return (struct lcd_tft *) &_lt;
102+
}
103+
104+
static void enable(struct lcd_tft *lt, bool enable)
105+
{
106+
(void) lt;
107+
108+
if (enable) {
109+
LTDC_GCR |= LTDC_GCR_LTDC_ENABLE;
110+
} else {
111+
LTDC_GCR &= ~LTDC_GCR_LTDC_ENABLE;
112+
}
113+
}
114+
115+
static void layer_window(unsigned num, const struct lcd_tft_layer *layer)
116+
{
117+
uint32_t hbp = (LTDC_BPCR >> LTDC_BPCR_AHBP_SHIFT) & LTDC_BPCR_AHBP_MASK;
118+
uint32_t vbp = (LTDC_BPCR >> LTDC_BPCR_AVBP_SHIFT) & LTDC_BPCR_AVBP_MASK;
119+
uint16_t start, stop;
120+
121+
start = hbp + layer->framebuffer.x + 1;
122+
stop = hbp + layer->framebuffer.x + layer->framebuffer.width;
123+
LTDC_LxWHPCR(num) = (stop << 16) | (start << 0);
124+
125+
start = vbp + layer->framebuffer.y + 1;
126+
stop = vbp + layer->framebuffer.y + layer->framebuffer.height;
127+
LTDC_LxWVPCR(num) = (stop << 16) | (start << 0);
128+
}
129+
130+
static const uint32_t pixel_format_conv[] = {
131+
[LCD_TFT_ARGB8888] = LTDC_LxPFCR_ARGB8888,
132+
[LCD_TFT_RGB888] = LTDC_LxPFCR_RGB888,
133+
[LCD_TFT_RGB565] = LTDC_LxPFCR_RGB565,
134+
[LCD_TFT_ARGB1555] = LTDC_LxPFCR_ARGB1555,
135+
[LCD_TFT_ARGB4444] = LTDC_LxPFCR_ARGB4444,
136+
[LCD_TFT_L8] = LTDC_LxPFCR_L8,
137+
[LCD_TFT_AL44] = LTDC_LxPFCR_AL44,
138+
[LCD_TFT_AL88] = LTDC_LxPFCR_AL88
139+
};
140+
141+
static const unsigned pixel_format_bytes[] = {
142+
[LCD_TFT_ARGB8888] = 4,
143+
[LCD_TFT_RGB888] = 3,
144+
[LCD_TFT_RGB565] = 2,
145+
[LCD_TFT_ARGB1555] = 2,
146+
[LCD_TFT_ARGB4444] = 2,
147+
[LCD_TFT_L8] = 1,
148+
[LCD_TFT_AL44] = 1,
149+
[LCD_TFT_AL88] = 2
150+
};
151+
152+
static void layer_data(unsigned num, const struct lcd_tft_layer *layer)
153+
{
154+
LTDC_LxPFCR(num) = pixel_format_conv[layer->framebuffer.format];
155+
LTDC_LxDCCR(num) = layer->background;
156+
LTDC_LxCACR(num) = 0xFF;
157+
LTDC_LxBFCR(num) = (LTDC_LxBFCR_BF1_CONST_ALPHA << 8) |
158+
(LTDC_LxBFCR_BF2_CONST_ALPHA << 0);
159+
LTDC_LxCFBAR(num) = (uint32_t) layer->framebuffer.data;
160+
161+
unsigned bpp = pixel_format_bytes[layer->framebuffer.format];
162+
unsigned bytes = bpp * layer->framebuffer.width;
163+
LTDC_LxCFBLR(num) = (bytes << 16) | ((bytes + 3) << 0);
164+
LTDC_LxCFBLNR(num) = layer->framebuffer.height;
165+
}
166+
167+
static void layer_clut(unsigned num, const struct lcd_tft_layer *layer)
168+
{
169+
if (!layer->palette.count) {
170+
/* Not provided */
171+
LTDC_LxCR(num) &= ~LTDC_LxCR_CLUT_ENABLE;
172+
return;
173+
}
174+
175+
LTDC_LxCR(num) |= LTDC_LxCR_CLUT_ENABLE;
176+
177+
for (uint8_t i = 0; i < layer->palette.count; i++) {
178+
LTDC_LxCLUTWR(num) = (i << 24) | layer->palette.data[i];
179+
}
180+
}
181+
182+
static void layer_key_color(unsigned num, const struct lcd_tft_layer *layer)
183+
{
184+
if (!layer->transparent.count) {
185+
/* Not provided */
186+
LTDC_LxCR(num) &= ~LTDC_LxCR_COLKEY_ENABLE;
187+
return;
188+
}
189+
190+
/* Warning: Only single transparent color supported */
191+
LTDC_LxCR(num) |= LTDC_LxCR_COLKEY_ENABLE;
192+
LTDC_LxCKCR(num) = layer->transparent.data[0];
193+
}
194+
195+
static void layer_set(struct lcd_tft *lt, unsigned index,
196+
const struct lcd_tft_layer *layer)
197+
{
198+
(void) lt;
199+
200+
unsigned num = index + 1;
201+
202+
layer_window(num, layer);
203+
layer_data(num, layer);
204+
layer_clut(num, layer);
205+
layer_key_color(num, layer);
206+
LTDC_LxCR(num) |= LTDC_LxCR_LAYER_ENABLE;
207+
208+
/* Reload immediate */
209+
LTDC_SRCR |= LTDC_SRCR_IMR;
210+
}
211+
212+
static void layer_enable(struct lcd_tft *lt, unsigned index, bool enable)
213+
{
214+
(void) lt;
215+
216+
unsigned num = index + 1;
217+
218+
if (enable) {
219+
LTDC_LxCR(num) |= LTDC_LxCR_LAYER_ENABLE;
220+
} else {
221+
LTDC_LxCR(num) &= ~LTDC_LxCR_LAYER_ENABLE;
222+
}
223+
}

0 commit comments

Comments
 (0)