• 正文
  • 相关推荐
申请入驻 产业图谱

如何在 STM32N6570-DK 上集成TouchGFX与Camera中间件

10/27 13:36
90
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

本文是意法半导体(ST)社区两篇系列的第一篇:在 STM32N6570-DK 上把中间件接起来:TouchGFX 做图形界面,Camera 中间件做实时采图。目标是说明这些组件在 STM32N6 上怎么一起跑、不打架,并为后面接 AI 留好基础。

引言

带图形和视觉的嵌入式应用越来越多。STM32N6570-DK 的处理器与外设能力适合这类任务。本工程演示如何在这块板上集成 TouchGFX 与 Camera 中间件,把资源用稳、界面跑顺。下面按搭建、配置与编码走一遍。

1. 前置条件

开始前请准备:

- N6 开发板:STM32N6570-DK

- STM32CubeMX(v6.17.0)

- STM32CubeProgrammer(v2.21.0)

- STM32CubeIDE(v1.19.0)

- TouchGFX(v4.26.1)

- stm32-mw-camera(v1.5.1)

- stm32-mw-isp(v2.0.0)

2. 硬件搭建

演示硬件为 STM32N6570-DK。编程时将器件设为 **DEV boot mode**。

若已熟悉 TouchGFX 操作,可跳过本节,直接进入 STM32CubeMX 配置;请确保包含文中所列要素。

3. 工程创建 - TouchGFX

TouchGFX 工程怎么建看需求。本文做一个简单 GUI,只放说明结果需要的元素;可按目标再改。

点击 [Create New]。按 “N6” 过滤并选择板卡;本例使用带 **ThreadX** 的 STM32N6570-DK。路径可保持不变,工程名示例为 MyProject。请使用相同版本以免冲突。点 [Create]。

要让摄像头正常工作、GUI 仍能响应,请按下列步骤做完,再按自己的喜好改界面。初始屏命名为 **Menu**,再进 **ActivateCamera**,下一篇再接 Activate AI model 屏。

文末附件 `images_part1.zip` 含所需图片。解压后在 TouchGFX Images 中点右上角 + 导入(可一次全选)。

逐屏操作如下。

3.1 Menu 屏

1. 背景:顶部工具栏第 3 项(Image)加入图片;选工程图片里的 `background.png`,本例重命名为 `Menu_Background`(ActivateCamera 屏可复用同一背景)。

2. 导航按钮:顶部工具栏第 2 项(Button)加入按钮,用于从 Menu 切到 ActivateCamera。

3. 按钮文字:顶部工具栏第 7 项(Text Area)叠在按钮上;文案按界面需要填写(例如进入摄像头)。

4. Typographies:打开 Texts → Typographies,新建自定义字体,设置字号、字重、字距等,使 Text Area 可读、与按钮匹配。

5. Interactions:右上角 Interactions 点 +,增加「点击该按钮 → Change screen → ActivateCamera」交互(Trigger 选按钮 Clicked,Action 选切换到 ActivateCamera)。

3.2 ActivateCamera 屏

与 Menu 相同方式加背景后:

1. 启用摄像头:再加一组 Button + Text Area,用于启动摄像头管线(后续在 `ActivateCameraView::EnableCamera` 中发 `MSG_CAMERA_ON`)。

2. 返回:再加 Back 按钮(及文字);点击后禁用管线并回到 Menu(对应 `DisableCamera` + Change screen → Menu)。

3. typography2:在 Typographies 再建一套字体(本例称 typography2),专供本屏文字,属性与 Menu 自定义字体类似,按屏上可读性微调。

4. Interactions(本屏关键):

- 启用按钮 Clicked → 调用 `EnableCamera`(或等价自定义动作),保持在本屏;

- Back 按钮 Clicked → 调用 `DisableCamera`,再 Change screen → Menu。

生成前可用 [Run simulator] 或 **F5** 预览。设计完成后用 [Generate Code] 或 **F4** 生成。

4. STM32CubeMX 配置

