Custom Firmware Example STM32

STM32 自定义固件示例

本章详细说明如何从 STM32CubeMX 硬件配置建立兼容 Vision 的灯具固件。请从 VisionExternalExamples/Examples/VisionExternalExample 开始。参考工程使用 STM32F051C8T6,并包含 STM32CubeIDE 和 Keil 的 Application、Bootloader 与 BootloaderUpdate 工程。

1. 选择正确的起点

首先不做修改地构建随附 STM32F051 工程。如果 MCU 和 PCB 相同,不需要新的 Hardware 工程。如果 MCU 或原理图不同,请生成新的厂商文件,并增加一个 Hardware/<BoardName>_<ExactMcuPartNumber> variant。

  • Fixture:产品行为,通常需要修改。
  • Hardware:一个准确 MCU 和 PCB 的 HAL 接口。
  • Framework:通用行为,通常不要修改。

对于每个所需接口,先在完整示例中检查同名 .c 文件。如果其功能或外设配置接近新产品,请复制该完整实现;如果没有接近实现,请从 VisionExternalExamples/Template 复制完整伪实现。Framework/Interfaces 中的稳定头文件是接口合同,绝不能复制或修改。

2. 创建 STM32 工程

  1. 安装 STM32CubeMX 或 STM32CubeIDE。
  2. 为准确的 MCU 型号创建工程。参考型号是 STM32F051C8T6。
  3. 分别创建 Application 和 Bootloader 工程。只有已经有匹配的 bootloader payload 时才创建 BootloaderUpdate。
  4. 生成的 Core、Drivers、startup、linker 和 .ioc 文件保留在各自 IDE 工程中。
创建 STM32 工程

3. 配置 Vision 引脚

  • IRQ:上升沿和下降沿触发的 GPIO 外部中断输入。
  • Fixture Is On:报告灯具已经开启并可通信的 GPIO 输出。
  • Main Wake Up:用于唤醒主 MCU 的 GPIO 输入。
  • SPI CS:GPIO 输出。
  • SPI SCK:主 MCU 输出的 SPI 时钟。
  • SPI MISO 和 MOSI:SPI 数据引脚。

在 CubeMX 中给引脚设置清楚的 user labels。Hardware variant 会直接使用这些生成的名称。

STM32 Vision 引脚名称

4. 配置时基和 GPIO

保持 SysTick 启用。Framework 使用 HAL_GetTick() 作为毫秒时基。

STM32 SysTick 配置

Vision IRQ 配置为上升沿和下降沿 EXTI。只有产品支持 MCU sleep 并通过 Vision wakeup 时才需要 Main Wake Up。

STM32 GPIO 配置

使能 EXTI interrupt,并给它较高优先级。参考配置使用优先级 0。

STM32 EXTI interrupt

5. 配置 SPI 和 DMA

  • 全双工 Master
  • Motorola frame、8-bit 数据、MSB first
  • CPOL Low,第一个时钟边沿
  • 软件控制 chip select
  • 时钟频率必须在 Vision SPI 规定的范围内
STM32 SPI 配置

SPI RX 和 TX 各启用一个 DMA channel。使能 SPI 和 DMA interrupts,优先级低于 Vision EXTI。参考配置中 SPI 和 DMA 使用优先级 1。

预留至少 520 字节并且兼容 DMA 的静态 RX 缓冲区,其大小应与 HW_VISION_MAX_TRANSFER_LENGTH 一致。如果所选 DMA 控制器不能直接从 Vision library buffer 发送,还要预留同样大小的静态 TX 缓冲区,并在启动 DMA 前复制请求的字节。传输是异步完成的,因此绝不能使用局部栈缓冲区。保存请求的传输长度,并在完成回调中只传递准确数量的接收字节。

STM32 DMA 配置
STM32 SPI 和 DMA interrupts
STM32 NVIC 优先级

6. 生成工程

Toolchain 选择 STM32CubeIDE 或 Keil MDK。当前 Vision SPI library 默认使用 static allocation,因此不需要增大 heap。只有明确删除 VISION_USE_STATIC_ALLOCATION 并使用 dynamic allocation 时,才把 heap 设置为至少 0x400。生成代码后,所有自定义初始化只放在 CubeMX user-code blocks 中。

