如何确保STM32在我们的设计中正确启动?

让我们更详细地看一下以下方面:

1.硬件注意事项
2.启动配置
3.软件
4.总结(TL;DR)

1.硬件注意事项

数据表和其他文档

请始终参考:

  • 电气和机械性能数据表
  • 功能说明参考手册
  • 最新的STM32勘误表,如果它们可能影响您,请执行所有建议的修复程序
  • 硬件入门应用程序说明
  • 与STM32相关的应用说明
 

电源

电源是STM32功能的关键部分。为了正确启动,STM32需要在至少Vdd和Vdda电源引脚上施加从零到最小启动电压(Option Bytes的默认BOR电平)的电源电压。在释放内部复位并从用户Option Bytes更新BOR电平之后,如果BOR电路具有定义的滞后,则电压可以下降到给定BOR电平可用的最小值。
注意,为了正确启动,电源电压必须降至0V才能重新连接,否则可能无法保证正确的通电复位。如果Vdd断开时GPIO上存在外部电压,则可能出现这种情况。在这种情况下,IO_FT引脚对于这样的信号是优选的。
您可以通过以下几种方式监控STM32的正确供应:
  • 用万用表读取Vdd-Vss和Vdda-Vssa对上的电压。它必须与STM32的设计电源电压和工作范围相匹配
  • 读取STM32的供电电流。在ST评估板上,这种功能是通过分裂Vdd路径上的跳线来实现的。启动电流应在几毫安至10毫安的范围内。过高的电流(100毫安及以上)可能意味着STM32损坏、PCB短路等。评估期间的良好做法是使用外部电源,将电流限制设置为预期电流消耗。
  • 测量NRST引脚-如果它一直处于低电平,电源电压不足以释放复位电路,或者STM32损坏
  • 如果存在Vcap引脚,则测量1.1-1.3 V范围内的Vcap电压
STM32通过几个电压域供电:
  • 数字(IO、备份域、Vcore电压调节器),通过多个Vdd-Vss电源对
  • 通过Vdda-Vssa对的模拟(ADC、DAC、比较器、PLL、复位)
  • 核心电压,可用作Vcap(从无引脚到多引脚)
  • 通过Vbat引脚的备份域(RTC、备份RAM)
  • 带专用电源引脚的特定外围设备(USB、MIPI DSI、LCD、GPIO_1.8V)的电压域
供应组织有一些要求,通常在应用程序说明中描述为特定STM32系列的硬件入门。产品数据表中规定了允许电压及其顺序。
 
STM32电源有以下常见要求:
  • 所有Vss引脚必须连接在一起,最大电压差为50mV,这意味着接地平面非常好
  • 所有Vdd引脚必须以最大电压差50mV连接在一起,这意味着非常好的电源连接。这种要求意味着无附加电感在任意两个Vdd引脚之间,对STM32造成灾难性后果。
  • 所有Vdd-Vss对都需要尽可能靠近封装的去耦电容器100nF
  • 如果设计需要,Vbat引脚应连接到备用电池,或连接到Vdd。将Vbat连接到Vss会使STM32短路并损坏它。
  • Vdda可以由与Vdd相同的电压源提供,并且允许其与LC滤波器解耦,以保证模拟外围设备的稳定供电。注意数据表中的时序特性。
  • 任何电源引脚的典型最大电压为3.6V,绝对最大短时电压为4V。跨越它,即使是暂时的,或者作为增加串联电感的影响,也会永久损坏芯片!请设计您的电源和ESD保护,以保证这些要求。
  • 由内部线性电压调节器产生的核心电压可以在Vcap1、Vcap2引脚上获得。如果封装上有这些引脚,则每个引脚必须配备典型容量为2.2-4.7 uF的低ESR电容器(见数据表)。不要错误地与4.7 nF电容器交换,因为这会严重影响调节器和整个芯片的稳定性!
  • 一些STM32系列的核心电压也可以从外部提供,以减少内部线性电压调节器的功率损耗。有关更多详细信息,请参阅数据表和硬件入门。
  • Vcore生成的另一种可能性可通过集成SMPS获得。如果SMPS未实现或不适用于给定的STM32(STM32L4、STM32H7),则在启动期间将核心电源切换为SMPS选项可能会使STM32无响应。解决方法是在BOOT0=1的情况下接通芯片电源,即启动仅依赖线性电压调节器的系统引导加载程序,然后擦除芯片。