生成代码后,打开工程 `.ioc`,配置时钟、摄像头管线与第二 LTDC 层。

4.1 激活 Camera Serial Interface(CSI)

Pinout & Configuration → Multimedia → CSI:在 Application 勾选并点 Activated。

4.2 激活 DCMIPP

同选项卡选择 DCMIPP 为 camera serial interface,按图配置 Pipe 1 并应用。

4.3 激活 LTDC 第二层

LTDC → Features 激活第二层;配置为两层,并按图填写细节。**Note:** 配置 Layer 1 Color Frame Buffer Start Address 前,点右侧小图标选 **[No check]**。

4.4 中断

System Core → NVIC1_S_Application:激活 DCMIPP global interrupt 与 CSI global interrupt;抢占优先级设为 **7**。

4.5 时钟

Clock Configuration:DCMIPP 目标 **300 MHz**,时钟源 IC17(来自 PLL2,分频 2)。按参考手册,CSI 物理连到 IC18,最大约 **20 MHz**;本例 PLL2 分频 30 作为 IC18 源,得到约 20 MHz CSI 时钟。

4.6 RIF

在 RIF 配置中为 DCMIPP 与 LTDC_L2 勾选 Privilege,以获得对 RAM 接口的特权访问。

4.7 生成代码

完成后点 [Generate code];警告弹窗选 [Yes]。

5. STM32CubeIDE 导入与设置

5.1 集成 BSP

从 `STM32Cube\Repository\STM32Cube_FW_N6_Vx.y.z\Drivers` 复制 BSP 到工程 Drivers(社区文作者所用版本 **1.3.0**;其他版本可能需改路径)。在 STM32N6570-DK_Appli 的 Drivers 下新建 BSP 文件夹,导入 `stm32n6570_discovery_bus.c`。

Include paths 增加:`../../../Drivers/BSP/STM32N6570-DK`。

若缺少 `stm32n6570_discovery_conf.h`:将 `stm32n6570_discovery_conf_template.h` 复制到 `Appli\Core\Inc` 并重命名为 `stm32n6570_discovery_conf.h`。

5.2 集成 STM32_ISP

将下载的 stm32-mw-isp 解压并放到 `Middlewares\ST`。在 IDE 中间件下建 STM32_ISP 文件夹并导入必要文件。Include:`../../../Middlewares/ST/stm32-mw-isp-2.0.0/isp/Inc`。

从 `isp_param_conf` 复制 `imx335_JudgeII_isp_param_conf.h` 到 `Appli\Core\Inc`,重命名为 `isp_param_conf.h`。确保 `../../../Appli/Core/Inc` 位于 include 列表顶部,以免用到 BSP 中的同名文件。

5.3 集成 stm32-mw-camera

将包放到 `Middlewares\ST`,按 BSP/ISP 类似方式导入;须导入附件自定义文件 `cmw_camera_customized.c` 到 `Appli\Core\Src` 并加入工程树。

打开 `cmw_camera_conf_template.h`,注释未用传感器,仅保留:

```c

#define USE_IMX335_SENSOR

```

放到 `Appli\Core\Inc` 并重命名为 `cmw_camera_conf.h`。

Include 增加:

```

../../../Middlewares/ST/stm32-mw-camera-main

../../../Middlewares/ST/stm32-mw-camera-main/sensors

../../../Middlewares/ST/stm32-mw-camera-main/sensors/imx335

```

此时构建可能仍报 `L2_BASE_ADDRESS` 未声明,属预期,因 Layer 2 缓冲故意未定义,在 Coding 节修复。

5.4 编码

在 `main.c` USER CODE BEGIN 0:

```c

DCMIPP_HandleTypeDef *hDcmipp;

ALIGN_32BYTES(uint8_t __attribute__((section (".DCMI_RAM"))) u8DCMIPP_ImageArray[400*240*2]);

#define L2_BASE_ADDRESS &u8DCMIPP_ImageArray[0]

```

链接脚本增加:

```

FB_RAM (xrw) : ORIGIN = 0x34146000, LENGTH = 0x001D6000

DCMI_RAM (xrw) : ORIGIN = 0x3431c000, LENGTH = 0x0002EE00

```

以及 `DCMIBufferSection (NOLOAD) { *(.DCMI_RAM) } >DCMI_RAM`。

Includes 加入 `#include "cmw_camera.h"`。因 CubeMX 已配置 I2C2,与 BSP 冲突:将 `MX_I2C2_Init` 重命名为 `MX_I2C2_Init_Cube`。

实现 `Camera_Config`(IMX335、fps 30、镜像等;Pipe1 RGB565;PixelPipePitch 1600;手动曝光等),在 USER CODE BEGIN 2 调用;若 CubeMX 再生后丢失,补上 `MX_TouchGFX_PreOSInit();`。

在 `app_threadx.c` 集成摄像头线程与消息队列。按 USER CODE 分区加入下列内容。

Includes / 命令枚举 / 栈与队列尺寸:

```c

/* USER CODE BEGIN Includes */

#include "main.h"

#include "cmw_camera.h"

/* USER CODE END Includes */

/* USER CODE BEGIN PTD */

typedef enum {

MSG_CAMERA_ON ,

MSG_CAMERA_OFF ,

} CameraCommand_t;

/* USER CODE END PTD */

/* USER CODE BEGIN PD */

#define THREAD_STACK_SIZE 1024

#define QUEUE_SIZE 128

/* USER CODE END PD */

/* USER CODE BEGIN PV */

extern DCMIPP_HandleTypeDef hdmipp;

extern LTDC_HandleTypeDef hltdc;

extern DCMIPP_HandleTypeDef *hDcmipp;

extern uint8_t u8DCMIPP_ImageArray[];

uint8_t Camera_thread_stack[THREAD_STACK_SIZE];

uint8_t Camera_queue[QUEUE_SIZE];

TX_THREAD Camera_thread_ptr;

TX_QUEUE Camera_Queue_ptr;

/* USER CODE END PV */

/* USER CODE BEGIN PFP */

VOID Camera_thread_entry(ULONG initial_input);

/* USER CODE END PFP */

```

在 `App_ThreadX_Init` 中创建队列与线程:

```c

/* USER CODE BEGIN App_ThreadX_Init */

tx_queue_create(&Camera_Queue_ptr,

"Camera_Queue",

1,

Camera_queue,

QUEUE_SIZE);

tx_thread_create(&Camera_thread_ptr,

"Camera_thread",

Camera_thread_entry,

0x1234,

Camera_thread_stack,

THREAD_STACK_SIZE,

15,

15,

1,

TX_AUTO_START);

/* USER CODE END App_ThreadX_Init */

```

线程入口:配置 DCMIPP 抽稀与 pitch、初始禁用 LTDC Layer 2、`CMW_CAMERA_Start` 后进入循环,按队列消息 Resume/Suspend 并开关 LTDC 层,运行中调用 `CMW_CAMERA_Run`:

```c

/* USER CODE BEGIN 1 */

VOID Camera_thread_entry(ULONG initial_input)

{

ISP_StatusTypeDef ret;

DCMIPP_DecimationConfTypeDef pDecConfig = {0};

uint32_t pitch_value;

ULONG received_State;

uint8_t camstatus = 0;

pitch_value = (800 * 2) / 2;

pDecConfig.HRatio = DCMIPP_HDEC_1_OUT_2;

pDecConfig.VRatio = DCMIPP_VDEC_1_OUT_2;

HAL_DCMIPP_PIPE_SetDecimationConfig(hDcmipp, DCMIPP_PIPE1, &pDecConfig);

HAL_DCMIPP_PIPE_EnableDecimation(hDcmipp, DCMIPP_PIPE1);

HAL_DCMIPP_PIPE_SetPitch(hDcmipp, DCMIPP_PIPE1, pitch_value);

HAL_LTDC_SetWindowSize(&hltdc, 800/2, 480/2, LTDC_LAYER_2);

__HAL_LTDC_LAYER_DISABLE(&hltdc, LTDC_LAYER_2);

HAL_LTDC_ReloadLayer(&hltdc, LTDC_RELOAD_VERTICAL_BLANKING, LTDC_LAYER_2);

SCB_CleanDCache();

if (CMW_CAMERA_Start(DCMIPP_PIPE1, (uint8_t *) u8DCMIPP_ImageArray, CMW_MODE_CONTINUOUS) != CMW_ERROR_NONE)

{

Error_Handler();

}

HAL_Delay(1000);

while (1)

{

UINT status = tx_queue_receive(&Camera_Queue_ptr, &received_State, 10);

if (status == TX_SUCCESS)

{

if (received_State == MSG_CAMERA_ON)

{

camstatus = 1;

SCB_CleanDCache();

if (CMW_CAMERA_Resume(DCMIPP_PIPE1) != CMW_ERROR_NONE)

{

Error_Handler();

}

__HAL_LTDC_LAYER_ENABLE(&hltdc, 1);

HAL_LTDC_ReloadLayer(&hltdc, LTDC_RELOAD_VERTICAL_BLANKING, 1);

SCB_CleanInvalidateDCache();

tx_thread_sleep(500);

}

else if (received_State == MSG_CAMERA_OFF)

{

camstatus = 0;

__HAL_LTDC_LAYER_DISABLE(&hltdc, 1);

HAL_LTDC_ReloadLayer(&hltdc, LTDC_RELOAD_VERTICAL_BLANKING, 1);

if (CMW_CAMERA_Suspend(DCMIPP_PIPE1) != CMW_ERROR_NONE)

{

Error_Handler();

}

SCB_CleanDCache();

tx_thread_sleep(500);

}

}

if (camstatus == 1)

{

ret = CMW_CAMERA_Run();

assert(ret == CMW_ERROR_NONE);

}

}

}

/* USER CODE END 1 */

```

在 `ActivateCameraView.cpp` / `.hpp` 中实现 `EnableCamera` / `DisableCamera`,经队列发命令。在 `ActivateCameraView.cpp` 中、`ActivateCameraView::ActivateCameraView()` 之前加入:

```c

#include "main.h"

extern "C"

{

#include "tx_api.h"

extern TX_QUEUE Camera_Queue_ptr;

extern LTDC_HandleTypeDef hltdc;

typedef enum {

MSG_CAMERA_ON ,

MSG_CAMERA_OFF ,

} CameraCommand_t;

}

```

在 `tearDownScreen` 之后实现:

```c

void ActivateCameraView::EnableCamera()

{

CameraCommand_t cmd = MSG_CAMERA_ON;

UINT status = tx_queue_send(&Camera_Queue_ptr, &cmd, TX_NO_WAIT);

if (status != TX_SUCCESS)

{

Error_Handler();

}

HAL_GPIO_WritePin(GPIOO, GPIO_PIN_1, GPIO_PIN_SET);

}

void ActivateCameraView::DisableCamera()

{

__HAL_LTDC_LAYER_DISABLE(&hltdc, 1);

HAL_LTDC_ReloadLayer(&hltdc, LTDC_RELOAD_VERTICAL_BLANKING, 1);

CameraCommand_t cmd = MSG_CAMERA_OFF;

UINT status = tx_queue_send(&Camera_Queue_ptr, &cmd, TX_NO_WAIT);

if (status != TX_SUCCESS)

{

Error_Handler();

}

HAL_GPIO_WritePin(GPIOO, GPIO_PIN_1, GPIO_PIN_RESET);

}

```

在 `ActivateCameraView.hpp` 于 `tearDownScreen` 后声明:

```c

virtual void EnableCamera();

virtual void DisableCamera();

```

在 `MX_DCMIPP_Init` 中配置 downsize 到 **800×480**(HRatio=25656,VRatio=33161,HSize=800,VSize=480,HDivFactor=316,VDivFactor=253),因传感器全分辨率 2592×1944,需缩小以匹配显示。

