【问题标题】:Why doesn't my Flash Control Register update when I write to it (STM32)?为什么我的闪存控制寄存器在我写入时没有更新(STM32)?
【发布时间】:2020-11-17 09:42:46
【问题描述】:

我正在尝试写来更新我在 STM32G0 上的工程字节,但我遇到了困难。我需要通过写入 FLASH_KEYR 寄存器来解锁闪存。手册是这样说的:

After reset, write into the FLASH control register (FLASH_CR) is not allowed so as to protect the Flash memory against possible unwanted operations due, for example, to electric disturbances. The following sequence unlocks these registers:

1. Write KEY1 = 0x4567 0123 in the FLASH key register (FLASH_KEYR)
2. Write KEY2 = 0xCDEF 89AB in the FLASH key register (FLASH_KEYR).

Any wrong sequence will lock the FLASH_CR registers until the next system reset. In the case of a wrong key sequence, a bus error is detected and a Hard Fault interrupt is generated.
The FLASH_CR registers can be locked again by software by setting the LOCK bit in one of these registers.

Note: The FLASH_CR register cannot be written when the BSY1 bit of the FLASH status register (FLASH_SR) is set. Any attempt to write to this register with the BSY1 bit set causes the AHB bus to stall until the BSY1 bit is cleared.

我确保在尝试写入时我的 BSY1 位是清晰的,我相信这是唯一的条件。

这就是我的写作方式:

#define KEY1  0x45670123
#define KEY2  0xCDEF89AB

... 

FLASH->KEYR = KEY1;
FLASH->KEYR = KEY2;

此时,我的 FLASH_KEYR 寄存器仍然是 0x0。有谁知道为什么?

编辑:这是我的代码

        #define TEST_FLASH_BYTES    ((uint32_t)0x0801FF00)

        ...

        FLASH->CR &= FLASH_CR_LOCK;
        FLASH->KEYR = KEY1;
        FLASH->KEYR = KEY2;

        while(__HAL_FLASH_GET_FLAG(FLASH_SR_BSY1) != 0) {}

        program_flash(TEST_FLASH_BYTES, 0x1234567887654321);

        while (__HAL_FLASH_GET_FLAG(FLASH_SR_BSY1) != 0) {}

        FLASH->SR &= FLASH_SR_EOP;
        FLASH->CR &= FLASH_CR_PG;

这里是program_flash

static void program_flash(uint32_t address, uint64_t data)
{
    *(uint32_t *)address = (uint32_t)data;

    (independently of compiler optimization behavior) */
    __ISB();

    *(uint32_t *)(address + 4U) = (uint32_t)(data >> 32U);
}

编辑:它是一个只写寄存器,所以我无法读回它。我想出了如何成功写入内存。

【问题讨论】:

  • FLASH_CR 默认值为 0x0000 0080.Bit 7 在检测到解锁序列后由硬件复位。所以期望值为 0x00。
  • @Babajan 您在哪里看到默认 val 是 0x0000 0080?地址偏移量为 0x008,其重置值为 0x0000 0000,但我不确定该默认值来自何处。
  • 默认寄存器值为 0x8000 0000 。这是一个链接st.com/resource/en/programming_manual/…参考第2.8.5章
  • @Babajan 用于 STM32F 系列

标签: memory embedded microcontroller stm32 flash-memory


【解决方案1】:

此代码使 boot0 引脚能够像传统 stm32 芯片一样工作。

    //enable BOOT0 pin
    while(GET32(0x40022010)&0x10000) continue;
    PUT32(0x40022008,0x45670123);
    PUT32(0x40022008,0xCDEF89AB);
    PUT32(0x4002200C,0x08192A3B);
    PUT32(0x4002200C,0x4C5D6E7F);
//from the manual:
//ST production value: 0xDFFF E1AA
    PUT32(0x40022020,0xDEFFE1AA);
    while(GET32(0x40022010)&0x10000) continue;
    PUT32(0x40022014,0x00020000);
    while(GET32(0x40022010)&0x10000) continue;

PUT32 执行 str 指令,GET32 执行 ldr 指令。

不同的STM32G0对其中一些寄存器有不同的默认值,我现在为FLASH_CR寄存器打开的是:

Reset value: 0xC000 0000

这是两个锁定位,因此上面的每个解锁序列都绑定到一个位,因此两个序列也是如此,理论上两个位都解锁。可以挖出一块板/芯片并尝试这个并编辑这个答案以确认。