其他电源可能(不)存在或可能在内部生成(Vdd_dsi、Vlcd、Vio_1.8V、Vusb)。如果允许这样的功能,则在内部对其进行监控,并且一旦可以获得并检测到这样的电压,就需要启用相关的外围设备并解除内部隔离。


时钟

每个STM32都以默认频率(通常为8或16 MHz)的内部RC振荡器启动,因此无需担心正确引导。
稍后,用户SW可以启用晶体振荡器(HSE、LSE)和/或PLL。从HSE和PLL提供时钟树后,外部噪声或ESD事件可能会导致频率暂时变化,或者,如果晶体被机械冲击损坏,则根本无法继续生成系统时钟。为了防止这种情况下的僵局,有两个主要工具:
  • STM32将不允许切换到这样的时钟源,如果它没有启用、稳定或锁定。在软件中,这是通过等待时钟切换命令的超时来管理的。
  • 启用CSS(硬件时钟“看门狗”)可确保当HSE消失时,整个时钟树转到HSI(启动RC振荡器),并通过非屏蔽中断(NMI)通知使用程序。这种行为允许使用内部资源恢复时钟,可能重新启动晶体振荡器,或安全关闭用户应用程序
注意:当STM32在外部电池提供的备份域和RTC运行的情况下唤醒或通电时,由于LSE已经在运行,LSE的标准初始化例程可能会超时。如果在(重新)初始化LSE\RTC操作之前没有测试它,则超时延迟可能约为30秒。
注意:请使用AN2867选择并验证您的水晶选择(STM8和STM32s振荡器设计指南)!晶体或驱动水平的错误选择可能导致HSE或LSE启动时间长或不可靠,尤其是在低温下。


STM32的外部设置

在施加电源之后,STM32等待,直到复位电路释放复位信号。在大多数设计和大多数STM32系列中,使用内部电压监控器(POR/PDR和BOR)而不需要外部电压监控器。
然而,这将一些STM32系列的最低工作电源电压限制在1.71V。为了能够在更低的电源电压(低至1.62V)下工作,需要外部电压监控器,并且必须禁用POR。您可以通过系紧引脚禁用POR(开机复位)打开(_O)Vss公司而不是Vdd公司(启用内部重置监控器的正常情况)。
当内部复位被释放时,STM32读取引脚BOOT0和BOOT1上的逻辑电平。在最近的STM32系列中,BOOT1被Option Bytes中的一个位所取代。
BOOT0的逻辑电平决定STM32是否进入用户应用程序(BOOT0接地到Vss)或系统引导加载程序或内部RAM(BOOT0连接到Vdd、BOOT1引脚或nBOOT1位决定)。当芯片是原始的并且闪存中没有代码时,也可以使用其他一些场景。详见AN2606。
请注意,如果系统引导加载程序被激活,它将侦听AN2606中规定的所有接口。如果必须使用系统引导程序,这就需要进行特定的设计:只有为主要通信设计的接口必须是活动的,与其他接口相关的所有其他引脚不得显示任何活动(在建立主要通信之前保持恒定值)。背后的原因是Bootloader扫描与所有指定外围设备相关联的任何和所有引脚上的活动,并且具有第一个检测到活动的外围设备被选择用于进一步通信。
如果BOOT0断开连接或与Vss的连接损坏(即跳线丢失),则可能无法或不可能进入用户应用程序,而系统引导程序则被执行,这是由于该输入引脚上的电压在通电或复位时的随机性。
选项字节设置可能会绕过BOOT0采样。当STM32在2级中被读出保护时,BOOT0被完全忽略。


复位电路

NRST引脚是双向的,具有开漏MOS晶体管和内部上拉电阻器。这允许通过按钮、外部看门狗、电压监控器等从各种电源内部和外部重置STM32。为了使内部重置电路正常工作,所有外部设备必须在开漏模式下运行,而不是在推挽配置下运行。
NRST引脚不需要外部驱动。唯一需要的部件是连接在NRST和Vss之间的100nF电容器。较大的电容器、外部上拉电阻器或推挽装置将导致内部MOS过载或可能错过复位脉冲。
新的低引脚数STM32设备可以将NRST引脚配置为仅输入,或者断开引脚的功能,让用户使用GPIO。
NRST应传播到调试连接器和/或测试焊盘。在各种情况下对其进行监控可以揭示STM32内部或外部的问题。


调试连接

