在 ALIENTEK 阿波罗STM32H743开发板上使用 openvela 运行LVGL示例

一、概述

本指南(参考在 STM32H750 上部署 openvela)将引导您在 ALIENTEK 阿波罗STM32H743开发板上,基于 openvela 实时操作系统,运行 Light and Versatile Graphics Library(LVGL)图形库的演示程序(Demo)。

说明:本文使用的RGBLCD 模块型号为 ATK-7016(7 寸,1024*600),采用GT911电容触控方案。

二、准备工作

在开始之前,请确保您已完成以下准备工作:

  1. 获取源码:参考文档快速入门下载最新代码。

    注意:请下载dev分支的代码,因为trunk分支的代码中未给STM32H7开启双缓冲。

    在这里插入图片描述

  2. 了解 openvela 架构:建议您预先阅读 openvela 架构以理解其分层设计。

  3. 查阅系统启动流程文档,获取更详细的启动时序和函数调用关系图。

  4. 准备好硬件及配套软件

三、创建代码目录结构

首先,在nuttx/boards/arm/stm32h7/目录下,创建一个名为 apollo-stm32h743i的新目录,并建立如下的子目录和文件结构。
代码路径: nuttx/boards/arm/stm32h7/apollo-stm32h743i/

apollo-stm32h743i
├── CMakeLists.txt
├── configs                           # defconfig 配置路径
│   └── lvgl
│       └── defconfig                 # LVGL示例的默认配置
├── include
│   └── board.h                       # 板级硬件配置头文件
├── Kconfig                           # 板级 Kconfig 配置文件
├── scripts                           # 链接脚本
│   ├── flash.script                  # 链接器脚本
│   └── Make.defs                     # 板级 Make 定义
└── src
    ├── CMakeLists.txt
    ├── Make.defs
    ├── stm32_appinit.c               # 实现 board_app_initialize
    ├── stm32_autoleds.c              # 实现系统状态 LED 控制
    ├── stm32_userleds.c              # 实现用户层 LED 驱动接口
    ├── stm32_buttons.c               # 实现按键驱动接口
    ├── stm32_boot.c                  # 实现 stm32_boardinitialize
    ├── stm32_bringup.c               # 实现驱动初始化
    ├── stm32_touchscreen.c			  # 实现触摸屏驱动接口
    ├── stm32_lcd.c			  		  # 实现LTDC LCD(RGB屏)驱动接口
    ├── ct_i2c.h			  		  # 
    ├── ct_i2c.c			  		  # 实现IIC驱动(软件模拟)
    ├── gt9xx.h			  			  # 
    ├── gt9xx.c			  			  # 实现gt911触控驱动
    └── apollo_stm32h743i.h           # 板级私有头文件

四、集成到构建系统

1、Kconfig 集成

Kconfig 用于管理内核和应用的功能配置。您需要执行以下三步来集成新板。

nuttx/boards/Kconfig 中定义板级选项:

添加一个新的 config 条目,用于在配置菜单中显示您的开发板。

config ARCH_BOARD_APOLLO_STM32H743I
	bool "ATK APOLLO-STM32H743I board"
	depends on ARCH_CHIP_STM32H743II
	select ARCH_HAVE_LEDS
	select ARCH_HAVE_BUTTONS
	select ARCH_HAVE_IRQBUTTONS
	---help---
		ATK Apollo-H743I board based on the STMicro STM32H743IIT6 MCU.
nuttx/boards/Kconfig 中设置默认板名:

当选中您的板型时,让 ARCH_BOARD 变量自动设置为您的 BSP 目录名。

config ARCH_BOARD
    string
    # ... 其他板的 default 设置 ...
    default "apollo-stm32h743i"      if ARCH_BOARD_APOLLO_H743I
nuttx/boards/Kconfig 中加载板级 Kconfig 文件:

确保选中您的板型时,会加载 BSP 目录下的 Kconfig 文件。