STM32 Project Manager

7. 把工程加入 VisionExternalExample

Projects/
  CubeIDE/
    VisionExternalExample_STM32F051C8T6_Application/
    VisionExternalExample_STM32F051C8T6_Bootloader/
    VisionExternalExample_STM32F051C8T6_BootloaderUpdate/
  Keil/
    VisionExternalExample_STM32F051C8T6_Application/
    VisionExternalExample_STM32F051C8T6_Bootloader/
    VisionExternalExample_STM32F051C8T6_BootloaderUpdate/

对于其他电路板,创建名称正确并包含 Inc 和 Src 的 Hardware 文件夹。把 Template/Hardware/Inc/hw_defines.h 复制到新的 Inc 文件夹,并替换所有必要的 Flash 和 MCU 占位值。阅读 Framework/Interfaces/Hardware 中的稳定头文件,再只从 Template/Hardware 复制需要的 hw_*.c 文件。已禁用功能不应有本地 Hardware 源文件。

8. 配置 sources 和 include paths

Application 工程编译生成的 Core/Drivers 文件、共享 Framework、一个 Fixture、准确一个 Hardware 文件夹和所选 libraries。Application 配置必须排除 Framework/Src/dfu_update.c 和 Framework/Src/bootloader_update.c。Bootloader 编译生成文件、Framework/Src/dfu_update.c、共享 DFU helpers、Vision SPI、RDM 和需要的 Hardware 源文件。

使用 linked/shared paths,不要把 Framework、interfaces 或 Fixture 源文件复制到每个 Cube 或 Keil 工程中。在 CubeIDE 中把目录加入 linked resources。每个相关 build configuration 都要加入 Framework/Inc、Framework/Interfaces、Fixture 配置路径和所选 Hardware 配置路径。绝不要把 Template 中的文件直接加入工程。

手动把每个当前本地 Fixture 和 Hardware .c 文件加入所有使用它的 CubeIDE 配置或 Keil Target。每个 Target 都要设置预包含 fixture_defines.h。不要把产品设置重新建立为工程宏。只保留生成代码需要的芯片厂商/工具链宏,以及 Application ReleaseBL 和 Bootloader 使用的 BUILD_FOR_BOOTLOADER。修改 linked resources 后执行 Clean/Rebuild;不要编辑自动生成的 subdir.mk 或配置输出目录。

在 Library 下显示两个 ManagedFlash 库,但要排除它们的 Src 文件夹,不能直接编译。Framework adapter 只编译 fixture_defines.h 中选择的实现。ColorConverter 只加入 libColorConverter.h 和与 compiler、MCU core 匹配的预编译库,不要加入 ColorConverter 源码文件夹。

需要新截图:当前 CubeIDE linked-resource tree 和 include-path settings。以前的源码树截图包含已经移除的文件名称,不能继续使用。

9. 连接生成的 callbacks

所选 Hardware variant 负责 HAL callbacks:

  • SPI DMA 完成时转发到 HwVisionOnSpiComplete()。
  • SPI 或 DMA 错误时转发到 HwVisionOnSpiError()。
  • EXTI callback 读取 IRQ pin,并把新 level 转发到 HwVisionOnIrqPinChanged()。
  • 启用 sleep 时,把 Main Wake Up 变化转发到 HwSystemOnWakeupPinChanged()。

每个 HAL callback 只能在一个地方实现,不要同时在 main.c 和 hw_vision.c 中实现同一个 callback。

10. 连接 main.c

Application startup 应保持很小:

/* USER CODE BEGIN 2 */
SystemInitialize();
/* USER CODE END 2 */

while (1)
{
    SystemTask(HAL_GetTick());
}

ReleaseBL 必须在 HAL 初始化前 relocation vector table。STM32F051 没有 VTOR,所以参考工程把 vectors 复制到 SRAM 并 remap SRAM。带 VTOR 的新 STM32 可以设置 SCB->VTOR = HW_FLASH_APPLICATION_ADDRESS。