STM32设备可以通过两个不同但重叠的接口进行调试:SWD或JTAG。选择是由调试探针和通过调试引脚的特定序列进行的。虽然协议不同,但两个接口的功能和速度在调试方面是匹配的。不过,SWD无法访问STM32的边界扫描。
当选择JTAG接口时,需要使用包括NJTRST在内的所有JTAG引脚。如果使用SWD,则只需要SWDIO和SWCLK进行正确的调试和编程。
需要进一步连接到调试探针:
  • Vdd用作电压监测输入和调试探针电压电平转换器的电源:JTAG连接器上的Vdd用作探针的输入,而不是STM32的电源!
  • 用于STM32硬件复位的NRST:如果与STM32的连接失败,如果任何软件错误配置阻止连接到STM32(无效时钟、GPIO设置等),则选择连接方法“重置下连接”允许重新连接
注意:在复位期间,JTAG引脚被配置为具有内部上拉或下拉的备用功能,并连接到JTAG电路。当设置为正常GPIO时,这可能会对可能由这些引脚控制的任何外部外围设备构成风险。从外部驱动这些引脚并向STM32提供多次复位可能会导致JTAG序列的注入,从而导致意外行为,如进入边界扫描模式。

当使用ETM调试接口时,请注意它是一个高频电路(数百MHz),需要考虑正确的PCB布局。为了使ETM正常运行,必须满足以下几点:

  • ETM必须在交替功能模式下与适当的GPIO引脚一起启用(通常通过调试脚本)
  • 必须在调试工具\IDE中输入正确的核心频率(在不同的探针和工具中存在一些频率限制)
  • 必须使用Cortex-M ETM启用的调试探针
  • 高速USB流跟踪优于缓冲跟踪
  • 如果ETM磁道长度不相等,则可能必须补偿数据偏斜
SWD接口可以使用SWO引脚进行扩展,允许通过SWD调试探针流式传输用户和ITM数据,并将其用作类似调试printf的输出。
 

2.启动配置

选项字节

选项字节存储在闪存的单独区域中。它们可以由用户配置,并包含各种启动选项(取决于STM32系列),如:
  • BOOT0选项的启动地址
  • nBOOT1位值
  • BOOT0锁定和预编程值
  • 推出独立监管机构
  • 软件进入低功率模式时自动复位
  • 读出保护电平
  • 写保护扇区
  • 安全部门
  • ROP保护的扇区
  • 默认核心安全模式
  • 双核系统的激活
有些选项可能有助于您使系统更加健壮,例如禁用引导加载程序条目(如果BOOT0可以通过Option Bytes控制),有些选项可能会让调试很麻烦(激活高于0的IWDG或RDP级别)。
如果您不打算使用低功率模式,请考虑在进入STOP和Stand-by时启用重置。
注意:
  • 调试您的软件,当您激活高于0的RDP级别时,将自动使闪存不可用,直到整个电源循环!
  • RDP级别2是不可逆的,并阻止对STM32的任何调试或系统引导加载程序访问。如果您错误配置STM32或其软件损坏,并且不允许在应用程序中重新编程,STM32将被永久砖砌!
  • 如果STM32在Option Bytes编程期间经历重置或电源循环,并且Option Bytes与其补码不匹配,则将强制执行RDP级别1。在这种情况下,需要回归到0级(带有完整的FLASH擦除)以恢复Option Bytes和FLASH访问。

启用IWDG HW激活时,STM32将在重置后立即启动独立看门狗。只有在调试模式下,才有可能临时阻止其操作,但一旦STM32开始或恢复SW执行,IWDG就需要定期更新。IWDG初始延迟只有几毫秒,因此其重新配置可能是启动代码的第一次操作,如果需要,将IWDG超时延长到数百或数千毫秒。如果使用大量RAM,初始IWDG超时可能太短,无法从main()重新配置,从而导致周期性重置。你们可以通过NRST引脚上的复位周期来检测这种情况。

3.软件

矢量表和初始设置