if ARCH_BOARD_APOLLO_DISCO
source "boards/arm/stm32h7/apollo-stm32h743i/Kconfig"
endif
在 ``nuttx/boards/arm/stm32h7/apollo-stm32h743i/Kconfig` 文件中可以添加此开发板特有的配置选项。
#
# For a description of the syntax of this configuration file,
# see the file kconfig-language.txt in the NuttX tools repository.
#

if ARCH_BOARD_APOLLO_STM32H743I

config APOLLO_STM32H743I_CT_I2C
	bool "enable CT_I2C"
	default n

menuconfig APOLLO_STM32H743I_ATK7016
	bool "LCD driver for ATK7016 Liquid Crystal Display Controller"
	default n
	---help---
		Enables  support for a connected display based on ATK7016 LCD Single Chip
		Driver.

if APOLLO_STM32H743I_ATK7016

choice
	prompt "TouchScreen Interface Type"
	default APOLLO_STM32H743I_ATK7016_GT911 if APOLLO_STM32H743I_CT_I2C

config APOLLO_STM32H743I_ATK7016_GT911
	bool "Enable support for nuttx touchscreen interface"
	depends on APOLLO_STM32H743I_CT_I2C
	---help---
		Enable lcd driver support for the nuttx touchscreen interface to displaying
		data via CT_I2C of the stm32h743i mcu.

endchoice # TouchScreen Interface Type

if APOLLO_STM32H743I_ATK7016_GT911

config GT9XX_NPOLLWAITERS
	int "Number of waiters to poll"
	default 1
	---help---
		Maximum number of threads that can be waiting on poll()

config GT9XX_I2C_FREQUENCY
	int "I2C frequency (Hz)"
	default 400000
	---help---
		I2C frequency in Hz

config GT9XX_POLLMODE
	bool "Polled mode"
	default y
	---help---
		Run the FGT9XX in a non-interrupt driven polled mode.  Events will
		not be driven by interrupts but rather based on a timed poll.

		This is a non-optimal design both because (1) it will lead to delays
		in detecting touch related events and (2) it will consume a
		significant amount of CPU time to perform the polling.

config GT9XX_SINGLEPOINT
	bool "Single point"
	default y
	---help---
		Do no report multi-touch events

endif # INPUT_GT9XX

choice
	prompt "LCD Interface Type"
	default APOLLO_STM32H743I_ATK7016_FBIFACE if STM32H7_LTDC

config APOLLO_STM32H743I_ATK7016_FBIFACE
	bool "Enable support for nuttx framebuffer interface"
	depends on STM32H7_LTDC
	---help---
		Enable lcd driver support for the nuttx framebuffer interface to displaying
		data via ltdc controller of the stm32h743i mcu.

endchoice # LCD Interface Type

if APOLLO_STM32H743I_ATK7016_FBIFACE

choice
	prompt "LCD Orientation"
	default APOLLO_STM32H743I_ATK7016_FBIFACE_LANDSCAPE
	---help---
		Configure display orientation.

config APOLLO_STM32H743I_ATK7016_FBIFACE_LANDSCAPE
	bool "Landscape orientation"
	---help---
		Define for "landscape" orientation support.

config APOLLO_STM32H743I_ATK7016_FBIFACE_PORTRAIT
	bool "Portrait orientation"
	---help---
		Define for "portrait" orientation support.

config APOLLO_STM32H743I_ATK7016_FBIFACE_RLANDSCAPE
	bool "Reverse landscape orientation"
	---help---
		Define for "reverse landscape" orientation support.

config APOLLO_STM32H743I_ATK7016_FBIFACE_RORTRAIT
	bool "Reverse portrait display"
	---help---
		Define for "reverse portrait" orientation support.

endchoice # LCD Interface Orientation

endif # APOLLO_STM32H743I_ATK7016_FBIFACE
endif # APOLLO_STM32H743I_ATK7016

endif # ARCH_BOARD_APOLLO_STM32H743I

2、创建默认配置 (defconfig)

defconfig 文件是一个最小化的系统配置集合,为用户提供了一个开箱即用的配置起点。

创建 nuttx/boards/arm/stm32h7/apollo-stm32h743i/configs/lvgl/deconfig 如下:

#
# This file is autogenerated: PLEASE DO NOT EDIT IT.
#
# You can use "make menuconfig" to make any modifications to the installed .config file.
# You can then do "make savedefconfig" to generate a new defconfig file that includes your
# modifications.
#
CONFIG_ALLOW_BSD_COMPONENTS=y
CONFIG_APOLLO_STM32H743I_ATK7016=y
CONFIG_APOLLO_STM32H743I_CT_I2C=y
CONFIG_ARCH="arm"
CONFIG_ARCH_BOARD="apollo-stm32h743i"
CONFIG_ARCH_BOARD_APOLLO_STM32H743I=y
CONFIG_ARCH_CHIP="stm32h7"
CONFIG_ARCH_CHIP_STM32H743II=y
CONFIG_ARCH_CHIP_STM32H7=y
CONFIG_ARCH_CHIP_STM32H7_CORTEXM7=y
CONFIG_ARCH_STACKDUMP=y
CONFIG_ARMV7M_DCACHE=y
CONFIG_ARMV7M_DCACHE_WRITETHROUGH=y
CONFIG_ARMV7M_DTCM=y
CONFIG_ARMV7M_ICACHE=y
CONFIG_ARM_MPU=y
CONFIG_BOARD_LATE_INITIALIZE=y
CONFIG_BOARD_LOOPSPERMSEC=43103
CONFIG_BUILTIN=y
CONFIG_DEBUG_SYMBOLS=y
CONFIG_DRIVERS_VIDEO=y
CONFIG_EXAMPLES_FB=y
CONFIG_EXAMPLES_LVGLDEMO=y
CONFIG_EXAMPLES_TOUCHSCREEN=y
CONFIG_FS_PROCFS=y
CONFIG_GRAPHICS_LVGL=y
CONFIG_HAVE_CXX=y
CONFIG_HAVE_CXXINITIALIZE=y
CONFIG_INIT_ENTRYPOINT="nsh_main"
CONFIG_INPUT=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_INTELHEX_BINARY=y
CONFIG_LV_DEF_REFR_PERIOD=5
CONFIG_LV_NUTTX_VSYNC_TIMER_PERIOD=5
CONFIG_LV_USE_CLIB_MALLOC=y
CONFIG_LV_USE_CLIB_SPRINTF=y
CONFIG_LV_USE_CLIB_STRING=y
CONFIG_LV_USE_DEMO_WIDGETS=y
CONFIG_LV_USE_LOG=y
CONFIG_LV_USE_NUTTX=y
CONFIG_LV_USE_NUTTX_TOUCHSCREEN=y
CONFIG_LV_USE_PERF_MONITOR=y
CONFIG_LV_USE_SYSMON=y
CONFIG_MM_HEAP_MEMPOOL_THRESHOLD=0
CONFIG_MM_REGIONS=5
CONFIG_MQ_MAXMSGSIZE=256
CONFIG_NSH_ARCHINIT=y
CONFIG_NSH_BUILTIN_APPS=y
CONFIG_NSH_DISABLE_IFUPDOWN=y
CONFIG_NSH_FILEIOSIZE=512
CONFIG_NSH_READLINE=y
CONFIG_PREALLOC_TIMERS=4
CONFIG_RAM_SIZE=524288
CONFIG_RAM_START=0x24000000
CONFIG_RAW_BINARY=y
CONFIG_RR_INTERVAL=200
CONFIG_SCHED_HPWORK=y
CONFIG_SCHED_WAITPID=y
CONFIG_START_DAY=6
CONFIG_START_MONTH=12
CONFIG_START_YEAR=2011
CONFIG_STM32H7_DMA1=y
CONFIG_STM32H7_DMA2=y
CONFIG_STM32H7_FMC=y
CONFIG_STM32H7_HSEM=y
CONFIG_STM32H7_LTDC=y
CONFIG_STM32H7_LTDC_FB_BASE=0xC0000000
CONFIG_STM32H7_LTDC_FB_SIZE=4096000
CONFIG_STM32H7_USART1=y
CONFIG_SYSTEM_NSH=y
CONFIG_USART1_SERIAL_CONSOLE=y
CONFIG_VIDEO_FB=y
  • 根据《STM32H743开发指南 V1.2》(下载地址:STM32H743阿波罗开发板V2 — 正点原子资料下载中心 1.0.0 文档第五十二章 内存管理实验表52.1.1 STM32H7内存分配表 ,设置

    CONFIG_RAM_START = 0x24000000 (AXI内存起始地址)

    CONFIG_RAM_SIZE= 524288 (AXI内存大小,512KB)

  • 根据《STM32H743开发指南 V1.2》 第二十六章 SDRAM实验图25.1.3.3 FMC存储块地址映像 可知,阿波罗STM32H743开发板板载了一颗32M字节容量的SDRAM芯片:W9825G6KH,挂载于SDRAM Bank1。将LTDC的帧缓存数组的地址定向到SDRAM的首地址,因此有:CONFIG_STM32H7_LTDC_FB_BASE=0xC0000000。选择STM32H7 的 LTDC 最大可以支持分辨率 1280*800 ,颜色格式RGB565,单层,全尺寸双缓冲,因此有:CONFIG_STM32H7_LTDC_FB_SIZE = 1280*800*2*1*2 = 4096000

五、代码实现步骤

1、定义硬件宏

src/apollo_stm32h743i.hinclude/board.h 中定义相关的硬件宏。

apollo_stm32h743i.h:板级私有定义

参考boards/arm/stm32h7/stm32h750b-dk/src/stm32h750b-dk.h

/****************************************************************************
 * boards/arm/stm32h7/apollo-stm32h743i/src/apollo_stm32h743i.h
 ****************************************************************************/

#ifndef __BOARDS_ARM_STM32H7_APOLLO_STM32H743I_SRC_APOLLO_STM32H743I_H
#define __BOARDS_ARM_STM32H7_APOLLO_STM32H743I_SRC_APOLLO_STM32H743I_H

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/config.h>
#include <nuttx/compiler.h>

#include <stdint.h>

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

/* Configuration ************************************************************/

#define HAVE_USBDEV     1
#define HAVE_USBHOST    1
#define HAVE_USBMONITOR 1

/* Can't support USB host or device features if USB OTG FS is not enabled */

#ifndef CONFIG_STM32H7_OTGFS
#  undef HAVE_USBDEV
#  undef HAVE_USBHOST
#endif

/* Can't support USB device if USB device is not enabled */

#ifndef CONFIG_USBDEV
#  undef HAVE_USBDEV
#endif

/* Can't support USB host is USB host is not enabled */

#ifndef CONFIG_USBHOST
#  undef HAVE_USBHOST
#endif

/* Check if we should enable the USB monitor before starting NSH */

#ifndef CONFIG_USBMONITOR
#  undef HAVE_USBMONITOR
#endif

#ifndef HAVE_USBDEV
#  undef CONFIG_USBDEV_TRACE
#endif

#if !defined(CONFIG_USBDEV_TRACE) && !defined(CONFIG_USBHOST_TRACE)
#  undef HAVE_USBMONITOR
#endif

/* APOLLO STM32H743I GPIOs ************************************************/

/* LED. 
 *       User LED1: the green LED is a user LED connected to board LED DS1
 * corresponding to MCU I/O PB0.
 *       User LED2: the red LED is a user LED connected to board LED DS0
 * corresponding to MCU I/O PB1.
 *
 * - When the I/O is HIGH value, the LED is on.
 * - When the I/O is LOW, the LED is off.
 */

#define GPIO_LED_RED       (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_PULLUP|GPIO_SPEED_50MHz|\
                            GPIO_OUTPUT_SET|GPIO_PORTB|GPIO_PIN1)
#define GPIO_LED_GREEN     (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_PULLUP|GPIO_SPEED_50MHz|\
                            GPIO_OUTPUT_SET|GPIO_PORTB|GPIO_PIN0)

/* BUTTONS -- NOTE that all have EXTI interrupts configured */
/*
 *        KEY0 : the KEY0 button is connected to the I/O PH3 of the STM32, PULLUP
 *        KEY1 : the KEY1 button is connected to the I/O PH2 of the STM32, PULLUP
 *        KEY2 : the KEY2 button is connected to the I/O PC13 of the STM32, PULLUP
 *        KEY3 : the KEY3 button is connected to the I/O PA0 of the STM32, PULLDOWM
 *
 */

#define MIN_IRQBUTTON   BUTTON_KEY0
#define MAX_IRQBUTTON   BUTTON_KEY3
#define NUM_IRQBUTTONS  4

#define GPIO_BTN_KEY0   (GPIO_INPUT|GPIO_PULLUP|GPIO_SPEED_50MHz|GPIO_EXTI|GPIO_PORTH|GPIO_PIN3)
#define GPIO_BTN_KEY1   (GPIO_INPUT|GPIO_PULLUP|GPIO_SPEED_50MHz|GPIO_EXTI|GPIO_PORTH|GPIO_PIN2)
#define GPIO_BTN_KEY2   (GPIO_INPUT|GPIO_PULLUP|GPIO_SPEED_50MHz|GPIO_EXTI|GPIO_PORTC|GPIO_PIN13)
#define GPIO_BTN_KEY3   (GPIO_INPUT|GPIO_PULLDOWN|GPIO_SPEED_50MHz|GPIO_EXTI|GPIO_PORTA|GPIO_PIN0)

/* Touchscreen definitions **************************************************/

/* The APOLLO-STM32H743I have connectors for the LCD model ATK-7016.
 * It comes with the GT911 touchscreen chip integrated.
 * 
 */

/* I2C address of the GT911 touchscreen chip */

#define GT9XX_I2C_ADDRESS  0x14

/* Touchscreen Interrupt line: PH7 */
#define GPIO_GT9XX_INT       (GPIO_INPUT|GPIO_FLOAT|GPIO_EXTI|GPIO_SPEED_100MHz| \
                            GPIO_PORTH|GPIO_PIN7)

#define GPIO_GT9XX_INT_FT    (GPIO_INPUT|GPIO_FLOAT|GPIO_SPEED_100MHz| \
                            GPIO_PORTH|GPIO_PIN7)
#define GPIO_GT9XX_INT_PP    (GPIO_INPUT|GPIO_PULLUP|GPIO_SPEED_100MHz| \
                            GPIO_PORTH|GPIO_PIN7)

/* The reset line is active low: PI8 */

#define GPIO_GT9XX_RST      (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_PULLUP|GPIO_SPEED_50MHz|\
                            GPIO_OUTPUT_SET|GPIO_PORTI|GPIO_PIN8)

/* LCD */    

#define GPIO_LCD_BL        (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|\
                            GPIO_OUTPUT_SET|GPIO_PORTB|GPIO_PIN5)


/****************************************************************************
 * Public Function Prototypes
 ****************************************************************************/

/****************************************************************************
 * Name: stm32_bringup
 *
 * Description:
 *   Perform architecture-specific initialization
 *
 *   CONFIG_BOARD_LATE_INITIALIZE=y :
 *     Called from board_late_initialize().
 *
 ****************************************************************************/

int stm32_bringup(void);

/****************************************************************************
 * Name: stm32_usbinitialize
 *
 * Description:
 *   Called from stm32_usbinitialize very early in inialization to setup
 *   USB-related GPIO pins for the STM32H745I-DISCO board.
 *
 ****************************************************************************/

#ifdef CONFIG_STM32H7_OTGFS
void weak_function stm32_usbinitialize(void);
#endif

/****************************************************************************
 * Name: stm32_usbhost_initialize
 *
 * Description:
 *   Called at application startup time to initialize the USB host
 *   functionality. This function will start a thread that will monitor for
 *   device connection/disconnection events.
 *
 ****************************************************************************/

#if defined(CONFIG_STM32H7_OTGFS) && defined(CONFIG_USBHOST)
int stm32_usbhost_initialize(void);
#endif

/****************************************************************************
 * Name: stm32_tsc_setup
 *
 * Description:
 *   This function is called by board-bringup logic to configure the
 *   touchscreen device.  This function will register the driver as
 *   /dev/inputN where N is the minor device number.
 *
 ****************************************************************************/

#ifdef CONFIG_APOLLO_STM32H743I_CT_I2C
int stm32_tsc_setup(int minor);
#endif

#endif /* __BOARDS_ARM_STM32H7_APOLLO_STM32H743I_SRC_APOLLO_STM32H743I_H */

include/board.h:公共板级定义

参考boards/arm/stm32h7/stm32h750b-dk/include/board.h

/****************************************************************************
 * boards/arm/stm32h7/apollo-stm32h743i/include/board.h
 ****************************************************************************/

#ifndef __BOARDS_ARM_STM32H7_APOLLO_STM32H743I_INCLUDE_BOARD_H
#define __BOARDS_ARM_STM32H7_APOLLO_STM32H743I_INCLUDE_BOARD_H

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/config.h>

#ifndef __ASSEMBLY__
# include <stdint.h>
#endif

/* Do not include STM32 H7 header files here */

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

/* Clocking *****************************************************************/

/* The APOLLO STM32H743I board provides the following clock sources:
 *
 *   X3:  32.768 KHz crystal for LSE
 *   X2:  25 MHz HSE crystal oscillator
 *
 * So we have these clock source available within the STM32
 *
 *   HSI: 16 MHz RC factory-trimmed
 *   LSI: 32 KHz RC
 *   HSE: 25 MHz oscillator X2
 *   LSE: 32.768 kHz
 */

#define STM32_HSI_FREQUENCY     16000000ul
#define STM32_LSI_FREQUENCY     32000
#define STM32_HSE_FREQUENCY     25000000ul
#define STM32_LSE_FREQUENCY     32768

/* Main PLL Configuration.
 *
 * PLL source is HSE = 25,000,000
 *
 * When STM32_HSE_FREQUENCY / PLLM <= 2MHz VCOL must be selected.
 * VCOH otherwise.
 *
 * PLL_VCOx = (STM32_HSE_FREQUENCY / PLLM) * PLLN
 * Subject to:
 *
 *     1 <= PLLM <= 63
 *     4 <= PLLN <= 512
 *   150 MHz <= PLL_VCOL <= 420MHz
 *   192 MHz <= PLL_VCOH <= 836MHz
 *
 * SYSCLK  = PLL_VCO / PLLP
 * CPUCLK  = SYSCLK / D1CPRE
 * Subject to
 *
 *   PLLP1   = {2, 4, 6, 8, ..., 128}
 *   PLLP2,3 = {2, 3, 4, ..., 128}
 *   CPUCLK <= 480 MHz
 */

#define STM32_BOARD_USEHSE

#define STM32_PLLCFG_PLLSRC      RCC_PLLCKSELR_PLLSRC_HSE

/* PLL1, wide 4 - 8 MHz input, enable DIVP, DIVQ
 *
 *   PLL1_VCO = (25,000,000 / 5) * 192 = 960 MHz
 *
 *   PLL1P = PLL1_VCO/2  = 960 MHz / 2   = 480 MHz
 *   PLL1Q = PLL1_VCO/4  = 960 MHz / 4   = 240 MHz
 *   PLL1R = PLL1_VCO/8  = 960 MHz / 8   = 120 MHz
 */

#define STM32_PLLCFG_PLL1CFG     (RCC_PLLCFGR_PLL1VCOSEL_WIDE | \
                                  RCC_PLLCFGR_PLL1RGE_4_8_MHZ | \
                                  RCC_PLLCFGR_DIVP1EN | \
                                  RCC_PLLCFGR_DIVQ1EN)
#define STM32_PLLCFG_PLL1M       RCC_PLLCKSELR_DIVM1(5)
#define STM32_PLLCFG_PLL1N       RCC_PLL1DIVR_N1(192)
#define STM32_PLLCFG_PLL1P       RCC_PLL1DIVR_P1(2)
#define STM32_PLLCFG_PLL1Q       RCC_PLL1DIVR_Q1(4)
#define STM32_PLLCFG_PLL1R       0

#define STM32_VCO1_FREQUENCY     ((STM32_HSE_FREQUENCY / 5) * 192)
#define STM32_PLL1P_FREQUENCY    (STM32_VCO1_FREQUENCY / 2)
#define STM32_PLL1Q_FREQUENCY    (STM32_VCO1_FREQUENCY / 4)
#define STM32_PLL1R_FREQUENCY    

/* PLL2, wide 4 - 8 MHz input, enable DIVP, DIVQ, DIVR
 *
 *   PLL2_VCO = (25 MHz / 5) * 88 = 440 MHz
 *
 *   PLL2P = PLL2_VCO/2  = 440 MHz / 2   = 220 MHz
 *   PLL2Q = PLL2_VCO/4  = 440 MHz / 2   = 220 MHz
 *   PLL2R = PLL2_VCO/8  = 440 MHz / 2   = 220 MHz
 */

#define STM32_PLLCFG_PLL2CFG (RCC_PLLCFGR_PLL2VCOSEL_WIDE | \
                              RCC_PLLCFGR_PLL2RGE_4_8_MHZ | \
                              RCC_PLLCFGR_DIVP2EN | \
                              RCC_PLLCFGR_DIVQ2EN | \
                              RCC_PLLCFGR_DIVR2EN)
#define STM32_PLLCFG_PLL2M       RCC_PLLCKSELR_DIVM2(5)
#define STM32_PLLCFG_PLL2N       RCC_PLL2DIVR_N2(88)
#define STM32_PLLCFG_PLL2P       RCC_PLL2DIVR_P2(2)
#define STM32_PLLCFG_PLL2Q       RCC_PLL2DIVR_Q2(2)
#define STM32_PLLCFG_PLL2R       RCC_PLL2DIVR_R2(2)

#define STM32_VCO2_FREQUENCY     ((STM32_HSE_FREQUENCY / 5) * 88)
#define STM32_PLL2P_FREQUENCY    (STM32_VCO2_FREQUENCY / 2)
#define STM32_PLL2Q_FREQUENCY    (STM32_VCO2_FREQUENCY / 2)
#define STM32_PLL2R_FREQUENCY    (STM32_VCO2_FREQUENCY / 2)

/* PLL3 is defined to 50 MHz to use with LCD */
/* PLL3, wide 1 - 2 MHz input, enable DIVP, DIVQ, DIVR
 *
 *   PLL3_VCO = (25 MHz / 25) * 300 = 300 MHz
 *
 *   PLL3P = PLL3_VCO/2  = 300 MHz / 2   = 150 MHz
 *   PLL3Q = PLL3_VCO/4  = 300 MHz / 2   = 150 MHz
 *   PLL3R = PLL3_VCO/8  = 300 MHz / 6   = 50 MHz
 */

#define STM32_PLLCFG_PLL3CFG     (RCC_PLLCFGR_PLL3VCOSEL_MEDIUM | \
                                  RCC_PLLCFGR_PLL3RGE_1_2_MHZ | \
                                  RCC_PLLCFGR_DIVR3EN)
#define STM32_PLLCFG_PLL3M       RCC_PLLCKSELR_DIVM3(25)

#define STM32_PLLCFG_PLL3N       RCC_PLL3DIVR_N3(300)
#define STM32_PLLCFG_PLL3P       RCC_PLL3DIVR_P3(2)
#define STM32_PLLCFG_PLL3Q       RCC_PLL3DIVR_Q3(2)
#define STM32_PLLCFG_PLL3R       RCC_PLL3DIVR_R3(6)

#define STM32_VCO3_FREQUENCY     ((STM32_HSE_FREQUENCY / 25) * 300)
#define STM32_PLL3P_FREQUENCY    (STM32_VCO3_FREQUENCY / 2)
#define STM32_PLL3Q_FREQUENCY    (STM32_VCO3_FREQUENCY / 2)
#define STM32_PLL3R_FREQUENCY    (STM32_VCO3_FREQUENCY / 6)

/* SYSCLK = PLL1P = 480 MHz
 * CPUCLK = SYSCLK / 1 = 480 MHz
 */

#define STM32_RCC_D1CFGR_D1CPRE  (RCC_D1CFGR_D1CPRE_SYSCLK)
#define STM32_SYSCLK_FREQUENCY   (STM32_PLL1P_FREQUENCY)
#define STM32_CPUCLK_FREQUENCY   (STM32_SYSCLK_FREQUENCY / 1)

/* Configure Clock Assignments */

/* AHB clock (HCLK) is SYSCLK/2 (480 MHz max)
 * HCLK1 = HCLK2 = HCLK3 = HCLK4
 */

#define STM32_RCC_D1CFGR_HPRE   RCC_D1CFGR_HPRE_SYSCLKd2        /* HCLK  = SYSCLK / 2 */
#define STM32_ACLK_FREQUENCY    (STM32_SYSCLK_FREQUENCY / 2)    /* ACLK in D1, HCLK3 in D1 */
#define STM32_HCLK_FREQUENCY    (STM32_SYSCLK_FREQUENCY / 2)    /* HCLK in D2, HCLK4 in D3 */

/* APB1 clock (PCLK1) is HCLK/2 (120 MHz) */

#define STM32_RCC_D2CFGR_D2PPRE1  RCC_D2CFGR_D2PPRE1_HCLKd2       /* PCLK1 = HCLK / 2 */
#define STM32_PCLK1_FREQUENCY     (STM32_HCLK_FREQUENCY/2)

/* APB2 clock (PCLK2) is HCLK/2 (120 MHz) */

#define STM32_RCC_D2CFGR_D2PPRE2  RCC_D2CFGR_D2PPRE2_HCLKd2       /* PCLK2 = HCLK / 2 */
#define STM32_PCLK2_FREQUENCY     (STM32_HCLK_FREQUENCY/2)

/* APB3 clock (PCLK3) is HCLK/2 (120 MHz) */

#define STM32_RCC_D1CFGR_D1PPRE   RCC_D1CFGR_D1PPRE_HCLKd2        /* PCLK3 = HCLK / 2 */
#define STM32_PCLK3_FREQUENCY     (STM32_HCLK_FREQUENCY/2)

/* APB4 clock (PCLK4) is HCLK/2 (120 MHz) */

#define STM32_RCC_D3CFGR_D3PPRE   RCC_D3CFGR_D3PPRE_HCLKd2       /* PCLK4 = HCLK / 2 */
#define STM32_PCLK4_FREQUENCY     (STM32_HCLK_FREQUENCY/2)

/* FLASH wait states
 *
 *  ------------ ---------- -----------
 *  Vcore        MAX ACLK   WAIT STATES
 *  ------------ ---------- -----------
 *  1.15-1.26 V     70 MHz    0
 *  (VOS1 level)   140 MHz    1
 *                 210 MHz    2
 *  1.05-1.15 V     55 MHz    0
 *  (VOS2 level)   110 MHz    1
 *                 165 MHz    2
 *                 220 MHz    3
 *  0.95-1.05 V     45 MHz    0
 *  (VOS3 level)    90 MHz    1
 *                 135 MHz    2
 *                 180 MHz    3
 *                 225 MHz    4
 *  ------------ ---------- -----------
 */

#define BOARD_FLASH_WAITSTATES 4
#define BOARD_FLASH_PROGDELAY  3
#define STM32_PWR_VOS_SCALE    PWR_D3CR_VOS_SCALE_1
#define STM32_VOS_OVERDRIVE    1 /* Enable VOS0 */

/* SDRAM FMC definitions ****************************************************/

/* The following settings correspond to W9825G6KH-6 SDRAM
 * part-number ("-6" speed grades ) and FMC_SDCLK frequency of 110 MHz
 * (period is ~ 9.09 ns).
 */

/* Though W9825G6KH-6 SDRAM itself provides 16-bit data bus,
 * linum board routes only DQ[15:0] bits.
 */

#define BOARD_FMC_CLK           RCC_D1CCIPR_FMCSEL_PLL2

#if CONFIG_STM32H7_FMC
#  define FMC_SDCLK_FREQUENCY  (STM32_PLL2R_FREQUENCY / 2)
#  if FMC_SDCLK_FREQUENCY > 110000000
#    error "FMC SDRAM settings need to be adjusted for a higher FMC_SDCLK frequency"
#  elif FMC_SDCLK_FREQUENCY < 110000000
#    warning "The current FMC SDRAM settings may not be optimal for a lower FMC_SDCLK frequency"
#  endif
#endif

#define BOARD_SDRAM1_SIZE               (32*1024*1024)

/* BOARD_FMC_SDCR[1..2] - Initial value for SDRAM control registers for SDRAM
 *      bank 1-2. Note that some bits in SDCR1 influence both SDRAM banks and
 *      are unused in SDCR2!
 */

#define BOARD_FMC_SDCR1  (FMC_SDCR_SDCLK_2X |   /* sdclk = 2 hclk */ \
                          FMC_SDCR_BURST_READ | /* enable burst read */ \
                          FMC_SDCR_RPIPE_0 |    /* rpipe = 0 hclk */ \
                          FMC_SDCR_COLBITS_9 |  /* numcols = 9 bits */ \
                          FMC_SDCR_ROWBITS_13 | /* numrows = 13 bits */ \
                          FMC_SDCR_WIDTH_16 |   /* width = 16 bits */ \
                          FMC_SDCR_BANKS_4 |    /* 4 internal banks */ \
                          FMC_SDCR_CASLAT_2)    /* cas latency = 3 cycles */
  

/* BOARD_FMC_SDTR[1..2] - Initial value for SDRAM timing registers for SDRAM
 *      bank 1-2. Note that some bits in SDTR1 influence both SDRAM banks and
 *      are unused in SDTR2!
 */

#define BOARD_FMC_SDTR1  (FMC_SDTR_TRC(7) |     /* tRC  min = 60ns */ \
                          FMC_SDTR_TRP(2) |     /* tRP  min = 15ns */ \
                          FMC_SDTR_TMRD(2) |    /* tMRD     = 2CLK */ \
                          FMC_SDTR_TXSR(8) |    /* tXSR min = 72ns */ \
                          FMC_SDTR_TRAS(7) |    /* tRAS min = 60ns */ \
                          FMC_SDTR_TWR(2) |     /* tWR      = 2CLK */ \
                          FMC_SDTR_TRCD(2))     /* tRCD min = 15ns */


#define BOARD_FMC_SDRAM_REFR_CYCLES  8192
#define BOARD_FMC_SDRAM_REFR_PERIOD  64
#define BOARD_FMC_SDRAM_AUTOREFRESH  8
#define BOARD_FMC_SDRAM_MODE         (FMC_SDCMR_MRD_BURST_LENGTH_1 | \
                                      FMC_SDCMR_MRD_BURST_TYPE_SEQUENTIAL | \
                                      FMC_SDCMR_MRD_CAS_LATENCY_2 | \
                                      FMC_SDCMR_MRD_OPERATING_MODE_STANDARD | \
                                      FMC_SDCMR_MRD_WRITEBURST_MODE_SINGLE)

#define BOARD_FMC_GPIO_CONFIGS \
  (GPIO_FMC_A0_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_A1_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_A2_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_A3_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_A4_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_A5_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_A6_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_A7_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_A8_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_A9_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_A10_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_A11_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_A12_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_D0_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_D1_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_D2_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_D3_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_D4_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_D5_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_D6_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_D7_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_D8_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_D9_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_D10_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_D11_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_D12_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_D13_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_D14_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_D15_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_NBL0_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_NBL1_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_BA0_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_BA1_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_SDNCAS_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_SDNRAS_0 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_SDNWE_2 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_SDNE0_1 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_SDCKE0_1 | GPIO_SPEED_100MHz), \
  (GPIO_FMC_SDCLK_0 | GPIO_SPEED_100MHz)

/* LED definitions **********************************************************/

 /*
 * If CONFIG_ARCH_LEDS is not defined, then the user can control the LEDs in
 * any way.  The following definitions are used to access individual LEDs.
 */

/* LED index values for use with board_userled() */

#define BOARD_LED1        0
#define BOARD_LED2        1
#define BOARD_NLEDS       2

/* LED bits for use with board_userled_all() */

#define BOARD_LED1_BIT    (1 << BOARD_LED1)
#define BOARD_LED2_BIT    (1 << BOARD_LED2)

/* If CONFIG_ARCH_LEDS is defined, the usage by the board port is defined in
 * include/board.h and src/stm32_autoleds.c. The LEDs are used to encode
 * OS-related events as follows:
 *
 *
 *   SYMBOL                     Meaning                      LED state
 *                                                        GREEN   RED 
 *   ----------------------  --------------------------  ------ ------ 
 */

#define LED_STARTED        0 /* NuttX has been started   ON     OFF       */
#define LED_HEAPALLOCATE   1 /* Heap has been allocated  OFF    ON        */
#define LED_IRQSENABLED    2 /* Interrupts enabled       ON     ON        */
#define LED_STACKCREATED   3 /* Idle stack created       OFF    ON        */
#define LED_INIRQ          4 /* In an interrupt          ON     ON        */
#define LED_SIGNAL         5 /* In a signal handler      N/C    ON        */
#define LED_ASSERTION      6 /* An assertion failed      ON     ON        */
#define LED_PANIC          7 /* The system has crashed   ON     Blink     */
#define LED_IDLE           8 /* MCU is is sleep mode     ON     ON        */

/* Thus if the Green LED is statically on, NuttX has successfully booted and
 * is, apparently, running normally.  If the Red LED is flashing at
 * approximately 2Hz, then a fatal error has been detected and the system
 * has halted.
 */

/* Button definitions *******************************************************/

/* The APOLLO Discovery supports 4 button: */

#define BUTTON_KEY0        0 /* KEY0 */
#define BUTTON_KEY1        1 /* KEY1 */
#define BUTTON_KEY2        2 /* KEY2 */
#define BUTTON_KEY3        3 /* KEY_UP*/

#define NUM_BUTTONS        4

#define BUTTON_KEY0_BIT    (1 << BUTTON_KEY0)
#define BUTTON_KEY1_BIT    (1 << BUTTON_KEY1)
#define BUTTON_KEY2_BIT    (1 << BUTTON_KEY2)
#define BUTTON_KEY3_BIT    (1 << BUTTON_KEY3)

/* Alternate function pin selections ****************************************/

/* USART1:
 *
 * The Apollo Discovery has no on-board serial devices, but the console is
 * brought out to PA9 (TX) and PA10 (RX) for connection to an external serial
 * device. (See the README.txt file for other options)
 */

#define GPIO_USART1_RX   (GPIO_USART1_RX_2 | GPIO_SPEED_100MHz)  /* PA10 */
#define GPIO_USART1_TX   (GPIO_USART1_TX_2 | GPIO_SPEED_100MHz)  /* PA9 */


/* LCD definitions */

#ifdef CONFIG_STM32H7_LTDC
# ifdef CONFIG_APOLLO_STM32H743I_ATK7016_FBIFACE

#if defined(CONFIG_APOLLO_STM32H743I_ATK7016_FBIFACE_LANDSCAPE) || \
    defined(CONFIG_APOLLO_STM32H743I_ATK7016_FBIFACE_RLANDSCAPE)
#  define BOARD_LTDC_WIDTH              1024
#  define BOARD_LTDC_HEIGHT             600
#else
#  define BOARD_LTDC_WIDTH              600
#  define BOARD_LTDC_HEIGHT             1024
#endif

#define BOARD_LTDC_OUTPUT_BPP           16
#define BOARD_LTDC_HFP                  160
#define BOARD_LTDC_HBP                  140
#define BOARD_LTDC_VFP                  12
#define BOARD_LTDC_VBP                  20
#define BOARD_LTDC_HSYNC                20
#define BOARD_LTDC_VSYNC                3

#define BOARD_LTDC_PLLSAIN              300
#define BOARD_LTDC_PLLSAIR              6

/* Pixel Clock Polarity */

#define BOARD_LTDC_GCR_PCPOL            0 /* !LTDC_GCR_PCPOL */

/* Data Enable Polarity */

#define BOARD_LTDC_GCR_DEPOL            0 /* !LTDC_GCR_DEPOL */

/* Vertical Sync Polarity */

#define BOARD_LTDC_GCR_VSPOL            0 /* !LTDC_GCR_VSPOL */

/* Horizontal Sync Polarity */

#define BOARD_LTDC_GCR_HSPOL            0 /* !LTDC_GCR_HSPOL */

/* GPIO pinset */

#define GPIO_LTDC_PINS                  16 /* 16-bit display */
#define GPIO_LTDC_R3                    (GPIO_LTDC_R3_1 | GPIO_SPEED_100MHz)
#define GPIO_LTDC_R4                    (GPIO_LTDC_R4_3 | GPIO_SPEED_100MHz)
#define GPIO_LTDC_R5                    (GPIO_LTDC_R5_4 | GPIO_SPEED_100MHz)
#define GPIO_LTDC_R6                    (GPIO_LTDC_R6_2 | GPIO_SPEED_100MHz)
#define GPIO_LTDC_R7                    (GPIO_LTDC_R7_2 | GPIO_SPEED_100MHz)

#define GPIO_LTDC_G2                    (GPIO_LTDC_G2_2 | GPIO_SPEED_100MHz)
#define GPIO_LTDC_G3                    (GPIO_LTDC_G3_3 | GPIO_SPEED_100MHz)
#define GPIO_LTDC_G4                    (GPIO_LTDC_G4_2 | GPIO_SPEED_100MHz)
#define GPIO_LTDC_G5                    (GPIO_LTDC_G5_2 | GPIO_SPEED_100MHz)
#define GPIO_LTDC_G6                    (GPIO_LTDC_G6_2 | GPIO_SPEED_100MHz)
#define GPIO_LTDC_G7                    (GPIO_LTDC_G7_3 | GPIO_SPEED_100MHz)

#define GPIO_LTDC_B3                    (GPIO_LTDC_B3_3 | GPIO_SPEED_100MHz)
#define GPIO_LTDC_B4                    (GPIO_LTDC_B4_3 | GPIO_SPEED_100MHz)
#define GPIO_LTDC_B5                    (GPIO_LTDC_B5_2 | GPIO_SPEED_100MHz)
#define GPIO_LTDC_B6                    (GPIO_LTDC_B6_2 | GPIO_SPEED_100MHz)
#define GPIO_LTDC_B7                    (GPIO_LTDC_B7_2 | GPIO_SPEED_100MHz)

#define GPIO_LTDC_VSYNC                 (GPIO_LTDC_VSYNC_3 | GPIO_SPEED_100MHz)
#define GPIO_LTDC_HSYNC                 (GPIO_LTDC_HSYNC_2 | GPIO_SPEED_100MHz)
#define GPIO_LTDC_DE                    (GPIO_LTDC_DE_2 | GPIO_SPEED_100MHz)
#define GPIO_LTDC_CLK                   (GPIO_LTDC_CLK_2 | GPIO_SPEED_100MHz)


#endif /* CONFIG_APOLLO_STM32F429I_ATK7016 display */
#endif /* CONFIG_STM32H7_LTDC */

/****************************************************************************
 * Public Data
 ****************************************************************************/

#ifndef __ASSEMBLY__

#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif

/****************************************************************************
 * Public Function Prototypes
 ****************************************************************************/

#undef EXTERN
#if defined(__cplusplus)
}
#endif

#endif /* __ASSEMBLY__ */
#endif /* __BOARDS_ARM_STM32H7_APOLLO_STM32H743I_INCLUDE_BOARD_H */

2、实现核心初始化函数

src/ 目录下,您需要创建并填充以下 C 文件。

stm32_boot.c:早期硬件初始化

此文件负责实现 stm32_boardinitialize(),用于在系统启动的最初阶段配置必要的硬件。参考boards/arm/stm32h7/stm32h750b-dk/src/stm32_boot.c

/****************************************************************************
 * boards/arm/stm32h7/apollo-stm32h743i/src/stm32_boot.c
 ****************************************************************************/

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/config.h>

#include <debug.h>

#include <nuttx/board.h>
#include <arch/board/board.h>

#include "apollo_stm32h743i.h"

/****************************************************************************
 * Public Functions
 ****************************************************************************/

/****************************************************************************
 * Name: stm32_boardinitialize
 *
 * Description:
 *   All STM32 architectures must provide the following entry point.
 *   This entry point is called early in the initialization -- after all
 *   memory has been configured and mapped but before any devices have been
 *   initialized.
 *
 ****************************************************************************/

void stm32_boardinitialize(void)
{
#ifdef CONFIG_ARCH_LEDS
  /* Configure on-board LEDs if LED support has been selected. */

  board_autoled_initialize();
#endif
}

/****************************************************************************
 * Name: board_late_initialize
 *
 * Description:
 *   If CONFIG_BOARD_LATE_INITIALIZE is selected, then an additional
 *   initialization call will be performed in the boot-up sequence to a
 *   function called board_late_initialize().  board_late_initialize()
 *   will be called immediately after up_initialize() is called and just
 *   before the initial application is started.  This additional
 *   initialization phase may be used, for example, to initialize board-
 *   specific device drivers.
 *
 ****************************************************************************/

#ifdef CONFIG_BOARD_LATE_INITIALIZE
void board_late_initialize(void)
{
  stm32_bringup();
}
#endif

stm32_bringup.c:设备驱动初始化

此文件中的 stm32_bringup() 函数负责初始化并注册所有板载设备的驱动程序。参考boards/arm/stm32h7/stm32h750b-dk/src/stm32_bringup.c


/****************************************************************************
 * boards/arm/stm32h7/apollo-stm32h743i/src/stm32_bringup.c
 ****************************************************************************/

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/config.h>

#include <sys/types.h>
#include <syslog.h>
#include <errno.h>

#include <nuttx/fs/fs.h>
#include <nuttx/mtd/mtd.h>
#include <nuttx/kmalloc.h>
#include <nuttx/usb/usbmonitor.h>

#include "stm32_gpio.h"

#include "apollo_stm32h743i.h"

#ifdef CONFIG_STM32H7_OTGFS
#include "stm32_usbhost.h"
#endif

#ifdef CONFIG_VIDEO_FB
#  include <nuttx/video/fb.h>
#endif

#ifdef CONFIG_RPTUN
#  include "stm32_rptun.h"
#endif

#ifdef CONFIG_RPMSG_UART
#  include <nuttx/serial/uart_rpmsg.h>
#endif

#ifdef CONFIG_INPUT_BUTTONS_LOWER
#  include <nuttx/input/buttons.h>
#endif

#ifdef CONFIG_USERLED
#  include <nuttx/leds/userled.h>
#endif

#include <arch/board/board.h>

/****************************************************************************
 * Public Functions
 ****************************************************************************/

#ifdef CONFIG_RPMSG_UART
/****************************************************************************
 * Name: rpmsg_serialinit
 ****************************************************************************/

void rpmsg_serialinit(void)
{
#ifdef CONFIG_ARCH_CHIP_STM32H7_CORTEXM7
  uart_rpmsg_init("cm4", "proxy", 4096, false);
#endif

#ifdef CONFIG_ARCH_CHIP_STM32H7_CORTEXM4
#  ifdef CONFIG_RPMSG_UART_CONSOLE
  uart_rpmsg_init("cm7", "proxy", 4096, true);
#  else
  uart_rpmsg_init("cm7", "proxy", 4096, false);
#  endif
#endif
}
#endif

/****************************************************************************
 * Name: stm32_bringup
 *
 * Description:
 *   Perform architecture-specific initialization
 *
 *   CONFIG_BOARD_LATE_INITIALIZE=y :
 *     Called from board_late_initialize().
 *
 *   CONFIG_BOARD_LATE_INITIALIZE=n && CONFIG_BOARDCTL=y &&
 *   CONFIG_NSH_ARCHINIT:
 *     Called from the NSH library
 *
 ****************************************************************************/

int stm32_bringup(void)
{
  int ret;

  UNUSED(ret);

#ifdef CONFIG_FS_PROCFS
  /* Mount the procfs file system */

  ret = nx_mount(NULL, "/proc", "procfs", 0, NULL);
  if (ret < 0)
    {
      syslog(LOG_ERR,
             "ERROR: Failed to mount the PROC filesystem: %d\n",  ret);
    }
#endif /* CONFIG_FS_PROCFS */

#ifdef CONFIG_RPTUN
#  ifdef CONFIG_ARCH_CHIP_STM32H7_CORTEXM7
  stm32_rptun_init("cm4");
#  else
  stm32_rptun_init("cm7");
#  endif
#endif

#ifdef CONFIG_APOLLO_STM32H743I_CT_I2C
  /* Initialize the touchscreen.
   * WARNING: stm32_tsc_setup() cannot be called from the IDLE thread.
   */

  ret = stm32_tsc_setup(0);
  if (ret < 0)
    {
      syslog(LOG_ERR, "ERROR: stm32_tsc_setup failed: %d\n", ret);
    }
#endif

#ifdef CONFIG_VIDEO_FB
  /* Initialize and register the framebuffer driver */

  ret = fb_register(0, 0);
  if (ret < 0)
    {
      syslog(LOG_ERR, "ERROR: fb_register() failed: %d\n", ret);
    }
#endif

#if !defined(CONFIG_ARCH_LEDS) && defined(CONFIG_USERLED_LOWER)
  /* Register the LED driver */

  // ret = userled_lower_initialize("/dev/userleds");
  ret = userled_lower_initialize(CONFIG_EXAMPLES_LEDS_DEVPATH);
  if (ret < 0)
    {
      syslog(LOG_ERR, "ERROR: userled_lower_initialize() failed: %d\n", ret);
    }
#endif

#ifdef CONFIG_INPUT_BUTTONS_LOWER
  /* Register the BUTTON driver */

  ret = btn_lower_initialize("/dev/buttons");
  if (ret < 0)
    {
      syslog(LOG_ERR, "ERROR: btn_lower_initialize() failed: %d\n", ret);
    }
#endif /* CONFIG_INPUT_BUTTONS_LOWER */

  return OK;
}

stm32_appinit.c:应用初始化桥梁

主要实现 int board_app_initialize(uintptr_t arg) 函数:

  • 如果打开 CONFIG_BOARD_LATE_INITIALIZE stm32_bringup() 将由board_late_initialize()调用。
  • 如果没有打开 CONFIG_BOARD_LATE_INITIALIZEstm32_bringup() 将由 board_app_initialize(arg) 调用。
/****************************************************************************
 * boards/arm/stm32h7/apollo-stm32h743i/src/stm32_appinitialize.c
 ****************************************************************************/

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/config.h>

#include <nuttx/board.h>
#include <sys/types.h>

#include "apollo_stm32h743i.h"

/****************************************************************************
 * Public Functions
 ****************************************************************************/

/****************************************************************************
 * Name: board_app_initialize
 *
 * Description:
 *   Perform application specific initialization.  This function is never
 *   called directly from application code, but only indirectly via the
 *   (non-standard) boardctl() interface using the command BOARDIOC_INIT.
 *
 * Input Parameters:
 *   arg - The boardctl() argument is passed to the board_app_initialize()
 *         implementation without modification.  The argument has no
 *         meaning to NuttX; the meaning of the argument is a contract
 *         between the board-specific initialization logic and the
 *         matching application logic.  The value could be such things as a
 *         mode enumeration value, a set of DIP switch switch settings, a
 *         pointer to configuration data read from a file or serial FLASH,
 *         or whatever you would like to do with it.  Every implementation
 *         should accept zero/NULL as a default configuration.
 *
 * Returned Value:
 *   Zero (OK) is returned on success; a negated errno value is returned on
 *   any failure to indicate the nature of the failure.
 *
 ****************************************************************************/

int board_app_initialize(uintptr_t arg)
{
#ifdef CONFIG_BOARD_LATE_INITIALIZE
  /* Board initialization already performed by board_late_initialize() */

  return OK;
#else
  /* Perform board-specific initialization */

  return stm32_bringup();
#endif
}

3、实现 LED 驱动

openvela将 LED 分为两类:一类用于指示系统状态(autoleds),另一类供用户应用程序控制(userleds)。

stm32_autoleds.c:系统状态 LED

该文件实现 board_autoled_* 系列函数,来控制实现 LED 的亮灭,由系统内核在特定事件(如启动、断言失败)发生时自动调用。此部分实现参照nuttx/boards/arm/stm32/stm32f429i-disco/src/stm32_autoleds.c


/****************************************************************************
 * boards/arm/stm32h7/apollo-stm32h743i/src/stm32_autoleds.c
 ****************************************************************************/

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/config.h>

#include <stdbool.h>
#include <debug.h>

#include <nuttx/board.h>
#include <arch/board/board.h>

#include "stm32_gpio.h"
#include "apollo_stm32h743i.h"

#ifdef CONFIG_ARCH_LEDS

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

/* The following definitions map the encoded LED setting to GPIO settings */

#define STM32H7_LED1      (1 << 0)
#define STM32H7_LED2      (1 << 1)

#define ON_SETBITS_SHIFT  (0)
#define ON_CLRBITS_SHIFT  (4)
#define OFF_SETBITS_SHIFT (8)
#define OFF_CLRBITS_SHIFT (12)

#define ON_BITS(v)        ((v) & 0xff)
#define OFF_BITS(v)       (((v) >> 8) & 0x0ff)
#define SETBITS(b)        ((b) & 0x0f)
#define CLRBITS(b)        (((b) >> 4) & 0x0f)

#define ON_SETBITS(v)     (SETBITS(ON_BITS(v))
#define ON_CLRBITS(v)     (CLRBITS(ON_BITS(v))
#define OFF_SETBITS(v)    (SETBITS(OFF_BITS(v))
#define OFF_CLRBITS(v)    (CLRBITS(OFF_BITS(v))

#define LED_STARTED_ON_SETBITS       ((STM32H7_LED1) << ON_SETBITS_SHIFT)
#define LED_STARTED_ON_CLRBITS       ((STM32H7_LED2) << ON_CLRBITS_SHIFT)
#define LED_STARTED_OFF_SETBITS      (0 << OFF_SETBITS_SHIFT)
#define LED_STARTED_OFF_CLRBITS      ((STM32H7_LED1|STM32H7_LED2) << OFF_CLRBITS_SHIFT)

#define LED_HEAPALLOCATE_ON_SETBITS  ((STM32H7_LED2) << ON_SETBITS_SHIFT)
#define LED_HEAPALLOCATE_ON_CLRBITS  ((STM32H7_LED1) << ON_CLRBITS_SHIFT)
#define LED_HEAPALLOCATE_OFF_SETBITS ((STM32H7_LED1) << OFF_SETBITS_SHIFT)
#define LED_HEAPALLOCATE_OFF_CLRBITS ((STM32H7_LED2) << OFF_CLRBITS_SHIFT)

#define LED_IRQSENABLED_ON_SETBITS   ((STM32H7_LED1|STM32H7_LED2) << ON_SETBITS_SHIFT)
#define LED_IRQSENABLED_ON_CLRBITS   ((STM32H7_LED2) << ON_CLRBITS_SHIFT)
#define LED_IRQSENABLED_OFF_SETBITS  ((STM32H7_LED2) << OFF_SETBITS_SHIFT)
#define LED_IRQSENABLED_OFF_CLRBITS  ((STM32H7_LED1) << OFF_CLRBITS_SHIFT)

#define LED_STACKCREATED_ON_SETBITS  ((STM32H7_LED1) << ON_SETBITS_SHIFT)
#define LED_STACKCREATED_ON_CLRBITS  ((STM32H7_LED1|STM32H7_LED2) << ON_CLRBITS_SHIFT)
#define LED_STACKCREATED_OFF_SETBITS ((STM32H7_LED1|STM32H7_LED2) << OFF_SETBITS_SHIFT)
#define LED_STACKCREATED_OFF_CLRBITS ((STM32H7_LED1|STM32H7_LED2) << OFF_CLRBITS_SHIFT)

#define LED_INIRQ_ON_SETBITS         ((STM32H7_LED2) << ON_SETBITS_SHIFT)
#define LED_INIRQ_ON_CLRBITS         ((0) << ON_CLRBITS_SHIFT)
#define LED_INIRQ_OFF_SETBITS        ((0) << OFF_SETBITS_SHIFT)
#define LED_INIRQ_OFF_CLRBITS        ((STM32H7_LED2) << OFF_CLRBITS_SHIFT)

#define LED_SIGNAL_ON_SETBITS        ((STM32H7_LED2) << ON_SETBITS_SHIFT)
#define LED_SIGNAL_ON_CLRBITS        ((0) << ON_CLRBITS_SHIFT)
#define LED_SIGNAL_OFF_SETBITS       ((0) << OFF_SETBITS_SHIFT)
#define LED_SIGNAL_OFF_CLRBITS       ((STM32H7_LED2) << OFF_CLRBITS_SHIFT)

#define LED_ASSERTION_ON_SETBITS     ((STM32H7_LED2) << ON_SETBITS_SHIFT)
#define LED_ASSERTION_ON_CLRBITS     ((0) << ON_CLRBITS_SHIFT)
#define LED_ASSERTION_OFF_SETBITS    ((0) << OFF_SETBITS_SHIFT)
#define LED_ASSERTION_OFF_CLRBITS    ((STM32H7_LED2) << OFF_CLRBITS_SHIFT)

#define LED_PANIC_ON_SETBITS         ((STM32H7_LED2) << ON_SETBITS_SHIFT)
#define LED_PANIC_ON_CLRBITS         ((0) << ON_CLRBITS_SHIFT)
#define LED_PANIC_OFF_SETBITS        ((0) << OFF_SETBITS_SHIFT)
#define LED_PANIC_OFF_CLRBITS        ((STM32H7_LED2) << OFF_CLRBITS_SHIFT)

#define LED_IDLE_ON_SETBITS         ((STM32H7_LED2) << ON_SETBITS_SHIFT)
#define LED_IDLE_ON_CLRBITS         ((0) << ON_CLRBITS_SHIFT)
#define LED_IDLE_OFF_SETBITS        ((0) << OFF_SETBITS_SHIFT)
#define LED_IDLE_OFF_CLRBITS        ((STM32H7_LED2) << OFF_CLRBITS_SHIFT)


/****************************************************************************
 * Private Data
 ****************************************************************************/

static const uint16_t g_ledbits[8] =
{
  (LED_STARTED_ON_SETBITS       | LED_STARTED_ON_CLRBITS |
  LED_STARTED_OFF_SETBITS      | LED_STARTED_OFF_CLRBITS),

  (LED_HEAPALLOCATE_ON_SETBITS  | LED_HEAPALLOCATE_ON_CLRBITS |
  LED_HEAPALLOCATE_OFF_SETBITS | LED_HEAPALLOCATE_OFF_CLRBITS),

  (LED_IRQSENABLED_ON_SETBITS   | LED_IRQSENABLED_ON_CLRBITS |
  LED_IRQSENABLED_OFF_SETBITS  | LED_IRQSENABLED_OFF_CLRBITS),

  (LED_STACKCREATED_ON_SETBITS  | LED_STACKCREATED_ON_CLRBITS |
  LED_STACKCREATED_OFF_SETBITS | LED_STACKCREATED_OFF_CLRBITS),

  (LED_INIRQ_ON_SETBITS         | LED_INIRQ_ON_CLRBITS |
  LED_INIRQ_OFF_SETBITS        | LED_INIRQ_OFF_CLRBITS),

  (LED_SIGNAL_ON_SETBITS        | LED_SIGNAL_ON_CLRBITS |
  LED_SIGNAL_OFF_SETBITS       | LED_SIGNAL_OFF_CLRBITS),

  (LED_ASSERTION_ON_SETBITS     | LED_ASSERTION_ON_CLRBITS |
  LED_ASSERTION_OFF_SETBITS    | LED_ASSERTION_OFF_CLRBITS),

  (LED_PANIC_ON_SETBITS         | LED_PANIC_ON_CLRBITS |
  LED_PANIC_OFF_SETBITS        | LED_PANIC_OFF_CLRBITS),

  (LED_IDLE_ON_SETBITS         | LED_IDLE_ON_CLRBITS |
  LED_IDLE_OFF_SETBITS        | LED_IDLE_OFF_CLRBITS)
};

/****************************************************************************
 * Private Functions
 ****************************************************************************/

static inline void led_clrbits(unsigned int clrbits)
{
  if ((clrbits & STM32H7_LED1) != 0)
    {
      /* 对于本开发板而言,对应IO输出高电平灭灯 */
      stm32_gpiowrite(GPIO_LED_GREEN, true);
    }

  if ((clrbits & STM32H7_LED2) != 0)
    {
      stm32_gpiowrite(GPIO_LED_RED, true);
    }
}

static inline void led_setbits(unsigned int setbits)
{
  if ((setbits & STM32H7_LED1) != 0)
    {
      /* 对于本开发板而言,对应IO输出低电平亮灯 */
      stm32_gpiowrite(GPIO_LED_GREEN, false);
    }

  if ((setbits & STM32H7_LED2) != 0)
    {
      stm32_gpiowrite(GPIO_LED_RED, false);
    }
}

static void led_setonoff(unsigned int bits)
{
  led_clrbits(CLRBITS(bits));
  led_setbits(SETBITS(bits));
}

/****************************************************************************
 * Public Functions
 ****************************************************************************/

/****************************************************************************
 * Name: board_autoled_initialize
 ****************************************************************************/

void board_autoled_initialize(void)
{
  /* Configure LED1-2 GPIOs for output */

  stm32_configgpio(GPIO_LED_GREEN);
  stm32_configgpio(GPIO_LED_RED);
}

/****************************************************************************
 * Name: board_autoled_on
 ****************************************************************************/

void board_autoled_on(int led)
{
  ledinfo("board_autoled_on(%d)\n", led);

  led_setonoff(ON_BITS(g_ledbits[led]));

}

/****************************************************************************
 * Name: board_autoled_off
 ****************************************************************************/

void board_autoled_off(int led)
{

  led_setonoff(OFF_BITS(g_ledbits[led]));
}

#endif /* CONFIG_ARCH_LEDS */

stm32_userleds.c:用户应用 LED
/****************************************************************************
 * boards/arm/stm32h7/stm32h745i-disco/src/stm32_userleds.c
 ****************************************************************************/

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/config.h>

#include <stdint.h>
#include <stdbool.h>
#include <debug.h>

#include <nuttx/board.h>
#include <nuttx/power/pm.h>
#include <arch/board/board.h>

#include "chip.h"
#include "arm_internal.h"
#include "stm32.h"

#include "apollo_stm32h743i.h"

#ifndef CONFIG_ARCH_LEDS

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

#define ARRAYSIZE(x) (sizeof((x)) / sizeof((x)[0]))

/****************************************************************************
 * Private Data
 ****************************************************************************/

/* This array maps an LED number to GPIO pin configuration and is indexed by
 * BOARD_LED_<color>
 */

static const uint32_t g_ledcfg[BOARD_NLEDS] =
{
  GPIO_LED_GREEN,
  GPIO_LED_RED
};

/****************************************************************************
 * Public Functions
 ****************************************************************************/

/****************************************************************************
 * Name: board_userled_initialize
 *
 * Description:
 *   If CONFIG_ARCH_LEDS is defined, then NuttX will control the on-board
 *   LEDs.  If CONFIG_ARCH_LEDS is not defined, then the
 *   board_userled_initialize() is available to initialize the LED from user
 *   application logic.
 *
 ****************************************************************************/

uint32_t board_userled_initialize(void)
{
  int i;

  /* Configure LED1-2 GPIOs for output */

  for (i = 0; i < ARRAYSIZE(g_ledcfg); i++)
    {
      stm32_configgpio(g_ledcfg[i]);
    }

  return BOARD_NLEDS;
}

/****************************************************************************
 * Name: board_userled
 *
 * Description:
 *   If CONFIG_ARCH_LEDS is defined, then NuttX will control the on-board
 *  LEDs.  If CONFIG_ARCH_LEDS is not defined, then the board_userled() is
 *  available to control the LED from user application logic.
 *
 ****************************************************************************/

void board_userled(int led, bool ledon)
{
  int i;

  for (i = 0; i < ARRAYSIZE(g_ledcfg); i++)
    {
      /* 对于本开发板而言,对应IO输出高电平灭灯,对应IO输出低电平亮灯*/
      if (i != led)
      {
        stm32_gpiowrite(g_ledcfg[i], ledon);
      }
      else
      {
        stm32_gpiowrite(g_ledcfg[i], !ledon);
      }
      
    }
}

/****************************************************************************
 * Name: board_userled_all
 *
 * Description:
 *   If CONFIG_ARCH_LEDS is defined, then NuttX will control the on-board
 *  LEDs.  If CONFIG_ARCH_LEDS is not defined, then the board_userled_all()
 *  is available to control the LED from user application logic. NOTE: since
 *  there is only a single LED on-board, this is function is not very useful.
 *
 ****************************************************************************/

void board_userled_all(uint32_t ledset)
{
  int i;

  for (i = 0; i < ARRAYSIZE(g_ledcfg); i++)
    {
      /* 对于本开发板而言,对应IO输出高电平灭灯,对应IO输出低电平亮灯*/
      stm32_gpiowrite(g_ledcfg[i], (ledset & (1 << i)) == 0);
    }
}

#endif /* !CONFIG_ARCH_LEDS */

4、实现按键驱动

stm32_buttons.c:按键驱动

该文件为通用的按键驱动(位于 nuttx/drivers/input/buttons_lower.c)提供底层的硬件操作接口。应用程序通过标准的 open(), read(), ioctl()等VFS接口访问 /dev/buttons来获取按键状态 。此部分实现参照boards/arm/stm32/stm32f429i-disco/src/stm32_buttons.c

我们需要提供下面的函数接口给 buttons_lower.c 调用:

注意 : 阿波罗stm32h743开发板上,KEY0、KEY1和KEY2是低电平有效的,而KEY_UP是高电平有效的,因此在读取KEY_UP按键状态时,需要反转一下状态值:

/****************************************************************************
 * boards/arm/stm32h7/apollo-stm32h743i/src/stm32_buttons.c
 ****************************************************************************/

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/config.h>

#include <stdint.h>
#include <errno.h>

#include <nuttx/arch.h>
#include <nuttx/board.h>
#include <arch/board/board.h>

#include "chip.h"
#include "arm_internal.h"
#include "stm32.h"

#include "apollo_stm32h743i.h"

#ifdef CONFIG_ARCH_BUTTONS

/****************************************************************************
 * Private Data
 ****************************************************************************/

/* Pin configuration for each STM32F4 Discovery button. This array is indexed
 * by the BUTTON_* definitions in board.h
 */

static const uint32_t g_buttons[NUM_BUTTONS] =
{
  GPIO_BTN_KEY0,
  GPIO_BTN_KEY1,
  GPIO_BTN_KEY2,
  GPIO_BTN_KEY3

};

/****************************************************************************
 * Public Functions
 ****************************************************************************/

/****************************************************************************
 * Name: board_button_initialize
 *
 * Description:
 *   board_button_initialize() must be called to initialize button resources.
 *   After that, board_buttons() may be called to collect the current state
 *   of all buttons or board_button_irq() may be called to register button
 *   interrupt handlers.
 *
 ****************************************************************************/

uint32_t board_button_initialize(void)
{
  int i;

  /* Configure the GPIO pins as inputs.  NOTE that EXTI interrupts are
   * configured for all pins.
   */

  for (i = 0; i < NUM_BUTTONS; i++)
    {
      stm32_configgpio(g_buttons[i]);
    }

  return NUM_BUTTONS;
}

/****************************************************************************
 * Name: board_buttons
 ****************************************************************************/

uint32_t board_buttons(void)
{
  uint32_t ret = 0;
  int i;

  /* Check that state of each key */

  for (i = 0; i < NUM_BUTTONS; i++)
    {
      /* A LOW value means that the key is pressed. */

      bool released = stm32_gpioread(g_buttons[i]);

      /* KEY_3 : PULLDOWN */
      if (i == 3)
      {
        released = !released;
      }

      /* Accumulate the set of depressed (not released) keys */

      if (!released)
        {
           ret |= (1 << i);
        }
    }

  return ret;
}

/****************************************************************************
 * Button support.
 *
 * Description:
 *   board_button_initialize() must be called to initialize button resources.
 *   After that, board_buttons() may be called to collect the current state
 *   of all buttons or board_button_irq() may be called to register button
 *   interrupt handlers.
 *
 *   After board_button_initialize() has been called, board_buttons() may be
 *   called to collect the state of all buttons.  board_buttons() returns an
 *   32-bit bit set with each bit associated with a button.  See the
 *   BUTTON_*_BIT definitions in board.h for the meaning of each bit.
 *
 *   board_button_irq() may be called to register an interrupt handler that
 *   will be called when a button is depressed or released. The ID value is a
 *   button enumeration value that uniquely identifies a button resource. See
 *   the BUTTON_* definitions in board.h for the meaning of enumeration
 *   value.
 *
 ****************************************************************************/

#ifdef CONFIG_ARCH_IRQBUTTONS
int board_button_irq(int id, xcpt_t irqhandler, void *arg)
{
  int ret = -EINVAL;

  /* The following should be atomic */

  if (id >= MIN_IRQBUTTON && id <= MAX_IRQBUTTON)
    {
      ret = stm32_gpiosetevent(g_buttons[id], true, true, true,
                               irqhandler, arg);
    }

  return ret;
}
#endif
#endif /* CONFIG_ARCH_BUTTONS */

5、实现RGBLCD驱动

stm32_lcd.c

参考boards/arm/stm32h7/stm32h750b-dk/src/stm32_lcd.c

说明:本文使用的RGBLCD 模块型号为 ATK-7016(7 寸,1024*600),采用GT911电容触控方案。

/****************************************************************************
 * boards/arm/stm32h7/apollo-stm32h743i/src/stm32_lcd.c
 ****************************************************************************/

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/config.h>

#include <errno.h>
#include <debug.h>

#include <nuttx/arch.h>
#include <nuttx/board.h>
#include <nuttx/video/fb.h>
#include <arch/board/board.h>

#include "stm32_gpio.h"
#include "stm32_ltdc.h"

#include "apollo_stm32h743i.h"

#ifdef CONFIG_STM32H7_LTDC
/****************************************************************************
 * Public Functions
 ****************************************************************************/

/****************************************************************************
 * Name: up_fbinitialize
 *
 * Description:
 *   Initialize the framebuffer video hardware associated with the display.
 *
 * Input Parameters:
 *   display - In the case of hardware with multiple displays, this
 *     specifies the display.  Normally this is zero.
 *
 * Returned Value:
 *   Zero is returned on success; a negated errno value is returned on any
 *   failure.
 *
 ****************************************************************************/

int up_fbinitialize(int display)
{
  /* Custom LCD display with RGB interface */
  stm32_configgpio(GPIO_LCD_BL);
  stm32_gpiowrite(GPIO_LCD_BL, true);

  return stm32_ltdcinitialize();
}

/****************************************************************************
 * Name: up_fbgetvplane
 *
 * Description:
 *   Return a a reference to the framebuffer object for the specified video
 *   plane of the specified plane.
 *   Many OSDs support multiple planes of video.
 *
 * Input Parameters:
 *   display - In the case of hardware with multiple displays, this
 *     specifies the display.  Normally this is zero.
 *   vplane - Identifies the plane being queried.
 *
 * Returned Value:
 *   A non-NULL pointer to the frame buffer access structure is returned on
 *   success; NULL is returned on any failure.
 *
 ****************************************************************************/

struct fb_vtable_s *up_fbgetvplane(int display, int vplane)
{
  return stm32_ltdcgetvplane(vplane);
}

/****************************************************************************
 * Name: up_fbuninitialize
 *
 * Description:
 *   Uninitialize the framebuffer support for the specified display.
 *
 * Input Parameters:
 *   display - In the case of hardware with multiple displays, this
 *     specifies the display.  Normally this is zero.
 *
 * Returned Value:
 *   None
 *
 ****************************************************************************/

void up_fbuninitialize(int display)
{
  stm32_gpiowrite(GPIO_LCD_BL, false);

  stm32_ltdcuninitialize();
}
#endif /* CONFIG_STM32H7_LTDC */

6、实现触摸屏驱动

说明:本文使用的RGBLCD 模块型号为 ATK-7016(7 寸,1024*600),采用GT911电容触控方案。

IIC驱动

通过《STM32H743 阿波罗开发指南V1.2》可知,此开发板与 ATK-7016的电容触摸屏通过四根线连接,分别是:T_PEN(CT_INT)、T_CS(CT_RST)、T_SCK(CT_SCL)和T_MOSI(CT_SDA)。其中:CT_INT、CT_RST、CT_SCL和CT_SDA分别是GT911的:中断输出信号、复位信号,IIC的SCL和SDA信号。开发板与触摸屏之间的IIC通讯采用软件模拟的方式实现。

ct_i2c.h

参考【正点原子】阿波罗V2 STM32H743开发板\4,LVGL例程\LVGL例程2 操作系统移植\Drivers\BSP\IIC\myiic.h(下载地址:STM32H743阿波罗开发板V2 — 正点原子资料下载中心 1.0.0 文档)。

/****************************************************************************
 * boards/arm/stm32h7/apollo-stm32h743i/src/ct_i2c.h
 ****************************************************************************/

#ifndef __BOARDS_ARM_STM32H7_APOLLO_STM32H743I_SRC_CT_I2C_H
#define __BOARDS_ARM_STM32H7_APOLLO_STM32H743I_SRC_CT_I2C_H

void ct_i2c_initialize(void);
void ct_i2c_delay(void);
void ct_i2c_start(void);
void ct_i2c_stop(void);
int8_t ct_i2c_wait_ack(void);
void ct_i2c_ack(void);
void ct_i2c_nack(void);
void ct_i2c_send_byte(uint8_t data);
uint8_t ct_i2c_read_byte(unsigned char ack);

#endif
ct_i2c.c

参考【正点原子】阿波罗V2 STM32H743开发板\4,LVGL例程\LVGL例程2 操作系统移植\Drivers\BSP\IIC\myiic.c(下载地址:STM32H743阿波罗开发板V2 — 正点原子资料下载中心 1.0.0 文档)。

/****************************************************************************
 * boards/arm/stm32h7/apollo-stm32h743i/src/ct_i2c.c
 ****************************************************************************/

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/config.h>
#include <nuttx/arch.h>
#include <nuttx/signal.h>

#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <debug.h>

#include <arch/board/board.h>

#include "arm_internal.h"
#include "chip.h"
#include "stm32.h"
#include "ct_i2c.h"


/* I2C - There is a GT9XX TouchPanel using these pins: */

#define GPIO_CT_I2C_SCL (GPIO_OUTPUT|GPIO_PULLUP|GPIO_SPEED_50MHz|GPIO_OPENDRAIN|GPIO_PORTH|GPIO_PIN6)
#define GPIO_CT_I2C_SDA (GPIO_OUTPUT|GPIO_PULLUP|GPIO_SPEED_50MHz|GPIO_OPENDRAIN|GPIO_PORTI|GPIO_PIN3)


/* IO操作*/
#define CT_IIC_SCL(x)       do{ x ? \
                                   stm32_gpiowrite(GPIO_CT_I2C_SCL, 1): \
                                   stm32_gpiowrite(GPIO_CT_I2C_SCL, 0); \
                               }while(0)                                                 /* SCL引脚 */

#define CT_IIC_SDA(x)       do{ x ? \
                                   stm32_gpiowrite(GPIO_CT_I2C_SDA, 1): \
                                   stm32_gpiowrite(GPIO_CT_I2C_SDA, 0); \
                               }while(0)                                                /* SDA引脚*/

#define CT_READ_SDA         stm32_gpioread(GPIO_CT_I2C_SDA)   /* 输入SDA */

/****************************************************************************
 * Private Data
 ****************************************************************************/





/****************************************************************************
 * Public Functions
 ****************************************************************************/

/****************************************************************************
 * Name: ct_i2c_initialize
 *
 * Description:
 *   
 *
 ****************************************************************************/

void ct_i2c_initialize(void)
{
  stm32_configgpio(GPIO_CT_I2C_SCL);
  stm32_configgpio(GPIO_CT_I2C_SDA);
  CT_IIC_SDA(1);
  CT_IIC_SCL(1);
}

/****************************************************************************
 * Public Functions
 ****************************************************************************/

/****************************************************************************
 * Name: ct_i2c_initialize
 *
 * Description:
 *   
 *
 ****************************************************************************/

void ct_i2c_delay(void)
{
//   nxsig_usleep(2);
  up_udelay(2);
//   usleep(2);
}

/****************************************************************************
 * Name: ct_i2c_start
 *
 * Description:
 *   
 *
 ****************************************************************************/

void ct_i2c_start(void)
{

  CT_IIC_SDA(1);
  CT_IIC_SCL(1);
  ct_i2c_delay();
  CT_IIC_SDA(0);
  ct_i2c_delay();
  CT_IIC_SCL(0);
  ct_i2c_delay();
}

/****************************************************************************
 * Name: ct_i2c_stop
 *
 * Description:
 *   
 *
 ****************************************************************************/

void ct_i2c_stop(void)
{

  CT_IIC_SDA(0);
  ct_i2c_delay();
  CT_IIC_SCL(1);
  ct_i2c_delay();
  CT_IIC_SDA(1);
  ct_i2c_delay();
}

/***************************************************************************
 * Name: ct_i2c_wait_ack
 *
 * Description:
 *   
 *
 ****************************************************************************/

int8_t ct_i2c_wait_ack(void)
{

  uint8_t waittime = 0;
  uint8_t rack = 0;
    
    CT_IIC_SDA(1);
    ct_i2c_delay();
    CT_IIC_SCL(1);
    ct_i2c_delay();

    while (CT_READ_SDA)
    {
        waittime++;

        if (waittime > 250)
        {
            ct_i2c_stop();
            rack = -1;
            break;
        }

        ct_i2c_delay();
    }

    CT_IIC_SCL(0);
    ct_i2c_delay();

    return rack;
}


/***************************************************************************
 * Name: ct_i2c_ack
 *
 * Description:
 *   
 *
 ****************************************************************************/
void ct_i2c_ack(void)
{
    CT_IIC_SDA(0);
    ct_i2c_delay();
    CT_IIC_SCL(1);
    ct_i2c_delay();
    CT_IIC_SCL(0);
    ct_i2c_delay();
    CT_IIC_SDA(1);
    ct_i2c_delay();
}

/***************************************************************************
 * Name: ct_i2c_nack
 *
 * Description:
 *   
 *
 ****************************************************************************/
void ct_i2c_nack(void)
{
    CT_IIC_SDA(1);
    ct_i2c_delay();
    CT_IIC_SCL(1);
    ct_i2c_delay();
    CT_IIC_SCL(0);
    ct_i2c_delay();
}

/***************************************************************************
 * Name: ct_i2c_send_byte
 *
 * Description:
 *   
 *
 ****************************************************************************/
void ct_i2c_send_byte(uint8_t data)
{
    uint8_t t;

    for (t = 0; t < 8; t++)
    {
        CT_IIC_SDA((data & 0x80) >> 7);
        ct_i2c_delay();
        CT_IIC_SCL(1);
        ct_i2c_delay();
        CT_IIC_SCL(0);
        data <<= 1;
    }

    CT_IIC_SDA(1);
}

/***************************************************************************
 * Name: ct_i2c_read_byte
 *
 * Description:
 *   
 *
 ****************************************************************************/
uint8_t ct_i2c_read_byte(unsigned char ack)
{
    uint8_t i, receive = 0;

    for (i = 0; i < 8; i++ )
    {
        receive <<= 1;
        CT_IIC_SCL(1);
        ct_i2c_delay();

        if (CT_READ_SDA)
        {
            receive++;
        }

        CT_IIC_SCL(0);
        ct_i2c_delay();
    }

    if (!ack)
    {
        ct_i2c_nack();
    }
    else
    {
        ct_i2c_ack();
    }

    return receive;
}

GT911驱动
gt9xx.h
/****************************************************************************
 * boards/arm/stm32h7/apollo-stm32h743i/src/gt9xx.h
 ****************************************************************************/

#ifndef __BOARDS_ARM_STM32H7_APOLLO_STM32H743I_SRC_GT9XX_H
#define __BOARDS_ARM_STM32H7_APOLLO_STM32H743I_SRC_GT9XX_H

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/compiler.h>
#include <nuttx/config.h>
#include <nuttx/irq.h>

#ifdef CONFIG_APOLLO_STM32H743I_ATK7016_GT911

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

/* Configuration ************************************************************/

/* Maximum number of threads than can be waiting for POLL events */

#ifndef CONFIG_GT9XX_NPOLLWAITERS
#  define CONFIG_GT9XX_NPOLLWAITERS 2
#endif

/* Check for some required settings.  This can save the user a lot of time
 * in getting the right configuration.
 */

#ifndef CONFIG_SCHED_WORKQUEUE
#  error "Work queue support required.  CONFIG_SCHED_WORKQUEUE must be selected."
#endif

/* GT9XX maximum number of simultaneously detected touches. */

#define GT9XX_MAX_TOUCHES                (5)

/* GT9XX raw touch data length. */

#define GT9XX_TOUCH_DATA_LEN             (0x24)

/* I2C Registers for Goodix GT9XX Touch Panel */

#define GTP_REG_CTRL       0x8040  /* CTRL Register  */
#define GTP_REG_VERSION    0x8140  /* Product ID */

#define GTP_READ_COOR_ADDR 0x814e  /* Touch Panel Status */
#define GTP_POINT1         0x814F  /* Touch Point 1 */
#define GTP_POINT2         0x8157  /* Touch Point 2 */
#define GTP_POINT3         0x815F  /* Touch Point 3 */
#define GTP_POINT4         0x8167  /* Touch Point 4 */
#define GTP_POINT5         0x816F  /* Touch Point 5 */

/*R/W CMD*/
#define GT9XX_CMD_WR                     (0X28)     /* 写命令 */
#define GT9XX_CMD_RD                     (0X29)     /* 读命令 */

/* Operations on struct gt9xx_touch_point_s */
#define TOUCH_POINT_GET_ID(t)             ((t).track_id & 0x07)
#define TOUCH_POINT_GET_X(t)              (((t).xh << 8) | (t).xl)
#define TOUCH_POINT_GET_Y(t)              (((t).yh << 8) | (t).yl)

/****************************************************************************
 * Public Types
 ****************************************************************************/

/* Describes on touchpoint returned by the GT9XX */

struct gt9xx_touch_point_s
{
  uint8_t track_id;
  uint8_t xl;
  uint8_t xh;
  uint8_t yl;
  uint8_t yh;
  uint8_t weight;
  uint8_t area;
};

/* Describes all touch data returned by the GT9XX */

struct gt9xx_touch_data_s
{
  uint8_t tdstatus;    /* Touch status */
  struct gt9xx_touch_point_s touch[GT9XX_MAX_TOUCHES];
};

/* Callback for Board-Specific Operations */

struct gt9xx_config_s
{
  /* Device characterization */

  uint8_t  address;    /* 7-bit I2C address (only bits 0-6 used) */
  uint32_t frequency;  /* Default I2C frequency */

#ifndef CONFIG_GT9XX_POLLMODE
  /* Attach the Interrupt Handler for Touch Panel */
  int (*attach) (FAR const struct gt9xx_config_s *state, xcpt_t isr, FAR void *arg);

  /* Enable or disable Interrupts for the Touch Panel */
  void (*enable) (FAR const struct gt9xx_config_s *state, bool enable);
  
  /* clear   - Acknowledge/clear any pending GPIO interrupt */
  void (*clear)(FAR const struct gt9xx_config_s *config);
#endif
  void (*wakeup)(FAR const struct gt9xx_config_s *config);
  void (*nreset)(FAR const struct gt9xx_config_s *config,
                 bool state);

  /* Power on or off the Touch Panel */

  int (*set_power) (const struct gt9xx_config_s *state, bool on);
};

/****************************************************************************
 * Public Function Prototypes
 ****************************************************************************/
#ifdef __cplusplus
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
 * Name: gt9xx_register
 *
 * Description:
 *   Register the driver for Goodix GT9XX Touch Panel.  Attach the
 *   Interrupt Handler for the Touch Panel and disable Touch Interrupts.
 *
 * Input Parameters:
 *   devpath      - Device Path (e.g. "/dev/input0")
 *   dev          - I2C Bus
 *   i2c_devaddr  - I2C Address of Touch Panel
 *   board_config - Callback for Board-Specific Operations
 *
 * Returned Value:
 *   Zero (OK) on success; a negated errno value is returned on any failure.
 *
 ****************************************************************************/

int gt9xx_register(const struct gt9xx_config_s *board_config, int minor);

int gt9xx_init(void);

#undef EXTERN
#ifdef __cplusplus
}
#endif

#endif

#endif /* __BOARDS_ARM_STM32H7_APOLLO_STM32H743I_SRC_GT9XX_H */

gt9xx.c

参考:

/****************************************************************************
 * boards/arm/stm32h7/apollo-stm32h743i/src/gt9xx.c
 ****************************************************************************/

/* Reference:
 * "NuttX RTOS for PinePhone: Touch Panel"
 * https://lupyuen.github.io/articles/touch2
 */

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/config.h>

#include <sys/types.h>

#include <stdbool.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <poll.h>
#include <errno.h>
#include <assert.h>
#include <debug.h>

#include <nuttx/irq.h>
#include <nuttx/kmalloc.h>
#include <nuttx/arch.h>
#include <nuttx/fs/fs.h>
#include <nuttx/mutex.h>
#include <nuttx/semaphore.h>
#include <nuttx/wqueue.h>
#include <nuttx/wdog.h>
#include <nuttx/signal.h>
#include <nuttx/spinlock.h>

#include <nuttx/input/touchscreen.h>

#include <arch/board/board.h>

#include "arm_internal.h"
#include "chip.h"
#include "stm32.h"

#include "apollo_stm32h743i.h"
#include "gt9xx.h"
#include "ct_i2c.h"

/****************************************************************************
 * Pre-Processor Definitions
 ****************************************************************************/

/* Driver support ***********************************************************/

/* This format is used to construct the /dev/input[n] device driver path.  It
 * defined here so that it will be used consistently in all places.
 */

#define DEV_FORMAT     "/dev/input%d"
#define DEV_NAMELEN    16

#define GT9XX_RST(x)       do{ x ? \
                                   stm32_gpiowrite(GPIO_GT9XX_RST, true): \
                                   stm32_gpiowrite(GPIO_GT9XX_RST, false); \
                               }while(0)   
/* Default I2C Frequency is 400 kHz */

#ifndef CONFIG_INPUT_GT9XX_I2C_FREQUENCY
#  define CONFIG_INPUT_GT9XX_I2C_FREQUENCY 400000
#endif

/* Default Number of Poll Waiters is 1 */

#ifndef CONFIG_INPUT_GT9XX_NPOLLWAITERS
#  define CONFIG_INPUT_GT9XX_NPOLLWAITERS 1
#endif


/* In polled mode, the polling rate will decrease when there is no touch
 * activity.  These definitions represent the maximum and the minimum
 * polling rates.
 */

#define POLL_MINDELAY  MSEC2TICK(50)
#define POLL_MAXDELAY  MSEC2TICK(200)
#define POLL_INCREMENT MSEC2TICK(10)

/****************************************************************************
 * Private Types
 ****************************************************************************/

/* Touch Panel Device */

struct gt9xx_dev_s
{
  uint8_t crefs;                            /* Number of times the device
                                             * has been opened */
  uint8_t nwaiters;                         /* Number of threads waiting for
                                             * GT9XX data */
  volatile bool valid;                      /* True:  New, valid touch data
                                             * in touchbuf[] */
#ifdef CONFIG_GT9XX_SINGLEPOINT
  uint8_t lastid;                           /* Last reported touch id */
  uint8_t lastevent;                        /* Last reported event */
  int16_t lastx;                            /* Last reported X position */
  int16_t lasty;                            /* Last reported Y position */
#endif
  mutex_t devlock;                          /* Manages exclusive access to
                                             * this structure */
  sem_t waitsem;                            /* Used to wait for the
                                             * availability of data */
  uint32_t frequency;                       /* Current I2C frequency */
#ifdef CONFIG_GT9XX_POLLMODE
  uint32_t delay;                           /* Current poll delay */
#endif

  FAR const struct gt9xx_config_s *config; /* Board configuration data */
  struct work_s work;                       /* Supports the interrupt
                                             * handling "bottom half" */
#ifdef CONFIG_GT9XX_POLLMODE
  struct wdog_s polltimer;                  /* Poll timer */
#endif
  uint8_t touchbuf[GT9XX_TOUCH_DATA_LEN];  /* Raw touch data */
  /* Poll Waiters for device */

  FAR struct pollfd *fds[CONFIG_INPUT_GT9XX_NPOLLWAITERS];
};

/****************************************************************************
 * Private Function Prototypes
 ****************************************************************************/
static int gt9xx_i2c_read(uint16_t reg, uint8_t *buf, size_t buflen);
static int gt9xx_i2c_write(uint16_t reg, uint8_t *buf, size_t buflen);
static int gt9xx_probe_device(FAR struct gt9xx_dev_s *dev);
static int gt9xx_set_status(FAR struct gt9xx_dev_s *dev, uint8_t status);

#ifdef CONFIG_GT9XX_POLLMODE
static void gt9xx_poll_timeout(wdparm_t arg);
#else
static int gt9xx_isr_handler(int irq, FAR void *context, FAR void *arg);
#endif


static void gt9xx_notify(FAR struct gt9xx_dev_s *priv);
static void gt9xx_data_worker(FAR void *arg);
static ssize_t gt9xx_sample(FAR struct gt9xx_dev_s *priv, FAR char *buffer,size_t len);
static ssize_t gt9xx_waitsample(FAR struct gt9xx_dev_s *priv,
                                 FAR char *buffer, size_t len);
static int  gt9xx_bringup(FAR struct gt9xx_dev_s *priv);
static void gt9xx_shutdown(FAR struct gt9xx_dev_s *priv);

 /* Character driver methods */
static int gt9xx_open(FAR struct file *filep);
static int gt9xx_close(FAR struct file *filep);
static ssize_t gt9xx_read(FAR struct file *filep, FAR char *buffer,
                          size_t len);
static int gt9xx_poll(FAR struct file *filep, FAR struct pollfd *fds,
                      bool setup);
static int gt9xx_ioctl(FAR struct file *filep, int cmd,
                         unsigned long arg);

/****************************************************************************
 * Private Data
 ****************************************************************************/

/* File Operations for Touch Panel */

static const struct file_operations g_gt9xx_fileops =
{
  gt9xx_open,   /* open */
  gt9xx_close,  /* close */
  gt9xx_read,   /* read */
  NULL,         /* write */
  NULL,         /* seek */
  gt9xx_ioctl,  /* ioctl */
  NULL,         /* truncate */
  NULL,         /* mmap */
  gt9xx_poll,   /* poll */
  NULL,         /* readv */
  NULL          /* writev */
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  , NULL        /* unlink */
#endif
};

static const uint16_t g_gtp_reg_map[GT9XX_MAX_TOUCHES] =
{
  GTP_POINT1, 
  GTP_POINT2, 
  GTP_POINT3, 
  GTP_POINT4,
  GTP_POINT5
};


/****************************************************************************
 * Private Functions
 ****************************************************************************/

/****************************************************************************
 * Name: gt9xx_i2c_read
 *
 * Description:
 *   Read a Touch Panel Register over I2C.
 *
 * Input Parameters:
 *   dev    - Touch Panel Device
 *   reg    - I2C Register to be read
 *   buf    - Receive Buffer
 *   buflen - Number of bytes to be read
 *
 * Returned Value:
 *   Zero (OK) on success; a negated errno value is returned on any failure.
 *
 ****************************************************************************/

static int gt9xx_i2c_read(uint16_t reg,
                          uint8_t *buf,
                          size_t buflen)
{
    uint8_t i;
    ct_i2c_start();
    ct_i2c_send_byte(GT9XX_CMD_WR);                             /* 发送写命令 */
    ct_i2c_wait_ack();
    ct_i2c_send_byte(reg >> 8);                                 /* 发送高8位地址 */
    ct_i2c_wait_ack();
    ct_i2c_send_byte(reg & 0XFF);                               /* 发送低8位地址 */
    ct_i2c_wait_ack();
    ct_i2c_start();
    ct_i2c_send_byte(GT9XX_CMD_RD);                             /* 发送读命令 */
    ct_i2c_wait_ack();

    for (i = 0; i < buflen; i++)
    {
        buf[i] = ct_i2c_read_byte(i == (buflen - 1) ? 0 : 1);   /* 接收数据 */
    }

    ct_i2c_stop();                                              /* 产生一个停止条件 */

#ifdef CONFIG_DEBUG_INPUT_INFO
  iinfodumpbuffer("gt9xx_i2c_read", buf, buflen);
#endif /* CONFIG_DEBUG_INPUT_INFO */

  return OK;
}

/****************************************************************************
 * Name: gt9xx_i2c_write
 *
 * Description:
 *   Write to a Touch Panel Register over I2C.
 *
 * Input Parameters:
 *   dev - Touch Panel Device
 *   reg - I2C Register to be written
 *   val - Value to be written
 *
 * Returned Value:
 *   Zero (OK) on success; a negated errno value is returned on any failure.
 *
 ****************************************************************************/

static int gt9xx_i2c_write(uint16_t reg, uint8_t *buf, size_t buflen)
{
    uint8_t i;
    int8_t ret = OK;
    ct_i2c_start();
    ct_i2c_send_byte(GT9XX_CMD_WR);     /* 发送写命令 */
    ct_i2c_wait_ack();
    ct_i2c_send_byte(reg >> 8);         /* 发送高8位地址 */
    ct_i2c_wait_ack();
    ct_i2c_send_byte(reg & 0XFF);       /* 发送低8位地址 */
    ct_i2c_wait_ack();

    for (i = 0; i < buflen; i++)
    {
        ct_i2c_send_byte(buf[i]);       /* 发送数据 */
        ret = ct_i2c_wait_ack();

        if (ret) break;
    }

    ct_i2c_stop();                      /* 产生一个停止条件 */
    return ret;
}

/****************************************************************************
 * Name: gt9xx_probe_device
 *
 * Description:
 *   Read the Product ID from the Touch Panel over I2C.
 *
 * Input Parameters:
 *   dev - Touch Panel Device
 *
 * Returned Value:
 *   Zero (OK) on success; a negated errno value is returned on any failure.
 *
 ****************************************************************************/

static int gt9xx_probe_device(FAR struct gt9xx_dev_s *dev)
{
  int ret;
  uint8_t id[4];

  /* Read the Product ID */

  gt9xx_i2c_read(GTP_REG_VERSION, id, sizeof(id));
  id[4] = 0;
  iinfo("CTP ID: %s\n", id);
  ret = strcmp((char *)id, "911");
  
  if (ret != 0)
    {
      // printf("I2C Probe failed: %d\n", ret);
      ierr("I2C Probe failed: %d\n", ret);
      return -1;
    }

  /* For GT917S: Product ID will be 39 31 37 53, i.e. "917S" */

#ifdef CONFIG_DEBUG_INPUT_INFO
  iinfodumpbuffer("gt9xx_probe_device", id, sizeof(id));
#endif /* CONFIG_DEBUG_INPUT_INFO */

  return OK;
}

/****************************************************************************
 * Name: gt9xx_set_status
 *
 * Description:
 *   Set the Touch Panel Status over I2C.
 *
 * Input Parameters:
 *   dev    - Touch Panel Device
 *   status - Status value to be set
 *
 * Returned Value:
 *   Zero (OK) on success; a negated errno value is returned on any failure.
 *
 ****************************************************************************/

static int gt9xx_set_status(FAR struct gt9xx_dev_s *dev, uint8_t status)
{
  int ret;

  iinfo("status=%d\n", status);
  DEBUGASSERT(dev);

  /* Write to the Status Register over I2C */

  ret = gt9xx_i2c_write(GTP_READ_COOR_ADDR, &status, sizeof(status));
  if (ret < 0)
    {
      ierr("Set Status failed: %d\n", ret);
      return ret;
    }

  return OK;
}

/****************************************************************************
 * Name: gt9xx_read
 *
 * Description:
 *   Read a Touch Sample from Touch Panel. Returns either 0 or 1
 *   Touch Points.
 *
 * Input Parameters:
 *   dev    - Touch Panel Device
 *   buffer - Returned Touch Sample (0 or 1 Touch Points)
 *   buflen - Size of buffer
 *
 * Returned Value:
 *   Zero (OK) on success; a negated errno value is returned on any failure.
 *
 ****************************************************************************/
#ifdef CONFIG_GT9XX_SINGLEPOINT
static ssize_t gt9xx_read(FAR struct file *filep, FAR char *buffer,
                          size_t len)
{
  FAR struct inode *inode;
  FAR struct gt9xx_dev_s *priv;
  struct touch_sample_s sample;
  const size_t outlen = sizeof(sample);
  int ret;

  /* Returned Touch Sample will have 0 or 1 Touch Points */
  iinfo("buflen=%ld\n",len);
  if (len < outlen)
    {
      ierr("Buffer should be at least %ld bytes, got %ld bytes\n",
           outlen, len);
      return -EINVAL;
    }

  /* Get the Touch Panel Device */

  inode = filep->f_inode;
  DEBUGASSERT(inode->i_private);
  priv = inode->i_private;

  /* Begin Mutex: Lock to prevent concurrent reads */

  ret = nxmutex_lock(&priv->devlock);
  if (ret < 0)
    {
      ierr("ERROR: nxmutex_lock failed: %d\n", ret);
      return ret;
    }

  /* Try to read sample data. */
  ret = gt9xx_sample(priv, buffer, len);
  while (ret == 0)
    {
      /* Sample data is not available now.  We would have to wait to receive
      * sample data.  If the user has specified the O_NONBLOCK option, then
      * just return an error.
      */

      if (filep->f_oflags & O_NONBLOCK)
        {
          ret = -EAGAIN;
          goto errout;
        }

      /* Wait for sample data */

      ret = gt9xx_waitsample(priv, buffer, len);
      if (ret < 0)
        {
          /* We might have been awakened by a signal */

          goto errout;
        }
    }

  ret = SIZEOF_TOUCH_SAMPLE_S(1);

errout:
  /* End Mutex: Unlock to allow next read */
  nxmutex_unlock(&priv->devlock);
  return ret;
}
#endif
/****************************************************************************
 * Name: gt9xx_open
 *
 * Description:
 *   Open the Touch Panel Device.  If this is the first open, we power on
 *   the Touch Panel, probe for the Touch Panel and enable Touch Panel
 *   Interrupts.
 *
 * Input Parameters:
 *   filep - File Struct for Touch Panel
 *
 * Returned Value:
 *   Zero (OK) on success; a negated errno value is returned on any failure.
 *
 ****************************************************************************/

static int gt9xx_open(FAR struct file *filep)
{
  FAR struct inode *inode;
  FAR struct gt9xx_dev_s *priv;
  unsigned int use_count;
  int ret;

  /* Get the Touch Panel Device */

  iinfo("\n");
  inode = filep->f_inode;
  DEBUGASSERT(inode->i_private);
  priv = inode->i_private;

  /* Begin Mutex: Lock to prevent concurrent update to Reference Count */

  ret = nxmutex_lock(&priv->devlock);
  if (ret < 0)
    {
      ierr("Lock Mutex failed: %d\n", ret);
      return ret;
    }

  /* Get next Reference Count */

  use_count = priv->crefs + 1;
  if (use_count == 0)
    {
      /* More than 255 opens; uint8_t overflows to zero */

      ret = -EMFILE;
      goto errout_with_lock;
    }

  /* When the reference increments to 1, this is the first open event
   * on the driver.. and the time when we must initialize the driver.
   */

  if (use_count == 1)
    {
      ret = gt9xx_bringup(priv);
      if (ret < 0)
        {
          ierr("ERROR: gt9xx_bringup failed: %d\n", ret);
          goto errout_with_lock;
        }
    }

  /* Save the new open count on success */

  priv->crefs = use_count;

errout_with_lock:
  nxmutex_unlock(&priv->devlock);
  return ret;
}

/****************************************************************************
 * Name: gt9xx_close
 *
 * Description:
 *   Close the Touch Panel Device.  If this is the final close, we disable
 *   Touch Panel Interrupts and power off the Touch Panel.
 *
 * Input Parameters:
 *   filep - File Struct for Touch Panel
 *
 * Returned Value:
 *   Zero (OK) on success; a negated errno value is returned on any failure.
 *
 ****************************************************************************/

static int gt9xx_close(FAR struct file *filep)
{
  FAR struct inode *inode;
  FAR struct gt9xx_dev_s *priv;
  int ret;

  /* Get the Touch Panel Device */

  iinfo("\n");
  inode = filep->f_inode;
  DEBUGASSERT(inode->i_private);
  priv = inode->i_private;

  /* Begin Mutex: Lock to prevent concurrent update to Reference Count */

  ret = nxmutex_lock(&priv->devlock);
  if (ret < 0)
    {
      ierr("ERROR: nxmutex_lock failed: %d\n", ret);
      return ret;
    }

  /* Decrement the reference count unless it would decrement a negative
   * value.
   */

  if (priv->crefs >= 1)
    {
      priv->crefs--;
    }

  /* When the count decrements to zero, there are no further open references
   * to the driver and it can be uninitialized.
   */

  if (priv->crefs == 0)
    {
      gt9xx_shutdown(priv);
    }

  nxmutex_unlock(&priv->devlock);
  return OK;
}

/****************************************************************************
 * Name: gt9xx_ioctl
 ****************************************************************************/

static int gt9xx_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
{
  FAR struct inode        *inode;
  FAR struct gt9xx_dev_s  *priv;
  int                      ret;

  iinfo("cmd: %d arg: %ld\n", cmd, arg);
  inode = filep->f_inode;

  DEBUGASSERT(inode->i_private);
  priv  = inode->i_private;

  /* Get exclusive access to the driver data structure */

  ret = nxmutex_lock(&priv->devlock);
  if (ret < 0)
    {
      ierr("ERROR: nxmutex_lock failed: %d\n", ret);
      return ret;
    }

  /* Process the IOCTL by command */

  switch (cmd)
    {
      case TSIOC_GETMAXPOINTS:
        {
          FAR uint32_t *ptr = (FAR uint32_t *)((uintptr_t)arg);
          DEBUGASSERT(priv->config != NULL && ptr != NULL);
          *ptr = 1;
        }
        break;

      default:
        ret = -ENOTTY;
        break;
    }

  nxmutex_unlock(&priv->devlock);
  return ret;
}

/****************************************************************************
 * Name: gt9xx_poll
 *
 * Description:
 *   Setup or teardown a poll for the Touch Panel Device.
 *
 * Input Parameters:
 *   filep - File Struct for Touch Panel
 *   fds   - The structure describing the events to be monitored, OR NULL if
 *           this is a request to stop monitoring events.
 *   setup - true: Setup the poll; false: Teardown the poll
 *
 * Returned Value:
 *   Zero (OK) on success; a negated errno value is returned on any failure.
 *
 ****************************************************************************/

static int gt9xx_poll(FAR struct file *filep, FAR struct pollfd *fds,
                      bool setup)
{
  FAR struct inode        *inode;
  FAR struct gt9xx_dev_s  *priv;
  int                       ret;
  int                       i;

  iinfo("setup: %d\n", (int)setup);
  DEBUGASSERT(fds);
  inode = filep->f_inode;

  DEBUGASSERT(inode->i_private);
  priv  = inode->i_private;

  /* Are we setting up the poll?  Or tearing it down? */

  ret = nxmutex_lock(&priv->devlock);
  if (ret < 0)
    {
      ierr("ERROR: nxmutex_lock failed: %d\n", ret);
      return ret;
    }

  if (setup)
    {
      /* Ignore waits that do not include POLLIN */

      if ((fds->events & POLLIN) == 0)
        {
          ierr("ERROR: Missing POLLIN: revents: %08" PRIx32 "\n",
               fds->revents);
          ret = -EDEADLK;
          goto errout;
        }

      /* This is a request to set up the poll.  Find an available
       * slot for the poll structure reference
       */

      for (i = 0; i < CONFIG_GT9XX_NPOLLWAITERS; i++)
        {
          /* Find an available slot */

          if (!priv->fds[i])
            {
              /* Bind the poll structure and this slot */

              priv->fds[i] = fds;
              fds->priv    = &priv->fds[i];
              break;
            }
        }

      if (i >= CONFIG_GT9XX_NPOLLWAITERS)
        {
          ierr("ERROR: No available slot found: %d\n", i);
          fds->priv = NULL;
          ret       = -EBUSY;
          goto errout;
        }

      /* Should we immediately notify on any of the requested events? */

      if (priv->valid)
        {
          poll_notify(&fds, 1, POLLIN);
        }
    }
  else if (fds->priv)
    {
      /* This is a request to tear down the poll. */

      FAR struct pollfd **slot = (FAR struct pollfd **)fds->priv;
      DEBUGASSERT(slot != NULL);

      /* Remove all memory of the poll setup */

      *slot     = NULL;
      fds->priv = NULL;
    }

errout:
  nxmutex_unlock(&priv->devlock);
  return ret;
}

/****************************************************************************
 * Name: gt9xx_poll_timeout
 ****************************************************************************/

#ifdef CONFIG_GT9XX_POLLMODE
static void gt9xx_poll_timeout(wdparm_t arg)
{
  FAR struct gt9xx_dev_s *priv = (FAR struct gt9xx_dev_s *)arg;
  int ret;

  /* Transfer processing to the worker thread.  Since GT9XX poll timer is
   * disabled while the work is pending, no special action should be
   * required to protected the work queue.
   */

  DEBUGASSERT(priv->work.worker == NULL);
  ret = work_queue(HPWORK, &priv->work, gt9xx_data_worker, priv, 0);
  if (ret != 0)
    {
      ierr("ERROR: Failed to queue work: %d\n", ret);
    }
}
#endif

/****************************************************************************
 * Name: gt9xx_isr_handler
 *
 * Description:
 *   Interrupt Handler for Touch Panel.
 *
 * Input Parameters:
 *   irq     - IRQ Number
 *   context - IRQ Context
 *   arg     - Touch Panel Device
 *
 * Returned Value:
 *   Zero (OK) on success; a negated errno value is returned on any failure.
 *
 ****************************************************************************/

#ifndef CONFIG_GT9XX_POLLMODE
static int gt9xx_isr_handler(int irq, FAR void *context, FAR void *arg)
{
  FAR struct gt9xx_dev_s *priv = (FAR struct gt9xx_dev_s *)arg;
  FAR const struct gt9xx_config_s *config;
  int ret;

  /* Get a pointer the callbacks for convenience (and so the code is not so
   * ugly).
   */

  config = priv->config;
  DEBUGASSERT(config != NULL);

  /* Disable further interrupts */

  config->enable(config, false);

  /* Transfer processing to the worker thread.  Since GT9XX interrupts are
   * disabled while the work is pending, no special action should be required
   * to protected the work queue.
   */

  DEBUGASSERT(priv->work.worker == NULL);
  ret = work_queue(HPWORK, &priv->work, gt9xx_data_worker, priv, 0);
  if (ret != 0)
    {
      ierr("ERROR: Failed to queue work: %d\n", ret);
    }

  /* Clear any pending interrupts and return success */

  config->clear(config);
  return OK;
}
#endif

/****************************************************************************
 * Public Functions
 ****************************************************************************/

/****************************************************************************
 * Name: gt9xx_register
 *
 * Description:
 *   Register the driver for Goodix GT9XX Touch Panel.  Attach the
 *   Interrupt Handler for the Touch Panel and disable Touch Interrupts.
 *
 * Input Parameters:
 *   devpath      - Device Path (e.g. "/dev/input0")
 *   i2c_devaddr  - I2C Address of Touch Panel
 *   board_config - Callback for Board-Specific Operations
 *
 * Returned Value:
 *   Zero (OK) on success; a negated errno value is returned on any failure.
 *
 ****************************************************************************/

int gt9xx_register(const struct gt9xx_config_s *config, int minor)
{
  char devpath[DEV_NAMELEN];
  struct gt9xx_dev_s *priv;
  int ret = 0;

  /* Debug-only sanity checks */

  DEBUGASSERT(config != NULL && minor >= 0 && minor < 100);
#ifdef CONFIG_GT9XX_POLLMODE
  DEBUGASSERT(config->wakeup != NULL && config->nreset != NULL);
#else
  DEBUGASSERT(config->attach != NULL && config->enable != NULL &&
              config->clear  != NULL && config->wakeup != NULL &&
              config->nreset != NULL);
#endif


  /* Allocate the Touch Panel Device Structure */

  priv = kmm_zalloc(sizeof(struct gt9xx_dev_s));
  if (!priv)
    {
      ierr("GT9XX Memory Allocation failed\n");
      return -ENOMEM;
    }

  /* Initialize the GT9XX device driver instance */

  priv->config = config;
  nxmutex_init(&priv->devlock);

  nxmutex_init(&priv->devlock);        /* Initialize device structure mutex */
  nxsem_init(&priv->waitsem, 0, 0);    /* Initialize pen event wait semaphore */
  
  #ifdef CONFIG_GT9XX_POLLMODE
  /* Allocate a timer for polling the GT9XX */

    priv->delay     = POLL_MAXDELAY;
  #else
    /* Make sure that the GT9XX interrupt interrupt is disabled */

    config->clear(config);
    config->enable(config, false);

    /* Attach the interrupt handler */

    ret = config->attach(config, gt9xx_isr_handler,
                        priv);
    if (ret < 0)
      {
        ierr("ERROR: Failed to attach interrupt\n");
        goto errout_with_priv;
      }
  #endif
  
  /* Register the Touch Input Driver */

  snprintf(devpath, sizeof(devpath), DEV_FORMAT, minor);
  iinfo("Registering %s\n", devpath);

  ret = register_driver(devpath, &g_gt9xx_fileops, 0666, priv);
  if (ret < 0)
    {
      ierr("ERROR: GT9XX Registration failed: %d\n", ret);
      goto errout_with_priv;
    }

  /* Schedule work to perform the initial sampling and to set the data
  * availability conditions.
  */

  ret = work_queue(HPWORK, &priv->work, gt9xx_data_worker, priv, 0);
  if (ret < 0)
    {
      ierr("ERROR: Failed to queue work: %d\n", ret);
      goto errout_with_priv;
    }

  /* And return success */

  return OK;

errout_with_priv:
  nxmutex_destroy(&priv->devlock);
  nxsem_destroy(&priv->waitsem);
  kmm_free(priv);
  return ret;
}

int gt9xx_init(void)
{
  int ret;
  uint8_t val[2];
    /* Configure the GT9XX interrupt pin as an input */

  stm32_configgpio(GPIO_GT9XX_RST);

  stm32_configgpio(GPIO_GT9XX_INT_PP);

  /* Get an instance of the I2C interface */

  ct_i2c_initialize();

  GT9XX_RST(0);
  nxsig_usleep(10*1000);
  GT9XX_RST(1);
  nxsig_usleep(10*1000);
  
  stm32_configgpio(GPIO_GT9XX_INT_FT);
  nxsig_usleep(100*1000);

  val[0] = 0x02;
  ret = gt9xx_i2c_write(GTP_REG_CTRL, val,1);
  if (ret < 0)
    {
      ierr("Set Software Reset failed: %d\n", ret);
      return ret;
    }

  nxsig_usleep(10*1000);

  val[0] = 0x00;
  ret = gt9xx_i2c_write(GTP_REG_CTRL, val,1);
  if (ret < 0)
    {
      ierr("End Software Reset failed: %d\n", ret);
      return ret;
    }

  return ret;

}

/****************************************************************************
 * Name: gt9xx_notify
 ****************************************************************************/

static void gt9xx_notify(FAR struct gt9xx_dev_s *priv)
{
  /* If there are threads waiting on poll() for GT9XX data to become
   * available, then wake them up now.  NOTE: we wake up all waiting threads
   * because we do not know that they are going to do.  If they all try to
   * read the data, then some make end up blocking after all.
   */

  poll_notify(priv->fds, CONFIG_INPUT_GT9XX_NPOLLWAITERS, POLLIN);

  /* If there are threads waiting for read data, then signal one of them
   * that the read data is available.
   */

  if (priv->nwaiters > 0)
    {
      /* After posting this semaphore, we need to exit because the GT9XX
       * is no longer available.
       */

      nxsem_post(&priv->waitsem);
    }
}

/****************************************************************************
 * Name: gt9xx_data_worker
 ****************************************************************************/

static void gt9xx_data_worker(FAR void *arg)
{
  FAR struct gt9xx_dev_s *priv = (FAR struct gt9xx_dev_s *)arg;
  FAR const struct gt9xx_config_s *config;
  uint8_t status[1];
  uint8_t status_code;
  uint8_t touched_points;
  uint8_t touch[7];
  uint8_t i;
  int ret;
  
  /* Get a pointer the callbacks for convenience */

  DEBUGASSERT(priv != NULL && priv->config != NULL);
  config = priv->config;

  /* We need to have exclusive access to the touchbuf so that we do not
   * corrupt any read operation that is in place.
   */

  nxmutex_lock(&priv->devlock);

    /* Read the Touch Panel Status */
  memset(status, 0, sizeof(status));
  ret = gt9xx_i2c_read(GTP_READ_COOR_ADDR, status, sizeof(status));
  if (ret < 0)
    {
      // printf("Read Touch Panel Status failed: %d\n", ret);
      ierr("Read Touch Panel Status failed: %d\n", ret);
      return;
    }

  /* Decode the Status Code and the Touched Points */

  status_code = status[0] & 0x80;
  touched_points = status[0] & 0x0f;

  /* If Touch Panel Status is OK and Touched Points is 1 or more */

  memcpy(priv->touchbuf, status, sizeof(status));
  
  if (status_code == 0x80  && touched_points <= GT9XX_MAX_TOUCHES )
    {
      /* Set the Touch Panel Status to 0 */
      ret = gt9xx_set_status(priv, 0);
      if (ret < 0)
        {
          ierr("Set Touch Panel Status failed: %d\n", ret);
        }
      if (touched_points >= 1)
        {
          /* Read Each Touch Point (6 bytes) */
          for (i=0; i < touched_points; i++)
            {
              ret = gt9xx_i2c_read(g_gtp_reg_map[i], touch, sizeof(touch));
              if (ret < 0)
                {
                  ierr("Read Touch Point_%d failed: %d\n", i+1, ret);
                  continue;
                }
              memcpy(&priv->touchbuf[i*7 + 1], touch, sizeof(touch));
            }
        }

      /* Notify any waiters that new GT9XX data is available */

      priv->valid = true;
      gt9xx_notify(priv);
      
    }
      
#ifdef CONFIG_GT9XX_POLLMODE
  if (status_code == 0x80 && touched_points <= GT9XX_MAX_TOUCHES)
    {

      /* Keep it at the minimum if touches are detected. */

          priv->delay = POLL_MINDELAY;
    }     
  else if (priv->delay < POLL_MAXDELAY)
    {
          /* Otherwise, let the poll rate rise gradually up to the maximum
           * if there is no touch.
           */

          priv->delay += POLL_INCREMENT;
    }
  
  /* Exit, re-starting the poll. */

  wd_start(&priv->polltimer, priv->delay,
           gt9xx_poll_timeout, (wdparm_t)priv);

#else
    
  /* Exit, re-enabling GT9XX interrupts */

  config->enable(config, true);
#endif

  nxmutex_unlock(&priv->devlock);
}

/****************************************************************************
 * Name: gt9xx_data_interrupt
 ****************************************************************************/

#ifndef CONFIG_GT9XX_POLLMODE
static int gt9xx_data_interrupt(int irq, FAR void *context, FAR void *arg)
{
  FAR struct gt9xx_dev_s *priv = (FAR struct gt9xx_dev_s *)arg;
  FAR const struct gt9xx_config_s *config;
  int ret;

  /* Get a pointer the callbacks for convenience (and so the code is not so
   * ugly).
   */

  config = priv->config;
  DEBUGASSERT(config != NULL);

  /* Disable further interrupts */

  config->enable(config, false);

  /* Transfer processing to the worker thread.  Since GT9XX interrupts are
   * disabled while the work is pending, no special action should be required
   * to protected the work queue.
   */

  DEBUGASSERT(priv->work.worker == NULL);
  ret = work_queue(HPWORK, &priv->work, gt9xx_data_worker, priv, 0);
  if (ret != 0)
    {
      ierr("ERROR: Failed to queue work: %d\n", ret);
    }

  /* Clear any pending interrupts and return success */

  config->clear(config);
  return OK;
}
#endif

/****************************************************************************
 * Name: gt9xx_sample
 ****************************************************************************/

#ifdef CONFIG_GT9XX_SINGLEPOINT
static ssize_t gt9xx_sample(FAR struct gt9xx_dev_s *priv, FAR char *buffer,
                             size_t len)
{
  FAR struct gt9xx_touch_data_s *raw;
  FAR struct gt9xx_touch_point_s *touch;
  FAR struct touch_sample_s *sample;
  FAR struct touch_point_s *point;
  int16_t x;
  int16_t y;
  uint8_t event;
  uint8_t id;
  
  if (!priv->valid)
    {
      return 0;  /* Nothing to read */
    }

  /* Raw data pointers (source) */

  raw = (FAR struct gt9xx_touch_data_s *)priv->touchbuf;
  touch = raw->touch;

  /* User data buffer points (sink) */

  /* Return the number of touches read */

  sample            = (FAR struct touch_sample_s *)buffer;
  point             = sample->point;
  memset(sample, 0, sizeof(*sample));

  if((raw->tdstatus & 0x8f) == 0x80)          /* 无触摸点按下 */
    {
      if (priv->lastevent & TOUCH_DOWN)       /* 之前是被按下的 */
        {
          priv->lastevent = TOUCH_UP | TOUCH_ID_VALID | TOUCH_POS_VALID;    /* 标记松开 */
          point[0].flags    = priv->lastevent;
          point[0].x        = priv->lastx;
          point[0].y        = priv->lasty;
          point[0].id       = 0;
          sample->npoints   = 1;
          // printf("touch up x=%d, y=%d\n", priv->lastx, priv->lasty);
          iinfo("touch up x=%d, y=%d\n", priv->lastx, priv->lasty);
        }
      else
        {
          /* No... no new touch data */

          goto reset_and_drop;

        }
    }
  else if((raw->tdstatus & 0x80) && (raw->tdstatus & 0x0f))
    {
      /* Get the reported X and Y positions */

      id = TOUCH_POINT_GET_ID(touch[0]);
      x = TOUCH_POINT_GET_X(touch[0]);
      y = TOUCH_POINT_GET_Y(touch[0]);
      event = TOUCH_DOWN | TOUCH_ID_VALID | TOUCH_POS_VALID;
          
      iinfo("touch down x=%d, y=%d\n", x, y);
      sample->npoints   = 1;
      priv->lastid      = id;
      priv->lastevent   = event;
      priv->lastx       = x;
      priv->lasty       = y;

      /* Decode and return the single touch point */
      
      point[0].id       = 0;
      point[0].flags    = event;
      point[0].x        = x;
      point[0].y        = y;
      point[0].h        = 0;
      point[0].w        = 0;
      point[0].pressure = 0;
           
    }

  priv->valid       = false;
  return SIZEOF_TOUCH_SAMPLE_S(1);

reset_and_drop:
  priv->lastx = 0;
  priv->lasty = 0;
  priv->valid = false;
  return 0;  /* No new touches read. */
}

#else
static ssize_t gt9xx_sample(FAR struct gt9xx_dev_s *priv, FAR char *buffer,
                             size_t len)
{
  FAR struct gt9xx_touch_data_s *raw;
  FAR struct gt9xx_touch_point_s *touch;
  FAR struct touch_sample_s *sample;
  FAR struct touch_point_s *point;
  unsigned int maxtouches;
  unsigned int ntouches;
  int i;

  maxtouches = (len - sizeof(int)) / sizeof(struct touch_point_s);
  DEBUGASSERT(maxtouches > 0);  /* Already verified */

  if (!priv->valid)
    {
      return 0;  /* Nothing to read */
    }

  /* Raw data pointers (source) */

  raw      = (FAR struct gt9xx_touch_data_s *)priv->touchbuf;
  touch    = raw->touch;

  /* Decode number of touches */

  ntouches = raw->tdstatus & 0x0f;
  DEBUGASSERT(ntouches <= GT9XX_MAX_TOUCHES);

  if (ntouches > maxtouches)
    {
      ntouches = maxtouches;
    }

  if (ntouches < 1)
    {
      priv->valid = false;
      return 0;  /* No touches read. */
    }

  /* User data buffer points (sink) */

  sample = (FAR struct touch_sample_s *)buffer;
  point  = sample->point;

  /* Return the number of touches read */

  sample->npoints = ntouches;
  priv->last_ntouches  = ntouches;

  /* Decode and return the touch points */

  for (i = 0; i < ntouches; i++)
    {

      point[i].id       = TOUCH_POINT_GET_ID(touch[i]);
      point[i].flags    = TOUCH_DOWN | TOUCH_ID_VALID | TOUCH_POS_VALID;
      point[i].x        = TOUCH_POINT_GET_X(touch[i]);
      point[i].y        = TOUCH_POINT_GET_Y(touch[i]);
      point[i].h        = 0;
      point[i].w        = 0;
      point[i].pressure = 0;

      priv->lastid[i]      = point[i].id;
      priv->lastevent[i]   = point[i].flags;
      priv->lastx[i]       = point[i].x;
      priv->lasty[i]       = point[i].y;

    }

  // priv->valid = false;
  return SIZEOF_TOUCH_SAMPLE_S(ntouches);
}
#endif /* CONFIG_GT9XX_SINGLEPOINT */

/****************************************************************************
 * Name: gt9xx_waitsample
 ****************************************************************************/

static ssize_t gt9xx_waitsample(FAR struct gt9xx_dev_s *priv,
                                 FAR char *buffer, size_t len)
{
  int ret;

  /* Now release the semaphore that manages mutually exclusive access to
   * the device structure.  This may cause other tasks to become ready to
   * run, but they cannot run yet because pre-emption is disabled.
   */

  nxmutex_unlock(&priv->devlock);

  /* Try to get the a sample... if we cannot, then wait on the semaphore
   * that is posted when new sample data is available.
   */

  while (!priv->valid)
    {
      /* Increment the count of waiters */

      priv->nwaiters++;

      /* Wait for a change in the GT9XX state */

      ret = nxsem_wait(&priv->waitsem);
      priv->nwaiters--;

      if (ret < 0)
        {
          ierr("ERROR: nxsem_wait failed: %d\n", ret);
          goto errout;
        }
    }

  /* Re-acquire the semaphore that manages mutually exclusive access to
   * the device structure.  We may have to wait here.  But we have our
   * sample.  Interrupts and pre-emption will be re-enabled while we wait.
   */

  ret = nxmutex_lock(&priv->devlock);
  if (ret >= 0)
    {
      /* Now sample the data.
       *
       * REVISIT:  Is it safe to assume that priv->valid will always be
       * true?  I think that sched_lock() would protect the setting.
       */

      ret = gt9xx_sample(priv, buffer, len);
    }

errout:
  return ret;
}

/****************************************************************************
 * Name: gt9xx_bringup
 ****************************************************************************/

static int gt9xx_bringup(FAR struct gt9xx_dev_s *priv)
{
  FAR const struct gt9xx_config_s *config;
  int ret;

  /* Get a pointer the callbacks for convenience (and so the code is not so
   * ugly).
   */

  config = priv->config;
  DEBUGASSERT(config != NULL);

  /* If first user, power on the Touch Panel */

  DEBUGASSERT(priv->config->set_power != NULL);
  ret = priv->config->set_power(priv->config, true);
  if (ret < 0)
    {
      return ret;
    }

  /* Let Touch Panel power up before probing */

  nxsig_usleep(100 * 1000);

  /* Check that Touch Panel exists on I2C */

  ret = gt9xx_probe_device(priv);
  if (ret < 0)
    {
      /* No such device, power off the Touch Panel */

      priv->config->set_power(priv->config, false);
      return ret;
    }

#ifndef CONFIG_GT9XX_POLLMODE
  /* Enable GT9XX interrupts */

  config->clear(config);
  config->enable(config, true);
#endif
  return OK;
}

/****************************************************************************
 * Name: gt9xx_shutdown
 ****************************************************************************/

static void gt9xx_shutdown(FAR struct gt9xx_dev_s *priv)
{
#ifdef CONFIG_GT9XX_POLLMODE
  /* Stop the poll timer */

  wd_cancel(&priv->polltimer);

#else
  FAR const struct gt9xx_config_s *config = priv->config;

  /* Make sure that the GT9XX interrupt is disabled */

  config->clear(config);
  config->enable(config, false);
#endif
}
stm32_touchscreen.c:触摸屏驱动

参考:boards/arm/stm32h7/stm32h750b-dk/src/stm32_ft5x06.c

/****************************************************************************
 * boards/arm/stm32h7/apollo-stm32h743i-disco/src/stm32_touchscreen.c
****************************************************************************/

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/config.h>

#include <assert.h>
#include <debug.h>
#include <errno.h>

#include <nuttx/spinlock.h>

#include <arch/board/board.h>

#include "chip.h"
#include "arm_internal.h"
#include "stm32.h"


#include "apollo_stm32h743i.h"
#include "gt9xx.h"

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

#define GT9XX_FREQUENCY 100000  /* For now, will boost later */

#ifndef CONFIG_APOLLO_STM32H743I_CT_I2C
#  error "GT9XX support requires CONFIG_APOLLO_STM32H743I_CT_I2C"
#endif

#ifndef CONFIG_GT9XX_DEVMINOR
#  define CONFIG_GT9XX_DEVMINOR 0
#endif

#define GT9XX_RST(x)       do{ x ? \
                                   stm32_gpiowrite(GPIO_GT9XX_RST, true): \
                                   stm32_gpiowrite(GPIO_GT9XX_RST, false)\
                               }while(0)  

/****************************************************************************
 * Private Types
 ****************************************************************************/

struct stm32_gt9xx_config_s
{
  xcpt_t  handler;  /* The GT9XX interrupt handler */
  void   *arg;      /* Interrupt handler argument */
};
/****************************************************************************
 * Private Function Ptototypes
 ****************************************************************************/
#ifndef CONFIG_GT9XX_POLLMODE
static int  stm32_gt9xx_irq_attach(const struct gt9xx_config_s *config,
                                xcpt_t isr, void *arg);
static void stm32_gt9xx_irq_enable(const struct gt9xx_config_s *config,
                                bool enable);
static void stm32_gt9xx_clear(const struct gt9xx_config_s *config);
#endif
static void stm32_gt9xx_wakeup(const struct gt9xx_config_s *config);
static void stm32_gt9xx_nreset(const struct gt9xx_config_s *config,
                                bool state);
static int stm32_gt9xx_set_power(const struct gt9xx_config_s *config,
                                     bool on);
/****************************************************************************
 * Private Data
 ****************************************************************************/

static const struct gt9xx_config_s g_gt9xx_config =
{
  .address   = GT9XX_I2C_ADDRESS,
  .frequency = GT9XX_FREQUENCY,
#ifndef CONFIG_GT9XX_POLLMODE
  .attach    = stm32_gt9xx_irq_attach,
  .enable    = stm32_gt9xx_irq_enable,
  .clear     = stm32_gt9xx_irq_clear,
#endif
  .wakeup    = stm32_gt9xx_wakeup,
  .nreset    = stm32_gt9xx_nreset,
  .set_power  = stm32_gt9xx_set_power
};

static struct stm32_gt9xx_config_s g_priv_config =
{
  .handler     = NULL,
  .arg         = NULL,
};
/****************************************************************************
 * Private Functions
 ****************************************************************************/

/****************************************************************************
 * Name: stm32_gt9xx_attach
 *
 * Description:
 *   Attach an gt9xx interrupt handler to a GPIO interrupt
 *
 ****************************************************************************/
#ifndef CONFIG_GT9XX_POLLMODE
static int  stm32_gt9xx_irq_attach(const struct gt9xx_config_s *config,
                                xcpt_t isr, void *arg)
{
  iinfo("Saving handler %p\n", isr);

  /* Just save the handler.  We will use it when EXTI interruptsare enabled */

  if (isr)
    {
      /* Just save the address of the handler for now.  The new handler will
       * be attached when the interrupt is next enabled.
       */

      iinfo("Attaching %p\n", isr);
      g_priv_config.handler = isr;
      g_priv_config.arg     = arg;
    }
  else
    {
      iinfo("Detaching %p\n", g_priv_config.handler);
      stm32_gt9xx_irq_enable(config, false);
      g_priv_config.handler = NULL;
      g_priv_config.arg     = NULL;
    }

  return OK;
}
#endif

/****************************************************************************
 * Name: stm32_gt9xx_enable
 *
 * Description:
 *   Enable or disable a GPIO interrupt
 *
 ****************************************************************************/

#ifndef CONFIG_GT9XX_POLLMODE
static void stm32_gt9xx_irq_enable(const struct gt9xx_config_s *config,
                                bool enable)
{
  irqstate_t flags;

  /* Attach and enable, or detach and disable.  Enabling and disabling GPIO
   * interrupts is a multi-step process so the safest thing is to keep
   * interrupts disabled during the reconfiguration.
   */

  flags = enter_critical_section();
  if (enable)
    {
      /* Configure the EXTI interrupt using the SAVED handler */

      stm32_gpiosetevent(GPIO_GT9XX_INT_FT, true, false, true,
                         g_priv_config.handler, g_priv_config.arg);
    }
  else
    {
      /* Configure the EXTI interrupt with a NULL handler to disable it */

     stm32_gpiosetevent(GPIO_GT9XX_INT_FT, false, false, false,
                        NULL, NULL);
    }

  leave_critical_section(flags);
}
#endif

/****************************************************************************
 * Name: stm32_gt9xx_clear
 *
 * Description:
 *   Acknowledge/clear any pending GPIO interrupt
 *
 ****************************************************************************/

#ifndef CONFIG_GT9XX_POLLMODE
static void stm32_gt9xx_clear(const struct gt9xx_config_s *config)
{
  /* Does nothing */
}
#endif

/****************************************************************************
 * Name: stm32_gt9xx_set_power
 *
 * Description:
 *   
 ****************************************************************************/

static int stm32_gt9xx_set_power(const struct gt9xx_config_s *config,
                                     bool on)
{
  /* Assume that Touch Panel is already powered on */

  iinfo("on=%d\n", on);
  return OK;
}

/****************************************************************************
 * Name: stm32_gt9xx_wakeup
 *
 * Description:
 *   Issue WAKE interrupt to FT5x06 to change the FT5x06 from Hibernate to
 *   Active mode.
 *
 ****************************************************************************/

static void stm32_gt9xx_wakeup(const struct gt9xx_config_s *config)
{
  /* We do not have access to the WAKE pin in the implementation */
}

/****************************************************************************
 * Name: stm32_gt9xx_nreset
 *
 * Description:
 *   Control the chip reset pin
 *
 ****************************************************************************/

static void stm32_gt9xx_nreset(const struct gt9xx_config_s *config,
                                bool state)
{
  /* We do not have access to the RESET pin in the implementation */
}

/****************************************************************************
 * Public Functions
 ****************************************************************************/

/****************************************************************************
 * Name: stm32_tsc_setup
 *
 * Description:
 *   This function is called by board-bringup logic to configure the
 *   touchscreen device.  This function will register the driver as
 *   /dev/inputN where N is the minor device number.
 *
 * Input Parameters:
 *   minor   - The input device minor number
 *
 * Returned Value:
 *   Zero is returned on success.  Otherwise, a negated errno value is
 *   returned to indicate the nature of the failure.
 *
 ****************************************************************************/

int stm32_tsc_setup(int minor)
{
  int ret;

  iinfo("minor %d\n", minor);
  DEBUGASSERT(minor == CONFIG_GT9XX_DEVMINOR);

  /* Check if we are already initialized */

  iinfo("Initializing\n");
  ret = gt9xx_init();
  if (ret < 0)
    {
      ierr("ERROR: Failed init GT9XX driver: %d\n", ret);
      return ret;
    }

  /* Initialize and register the I2C touchscreen device */

  ret = gt9xx_register(&g_gt9xx_config, CONFIG_GT9XX_DEVMINOR);
  if (ret < 0)
    {
      ierr("ERROR: Failed to register GT9XX driver: %d\n", ret);
      return ret;
    }

  return OK;
}

7、链接脚本

scripts/flash.script

参考boards/arm/stm32h7/stm32h750b-dk/scripts/flash.ld

/****************************************************************************
 * boards/arm/stm32h7/apollo-stm32h743i/scripts/flash.ld
 ****************************************************************************/

/* The STM32H743II has 2048Kb of main FLASH memory. The flash memory is
 * partitioned into a User Flash memory and a System Flash memory. Each
 * of these memories has two banks:
 *
 *   1) User Flash memory:
 *
 *      Bank 1: Start address 0x0800:0000 to 0x080F:FFFF with 8 sectors, 128Kb each
 *      Bank 2: Start address 0x0810:0000 to 0x081F:FFFF with 8 sectors, 128Kb each
 *
 *   2) System Flash memory:
 *
 *      Bank 1: Start address 0x1FF0:0000 to 0x1FF1:FFFF with 1 x 128Kb sector
 *      Bank 1: Start address 0x1FF4:0000 to 0x1FF5:FFFF with 1 x 128Kb sector
 *
 *   3) User option bytes for user configuration, only in Bank 1.
 *
 * In the STM32H743II, two different boot spaces can be selected through
 * the BOOT pin and the boot base address programmed in the BOOT_ADD0 and
 * BOOT_ADD1 option bytes:
 *
 *   1) BOOT=0: Boot address defined by user option byte BOOT_ADD0[15:0].
 *      ST programmed value: Flash memory at 0x0800:0000
 *   2) BOOT=1: Boot address defined by user option byte BOOT_ADD1[15:0].
 *      ST programmed value: System bootloader at 0x1FF0:0000
 *
 * NuttX does not modify these option bytes. On the unmodified openh743i
 * board, the BOOT0 pin is at ground so by default, the STM32 will boot
 * to address 0x0800:0000 in FLASH.
 *
 * The STM32H743II also has 1024Kb of data SRAM.
 * SRAM is split up into several blocks and into three power domains:
 *
 *   1) TCM SRAMs are dedicated to the Cortex-M7 and are accessible with
 *      0 wait states by the Cortex-M7 and by MDMA through AHBS slave bus
 *
 *      1.1) 128Kb of DTCM-RAM beginning at address 0x2000:0000
 *
 *           The DTCM-RAM is organized as 2 x 64Kb DTCM-RAMs on 2 x 32 bit
 *           DTCM ports. The DTCM-RAM could be used for critical real-time
 *           data, such as interrupt service routines or stack / heap memory.
 *           Both DTCM-RAMs can be used in parallel (for load/store operations)
 *           thanks to the Cortex-M7 dual issue capability.
 *
 *      1.2)  64Kb of ITCM-RAM beginning at address 0x0000:0000
 *
 *           This RAM is connected to ITCM 64-bit interface designed for
 *           execution of critical real-times routines by the CPU.
 *
 *   2) AXI SRAM (D1 domain) accessible by all system masters except BDMA
 *      through D1 domain AXI bus matrix
 *
 *      2.1) 512Kb of SRAM beginning at address 0x2400:0000
 *
 *   3) AHB SRAM (D2 domain) accessible by all system masters except BDMA
 *      through D2 domain AHB bus matrix
 *
 *      3.1) 128Kb of SRAM1 beginning at address 0x3000:0000
 *      3.2) 128Kb of SRAM2 beginning at address 0x3002:0000
 *      3.3)  32Kb of SRAM3 beginning at address 0x3004:0000
 *
 *      SRAM1 - SRAM3 are one contiguous block: 288Kb at address 0x3000:0000
 *
 *   4) AHB SRAM (D3 domain) accessible by most of system masters
 *      through D3 domain AHB bus matrix
 *
 *      4.1)  64Kb of SRAM4 beginning at address 0x3800:0000
 *      4.1)   4Kb of backup RAM beginning at address 0x3880:0000
 *
 * When booting from FLASH, FLASH memory is aliased to address 0x0000:0000
 * where the code expects to begin execution by jumping to the entry point in
 * the 0x0800:0000 address range.
 */

MEMORY
{
  itcm  (rwx) : ORIGIN = 0x00000000, LENGTH =   64K
  flash (rx)  : ORIGIN = 0x08000000, LENGTH = 2048K
  dtcm1 (rwx) : ORIGIN = 0x20000000, LENGTH =   64K
  dtcm2 (rwx) : ORIGIN = 0x20010000, LENGTH =   64K
  sram  (rwx) : ORIGIN = 0x24000000, LENGTH =  512K
  sram1 (rwx) : ORIGIN = 0x30000000, LENGTH =  128K
  sram2 (rwx) : ORIGIN = 0x30020000, LENGTH =  128K
  sram3 (rwx) : ORIGIN = 0x30040000, LENGTH =   32K
  sram4 (rwx) : ORIGIN = 0x38000000, LENGTH =   64K
  bbram (rwx) : ORIGIN = 0x38800000, LENGTH =    4K
  sdram (rwx) : ORIGIN = 0xC0000000, LENGTH =   32M
}

OUTPUT_ARCH(arm)
EXTERN(_vectors)
ENTRY(_stext)
SECTIONS
{
    .text :
    {
        _stext = ABSOLUTE(.);
        *(.vectors)
        *(.text .text.*)
        *(.fixup)
        *(.gnu.warning)
        *(.rodata .rodata.*)
        *(.gnu.linkonce.t.*)
        *(.glue_7)
        *(.glue_7t)
        *(.got)
        *(.gcc_except_table)
        *(.gnu.linkonce.r.*)
        _etext = ABSOLUTE(.);
    } > flash

    .init_section :
    {
        _sinit = ABSOLUTE(.);
        *(.init_array .init_array.*)
        _einit = ABSOLUTE(.);
    } > flash

    .ARM.extab :
    {
        *(.ARM.extab*)
    } > flash

    __exidx_start = ABSOLUTE(.);
    .ARM.exidx :
    {
        *(.ARM.exidx*)
    } > flash
    __exidx_end = ABSOLUTE(.);

    _eronly = ABSOLUTE(.);

    .data :
    {
        _sdata = ABSOLUTE(.);
        *(.data .data.*)
        *(.gnu.linkonce.d.*)
        CONSTRUCTORS
        . = ALIGN(4);
        _edata = ABSOLUTE(.);
    } > sram AT > flash

    .bss :
    {
        _sbss = ABSOLUTE(.);
        *(.bss .bss.*)
        *(.gnu.linkonce.b.*)
        *(COMMON)
        . = ALIGN(4);
        _ebss = ABSOLUTE(.);
    } > sram

    /* Emit the the D3 power domain section for locating BDMA data
     *
     * Static data with locate_data(".sram4") will be located
     * at start of SRAM4; the rest of SRAM4 will be added to the heap.
     */

    .sram4_reserve (NOLOAD) :
    {
        *(.sram4)
        . = ALIGN(4);
        _sram4_heap_start = ABSOLUTE(.);
    } > sram4

    /* Stabs debugging sections. */

    .stab 0 : { *(.stab) }
    .stabstr 0 : { *(.stabstr) }
    .stab.excl 0 : { *(.stab.excl) }
    .stab.exclstr 0 : { *(.stab.exclstr) }
    .stab.index 0 : { *(.stab.index) }
    .stab.indexstr 0 : { *(.stab.indexstr) }
    .comment 0 : { *(.comment) }
    .debug_abbrev 0 : { *(.debug_abbrev) }
    .debug_info 0 : { *(.debug_info) }
    .debug_line 0 : { *(.debug_line) }
    .debug_pubnames 0 : { *(.debug_pubnames) }
    .debug_aranges 0 : { *(.debug_aranges) }
}

scripts/Make.defs

参考boards/arm/stm32h7/stm32h750b-dk/scripts/Make.defs

############################################################################
# boards/arm/stm32h7/apollo-stm32h743i/scripts/Make.defs
############################################################################

include $(TOPDIR)/.config
include $(TOPDIR)/tools/Config.mk
include $(TOPDIR)/arch/arm/src/armv7-m/Toolchain.defs

LDSCRIPT = flash.ld

ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)$(LDSCRIPT)

ARCHPICFLAGS = -fpic -msingle-pic-base -mpic-register=r10

CFLAGS := $(ARCHCFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) -pipe
CPICFLAGS = $(ARCHPICFLAGS) $(CFLAGS)
CXXFLAGS := $(ARCHCXXFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHXXINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) -pipe
CXXPICFLAGS = $(ARCHPICFLAGS) $(CXXFLAGS)
CPPFLAGS := $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS)
AFLAGS := $(CFLAGS) -D__ASSEMBLY__

NXFLATLDFLAGS1 = -r -d -warn-common
NXFLATLDFLAGS2 = $(NXFLATLDFLAGS1) -T$(TOPDIR)/binfmt/libnxflat/gnu-nxflat-pcrel.ld -no-check-sections
LDNXFLATFLAGS = -e main -s 2048

# ELF module definitions

CELFFLAGS = $(CFLAGS) -mlong-calls # --target1-abs
CXXELFFLAGS = $(CXXFLAGS) -mlong-calls # --target1-abs

LDELFFLAGS = -r -e main
LDELFFLAGS += -T $(call CONVERT_PATH,$(TOPDIR)/binfmt/libelf/gnu-elf.ld)

8、项目配置文件

src/Makefile
  • 编写nuttx/boards/arm/stm32h7/apollo-stm32h743i/src/Makefile

    ############################################################################
    # boards/arm/stm32h7/apollo-stm32h743i/src/Makefile
    ############################################################################
    
    include $(TOPDIR)/Make.defs
    
    CSRCS = stm32_boot.c stm32_bringup.c
    
    ifeq ($(CONFIG_ARCH_LEDS),y)
    CSRCS += stm32_autoleds.c
    else
      ifeq ($(CONFIG_USERLED),y)
      CSRCS += stm32_userleds.c
      endif
    endif
    
    ifeq ($(CONFIG_ARCH_BUTTONS),y)
    CSRCS +=  stm32_buttons.c
    endif
    
    ifeq ($(CONFIG_BOARDCTL),y)
    CSRCS += stm32_appinitialize.c
    endif
    
    ifeq ($(CONFIG_STM32H7_LTDC),y)
    CSRCS += stm32_lcd.c
    endif
    
    ifeq ($(CONFIG_APOLLO_STM32H743I_CT_I2C),y)
     CSRCS += ct_i2c.c \
            gt9xx.c \
            stm32_touchscreen.c
    endif
    
    include $(TOPDIR)/boards/Board.mk
    
    
    
src/CMakeList.txt
  • 更新nuttx/boards/arm/stm32h7/apollo-stm32h743i/src/CMakeList.txt

    
    # ##############################################################################
    # boards/arm/stm32h7/apollo-stm32h743i/src/CMakeLists.txt
    # ##############################################################################
    
    set(SRCS stm32_boot.c stm32_bringup.c)
    
    if(CONFIG_ARCH_LEDS)
      list(APPEND SRCS stm32_autoleds.c)
    endif()
    
    if(CONFIG_USERLED)
      list(APPEND SRCS stm32_userled.c)
    endif()
    
    if(CONFIG_ARCH_BUTTONS)
      list(APPEND SRCS stm32_buttons.c)
    endif()
    
    if(CONFIG_BOARDCTL)
      list(APPEND SRCS stm32_appinitialize.c)
    endif()
    
    if(CONFIG_STM32H7_LTDC)
      list(APPEND SRCS stm32_lcd.c)
    endif()
    
    if(CONFIG_APOLLO_STM32H743I_CT_I2C)
      list(APPEND SRCS ct_i2c.c gt9xx.c stm32_touchscreen.c)
    endif()
    
    target_sources(board PRIVATE ${SRCS})
    
    if(CONFIG_ARCH_CHIP_STM32H7_CORTEXM7)
      set_property(GLOBAL PROPERTY LD_SCRIPT "${NUTTX_BOARD_DIR}/scripts/flash.ld")
    endif()
    
    
    
CMakeLists.txt
# ##############################################################################
# boards/arm/stm32h7/apollo-stm32h743i/CMakeLists.txt
# ##############################################################################

add_subdirectory(src)

六、编译

1、加载并配置项目

  1. 打开 menuconfig 配置界面:
# 进入 openvela 根目录  
# 进入menuconfig配置界面
./build.sh apollo-stm32h743i:lvgl menuconfig

在这里插入图片描述

  1. 按 / 键搜索并禁用STM32H7_LTDC_L2在这里插入图片描述
  2. 保存配置,按 Q 键退出菜单,选择 Y 键保存配置。

2、编译代码

在完成上面的步骤后,按以下流程为 阿波罗STM32H743开发板生成所需二进制文件:

# 进入 openvela 根目录  
# 清除之前的构建产物
./build.sh apollo-stm32h743i:lvgl distclean
# 基于新配置构建项目 
./build.sh apollo-stm32h743i:lvgl -j8

编译完成后,生成的文件位于 nuttx 目录下,包括:

  • nuttx.bin
  • nuttx.hex

3、烧录固件

参考在 STM32F411 上使用 openvela 点亮 LED: : 四、运行Demo::5、烧录固件

七、运行

1、连接串口

参考在 STM32F411 上使用 openvela 点亮 LED: : 四、运行Demo::6、连接串口

2、运行示例

  1. 重新打开 minicom,连接成功后,在 Minicom 终端中按回车,您会看到 nsh> 提示符。

  2. 运行按键示例,请输入以下命令:

    lvgldemo
    
  3. 串口终端会输出相应的提示。
    在这里插入图片描述

    运行效果如下

LVGL_WIDGET_DEMO_h743i

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