STM32F091

前言

看过另一篇实战经验《STM32F091 空片使用 System Bootloader 下载代码》 之后,就会知道 STM32F091 有一项特殊的功能,就是在空片的情况下既可以使用 ST-Link 等编程工具进行编程,也可以使用 System Memory 中的 Bootloader 进行下载代码。这完善了整个编程体系,给用户在编程方案的选择上带来很大的方便。但是,在某些特定应用上,好心也可能会干坏事哦。

下面就来聊聊这个事是怎么来的,并且找出相应的对策。

问题

某客户在其产品的设计中,使用了 STM32F091RCT6。客户使用 ST-Link 对 STM32F091RCT6 进行编程,发现对空片进行编程之后,必须要重新上电才能运行用户代码;但是如果不是空片,则编程后就可以直接运行用户代码。由于客户的测试系统是直接烧写完芯片后在不断电的情况直接进入测试模式,如果空片烧写需要断电的话,带来一定的麻烦。客户希望搞明白这件事,并希望找到办法,能在空片编程后也可以直接运行用户代码。

调研

1.还原问题

在这里,使用带有 STM32F091RCT6 的 NUCLEO-F091RC 板来进行问题还原,将此 Nucleo 板通过 USB 线连接到电脑。打开 STM32 ST-LINK Utility,点击“Connect to the target”按钮进行芯片连接,连接后打开一个准备好的 LED 灯闪烁的.hex 文件代码,点击“Program verify”按钮准备进行编程。

STM32F091 空片使用 ST-LINK 编程后不能直接运行用户代码

在这里,我们勾选了“Reset after programming”,目的在于编程后对芯片进行复位,可以运行用户代码。然后点击“Start”按钮开始进行编程。

编程之后,按道理可以看到 LED 灯闪烁的,但是并没有出现。需要给 MCU 进行断电后,重新上电才能看到 LED 灯闪烁。也就是说需要一次上电复位才能运行用户代码。

2.分析问题

先来回顾一下 STM32F091 的参考手册 RM0091 对于 Empty Check 的描述:

STM32F091 空片使用 ST-LINK 编程后不能直接运行用户代码

首先,芯片内部存在一个查空标志,用来标志芯片是否为空片。这个标志位在 BOOT0 脚被定义到从 Main Flash memory 启动的时候使用。当这个标志位被置“1”的时候,此芯片被认为是空的,系统将从 System memory 中启动 Bootloader,以允许用户进行代码下载,即使现在 BOOT0 脚定义的是从 Main Flash memory 启动。此标志位只在载入 Option bytes 时更新:

当地址 0x0800 0000 读出的内容为 0xFFFF FFFF 时,此标志位置“1”,否则为“0”。这意味着当烧写完一个空片后需要在系统复位后执行用户代码的话,是必须要重新上电以产生或者在 FLASH_CR 寄存器中置位 OBL_LAUNCH 来启动 Option byte loader reset,以清除此查空标志。

现在就可以来分析目前所遇到的情况了:

当空片通过 SWD 连接到 ST-Link 进行烧写的情况下,由于上电时空片检测检测到此芯片为空片,查空标志被置位,所以系统此时从 System memory 中启动 Bootloader 开始运行。通过简单的 SWD 接口对芯片进行编程,勾选的“Reset after programming”将在编程结束后在 RESET 引脚上产生一个复位信号,但是不幸的是这个复位并不能清除查空标志,导致复位后仍然从 System memory 中启动 Bootloader,而没有运行用户代码,也就是我们之前遇到的现象。

一般情况下,我们都可以通过重新上电来产生 POR 以清除查空标志,从 Main Flash memory 启动运行用户代码。但是,客户目前的这种特殊需求就会带来一定的麻烦。还有一种应用也会比较麻烦,也就是使用锂电池的产品,而且这个电池直接焊接到用户板上,无法方便地进行断电上电。此时,若是空片是焊接在板子上进行在线编程,那么,问题来了。空片编程之后,由于不方便进行断电,而无法完成 POR 的动作,不能运行用户代码也就无法实现一个 Option byte loader reset。查空标志无法清除,程序运行将锁死在 System memory 的 Bootloader。

3.问题解决

这种问题呢,解决方法当然有很多种,下面来大概地探讨一下:

1) 从生产上来解决:芯片在编程器上进行单独编程,之后再上板子,避开空片烧写后没有 POR。

2) 从硬件上来解决:使用一个跳线,或者使用其他方式,比如在夹具上想办法,以达到通过人工的断电再连通上电,实现一个 POR。需要在 PCB 板上预留。大家可自行选择对策。但是这会增加生产上的麻烦,降低效率。