STM32通常从固定地址开始:0x0000 0000。在这里,它期望一个向量表,其中包含不同例程(重置、故障、中断)的32位地址,第一个地址是重置后由内核加载到MSP的初始堆栈指针的值,第二个是重置处理程序的地址。
然而,STM32在默认情况下从地址0x0800 0000放置闪存。这允许为内存重新映射“腾出空间”,因此,使用内存镜像,STM32可以通过BOOT0\BOOT1配置向地址0x0的核心提供各种类型的内存:0x0800 0000的FLASH、0x1FF0 0000的System Bootloader或0x2000 0000的RAM。运行时的软件重新映射也可用。
当自定义引导加载程序在多级引导中实现时,当向量表与用户应用程序重新映射到扇区时,这很有用,以允许应用程序利用自己的一组故障和中断向量。这可通过NVIC->VTOR获得。
注意:VTOR地址必须和矢量表的大小对齐(即以1kB为步长)。如果不遵守对准,岩心将进入不可恢复的断层。
CMSIS代码可以通过宏USER_VECT_TAB_ADDRESS和VECT_TAB_OFFSET管理重新映射。
当STM32引导时,核心加载初始SP,并以特权线程模式跳转到reset_handler。从现在起,STM32的控制权在用户程序上。
reset_handler继续调用函数SystemInit,该函数根据所选内核启用FPU,设置与用户设置匹配的矢量表地址,可能启用F(S)MC接口以访问外部RAM和FLASH存储器,将时钟重置为内部RC源,并可能重新配置其他振荡器。
从SystemInit返回后的下一步取决于编译器运行库(RTL)的实现,但通常启动RAM初始化(从FLASH复制RW,清除ZI)、堆栈和堆设置、in\OUT\ERR通道初始化、C++静态构造函数调用等。
最后一步,调用围绕main()的包装器,最后调用main()本身。
正常的STM32应用程序不应退出,但可能会实现__rt_exit()等函数,定义此类情况下的行为。
注意:如果在启动过程中输入硬故障,则可能:
  • RAM无法启用\访问。当额外的RAM在不同的域中并且需要启用其时钟时,或者RAM在外部存储器空间中时,可能会发生这种情况。可以通过在SystemInit中正确设置F(S)MC来解决。
  • FLASH内存不可用(如果您的代码也存储在外部FLASH中,或者检测到ECC错误)
  • 静态C++构造函数的调用顺序错误
注意:基于Cortex-M7的STM32s在Option Bytes中有可配置的启动地址,用于不同的BOOT0配置。
 

内存设置

用户应用程序的内存布局由链接器描述文件定义。默认内存设置可能无法覆盖所有可用内存,这是有充分理由的。用户可以扩展或修改链接器描述文件(或分散文件,用不同的术语)来访问这些内存区域,但需要一些谨慎和知识。
各种STM32系列通过不同的总线提供不同的RAM:主数据SRAM、D-TCM和I-TCM RAM、备份SRAM、不同电源域中的SRAM。其中一些只能由核心使用,一些可以与其他总线主机共享,如GPDMA、ETH DMA、USB DMA、SDMMC DMA或其他核心。在没有先验知识的情况下,用户可能会引入难以调试的问题,即当核心专用内存包含在正常的链接器设置中,并且链接器决定在这种内存中分配堆栈或堆时。如果这样的RAM随后被分配并用作DMA的缓冲器,则DMA将失败并报告永久错误。DMA通常需要对齐的访问,因此必须正确分配缓冲区。
访问I-TCM RAM可能导致数据中止故障等。
 

缓存和MPU

高速缓存的使用对STM32的性能有重大影响,尤其是在高核心速度或QSPI或SDRAM等外部存储器的情况下。然而,必须充分考虑使用情况,特别是如果缓存内存与其他总线主机共享。需要选择适当的缓存策略和分区来保证数据的一致性。可以定义高速缓存内的各种块,并通过MPU利用率选择不同的策略。
MPU可以在存储器内定义多达8个或16个具有不同大小和位置的重叠块。每个块设置都会影响底层内存是否会被缓存、缓冲、视为设备或具有随机访问的内存等。
缓存行可能需要无效。如果不同的内容存储在一个缓存行中,当无效时,它可能会损坏,因此可能需要对齐数据。
如果启用数据缓存,请提取非缓存区域中MDMA或ETH DMA的所有DMA缓冲区或控制块。
私人程序数据可以自由缓存。
 

调试工具、RTL和重定目标

在调试模式下编译应用程序时,RTL代码可能包含允许所谓重定目标的例程,即通过侧通道将数据传递给调试器。例程要么使用指令BKPT通过矢量捕获将数据传递给调试器,要么实现其他通信方式——内存缓冲区、ITM接口等。当程序调用此类例程时,某些配置可能会阻止程序正常运行。然后代码可能会卡住。
解决方案是在关闭重定目标的情况下使用RTL库编译应用程序。
注意不同版本的RTL库,它们可能提供完整、中等或最低限度的功能。通常,它们实现printf或scanf的各种功能,但对64位算术的支持可能会被默默地放弃,而其他标准C功能,如对文件流或时区转换的支持,可能会非常简化。
依赖这样的标准C特性可能是危险的,并会导致运行时问题。
当使用HAL库调试应用程序时,定义宏USE_FULL_ASSERT并在例程ASSERT_failed中放置断点非常有用。此设置在大多数HAL函数中生成代码检查参数。当检测到错误的设置时,将使用失败测试的文件名和行号调用assert_failed。在释放模式下,删除宏以提高性能!

