第一篇:硬件架构全解析——三层分板设计与引脚分配

系列二 · 嵌入式工业控制系统从设计到量产

前言

在机器视觉和工业检测领域,光源控制器是整个系统中容易被忽视却至关重要的一环。一个设计不好的光源控制器,轻则亮度不稳定影响算法,重则在触发瞬间产生电流尖峰损坏光源。

本系列文章记录了一款 4 通道 OverDrive 工业光源控制器(ODCC)的完整开发历程——从硬件选型到固件实现,从单板调试到量产验证。本篇是系列二的开篇,重点介绍整机的硬件架构:为什么要做三层分板、RK3588S 核心板扮演什么角色、STM32F103C8T6 如何嵌入其中承担实时控制,以及引脚分配背后的设计考量。

📌 系列背景: 本系列承接「系列一:4通道OverDrive恒流光源控制器」(6篇),读者如需了解 GaN FET 驱动、INA241A PID 闭环、HCPL-314J 触发隔离等硬件设计细节,请参考系列一。本系列聚焦 STM32 固件实现与系统集成。

一、为什么选择三层分板架构

1.1 单板方案的痛点

早期版本曾尝试将所有功能集成在一块 PCB 上。这种方案在样机阶段暴露了几个明显问题:

  • 功率回路与控制回路共板,大电流切换产生的 di/dt 噪声直接耦合到 STM32 的 ADC 和通信总线,调试极为痛苦
  • 光源驱动部分(24V 工作域)与控制部分(3.3V)需要大量隔离器件,PCB 面积膨胀
  • 客户定制需求多样——有的只需要光源控制,有的还需要 RK3588S 做图像处理——单板方案无法灵活组合
  • 功率器件发热量大,散热设计与精密控制电路冲突

1.2 三层分板方案

最终采用三层分板设计,各层职责清晰:

层级

板卡名称

核心器件

主要职责

第一层

核心板(Core Board)

RK3588S(OPi CM5)

Linux 系统、上位机软件、以太网管理、USB/HDMI 接口

第二层

主控板(Control Board)

STM32F103C8T6 + YT8531C

实时控制、Modbus RTU、PWM 输出、数字 I/O、F-RAM 存储

第三层

功率板(Power Board)

GaN FET + INA241A + LM339

4CH 大电流驱动、PID 闭环恒流、OverDrive 脉冲、过流保护

三层之间通过 Board-to-Board 连接器(JP1/JP2/JP3,50Pin×3)互联,信号分组走线,功率回路与控制信号完全隔离。这种设计带来的直接好处是:

  • 主控板可以单独测试固件,无需功率板上电
  • 功率板可以单独做老化测试,不影响 RK3588S 系统
  • 客户只需光源控制时,去掉核心板即可,成本直降
  • 后续迭代可以只更换某一层,其他层复用

💡 设计经验: Board-to-Board 连接器的 Pin 分配建议将 GND 引脚均匀分布在信号引脚之间,尤其是高速信号(SPI、USART)两侧必须有 GND 保护,否则在长期振动环境下容易串扰。本项目 JP2 采用 50Pin 连接器,GND 占比约 40%。

二、核心板:Orange Pi CM5(RK3588S)

2.1 核心板选型理由

RK3588S 是瑞芯微 2022 年推出的旗舰 SoC,4×Cortex-A76(大核)+ 4×Cortex-A55(小核)的 big.LITTLE 架构,NPU 达 6TOPS。在工业光源控制器这个应用场景里,选它的理由并不是算力——而是接口丰富度和生态成熟度。

接口

规格

在本项目的用途

以太网

双口 Gigabit(GMAC0 + GMAC1)

一路接工厂交换机(Modbus TCP 上位机),一路预留相机直连

USB 3.0

Type-A × 1,Gen1(5Gbps)

接 USB3 工业相机或高速存储

USB 2.0

Mini-B × 1(OTG)

烧录/调试/ADB

HDMI

2.1 TX × 1(4K@60Hz)

本地显示(参数配置界面)

PCIe 2.0

1Lane(通过 JP2 引出)

预留扩展(SSD 或 PCIe 转 CAN)

MIPI CSI

4×Lane × 2 组(通过 JP2 引出)

预留直接接 MIPI 相机

