1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #17437 from aabadie/pr/cpu/stm32_ltdc

cpu/stm32: add driver for the LTDC peripheral
This commit is contained in:
benpicco 2022-01-07 15:26:13 +01:00 committed by GitHub
commit 5e79ec6fd4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 1719 additions and 5 deletions

View File

@ -16,6 +16,7 @@ config BOARD_STM32F746G_DISCO
select HAS_PERIPH_DMA
select HAS_PERIPH_ETH
select HAS_PERIPH_I2C
select HAS_PERIPH_LTDC
select HAS_PERIPH_RTC
select HAS_PERIPH_RTT
select HAS_PERIPH_SPI

View File

@ -5,3 +5,7 @@ endif
ifneq (,$(filter netdev_default,$(USEMODULE)))
USEMODULE += stm32_eth
endif
ifneq (,$(filter disp_dev,$(USEMODULE)))
FEATURES_REQUIRED += periph_ltdc
endif

View File

@ -5,6 +5,7 @@ CPU_MODEL = stm32f746ng
FEATURES_PROVIDED += periph_dma
FEATURES_PROVIDED += periph_eth
FEATURES_PROVIDED += periph_i2c
FEATURES_PROVIDED += periph_ltdc
FEATURES_PROVIDED += periph_rtc
FEATURES_PROVIDED += periph_rtt
FEATURES_PROVIDED += periph_spi

View File

@ -18,9 +18,19 @@
* @}
*/
#include "kernel_defines.h"
#include "board.h"
#include "periph/gpio.h"
void board_init(void)
{
gpio_init(BACKLIGHT_PIN, GPIO_OUT);
if (IS_USED(MODULE_PERIPH_LTDC)) {
gpio_init(LCD_DISP_PIN, GPIO_OUT);
gpio_set(LCD_DISP_PIN);
gpio_set(BACKLIGHT_PIN);
}
else {
gpio_clear(BACKLIGHT_PIN);
}
}

View File

@ -27,7 +27,7 @@ Current hardware support:
| Ethernet | X | |
| USB OTG FS | X | |
| USB OTG HS | - | |
| TFT LCD | - | |
| TFT LCD | X | |
| Capacitive touch screen | - | |
| User microphones | - | |
| External Quad-SPI Flash | - | |

View File

