RK3588S + STM32F103C8T6 工业光源控制器
第一篇:硬件架构全解析——三层分板设计与引脚分配
系列二 · 嵌入式工业控制系统从设计到量产
前言
在机器视觉和工业检测领域,光源控制器是整个系统中容易被忽视却至关重要的一环。一个设计不好的光源控制器,轻则亮度不稳定影响算法,重则在触发瞬间产生电流尖峰损坏光源。
本系列文章记录了一款 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,以及掉电保存参数的完整设计方案。
如果本文对你有帮助,欢迎点赞收藏,系列持续更新中 🚀
更多推荐

所有评论(0)