OPi CM5(Orange Pi CM5)是基于 RK3588S 的核心板,板载 LPDDR4X(最高 16GB)和 eMMC(最高 256GB),尺寸 55×40mm,通过 3 个 100Pin BTB 连接器(JP1/JP2/JP3)引出所有 IO。相比直接采购 RK3588S 芯片自行设计核心板,OPi CM5 的优势在于:

  • 原厂维护的 BSP Linux 内核和 Ubuntu/Debian 镜像,省去驱动开发工作
  • 稳定供货,有批量采购渠道
  • 55×40mm 的标准尺寸,已有大量开源底板设计可参考

2.2 核心板与主控板的通信接口

核心板(RK3588S)与主控板(STM32)之间的通信走 Modbus RTU over TCP 方案,而不是直接 UART 硬连线。这个选择看起来绕了一圈,背后有明确的工程考量:

方案

优点

缺点

最终选择

UART 直连

延迟低、实现简单

RK3588S 与 STM32 直接耦合,固件升级需同时修改两端

SPI/I2C

速度快

需要自定义协议,维护成本高

Modbus RTU over TCP

标准协议,上位机/PLC/RK3588S 三方都能直接用

多一层网络栈,延迟略高(ms 级)

采用 Modbus TCP 后,上位机软件(运行在 RK3588S 的 Linux 上)通过标准 Socket 连接 STM32 的以太网接口(192.168.0.205:502),和任何第三方 PLC 或 SCADA 系统的接入方式完全相同。这意味着这套固件无需任何修改,就可以直接被工厂已有的自动化系统集成。

三、主控板:STM32F103C8T6 的定位与选型

3.1 为什么是 STM32F103C8T6

在 RK3588S 已经是旗舰 SoC 的情况下,主控选 STM32F103C8T6——一个 2007 年就推出的 Cortex-M3 微控制器,看起来有些「降级」。但这恰恰是嵌入式系统设计中一个重要的原则:**用合适的芯片做合适的事**。

维度

RK3588S

STM32F103C8T6

定位

应用处理器

微控制器

启动时间

约 20 秒(Linux 启动)

< 1ms(直接执行)

实时性

无法保证(Linux 非 RTOS)

确定性响应(中断延迟 < 1μs)

PWM 输出

需要 DMA 配合,抖动大

硬件定时器,120kHz 精确输出

GPIO 中断

系统调用开销大

直接 EXTI,下降沿 < 1μs

掉电保持

需要文件系统,写入有延迟

F-RAM 直接 SPI 写入,无延迟

成本

极低(< ¥8)

STM32F103C8T6 在本项目中的核心价值是三个字:**确定性**。触发信号来了必须在确定时间内响应,PWM 频率必须精确到 120kHz,过流必须在 μs 级关断——这些都不能依赖跑 Linux 的 RK3588S。

3.2 资源使用情况

STM32F103C8T6 的片内资源:64KB Flash、20KB SRAM。本项目的固件编译后:

Program Size: Code=8432 RO-data=408 RW-data=120 ZI-data=1896

Flash 使用:8432 + 408 = 8840 Bytes ≈ 13.7%

SRAM  使用:120 + 1896 = 2016 Bytes ≈ 9.8%

资源余量充裕,后续可扩展更多 Modbus 寄存器或增加 ADC 采样功能

四、引脚分配全解析

4.1 设计原则

引脚分配不是随意的,本项目遵循以下原则:

  • 同一功能模块的引脚尽量在同一 GPIO 组(减少 RCC 时钟使能操作)
  • 高速信号(SPI1、TIM1 PWM)优先使用默认映射,减少 AFIO 重映射带来的风险
  • JTAG 引脚(PA15/PB3/PB4)在初始化时统一禁用,释放给 IN3/IN4/OUT1 使用
  • 共享中断(EXTI15_10)的引脚统一在同一 ISR 处理,按优先级顺序判断

4.2 完整引脚分配表

引脚

网络名

方向

功能

备注

PA8

CH1_I/O

OUT

TIM1_CH1 PWM 输出

120kHz,经 74HC245 缓冲

PA9

CH2_I/O

OUT

TIM1_CH2 PWM 输出

120kHz,经 74HC245 缓冲

PA10

CH3_I/O

OUT

TIM1_CH3 PWM 输出

120kHz,经 74HC245 缓冲

PA11

CH4_I/O

OUT

TIM1_CH4 PWM 输出

120kHz,经 74HC245 缓冲

PA12

OE#_DRV

OUT

74HC245 总使能(高有效)

2N7002 反相驱动,过流时拉低

PA4

FM25L16/CS#

OUT