6. 生成并烧录可信固件

构建应无错误。在 FSBL Debug 目录用 `STM32_SigningTool_CLI.exe` 签名(将 PATH 配好),示例:

```

STM32_SigningTool_CLI.exe -bin Project.bin -nk -of 0x80000000 -t fsbl -o Project-trusted.bin -hv 2.3 -dump Project-trusted.bin -align

```

用 STM32CubeProgrammer(配置好外部存储器 loader)将可信 FSBL 烧到 **0x70000000**;对 Appli 同样签名后烧到 **0x70100000**;再烧录 `STM32N6570-DK_Appli_assets.hex`(hex 无需指定地址)。

7. 测试

烧录后板卡界面应与文中预期界面一致(Menu / ActivateCamera 及摄像头画面)。注:可进一步优化,例如为摄像头任务实现类似 TouchGFX 的双缓冲以改善显示。

结论

第一部分说明如何在 STM32N6570-DK 上集成 TouchGFX、Camera 与 ISP 中间件,配双层 LTDC,并拉起摄像头管线。集成顺了,后面做更丰富的图形、视觉和 AI(第二篇)会省事。

另一途径

自 TouchGFX Designer **4.26.1** 起,也可用板级演示 “Camera output in TextureMapper” 做出等效摄像头画面,并支持移动/缩放/旋转等。本文仍保留分步集成流程,方便衔接下文 AI 用例。

来源:https://community.st.com/stm32-mcus-60/how-to-integrate-touchgfx-and-camera-middleware-on-an-stm32n6570-dk-159856

参数以意法半导体官方最新资料为准。

意法半导体

意法半导体

意法半导体拥有49,000名半导体技术的创造者和创新者,掌握半导体供应链和先进的制造设备。作为一家半导体垂直整合制造商(IDM),意法半导体与二十多万家客户、成千上万名合作伙伴一起研发产品和解决方案,共同构建生态系统,帮助他们更好地应对各种挑战和新机遇,满足世界对可持续发展的更高需求。意法半导体的技术让人们的出行更智能,让电源和能源管理更高效,让云连接的自主化设备应用更广泛。我们正按计划在所有直接和间接排放(包括范围1和范围2)、产品运输、商务旅行以及员工通勤排放(重点关注的范围3)方面实现碳中和,并在2027年底前实现100%使用可再生电力的目标。 详情请浏览意法半导体公司网站:www.st.com.cn

意法半导体拥有49,000名半导体技术的创造者和创新者,掌握半导体供应链和先进的制造设备。作为一家半导体垂直整合制造商(IDM),意法半导体与二十多万家客户、成千上万名合作伙伴一起研发产品和解决方案,共同构建生态系统,帮助他们更好地应对各种挑战和新机遇,满足世界对可持续发展的更高需求。意法半导体的技术让人们的出行更智能,让电源和能源管理更高效,让云连接的自主化设备应用更广泛。我们正按计划在所有直接和间接排放(包括范围1和范围2)、产品运输、商务旅行以及员工通勤排放(重点关注的范围3)方面实现碳中和,并在2027年底前实现100%使用可再生电力的目标。 详情请浏览意法半导体公司网站:www.st.com.cn收起

查看更多

相关推荐

意法半导体拥有49,000名半导体技术的创造者和创新者,掌握半导体供应链和先进的制造设备。作为一 家半导体垂直整合制造商(IDM),意法半导体与二十多万家客户、成千上万名合作伙伴一起研发产品和 解决方案,共同构建生态系统,帮助他们更好地应对各种挑战和新机遇,满足世界对可持续发展的更高需 求。意法半导体的技术让人们的出行更智能,让电源和能源管理更高效,让云连接的自主化设备应用更广 泛。我们正按计划在所有直接和间接排放(包括范围1和范围2)、产品运输、商务旅行以及员工通勤排 放(重点关注的范围3)方面实现碳中和,并在2027年底前实现100%使用可再生电力的目标。 详情请浏 览意法半导体公司网站:www.st.com.cn