在 ALIENTEK 阿波罗STM32H743开发板上使用 openvela 运行LVGL示例
在 ALIENTEK 阿波罗STM32H743开发板上运行LVGL示例 本文介绍了如何在ALIENTEK阿波罗STM32H743开发板上基于openvela实时操作系统运行LVGL图形库演示程序。
在 ALIENTEK 阿波罗STM32H743开发板上使用 openvela 运行LVGL示例
文章目录
一、概述
本指南(参考在 STM32H750 上部署 openvela)将引导您在 ALIENTEK 阿波罗STM32H743开发板上,基于 openvela 实时操作系统,运行 Light and Versatile Graphics Library(LVGL)图形库的演示程序(Demo)。
说明:本文使用的RGBLCD 模块型号为 ATK-7016(7 寸,1024*600),采用GT911电容触控方案。
二、准备工作
在开始之前,请确保您已完成以下准备工作:
-
获取源码:参考文档快速入门下载最新代码。
注意:请下载dev分支的代码,因为trunk分支的代码中未给STM32H7开启双缓冲。

-
了解
openvela架构:建议您预先阅读 openvela 架构以理解其分层设计。 -
查阅系统启动流程文档,获取更详细的启动时序和函数调用关系图。
三、创建代码目录结构
首先,在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.h和 include/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_INITIALIZE,stm32_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
参考:
- drivers/input/gt9xx.c
- drivers/input/ft5x06.c
- 【正点原子】阿波罗V2 STM32H743开发板\4,LVGL例程\LVGL例程2 操作系统移植\Drivers\BSP\TOUCH\gt9xxx.c(下载地址:STM32H743阿波罗开发板V2 — 正点原子资料下载中心 1.0.0 文档)。
/****************************************************************************
* 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、加载并配置项目
- 打开
menuconfig配置界面:
# 进入 openvela 根目录
# 进入menuconfig配置界面
./build.sh apollo-stm32h743i:lvgl menuconfig

- 按 / 键搜索并禁用
STM32H7_LTDC_L2
- 保存配置,按 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、运行示例
-
重新打开 minicom,连接成功后,在 Minicom 终端中按回车,您会看到
nsh>提示符。 -
运行按键示例,请输入以下命令:
lvgldemo -
串口终端会输出相应的提示。

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


所有评论(0)