SPI1 片选(F-RAM)

低有效,软件控制

PA5

FM25L16/SCK

OUT

SPI1 时钟

72MHz/8 = 9MHz

PA6

FM25L16/SO

IN

SPI1 MISO(F-RAM)

浮空输入

PA7

FM25L16/SI

OUT

SPI1 MOSI(F-RAM)

复用推挽

PA0

CA1

OUT

触发对应输出 1

高有效,普通 GPIO

PA1

CA2

OUT

触发对应输出 2

高有效,普通 GPIO

PA2

CA3

OUT

触发对应输出 3

高有效,普通 GPIO

PA3

CA4

OUT

触发对应输出 4

高有效,普通 GPIO

PB6

UART4_TX

OUT

USART1 TX(重映射)

Modbus RTU,9600bps

PB7

UART4_RX

IN

USART1 RX(重映射)

浮空输入

PB10

TG1/IN

IN

TG1 外部中断

EXTI10,下降沿,4.7K上拉,EL354N隔离

PB11

TG2/IN

IN

TG2 外部中断

EXTI11,下降沿,4.7K上拉,EL354N隔离

PB13

TG3/IN

IN

TG3 外部中断

EXTI13,下降沿,4.7K上拉,EL354N隔离

PB14

TG4/IN

IN

TG4 外部中断

EXTI14,下降沿,4.7K上拉,EL354N隔离

PB12

I_OP_I/O

IN

过流检测 EXTI

EXTI12,下降沿,与TG共享EXTI15_10

PB0

IN1_IO

IN

数字输入 1

光耦 EL354N 隔离,低有效,内部上拉

PB1

IN2_IO

IN

数字输入 2

光耦 EL354N 隔离,低有效,内部上拉

PA15

IN3_IO

IN

数字输入 3

JTAG 引脚复用,需禁用 JTDI

PB3

IN4_IO

IN

数字输入 4

JTAG 引脚复用,需禁用 JTDO

PB4

OUT1_IO

OUT

数字输出 1

JTAG 引脚复用,高有效→ULN2003→EL354N

PB5

OUT2_IO

OUT

数字输出 2

高有效→ULN2003→EL354N

PB8

OUT3_IO

OUT

数字输出 3

高有效→ULN2003→EL354N

PB9

OUT4_IO

OUT

数字输出 4

高有效→ULN2003→EL354N

PC13

STM32/LED

OUT

心跳指示灯

500ms 翻转

PC14

IN_LED_IO

OUT

数字输入状态灯

共阳极,低有效点亮

PC15

OUT_LED_IO

OUT

数字输出状态灯

共阳极,低有效点亮

PA13

SWDIO

I/O

SWD 调试接口

系统默认,无需配置

PA14

SWCLK

IN

SWD 时钟

系统默认,无需配置

4.3 三个关键设计细节

① USART1 为什么重映射到 PB6/PB7

USART1 默认引脚是 PA9(TX)和 PA10(RX),而 PA9/PA10 已经被 TIM1 的 CH2/CH3 占用(PWM 输出)。两个外设争引脚,必须有一个让路。

TIM1 的 PWM 引脚只有默认映射有效(PA8~PA11),无法重映射;USART1 支持重映射到 PB6/PB7。因此 USART1 让路,重映射到 PB6/PB7。

// modbus.c — USART1 重映射初始化

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

GPIO_PinRemapConfig(GPIO_Remap_USART1, ENABLE);  // 重映射到 PB6/PB7

② JTAG 引脚的处理

STM32F103C8T6 上电后,PA15/PB3/PB4 默认作为 JTAG 的 JTDI/JTDO/JTRST,无法直接用作 GPIO。本项目需要这三个引脚分别作为 IN3/IN4/OUT1,所以必须在初始化时关闭 JTAG,保留 SWD:

// gpio_io.c — JTAG 禁用(保留 SWD)

static void JTAG_Disable(void)

{

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

    GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);

    // 此后 PA15/PB3/PB4 可用作普通 GPIO

    // PA13/PA14 仍保持 SWDIO/SWCLK 功能

}

⚠️ 注意: JTAG_Disable() 必须在 DIN_Init() 和 DOUT_Init() 之前调用,否则 PA15/PB3/PB4 的 GPIO 模式配置无效。本项目在 GPIO_IO_Init() 的第一行调用,顺序已确保正确。

③ EXTI15_10 共享中断的处理策略