看起来您是从程序中执行此操作的,这些芯片非常挑剔,擦除闪存(如在新芯片中)后,您可以使用引导加载程序进行加载,一旦有东西,您就可以通过 SWD 进入(我假设有一种方法可以阻止它),但是你不能使用 swd 来编写这些寄存器来执行这些你必须运行代码的任务,你可以从 ram 或 flash 运行它。

根据您要更改的内容,您可能需要重启芯片才能看到更改生效。

编辑

while(GET32(0x40022010)&0x10000) continue; //need this here?
ra=GET32(0x40022014); //FLASH_CR
while(GET32(0x40022010)&0x10000) continue;
PUT32(0x40022008,0x45670123);
PUT32(0x40022008,0xCDEF89AB);
rb=GET32(0x40022014); //FLASH_CR
PUT32(0x4002200C,0x08192A3B);
PUT32(0x4002200C,0x4C5D6E7F);
rc=GET32(0x40022014); //FLASH_CR
hexstring(ra);
hexstring(rb);
hexstring(rc);

串口输出

C0000000 
40000000 
00000000 

正如文档中所预期的那样。

您如何以及何时阅读注册表?您是否在解锁和读取之间触摸任何寄存器?

【讨论】:

  • 使用地址和幻数完全没有意义。这个“伪代码”也是。
  • which is the two lock bit 第二个不相关,因为它锁定 OPTION BYTES 与 OP 问题无关
  • @P__J__ 代码中没有一个魔幻数字 FLASH_CR 是魔幻的,是的,您必须深入挖掘代码层才能找出它是什么,但这 100% 来自文档,零魔幻,零神秘,微不足道。
  • OP 正在读取零,要达到零,您需要根据文档清除这两个位,这演示了到零的路径以及在解锁任何东西之前,先解锁一件事然后解锁另一件事。 OPTION BYTES 与读取零有关(或由于魔术隐藏标头等而没有正确的地址)
  • OP 读数为零,因为他没有启用 FLASH 外围设备。它不是 FLASH 存储器专用的数字接口,用于对 FLASH 存储器进行编程和设置。否则,他将读取该寄存器的默认值,其中 LOCK 位复位不为零。顺便说一句,读取您不需要解锁它的值。
【解决方案2】:

我猜你没有启用数字 FLASH 接口。

RCC -> AHBENR |= RCC_AHBENR_FLASHEN;

然后

等待 FLASH 外设

while (FLASH -> SR & FLASH_SR_BSY1) ;
        RCC -> AHBENR |= RCC_AHBENR_FLASHEN;
        (*void)RCC -> AHBENR; // readback instead of delay to let this change to propagate throut the bus.
        while(FLASH -> SR & FLASH_SR_BSY1));
        //FLASH->CR &= FLASH_CR_LOCK; this line is worng. First of all it is not the way of reseting the bits, Secondly this bit is SET ONLY which meand that you can set it to enable the lock again
        FLASH->KEYR = KEY1;
        FLASH->KEYR = KEY2;

        while(FLASH -> SR & FLASH_SR_BSY1));

【讨论】:

  • 请不要使用隐藏值,使用文档中显示的值。这个问题是关于文档而不是关于某些库中的神奇隐藏值。
  • @old_timer 它们不是幻数。这些定义由 STM 提供(它不仅是库,只是具有人类可读性的头文件,类似于 STM 文档定义中使用的)。而且代码很容易阅读。 RCC 是外围设备,它的寄存器称为AHBENR。您需要在此寄存器中设置位FLASHEN。所以定义是RCC_AHBENR_FLASHEN*(volatile uint32_t *)0x40005678 |= 0x00010000 对人们来说很难解码。
  • @P__J__ 为什么设置RCC -> AHBENR |= RCC_AHBENR_FLASHEN; 有助于解锁闪光灯?我尝试添加它并没有改变任何东西
  • 因为它启用了FLASH接口时钟。在此之后,您应该读取 FLASH -> CR 寄存器的默认值。如果您仍然读取零,则意味着您在其他地方犯了错误,如果没有看到完整的代码,我将无法帮助您。
  • @P__J__ 我刚刚将完整代码添加到我的问题中 :)
猜你喜欢
  • 2020-07-15
  • 1970-01-01
  • 2021-11-13
  • 2019-12-02
  • 2020-10-26
  • 2021-09-23
  • 1970-01-01
  • 2017-05-18
  • 2022-09-26
相关资源
最近更新 更多