@ -27,6 +27,36 @@
extern "C" {
#endif
/**
* @name LCD Backlight control defines
* @{
*/
#define BACKLIGHT_PIN GPIO_PIN(PORT_K, 3) /**< Backlight pin */
#define BACKLIGHT_MASK (1 << 3) /**< Backlight pin mask */
/** Set the backlight pin */
#define BACKLIGHT_ON (GPIOK->BSRR = BACKLIGHT_MASK)
/** Clear the backlight pin */
#define BACKLIGHT_OFF (GPIOK->BSRR = (BACKLIGHT_MASK << 16))
/** Toggle the backlight pin */
#define BACKLIGHT_TOGGLE (GPIOK->ODR ^= BACKLIGHT_MASK)
/** @} */
/**
* @name LCD display enable pin
* @{
*/
#define LCD_DISP_PIN GPIO_PIN(PORT_I, 12) /**< LCD screen enable pin */
/** @} */
/**
* @name LCD screen dimensions
* @{
*/
#define LCD_SCREEN_WIDTH 480 /**< LCD screen width */
#define LCD_SCREEN_HEIGHT 272 /**< LCD screen height */
/** @} */
/**
* @name User button
* @{

View File

@ -173,6 +173,62 @@ static const eth_conf_t eth_config = {
#define ETH_DMA_ISR isr_dma2_stream0
/** @} */
/**
* @name LTDC configuration
* @{
*/
/** LTDC static configuration struct */
static const ltdc_conf_t ltdc_config = {
.bus = APB2,
.rcc_mask = RCC_APB2ENR_LTDCEN,
.clk_pin = { .pin = GPIO_PIN(PORT_I, 14), .af = GPIO_AF14, },
.de_pin = { .pin = GPIO_PIN(PORT_K, 7), .af = GPIO_AF14, },
.hsync_pin = { .pin = GPIO_PIN(PORT_I, 10), .af = GPIO_AF14, },
.vsync_pin = { .pin = GPIO_PIN(PORT_I, 9), .af = GPIO_AF14, },
.r_pin = {
{ .pin = GPIO_PIN(PORT_I, 15), .af = GPIO_AF14, },
{ .pin = GPIO_PIN(PORT_J, 0), .af = GPIO_AF14, },
{ .pin = GPIO_PIN(PORT_J, 1), .af = GPIO_AF14, },
{ .pin = GPIO_PIN(PORT_J, 2), .af = GPIO_AF14, },
{ .pin = GPIO_PIN(PORT_J, 3), .af = GPIO_AF14, },
{ .pin = GPIO_PIN(PORT_J, 4), .af = GPIO_AF14, },
{ .pin = GPIO_PIN(PORT_J, 5), .af = GPIO_AF14, },
{ .pin = GPIO_PIN(PORT_J, 6), .af = GPIO_AF14, },
},
.g_pin = {
{ .pin = GPIO_PIN(PORT_J, 7), .af = GPIO_AF14, },
{ .pin = GPIO_PIN(PORT_J, 8), .af = GPIO_AF14, },
{ .pin = GPIO_PIN(PORT_J, 9), .af = GPIO_AF14, },
{ .pin = GPIO_PIN(PORT_J, 10), .af = GPIO_AF14, },
{ .pin = GPIO_PIN(PORT_J, 11), .af = GPIO_AF14, },
{ .pin = GPIO_PIN(PORT_K, 0), .af = GPIO_AF14, },
{ .pin = GPIO_PIN(PORT_K, 1), .af = GPIO_AF14, },
{ .pin = GPIO_PIN(PORT_K, 2), .af = GPIO_AF14, },
},
.b_pin = {
{ .pin = GPIO_PIN(PORT_E, 4), .af = GPIO_AF14, },
{ .pin = GPIO_PIN(PORT_J, 13), .af = GPIO_AF14, },
{ .pin = GPIO_PIN(PORT_J, 14), .af = GPIO_AF14, },
{ .pin = GPIO_PIN(PORT_J, 15), .af = GPIO_AF14, },
{ .pin = GPIO_PIN(PORT_G, 12), .af = GPIO_AF9, },
{ .pin = GPIO_PIN(PORT_K, 4), .af = GPIO_AF14, },
{ .pin = GPIO_PIN(PORT_K, 5), .af = GPIO_AF14, },
{ .pin = GPIO_PIN(PORT_K, 6), .af = GPIO_AF14, },
},
/* values below come from STM32CubeF7 code and differ from the typical
* values mentioned in the RK043FN48H datasheet. Both sets of values work
* with the display.
* See the discussion in https://community.st.com/s/question/0D50X0000BOvdWP/how-to-set-displays-parameters-
*/
.hsync = 41,
.vsync = 10,
.hbp = 13,
.hfp = 32,
.vbp = 2,
.vfp = 2,
};
/** @} */
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,96 @@
/*
* Copyright (C) 2021 Inria
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_stm32
* @{
*
* @file
* @brief LTDC CPU specific definitions for the STM32 family
*
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
*/
#ifndef PERIPH_CPU_LTDC_H
#define PERIPH_CPU_LTDC_H
#include <stdint.h>
#include "periph/cpu_gpio.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief LTDC GPIO configuration
*/
typedef struct {
gpio_t pin; /**< GPIO pin */
gpio_af_t af; /**< Alternate function */
} ltdc_gpio_t;
/**
* @brief LTDC Peripheral configuration
*/
typedef struct {
uint8_t bus; /**< APB bus */
uint32_t rcc_mask; /**< bit in clock enable register */
ltdc_gpio_t clk_pin; /**< CLK pin */
ltdc_gpio_t de_pin; /**< Data enable pin */
ltdc_gpio_t hsync_pin; /**< Horizontal synchronization pin */
ltdc_gpio_t vsync_pin; /**< Vertical synchronization pin */
ltdc_gpio_t r_pin[8]; /**< Red color pins */
ltdc_gpio_t g_pin[8]; /**< Green color pins */
ltdc_gpio_t b_pin[8]; /**< Blue color pins */
uint8_t hsync; /**< Horizontal synchronization */
uint8_t vsync; /**< Vertical synchronization */
uint8_t hbp; /**< Horizontal back porch */
uint8_t hfp; /**< Horizontal front porch */
uint8_t vbp; /**< Vertical back porch */
uint8_t vfp; /**< Vertical front porch */
} ltdc_conf_t;
/**
* @brief Initialize the LTDC (LCD-TFT Display Controller) peripheral
*/
void ltdc_init(void);
/**
* @brief Clear the LTDC display
*/
void ltdc_clear(void);
/**
* @brief Map a buffer of RGB565 (16bit depth) colors to the display
*
* @param[in] x1 horizontal start position
* @param[in] x2 horizontal end position (included)
* @param[in] y1 vertical start position
* @param[in] y2 vertical end position (included)
* @param[in] color the color buffer
*/
void ltdc_map(uint16_t x1, uint16_t x2, uint16_t y1, uint16_t y2, const uint16_t *color);
/**
* @brief Fill a region of the display with the same color
*
* @param[in] x1 horizontal start position
* @param[in] x2 horizontal end position (included)
* @param[in] y1 vertical start position
* @param[in] y2 vertical end position (included)
* @param[in] color the color value in RGB565 format (16bit depth)
*/
void ltdc_fill(uint16_t x1, uint16_t x2, uint16_t y1, uint16_t y2, const uint16_t color);
#ifdef __cplusplus
}
#endif
#endif /* PERIPH_CPU_LTDC_H */
/** @} */