PB10/PB11/PB12/PB13/PB14 全部复用 EXTI15_10_IRQn。这五路信号包含:TG1~TG4 触发输入(业务逻辑)和 I_OP 过流检测(安全保护)。在同一个 ISR 里处理五路信号,优先级设计至关重要:

// gpio_io.c — EXTI15_10 ISR(简化版)

void GPIO_EXTI15_10_IRQHandler(void)

{

    // ① 过流检测:最高优先级,无条件关断 PWM

    if (EXTI_GetITStatus(IOP_EXTI_LINE) != RESET) {

        PWM_Disable();              // 立即拉低 OE#

        g_fault_status |= 0x01U;   // 写 FAULT 标志位

        EXTI_ClearITPendingBit(IOP_EXTI_LINE);

    }

    // ② TG1~TG4:仅在触发模式下响应

    if (EXTI_GetITStatus(TG1_EXTI_LINE) != RESET) {

        if (g_pwm_mode == PWM_MODE_TRIGGER) {

            // 启动状态机 PENDING → ACTIVE

            g_tg_state[0] = TG_STATE_PENDING;

            g_tg_trigger_tick[0] = g_systick_ms;

        }

        EXTI_ClearITPendingBit(TG1_EXTI_LINE);

    }

    // TG2~TG4 类似...

}

过流保护放在最前面判断,保证无论何时 IOP 触发,PWM_Disable() 都是第一个执行的操作,不会被任何触发逻辑延迟。

五、sys_config.h:一个头文件管所有引脚

5.1 设计理念

在多人协作的嵌入式项目中,引脚定义散落在各个 .c 文件里是噩梦——改一个引脚需要全局搜索,漏改一处就是 bug。本项目将所有硬件相关的定义集中在 sys_config.h:

// sys_config.h 的结构

/* 系统时钟 */

#define SYS_SYSCLK_HZ    72000000UL

#define SYS_APB2_HZ      72000000UL

/* MODBUS USART1(重映射) */

#define MODBUS_GPIO_PORT  GPIOB

#define MODBUS_TX_PIN     GPIO_Pin_6   // PB6

#define MODBUS_RX_PIN     GPIO_Pin_7   // PB7

/* PWM TIM1 */

#define PWM_ARR_VAL  ((uint16_t)(SYS_APB2_HZ / PWM_FREQ_HZ - 1))  // = 599

/* OE# 宏 —— 高有效 */

#define PWM_OE_ENABLE()   GPIO_SetBits(PWM_OE_PORT, PWM_OE_PIN)

#define PWM_OE_DISABLE()  GPIO_ResetBits(PWM_OE_PORT, PWM_OE_PIN)

5.2 ARR 值的推导

TIM1 挂载在 APB2 总线,APB2 预分频系数为 1 时,TIM1 时钟直接等于 HCLK(72MHz),不需要 ×2 修正。这是一个容易犯错的地方:

APB 预分频

APB 频率

TIM 时钟

÷1(本项目 APB2)

72MHz

72MHz(直接等于 HCLK)

÷2 及以上(APB1)

36MHz

72MHz(×2 修正)

// 频率计算

// TIM1 时钟 = APB2 = 72MHz(APB2 预分频 = 1,无需 ×2)

// PSC = 0(不分频)

// ARR = TIM_CLK / PWM_FREQ - 1 = 72000000 / 120000 - 1 = 599

// CCR = duty * (ARR+1) / 256 = duty * 600 / 256

#define PWM_FREQ_HZ   120000UL

#define PWM_ARR_VAL   ((uint16_t)(SYS_APB2_HZ / PWM_FREQ_HZ - 1))  // = 599

💡 高级定时器必须使能 MOE: TIM1 是高级定时器,必须调用 TIM_CtrlPWMOutputs(TIM1, ENABLE) 使能主输出(MOE 位),否则即使 CCR 有值,引脚也不会有 PWM 波形输出。这是 TIM1/TIM8 区别于普通定时器的最常见踩坑点。

六、实物展示

6.1 主控板正面

主控板正面集成了所有对外接口:

  • 左侧:双 RJ45(百兆 + 千兆以太网,YT8531C PHY),USB 3.0 Type-A,Mini USB 2.0(OTG)
  • 中上:HDMI 2.1 输出
  • 顶部绿色端子:CH1~CH4 PWM 光源输出、TG1~TG4 触发输入、CA1~CA4 同步输出
  • 右侧绿色端子:IN1~IN4 数字输入、OUT1~OUT4 数字输出(24V 域,光耦隔离)
  • 右上角:电源指示 LED(CKS_LED),数字 I/O 状态 LED(IN_LED / OUT_LED)