捕捉错误

硬件设计稳定的应用程序的典型问题是软件或配置故障,导致某种类型的Cortex-M故障或算法或外围设备死锁。应用程序应准备好以预期和可靠的方式处理它们。
Cortex-M产生的故障可分为使用故障(由内核产生,即指令未定义、特权不好)、总线错误故障(由总线矩阵产生)和内存保护故障(由MPU产生)。当没有定义故障处理程序时,所有这些都会升级为硬故障。硬故障不会显示系统中的任何特定故障,它被视为其他未处理故障(使用、总线、MPU、优先级反转)的收集器。
除了Cortex-M0,STM32的所有高级Cortex-M实现都提供寄存器,用户可以在其中读取错误的原始源和相关标志以及故障地址。其他信息和调用者的上下文一起存储在堆栈中。即使有这样的细节,也可能很难识别错误的来源,因此ETM接口可能会变得方便,但通常情况下,您的应用程序应该可靠而果断地处理这些错误。您可以实现错误上下文的某种解析器,将其存储到某个日志或非易失性内存中并重置应用程序,或者,如果错误在应用程序中可能无法恢复,则可以正常关闭并停止任何操作,从而将外部风险降至最低。这样的故障实现将创建确定性行为,这将允许未来的调试并改善用户体验。
可以在Keil.com和其他网站上找到硬故障处理程序的示例。
软件故障可能很难发现,尤其是当它们导致死锁时。HAL库函数包含用户定义的超时,以在底层外围设备配置错误或外部故障或ESD事件导致外围设备跳闸时防止死锁。在这种情况下,功能将返回HAL_TIMEOUT,用户应考虑外设或系统重置。
算法问题可能无法在默认情况下阻止自己检测超时,或者可能会对效率产生很大影响。为此,STM32提供了两个硬件监管机构-WWDG和IWDG。WWDG非常适合监测最小和最大长度的各种算法,IWDG可用于长期过程。这两个看门狗都提供独立的时钟源、API接口和功能。当您的应用程序被这两个看门狗中的任何一个重置时,您可以从RCC->RSR中识别重置源。如果您按照X-CUBE-CLASSB包中描述的方式设计例程,则可以使用函数调用戳来检测看门狗在哪个例程上超时。
 

4.总结(TL;DR)

  • 阅读数据表、参考手册、勘误表和应用说明
  • 设计可靠的电源,测量它,永远不要跨越AMR!
  • 注意Vss和Vdd引脚之间的电压差,使用100 nF电容器很好地去耦
  • 监控电源电流和Vcap电压
  • Vbat必须始终为正极,从不接地
  • NRST应无(推挽装置、外部上拉和容量超过100 nF),电源电压应达到0V,以进行适当的电源循环
  • 监控NRST的启动问题,读取RCC->RSR中的重置原因
  • 针对AN2867验证水晶,启用CSS
  • 当系统引导加载程序未使用时,始终将BOOT0接地,可能带有下拉菜单,并允许通过测试点进行访问
  • 当使用系统引导程序时,请注意所有可能的通信接口,请参阅AN2606
  • 在设计调试接口时,将SWO、NRST和Vdd添加到调试探针电缆中
  • 使用调试器的“重置时连接”功能
  • 如果您的软件意外启用SMPS,请引导到系统引导程序,然后通过SWD/JTAG擦除芯片
  • setup Option字节正确,使用尽可能多的安全功能,但在启用芯片保护时要注意调试限制-可能需要电源循环!
  • 将矢量表与1 kB边界对齐
  • 定义简洁的存储器布局,尊重各种总线主控器的不同访问限制
  • 使用MPU定义启用缓存\缓冲\重新排序\禁用的区域,特别是与DMA单元和核心共享的缓冲区
  • 选择具有正确功能集的正确RTL(与您的项目链接的C库),并对其进行正确测试
  • 在软件的Release版本中删除重定目标
  • 在调试模式下定义宏USE_FULL_SSERT,允许在调用HAL例程时捕获运行时错误
  • 实现故障处理程序,记录错误并定义响应策略(系统重置、停止、可恢复的情况)
  • 使用看门狗,根据X-CUBE-CLASSB实现软件结构和自检
  • 测试堆栈和堆的使用情况,并利用关键例程调用返回的错误代码