View File

@ -63,6 +63,7 @@
#include "periph/cpu_eth.h"
#include "periph/cpu_gpio.h"
#include "periph/cpu_i2c.h"
#include "periph/cpu_ltdc.h"
#include "periph/cpu_pm.h"
#include "periph/cpu_pwm.h"
#include "periph/cpu_qdec.h"

View File

@ -34,3 +34,9 @@ config MODULE_PERIPH_ADC
select MODULE_ZTIMER if HAS_CPU_STM32F3 || HAS_CPU_STM32L4 || HAS_CPU_STM32WL
select MODULE_ZTIMER_MSEC if HAS_CPU_STM32F3 || HAS_CPU_STM32L4 || HAS_CPU_STM32WL
select MODULE_PERIPH_COMMON
config MODULE_PERIPH_LTDC
bool "LTDC peripheral driver"
depends on HAS_PERIPH_LTDC
help
STM32 LCD-TFT Display controller

255
cpu/stm32/periph/ltdc.c Normal file
View File

@ -0,0 +1,255 @@
/*
* Copyright (C) 2021 Inria
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_stm32
* @{
*
* @file
* @brief Low-level LTDC (LCD-TFT Display controller) driver implementation
*
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
*
* @}
*/
#include <assert.h>
#include <stdint.h>
#include <stdalign.h>
#include <string.h>
#include "cpu.h"
#include "board.h"
#include "periph/gpio.h"
#include "periph_conf.h"
#if IS_USED(MODULE_DISP_DEV)
#include "disp_dev.h"
#endif
#define ENABLE_DEBUG 0
#include "debug.h"
#ifndef LCD_SCREEN_WIDTH
#define LCD_SCREEN_WIDTH 480
#endif
#ifndef LCD_SCREEN_HEIGHT
#define LCD_SCREEN_HEIGHT 272
#endif
#define LTDC_BLENDING_FACTOR1_CA 0x00000400U
#define LTDC_BLENDING_FACTOR2_CA 0x00000005U
typedef struct {
uint32_t hsync;
uint32_t vsync;
uint32_t acc_hbp;
uint32_t acc_vbp;
uint32_t acc_active_h;
uint32_t acc_active_w;
uint32_t height;
uint32_t width;
} ltdc_display_conf_t;
/* allocate array of 16bit pixels for the framebuffer (TODO: use external SRAM via FMC) */
static uint16_t _ltdc_frame_buffer[LCD_SCREEN_WIDTH * LCD_SCREEN_HEIGHT];
static void _init_gpio(void)
{
gpio_init(ltdc_config.clk_pin.pin, GPIO_OUT);
gpio_init_af(ltdc_config.clk_pin.pin, ltdc_config.clk_pin.af);
gpio_init(ltdc_config.de_pin.pin, GPIO_OUT);
gpio_init_af(ltdc_config.de_pin.pin, ltdc_config.de_pin.af);
gpio_init(ltdc_config.hsync_pin.pin, GPIO_OUT);
gpio_init_af(ltdc_config.hsync_pin.pin, ltdc_config.hsync_pin.af);
gpio_init(ltdc_config.vsync_pin.pin, GPIO_OUT);
gpio_init_af(ltdc_config.vsync_pin.pin, ltdc_config.vsync_pin.af);
for (uint8_t pin = 0; pin < 8; ++pin) {
if (!gpio_is_valid(ltdc_config.r_pin[pin].pin)) {
continue;
}
gpio_init(ltdc_config.r_pin[pin].pin, GPIO_OUT);
gpio_init_af(ltdc_config.r_pin[pin].pin, ltdc_config.r_pin[pin].af);
gpio_init(ltdc_config.g_pin[pin].pin, GPIO_OUT);
gpio_init_af(ltdc_config.g_pin[pin].pin, ltdc_config.g_pin[pin].af);
gpio_init(ltdc_config.b_pin[pin].pin, GPIO_OUT);
gpio_init_af(ltdc_config.b_pin[pin].pin, ltdc_config.b_pin[pin].af);
}
}
static void _configure_ltdc(void)
{
uint32_t tmp;
const ltdc_display_conf_t ltdc_display_config = {
.hsync = ltdc_config.hsync - 1,
.vsync = ltdc_config.vsync - 1,
.acc_hbp = ltdc_config.hsync + ltdc_config.hbp - 1,
.acc_vbp = ltdc_config.vsync + ltdc_config.vbp - 1,
.acc_active_h = LCD_SCREEN_HEIGHT + ltdc_config.vsync + ltdc_config.vbp - 1,
.acc_active_w = LCD_SCREEN_WIDTH + ltdc_config.hsync + ltdc_config.hbp - 1,
.height = LCD_SCREEN_HEIGHT + ltdc_config.vsync + ltdc_config.vbp + ltdc_config.vfp - 1,
.width = LCD_SCREEN_WIDTH + ltdc_config.hsync + ltdc_config.hbp + ltdc_config.hfp - 1,
};
/* Configure the HS, VS, DE and PC polarity: all active low*/
LTDC->GCR &= ~(LTDC_GCR_HSPOL | LTDC_GCR_VSPOL | LTDC_GCR_DEPOL | LTDC_GCR_PCPOL);
/* Set Synchronization size */
LTDC->SSCR &= ~(LTDC_SSCR_VSH | LTDC_SSCR_HSW);
tmp = (ltdc_display_config.hsync << 16U);
LTDC->SSCR |= (tmp | ltdc_display_config.vsync);
/* Set Accumulated Back porch */
LTDC->BPCR &= ~(LTDC_BPCR_AVBP | LTDC_BPCR_AHBP);
tmp = (ltdc_display_config.acc_hbp << 16U);
LTDC->BPCR |= (tmp | ltdc_display_config.acc_vbp);
/* Set Accumulated Active Width */
LTDC->AWCR &= ~(LTDC_AWCR_AAH | LTDC_AWCR_AAW);
tmp = (ltdc_display_config.acc_active_w << 16U);
LTDC->AWCR |= (tmp | ltdc_display_config.acc_active_h);
/* Set Total Width */
LTDC->TWCR &= ~(LTDC_TWCR_TOTALH | LTDC_TWCR_TOTALW);
tmp = (ltdc_display_config.width << 16U);
LTDC->TWCR |= (tmp | ltdc_display_config.height);
/* Set the background color value: black */
LTDC->BCCR &= ~(LTDC_BCCR_BCBLUE | LTDC_BCCR_BCGREEN | LTDC_BCCR_BCRED);
/* Enable LTDC */
LTDC->GCR |= LTDC_GCR_LTDCEN;
}
static void _configure_ltdc_layer(void)
{
uint32_t tmp;
/* Configure the horizontal start and stop position */
tmp = ((LCD_SCREEN_WIDTH + ((LTDC->BPCR & LTDC_BPCR_AHBP) >> 16U)) << 16U);
LTDC_Layer1->WHPCR &= ~(LTDC_LxWHPCR_WHSTPOS | LTDC_LxWHPCR_WHSPPOS);
LTDC_Layer1->WHPCR = ((0 + ((LTDC->BPCR & LTDC_BPCR_AHBP) >> 16U) + 1U) | tmp);
/* Configure the vertical start and stop position */
tmp = ((LCD_SCREEN_HEIGHT + (LTDC->BPCR & LTDC_BPCR_AVBP)) << 16U);
LTDC_Layer1->WVPCR &= ~(LTDC_LxWVPCR_WVSTPOS | LTDC_LxWVPCR_WVSPPOS);
LTDC_Layer1->WVPCR = ((0 + (LTDC->BPCR & LTDC_BPCR_AVBP) + 1U) | tmp);
/* Set the pixel format: RGB565 (16bit) */
LTDC_Layer1->PFCR &= ~(LTDC_LxPFCR_PF);
LTDC_Layer1->PFCR = 2;
/* Configure the default color values: all black */
LTDC_Layer1->DCCR &= ~(LTDC_LxDCCR_DCBLUE | LTDC_LxDCCR_DCGREEN | LTDC_LxDCCR_DCRED | LTDC_LxDCCR_DCALPHA);
/* Set the constant alpha value: fully opaque */
LTDC_Layer1->CACR &= ~(LTDC_LxCACR_CONSTA);
LTDC_Layer1->CACR = 255;
/* Set the blending factors */
LTDC_Layer1->BFCR &= ~(LTDC_LxBFCR_BF2 | LTDC_LxBFCR_BF1);
LTDC_Layer1->BFCR = (LTDC_BLENDING_FACTOR1_CA | LTDC_BLENDING_FACTOR2_CA);
/* Configure the color frame buffer start address */
LTDC_Layer1->CFBAR &= ~(LTDC_LxCFBAR_CFBADD);
LTDC_Layer1->CFBAR = (uint32_t)_ltdc_frame_buffer;
/* Configure the color frame buffer pitch in byte */
LTDC_Layer1->CFBLR &= ~(LTDC_LxCFBLR_CFBLL | LTDC_LxCFBLR_CFBP);
LTDC_Layer1->CFBLR = (((LCD_SCREEN_WIDTH * 2) << 16U) | ((LCD_SCREEN_WIDTH * 2) + 3U));
/* Configure the frame buffer line number */
LTDC_Layer1->CFBLNR &= ~(LTDC_LxCFBLNR_CFBLNBR);
LTDC_Layer1->CFBLNR = LCD_SCREEN_HEIGHT;
/* Enable LTDC_Layer by setting LEN bit */
LTDC_Layer1->CR |= (uint32_t)LTDC_LxCR_LEN;
}
void ltdc_init(void)
{
DEBUG("[ltdc] init: initializing device\n");
periph_clk_en(ltdc_config.bus, ltdc_config.rcc_mask);
_init_gpio();
_configure_ltdc();
_configure_ltdc_layer();
}
void ltdc_clear(void)
{
memset(_ltdc_frame_buffer, 0, LCD_SCREEN_WIDTH * LCD_SCREEN_HEIGHT * sizeof(uint16_t));
LTDC->SRCR = LTDC_SRCR_IMR;
}
void ltdc_map(uint16_t x1, uint16_t x2, uint16_t y1, uint16_t y2, const uint16_t *color)
{
for (uint16_t y = y1; y <= y2; y++) {
for (uint16_t x = x1; x <= x2; x++) {
*(_ltdc_frame_buffer + (x + y * LCD_SCREEN_WIDTH)) = *color++;
}
}
LTDC->SRCR = LTDC_SRCR_IMR;
}
void ltdc_fill(uint16_t x1, uint16_t x2, uint16_t y1, uint16_t y2, const uint16_t color)
{
for (uint16_t y = y1; y <= y2; y++) {
for (uint16_t x = x1; x <= x2; x++) {
*(_ltdc_frame_buffer + (x + y * LCD_SCREEN_WIDTH)) = color;
}
}
LTDC->SRCR = LTDC_SRCR_IMR;
}
#if IS_USED(MODULE_DISP_DEV)
static void _ltdc_map(const disp_dev_t *disp_dev, uint16_t x1, uint16_t x2,
uint16_t y1, uint16_t y2, const uint16_t *color)
{
(void)disp_dev;
ltdc_map(x1, x2, y1, y2, color);
}
static uint16_t _ltdc_height(const disp_dev_t *disp_dev)
{
(void)disp_dev;
return LCD_SCREEN_HEIGHT;
}
static uint16_t _ltdc_width(const disp_dev_t *disp_dev)
{
(void)disp_dev;
return LCD_SCREEN_WIDTH;
}
static uint8_t _ltdc_color_depth(const disp_dev_t *disp_dev)
{
(void)disp_dev;
return 16;
}
static void _ltdc_set_invert(const disp_dev_t *disp_dev, bool invert)
{
(void)disp_dev;
(void)invert;
}
const disp_dev_driver_t stm32_ltdc_disp_dev_driver = {
.map = _ltdc_map,
.height = _ltdc_height,
.width = _ltdc_width,
.color_depth = _ltdc_color_depth,
.set_invert = _ltdc_set_invert,
};
#endif