6.2 功率板背面

功率板背面可以看到:

  • 顶部一排 TO-252 封装功率管(GaN FET),4 通道对称排列,散热均匀
  • 下方 SOT-23 封装的电流采样放大器(INA241A)
  • 中右侧 JP1/JP2/JP3 三个 50Pin Board-to-Board 连接器,与主控板对插
  • 板载大容量铝电解电容(100μF/50V),为 OverDrive 脉冲提供瞬时能量

📝 说明: 实物照片中可以看到功率板背面仍有几个通孔位置未焊元件(预留的扩展焊盘),这是为后续 A/B 方案切换预留的,不影响当前功能。

七、上电初始化流程

7.1 初始化顺序设计

main.c 的初始化顺序不是随意排列的,每一步都有依赖关系:

int main(void)

{

    SysClock_Init();        // ① 系统时钟:72MHz,一切的基础

    NVIC_GroupConfig();     // ② 中断优先级分组:抢占 2 位,子 2 位

    FRAM_Init();            // ③ F-RAM SPI1:先初始化存储

    FRAM_LoadParams();      // ④ 加载掉电保存的参数

    PWM_Init();             // ⑤ TIM1 初始化:OE# 默认低(禁止输出)

    for (i = 0; i < 4; i++) // ⑥ 恢复占空比设定值

        PWM_SetDuty(i+1, g_pwm_duty[i]);

    for (i = 0; i < 4; i++) // ⑦ 恢复通道开关状态

        PWM_SetChEnable(i+1, g_pwm_ch_enable[i]);

    GPIO_IO_Init();         // ⑧ 数字 I/O + 触发中断 + 过流中断

    /* 恢复 OUT 输出状态 */ // ⑨ 恢复数字输出状态

    PWM_Enable();           // ⑩ 最后才使能 OE#,避免上电输出抖动

    MODBUS_Init(9600);      // ⑪ USART1 Modbus RTU 初始化

}

关键点:⑩ PWM_Enable()(使能 OE#)必须在所有参数恢复完成后才执行。如果 OE# 在占空比恢复之前使能,光源会在上电瞬间以上次保存的占空比输出,而此时 CCR 寄存器还是 0,输出为 0,再恢复才跳变——对于对瞬态敏感的光源应用,这种跳变是不可接受的。

💡 防上电抖动设计: 先设置 CCR(占空比),再使能 OE#,确保 PWM 信号稳定后才开始输出。这在光源控制场景中非常重要——相机触发和光源点亮必须同步,上电时的任何意外输出都可能干扰第一帧图像。

八、量产状态与后续计划

8.1 当前状态

本项目目前已完成以下里程碑:

阶段

状态

说明

硬件设计

完成

PCB 分板方案定稿,原理图 v2 完成

固件开发

完成

代码版本 v2.0,四模块架构

生产测试

通过

测试指南 V1.0,生产部验证通过

量产

🔄 进行中

已开始量产阶段

RK3588S 上位机软件

📋 规划中

Linux 上位机应用开发

8.2 本系列后续文章

本系列共规划 5 篇,后续文章将深入固件实现层面:

  • 第二篇:FM25L16B F-RAM 驱动——工业级掉电保存的正确实现
  • 第三篇:STM32 固件架构——四模块分层设计与 Modbus 寄存器地址规划
  • 第四篇:双模式 PWM 光源控制——常亮模式与外部触发模式
  • 第五篇:量产测试实录——Modbus TCP 联调全流程与踩坑记录

总结

本篇从架构层面介绍了这款工业光源控制器的硬件设计:三层分板隔离了功率域与控制域,RK3588S 负责系统级管理,STM32F103C8T6 负责实时控制,两者通过 Modbus TCP 解耦通信。引脚分配设计上,利用 USART1 重映射解决 PA9/PA10 引脚冲突,统一处理 JTAG 引脚复用,以及 EXTI15_10 共享中断的优先级管理,这些细节都是在实际工程中经过反复验证的经验积累。

下一篇将聚焦 FM25L16B F-RAM 的驱动实现,重点讲解为什么工业场景要选 F-RAM 而不是 Flash,以及掉电保存参数的完整设计方案。

如果本文对你有帮助,欢迎点赞收藏,系列持续更新中 🚀

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