3) 从编程方法来解决:不使用 ST-Link 进行编程,直接使用 Bootloader 进行串口升级,升级后跳转到 Main Flash memory 去运行用户代码。需要在用户代码中加入将 Main Flash memory 映射到 0x0000 0000 的代码。

4) 前面几种方式大家一看就明白如果去解决了。但是,如果一定要使用 ST-Link 通过 SWD 进行烧写的话,就另当别论,我们下面来探讨这种方式。

一般看到这种问题,直观思维就是思考是否有办法,可以在 ST-LINK 烧写后通过一定的 ST-LINK 命令跳转到用户代码去运行用户代码。方法看起来可行,但是有点复杂。第一,STM32 ST-LINK Utility 没有提供类似的功能,需要用户自行使用 ST-LINK_CLI 命令;第二,需要在用户代码中加入别忘了将 Main Flash memory 映射到 0x0000 0000 的代码;第三,由于查空标志未清除,需担心意外的复位信号或干扰,导致复位后又跑回 System Memory,还需要在用户代码中加入“每次运行都判断是否为 Option Bytes Loader reset,如果不是,就直接执行一次 Option Bytes Loader reset 以清除查空标志”。

我们的直观思维都是出现问题解决问题,但是看了上面的描述,这样的解决办法还真有点麻烦。那有没有什么其他简单的办法呢?答案是有的,我们不要把思维停留在出现问题解决问题上,而是如何去避免产生问题。下面来理一理思路:

这个问题的根源在于查空标志的存在,所以需要思考的是怎么避免查空标志的影响?
来看一下查空标志产生的条件:

a) 使用了 BOOT0 引脚
b) BOOT0 引脚为低电平,启动区域指向 Main Flash memory
c) 读取 0x0800 0000 地址的值为 0xFFFF FFFF

由于是空片编程,所以第三种条件是肯定是成立的;由于硬件设计,BOOT0 引脚的电平也不方便改来改去;所以需要把关注点放在第一个条件上——“使用了 BOOT0 引脚”。由于 STM32F091 的特性,刚好有机会可以不使用BOOT0 引脚,而是直接使用选项字节,所以解决的办法有了。

步骤如下:
i. 打开 STM32 ST-LINK Utility,点击“Connect to the target”按钮进行连接;
ii. 从菜单“Target → Option Bytes”调出选项字节对话框

STM32F091 空片使用 ST-LINK 编程后不能直接运行用户代码

将“nBoot0_SW_Cfg”的打勾去掉,点击“Apply”,改成使用选项字节中的 nBoot0 和 nBoot1 来控制启动区域
iii. 再打开需要烧写的代码文件,点击“Program Verify”按钮,对话框中勾选“Reset after programming”,点击“Start”完成烧写动作就可以了。
STM32F091 空片使用 ST-LINK 编程后不能直接运行用户代码

这样就可以看到用户代码已经在运行了,是不是很简单。
如果,希望更简单的完成,可以使用 ST-LINK_CLI,写一个批处理文件,包含以下动作:
 ST-LINK_CLI -c SWD UR
 ST-LINK_CLI -ME
 ST-LINK_CLI -p xxxxxxxx.hex -v “while_programming”
 ST-LINK_CLI -OB nBOOT0_SW_Cfg=0
 ST-LINK_CLI -Rst 

ST-LINK_CLI.exe 位于 STM32 ST-LINK Utility 安装目录里,关于命令请参考《ST-LINK Utility UM.pdf》。

结论

由于查空检测机制,导致 STM32F091 空片在使用 ST-LINK 编程后,不断电的情况下复位将回到 System Memory,无法进入Main Flash memory 去运行用户代码。所以,在特殊应用中,如果无法进行断电再上电,需要使用办法对这种机制进行破坏。

处理

将 Boot 启动配置为用选项字节进行控制,而不是使用 Boot0 引脚,以此来破坏查空机制的影响。

建议

对于问题的解决,一般从两个方向进行思考:一是出现了问题再来找解决问题的办法;二是如何避免出现问题。很多时候,由于思维惯性,很多工程师可能会更喜欢直接从第一种方向去思考问题;然而,事实上,如果能从第二种方向思考,阻止问题的产生,那才是最好的办法。

来源:ST

围观 567

前言

我们在《STM32F09x 不使用 BOOT 脚实现 System Bootloader 升级代码》中实现了通过修改 Option Bytes 来达到控制BOOT0 和 BOOT1,在不需要外部 BOOT 脚的情况下实现了使用 System Bootloader 进行代码升级的功能。可是,这个功能必须在程序中预先烧写了功能程序后,才能不断地进行升级。也就是说,在第一次空片烧写时,必须使用 SWD 进行烧写的。