View File

@ -92,6 +92,13 @@
#error No suitable 48MHz found, USB will not work
#endif
/* PLLSAI is enabled when LTDC is used */
#if IS_USED(MODULE_PERIPH_LTDC)
#define CLOCK_REQUIRE_PLLSAIR 1
#else
#define CLOCK_REQUIRE_PLLSAIR 0
#endif
/* PLLI2S configuration: the following parameters configure a 48MHz I2S clock
with HSE (8MHz) or HSI (16MHz) as PLL input clock */
#ifndef CONFIG_CLOCK_PLLI2S_M
@ -175,7 +182,7 @@
#define CONFIG_CLOCK_PLLSAI_Q (8) /* SAI clock, 48MHz by default */
#endif
#ifndef CONFIG_CLOCK_PLLSAI_R
#define CONFIG_CLOCK_PLLSAI_R (8) /* LCD clock, 48MHz by default */
#define CONFIG_CLOCK_PLLSAI_R (4) /* LCD clock, 48MHz by default */
#endif
#if defined(RCC_PLLSAICFGR_PLLSAIM_Pos)
@ -455,7 +462,7 @@
#endif
/* Check whether PLLSAI must be enabled */
#if IS_ACTIVE(CLOCK_REQUIRE_PLLSAIP)
#if IS_ACTIVE(CLOCK_REQUIRE_PLLSAIP) || IS_ACTIVE(CLOCK_REQUIRE_PLLSAIR)
#define CLOCK_ENABLE_PLLSAI 1
#else
#define CLOCK_ENABLE_PLLSAI 0
@ -556,6 +563,20 @@ void stmclk_init_sysclk(void)
}
#endif
#if defined(RCC_DCKCFGR1_PLLSAIDIVR)
if (IS_USED(MODULE_PERIPH_LTDC)) {
RCC->DCKCFGR1 &= ~RCC_DCKCFGR1_PLLSAIDIVR;
RCC->DCKCFGR1 |= RCC_DCKCFGR1_PLLSAIDIVR_0; /* Divide by 4 */
}
#endif
#if defined(RCC_DCKCFGR_PLLSAIDIVR)
if (IS_USED(MODULE_PERIPH_LTDC)) {
RCC->DCKCFGR &= ~RCC_DCKCFGR_PLLSAIDIVR;
RCC->DCKCFGR |= RCC_DCKCFGR_PLLSAIDIVR_0; /* Divide by 4 */
}
#endif
#if defined(RCC_CR_PLLSAION)
if (IS_ACTIVE(CLOCK_ENABLE_PLLSAI)) {
RCC->PLLSAICFGR = (PLLSAI_M | PLLSAI_N | PLLSAI_P | PLLSAI_Q | PLLSAI_R);

View File

@ -206,6 +206,12 @@ config HAS_PERIPH_LPUART
help
Indicates that a low-power UART peripheral is present.
config HAS_PERIPH_LTDC
bool
select MODULE_PERIPH_LTDC if MODULE_DISP_DEV
help
Indicates that a LTDC peripheral is present.
config HAS_PERIPH_MCG
bool
help

View File

@ -22,6 +22,7 @@ extern "C" {
#endif
#include <stdint.h>
#include "kernel_defines.h"
#include "lvgl_riot_conf.h"
/*====================
@ -50,7 +51,11 @@ extern "C" {
/* Swap the 2 bytes of RGB565 color.
* Useful if the display has a 8 bit interface (e.g. SPI)*/
#ifndef LV_COLOR_16_SWAP
#if IS_USED(MODULE_ILI9341)
#define LV_COLOR_16_SWAP 1
#else
#define LV_COLOR_16_SWAP 0
#endif
#endif
/* 1: Enable screen transparency.

View File

@ -0,0 +1,44 @@
/*
* Copyright (C) 2021 Inria
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_auto_init
* @{
* @file
* @brief initializes LTDC peripheral display device
*
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
* @}
*/
#include <assert.h>
#include <stddef.h>
#include "log.h"
#include "disp_dev.h"
#include "periph_cpu.h"
static disp_dev_reg_t _disp_dev_reg;
static disp_dev_t _disp_dev;
extern const disp_dev_driver_t stm32_ltdc_disp_dev_driver;
void auto_init_periph_ltdc(void)
{
LOG_DEBUG("[auto_init_screen] initializing LTDC periph\n");
ltdc_init();
_disp_dev_reg.dev = &_disp_dev;
_disp_dev_reg.screen_id = 0;
_disp_dev_reg.dev->driver = &stm32_ltdc_disp_dev_driver;
/* add to disp_dev registry */
disp_dev_reg_add(&_disp_dev_reg);
}

View File

@ -29,6 +29,10 @@ void auto_init_screen(void)
extern void auto_init_ili9341(void);
auto_init_ili9341();
}
if (IS_USED(MODULE_PERIPH_LTDC)) {
extern void auto_init_periph_ltdc(void);
auto_init_periph_ltdc();
}
}
if (IS_USED(MODULE_TOUCH_DEV)) {

View File

@ -20,6 +20,7 @@
#include <stdio.h>
#include "board.h"
#include "disp_dev.h"
#include "riot_logo.h"
@ -30,7 +31,11 @@
#include "ili9341.h"
#endif
#ifdef LCD_SCREEN_WIDTH
#define DISPLAY_BUFFER_MAX_SIZE (LCD_SCREEN_WIDTH)
#else
#define DISPLAY_BUFFER_MAX_SIZE (320)
#endif
static uint16_t display_buffer[DISPLAY_BUFFER_MAX_SIZE] = { 0 };
int main(void)

View File

@ -0,0 +1,9 @@
BOARD ?= stm32f746g-disco
include ../Makefile.tests_common
FEATURES_REQUIRED += periph_ltdc
USEMODULE += ztimer
USEMODULE += ztimer_msec
include $(RIOTBASE)/Makefile.include

98
tests/periph_ltdc/main.c Normal file
View File

@ -0,0 +1,98 @@
/*
* Copyright (C) 2021 Inria
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup tests
* @{
*
* @file
* @brief Test application for the LCD-TFT display controller
*
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
*
* @}
*/
#include <stdio.h>
#include "timex.h"
#include "ztimer.h"
#include "board.h"
#include "periph_cpu.h"
#include "riot_logo.h"
#define RECT_WIDTH 200
#define RECT_HEIGHT 100
#define PICTURE_WIDTH 128
#define PICTURE_HEIGHT 69
int main(void)
{
ltdc_init();
ltdc_fill(0, RECT_WIDTH, 0, RECT_HEIGHT, 0xf800); /* top left red rectangle */
ztimer_sleep(ZTIMER_MSEC, MS_PER_SEC);
ltdc_clear();
ltdc_fill( /* middle green rectangle */
(LCD_SCREEN_WIDTH - RECT_WIDTH) >> 1, (LCD_SCREEN_WIDTH + RECT_WIDTH) >> 1,
(LCD_SCREEN_HEIGHT - RECT_HEIGHT) >> 1, (LCD_SCREEN_HEIGHT + RECT_HEIGHT) >> 1,
0x07e0
);
ztimer_sleep(ZTIMER_MSEC, MS_PER_SEC);
ltdc_clear();
ltdc_fill( /* bottom right blue rectangle */
LCD_SCREEN_WIDTH - RECT_WIDTH, LCD_SCREEN_WIDTH - 1,
LCD_SCREEN_HEIGHT - RECT_HEIGHT, LCD_SCREEN_HEIGHT - 1,
0x001f
);
ztimer_sleep(ZTIMER_MSEC, MS_PER_SEC);
ltdc_clear();
/* Display the RIOT logo in all 4 screen corners */
ltdc_map(
0, PICTURE_WIDTH - 1, 0, PICTURE_HEIGHT - 1,
(const uint16_t *)picture
);
ztimer_sleep(ZTIMER_MSEC, MS_PER_SEC);
ltdc_clear();
ltdc_map(
LCD_SCREEN_WIDTH - PICTURE_WIDTH, LCD_SCREEN_WIDTH - 1, 0, PICTURE_HEIGHT - 1,
(const uint16_t *)picture
);
ztimer_sleep(ZTIMER_MSEC, MS_PER_SEC);
ltdc_clear();
ltdc_map(
LCD_SCREEN_WIDTH - PICTURE_WIDTH, LCD_SCREEN_WIDTH - 1,
LCD_SCREEN_HEIGHT - PICTURE_HEIGHT, LCD_SCREEN_HEIGHT - 1,
(const uint16_t *)picture
);
ztimer_sleep(ZTIMER_MSEC, MS_PER_SEC);
ltdc_clear();
ltdc_map(
0, PICTURE_WIDTH - 1, LCD_SCREEN_HEIGHT - PICTURE_HEIGHT, LCD_SCREEN_HEIGHT - 1,
(const uint16_t *)picture
);
ztimer_sleep(ZTIMER_MSEC, MS_PER_SEC);
ltdc_clear();
/* Display the RIOT logo in the center of the screen */
ltdc_map(
((LCD_SCREEN_WIDTH - PICTURE_WIDTH) >> 1), ((LCD_SCREEN_WIDTH + PICTURE_WIDTH) >> 1) - 1,
((LCD_SCREEN_HEIGHT - PICTURE_HEIGHT) >> 1), ((LCD_SCREEN_HEIGHT + PICTURE_HEIGHT) >> 1) - 1,
(const uint16_t *)picture
);
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -7,4 +7,4 @@ config APPLICATION
config BOARD_HAS_DISPLAY
bool
default y
depends on BOARD_PINETIME || BOARD_ADAFRUIT_CLUE || BOARD_STM32F429I_DISC1 || BOARD_STM32F429I_DISCO || BOARD_ESP32_WROVER_KIT
depends on BOARD_PINETIME || BOARD_ADAFRUIT_CLUE || BOARD_STM32F429I_DISC1 || BOARD_STM32F429I_DISCO || BOARD_STM32F746G_DISCO || BOARD_ESP32_WROVER_KIT

View File

@ -1,4 +1,4 @@
# Boards with a screen can use disp_dev
ifneq (,$(filter stm32f429i-disc% pinetime adafruit-clue esp32-wrover-kit,$(BOARD)))
ifneq (,$(filter stm32f429i-disc% stm32f746g-disco pinetime adafruit-clue esp32-wrover-kit,$(BOARD)))
USEMODULE += disp_dev
endif

View File

@ -42,7 +42,11 @@ static uint8_t qr0[qrcodegen_BUFFER_LEN_FOR_VERSION(ENCODER_VERSION)];
static uint8_t buffer[qrcodegen_BUFFER_LEN_FOR_VERSION(ENCODER_VERSION)];
#ifdef MODULE_DISP_DEV
#ifdef LCD_SCREEN_WIDTH
#define DISPLAY_BUFFER_MAX_SIZE (LCD_SCREEN_WIDTH)
#else
#define DISPLAY_BUFFER_MAX_SIZE (320)
#endif
static uint16_t display_buffer[DISPLAY_BUFFER_MAX_SIZE] = { 0 };
#endif