Bootloader 在 HAL 初始化前调用 DfuCheckBootReason(),在 GPIO、DMA、SPI 和 timebase 初始化后调用 DfuDownloadFlash()。Bootloader 的 main.c 必须实现 Framework/Inc/dfu_update.h 声明的全部 MCU 回调:

  • HardwareSetMsp():跳转到 Application 之前立即加载 Application stack pointer。
  • HardwareEraseFlash():擦除请求的 Application page 或 sector;发生任何 HAL Flash 错误时返回 false。
  • HardwareWriteFlash():按照 MCU 写入宽度写入已对齐的升级数据;发生任何 HAL Flash 错误时返回 false。
  • HardwareVisionSetFixtureIsOn():驱动 Vision Fixture Is On 输出。
  • HardwareGpioSetSignalLed():驱动 Bootloader 状态 LED;如果电路板没有该 LED,则提供安全的空操作实现。
  • HardwareTimeMs():返回单调递增的毫秒时基。
  • HardwareCheckDFUPin():按住恢复输入时返回 true;只有电路板确实没有恢复输入时才始终返回 false。

强烈建议提供恢复按键或测试点。复位时按住它,即使 Application 无效,设备也必须停留在 Bootloader。启用 Vision DFU 时,SPI 传输完成后用接收字节调用 DfuVisionSpiTxRxComplete(),Vision IRQ 的上升沿和下降沿都用当前引脚电平调用 DfuVisionIrqPinIrq()。这些回调只访问 MCU 或转发事件;不要把 DFU 状态处理从 Framework/Src/dfu_update.c 复制出来。

11. 配置 Flash 和 linker files

所有物理 Flash 参数属于所选 Hardware 文件夹的 hw_defines.h。随附 STM32F051 使用:

Bootloader:       0x08000000 - 0x08003FFF
DFU config:       0x08004000 - 0x080043FF
Application:      0x08004400 - 0x0800E3FF
Managed storage:  0x0800E400 - 0x0800FFFF

Bootloader linker file 必须在 0x08004000 前结束。Application Debug 从 MCU Flash base 开始,Application ReleaseBL 从 0x08004400 开始,并在 Managed Flash storage 前结束。布局改变时必须同时更新 CubeIDE linker scripts 和 Keil memory regions。

12. 配置 Fixture

创建新灯具时,把 Template/Fixture/Inc/fixture_defines.h 复制到 Fixture/Inc,并先把所有可选功能设为 0。替换身份、安全密钥、版本、输入和 DMX 默认值、personality 与 footprint、App footprint、LED 数量、颜色数量和功率数据。加入始终需要的 fixture_dmx_mapping.c 和 fixture_rdm.c。如果有接近的完整实现,优先复制该文件;否则从 Template 同名伪文件开始。

启用可选功能前,先按 Template README 复制全部所需 Fixture 和 Hardware 文件,替换每个伪操作,把本地文件加入所有需要的 IDE Target,并成功编译。然后才把对应 FIXTURE_ENABLE_... 设为 1。产品没有某项功能时,不要删除通用 Framework button 或 input 代码;保持对应 feature 为 0,并省略其可选 Fixture 和 Hardware 实现文件。

13. 构建和验证

  1. 运行 VisionExternalExamples/Tools/TestExamples.ps1。
  2. 构建产品使用的每一个 CubeIDE 或 Keil configuration。
  3. 检查生成的 map files,确保代码位于分配的 Flash regions 内。
  4. 在目标 PCB 上测试 Vision SPI、RDM、每个 DMX personality 和 footprint、输入 reception state 和 timeout、Fixture Is On、wakeup、reset 和 DFU。
  5. 测试每个已启用的 LED、display/menu、button、battery、sensor、wired DMX、wireless DMX、自定义保存参数、错误/警告和 ColorConverter 功能。PC 编译成功不能验证电气行为。

相关文档

© KKT Künzler Technologies GbR.
Developed by KKT - Künzler Technologies GbR