那有没有可能在空片烧写时,就可以直接使用 System Bootloader 进行烧写呢?这样我们就可以完全使用串口进行烧写和升级了。现在,我们来探讨这个问题。

问题

在使用 STM32F091RCT6 时,能否进行对空片的串口烧写,结合《STM32F09x 不使用 BOOT 脚实现 System Bootloader 升级代码》实现完全使用串口进行烧写?

调研

1.认识一下 STMF09x 和 STM32F04x 在 Boot Configuration 中的新特性打开参考手册 RM0091,翻到 Boot Configuration 那一节,我们可以看到 Table 3 中对 Boot Mode 进行了描述,如下:

STM32F091 空片使用 System Bootloader 下载代码

从表格中,在《STM32F09x 不使用 BOOT 脚实现 System Bootloader 升级代码》一文中我们只提到了第 1 条注释:
“Grey options are available on STM32F04x and STM32F09x devices only.”
现在,我们再来看一下第 2 条注释:
“For STM32F04x and STM32F09x devices, see also Empty check description.”
那我们再来看一下 Empty check 的描述:

STM32F091 空片使用 System Bootloader 下载代码

首先,我们看到,“Empty Check”是只有 STM32F04x 和 STM32F09x 才有的功能,内部有一个查空标志,可用于使用Bootloader 对未编程过的芯片进行简单编程。这个标志位在 BOOT0 脚被定义到从 Main Flash memory 启动的时候使用。当这个标志位被置“1”的时候,此芯片被认为是空的,系统将从 System memory 中启动 Bootloader,以允许用户进行代码下载,即使现在 BOOT0 脚定义的是从 Main Flash memory 启动。此标志位只在载入 Option bytes 时更新:当地址 0x08000000 读出的内容为 0xFFFF FFFF 时,此标志位置“1”,否则为“0”。这意味着当烧写完一个空片后需要在系统复位后执行代码的话,是必须要重新上电或者在 FLASH_CR 寄存器中置位 OBL_LAUNCH。

也就是说,当我们把 BOOT0 设置为 0,设置为从 Main Flash memory 中启动时,当上电时或者置位 OBL_LAUNCH 启动一个带载入新的 Option bytes 的复位后。当 Option bytes 载入的时候,STM32F04x/STM32F09x 会读取读取 0x0800 0000 的内容,如果其值为 0xFFFF FFFF,认为此芯片为空片,直接进入 System Memory 中,使用 Bootloader 启动;如果其值不是0xFFFF FFFF,则认为此芯片不是空片,直接从用户代码启动。

2.实验验证

实验使用工具:PC 一台,NUCLEO-F091RC 一块,USB 线 1 条(用来连接 NUCLEO 板与 PC)
实验使用软件:STM32 ST-LINK Utility,Flash Loader Demonstrator
实验使用软件库:STM32Cube_FW_F0_V1.2.0
我们先来看第一个实验:

• 实验 1:空片测试

1) 使用 USB 线连接 PC 与 NUCLEO-F091RC
2) 打开 STM32 ST-LINK Utility 软件,点击“Connect to the target”按钮,连接 STM32F091。然后点击“Full chip erase”按钮对 Main Flash Memory 进行擦除。结果如图所示:

STM32F091 空片使用 System Bootloader 下载代码

3) 我们再点击菜单“Target→Option Bytes”检查一下 Option Bytes 的配置确实是初始值的状态。如下图:

STM32F091 空片使用 System Bootloader 下载代码

4) 若是确认 Option Bytes 是初始值,直接点“Cancel”退出对话框;若是 Option Bytes 为非初始值,修改为初始值后点“Apply”完成 Option Bytes 的更新并退出对话框。
5) 回到 STM32 ST-LINK Utility,点击“Disconnect”按钮断开连接。
6) 断开 USB 连接线,并重新连接。为 STM32F091 重新上电。
7) 打开 Flash Loader Demonstrator,选择正确的配置,比如下图:

STM32F091 空片使用 System Bootloader 下载代码

NUCLEO 板上的 ST-LINK 自带虚拟串口,而且已经连接到 STM32F091 芯片上。此时虚拟串口对应的是
COM16,所以选择 COM16。
8) 点击“Next”测试连接,并继续往下测试烧写。
9) 测试结果:成功!
10) 到此,我们证明空片是可以直接使用 Flash Loader Demonstrator 进行串口烧写的。但是我们再来探讨一些其他情况。

• 实验 2:测试 0x0800 0000 地址的值为 0xFFFF FFFF 的情况。

按参考手册 RM0091 的描述,只要 0x0800 0000 地址的值为 0xFFFF FFFF 就可以进入 System bootloader 了,即使BOOT 配置为 Main Flash memory 启动。所以我们再来做一个实验:

1) 使用 USB 线连接 PC 与 NUCLEO-F091RC
2) 打开 STM32 ST-LINK Utility 软件,点击“Connect to the target”按钮,连接 STM32F091。并点击“Open file”按钮,打开位于\ STM32Cube_FW_F0_V1.2.0\Projects\STM32F091RC-Nucleo\Demonstrations\Binary 的示例代码文件 STM32CubeF0_Demo_STM32F091RC-Nucleo.hex。如图:

STM32F091 空片使用 System Bootloader 下载代码

3) 点击“Program verify”按钮进行烧写。
4) 点击“Disconnect”按钮断开连接。
5) 断开 USB 连接线,并重新连接。为 STM32F091 重新上电。
6) 打开 Flash Loader Demonstrator,点击“Next”,就会弹出下图所示的警告,证明无法连接。失败!

STM32F091 空片使用 System Bootloader 下载代码

7) 切回 STM32 ST-LINK Utility 软件,点击“Connect to the target”按钮,连接 STM32F091。在“Device
Memory @ 0x08000000:”页面中直接将 0x0800 0000 地址中的数值修改为 0xFFFF FFFF,这时软件会自动更新代码,将修改过的代码烧写到 STM32F091 中,如下图:

STM32F091 空片使用 System Bootloader 下载代码

8) 点击“Disconnect”按钮断开连接。
9) 断开 USB 连接线,并重新连接。为 STM32F091 重新上电。
10) 打开 Flash Loader Demonstrator,点击“Next”测试连接,并继续往下测试烧写。
11) 测试结果:成功!
12) 到此,我们证明确实在 Main Flash memory 中只要 0x0800 0000 地址中的数值是 0xFFFF FFFF 就可以直接使用 Flash Loader Demonstrator 进行串口烧写的。其他地址的数值并没有关系。那么,是不是只要这个条件就能保证可以串口烧写呢?我们再来看下一个实验。

• 实验 3:Option Bytes 测试

1) 使用 USB 线连接 PC 与 NUCLEO-F091RC
2) 打开 STM32 ST-LINK Utility 软件,点击“Connect to the target”按钮,连接 STM32F091。然后点击“Full chip erase”按钮对 Main Flash Memory 进行擦除。结果如图所示:

STM32F091 空片使用 System Bootloader 下载代码

3) 我们再点击菜单“Target→Option Bytes”,将 Option Bytes 中的 nBOOT0_SW_Cfg 位(也就是 BOOT_SEL)的打勾去掉。如下图:

STM32F091 空片使用 System Bootloader 下载代码

4) 点击 “Apply”完成 Option Bytes 的烧写并退出对话框。
5) 回到 STM32 ST-LINK Utility,点击“Disconnect”按钮断开连接。
6) 断开 USB 连接线,并重新连接。为 STM32F091 重新上电。
7) 打开 Flash Loader Demonstrator,点击“Next”,又见到弹出下图所示的警告,证明无法连接。失败!

STM32F091 空片使用 System Bootloader 下载代码

8) 那么,这是否证明如果 Option Bytes 的值不是初始值的话,Empty Check 的功能将失效?同样的过程,我们再来试另外一个配置:

STM32F091 空片使用 System Bootloader 下载代码

在这个配置中,我们将 nBOOT0_SW_Cfg 位改回来“打勾”,再将其他打勾的项都取消掉。

9) 点击 “Apply”完成 Option Bytes 的烧写并退出对话框。
10) 回到 STM32 ST-LINK Utility,点击“Disconnect”按钮断开连接。
11) 断开 USB 连接线,并重新连接。为 STM32F091 重新上电。
12) 打开 Flash Loader Demonstrator,点击“Next”测试连接,并继续往下测试烧写。
13) 测试结果:成功!
14) 到此,我们证明 Empty Check 是会对 Option Bytes 中的 BOOT_SEL 位进行检测的。只要 BOOT_SEL 的值为“0”,而不是“1”,Empty Check 就认为这不是一个空片,不会跳往 System Memory 去执行 Bootloader。

结论

关于 Empty Check 的断定条件,不仅仅是 RM0091 所描述的检查 Main Flash memory 中地址 0x0800 0000 的值是否为0xFFFF FFFF,还检查了 Option Bytes 中 BOOT_SEL 位的值是否为“1”。只有在 Main Flash memory 中地址 0x08000000 的值为 0xFFFF FFFF,且 Option Bytes 中 BOOT_SEL 位的值为“1”的情况下,才会跳往 System Memory 去执行Bootloader。

到此,结合上一篇应用文档《STM32F09x 不使用 BOOT 脚实现 System Bootloader 升级代码》,我们就可真正地完全使用串口来进行代码烧写了。

来源:ST

围观 643
订阅 RSS - STM32F091