Skip to content

Commit f380d70

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

File tree

6 files changed

+473
-0
lines changed

6 files changed

+473
-0
lines changed

include/unicore-mx/lcd_tft/lcd_tft.h

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
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+
/**
102+
* Hardware palette or Color Look-Up Table (CLUT).
103+
* Only valid for format = L8, AL44, AL88
104+
* Pass @a data = NULL and @a count = 0 to disable.
105+
* @note @a data format is RGB888
106+
*/
107+
struct {
108+
const uint32_t *data;
109+
size_t count;
110+
} palette;
111+
112+
/**
113+
* These colors are seen as transparent if found in frame buffer.
114+
* Pass @a data = NULL and @a count = 0 to disable.
115+
* @note @a data format is RGB888
116+
*/
117+
struct {
118+
const uint32_t *data;
119+
size_t count;
120+
} transparent;
121+
};
122+
123+
/**
124+
* Initalize LCD TFT
125+
* @param backend LCD TFT backend
126+
* @param config Configuration
127+
* @return lcd_tft LCD TFT object
128+
*/
129+
lcd_tft *lcd_tft_init(const lcd_tft_backend *backend,
130+
const struct lcd_tft_config *config);
131+
132+
/**
133+
* Enable the LCD TFT
134+
* @param backend LCD TFT backend
135+
* @param enable Enable
136+
*/
137+
void lcd_tft_enable(lcd_tft *lt, bool enable);
138+
139+
/**
140+
* Setup a layer for LCD TFT
141+
* @param ldc_tft LCD TFT object
142+
* @param index Layer index (0...N)
143+
* @param layer Layer data
144+
*/
145+
void lcd_tft_layer_set(lcd_tft *lt, unsigned index,
146+
const struct lcd_tft_layer *layer);
147+
148+
/**
149+
* Enable the LCD TFT layer
150+
* @param lt LCD TFT object
151+
* @param index Layer index (0...N)
152+
* @param enable Enable
153+
*/
154+
void lcd_tft_layer_enable(lcd_tft *lt, unsigned index,
155+
bool enable);
156+
157+
END_DECLS
158+
159+
#endif
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
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_LxCFBAR(num) = (uint32_t) layer->framebuffer.data;
156+
157+
unsigned bpp = pixel_format_bytes[layer->framebuffer.format];
158+
unsigned bytes = bpp * layer->framebuffer.width;
159+
LTDC_LxCFBLR(num) = (bytes << 16) | ((bytes + 3) << 0);
160+
LTDC_LxCFBLNR(num) = layer->framebuffer.height;
161+
}
162+
163+
static void layer_clut(unsigned num, const struct lcd_tft_layer *layer)
164+
{
165+
if (!layer->palette.count) {
166+
/* Not provided */
167+
LTDC_LxCR(num) &= ~LTDC_LxCR_CLUT_ENABLE;
168+
return;
169+
}
170+
171+
LTDC_LxCR(num) |= LTDC_LxCR_CLUT_ENABLE;
172+
173+
for (uint8_t i = 0; i < layer->palette.count; i++) {
174+
LTDC_LxCLUTWR(num) = (i << 24) | layer->palette.data[i];
175+
}
176+
}
177+
178+
static void layer_key_color(unsigned num, const struct lcd_tft_layer *layer)
179+
{
180+
if (!layer->transparent.count) {
181+
/* Not provided */
182+
LTDC_LxCR(num) &= ~LTDC_LxCR_COLKEY_ENABLE;
183+
return;
184+
}
185+
186+
/* Warning: Only single transparent color supported */
187+
LTDC_LxCR(num) |= LTDC_LxCR_COLKEY_ENABLE;
188+
LTDC_LxCKCR(num) = layer->transparent.data[0];
189+
}
190+
191+
static void layer_set(struct lcd_tft *lt, unsigned index,
192+
const struct lcd_tft_layer *layer)
193+
{
194+
(void) lt;
195+
196+
unsigned num = index + 1;
197+
198+
layer_window(num, layer);
199+
layer_data(num, layer);
200+
layer_clut(num, layer);
201+
layer_key_color(num, layer);
202+
LTDC_LxCR(num) |= LTDC_LxCR_LAYER_ENABLE;
203+
204+
/* Reload immediate */
205+
LTDC_SRCR = LTDC_SRCR_IMR;
206+
}
207+
208+
static void layer_enable(struct lcd_tft *lt, unsigned index, bool enable)
209+
{
210+
(void) lt;
211+
212+
unsigned num = index + 1;
213+
214+
if (enable) {
215+
LTDC_LxCR(num) |= LTDC_LxCR_LAYER_ENABLE;
216+
} else {
217+
LTDC_LxCR(num) &= ~LTDC_LxCR_LAYER_ENABLE;
218+
}
219+
}

0 commit comments

Comments
 (0)