循环中的 WFI 会阻止调试器附加

问题描述 投票:0回答:1

我正在学习STM32F103 MCU,我正在尝试用裸机和systick定时器实现“blink led”程序。

这是我想出的:

#include <stdint.h>

static void enable_port_clock(void);
static void configure_pin(void);
static void configure_sys_tick_timer(void);

void start(void)
{
    enable_port_clock();
    configure_pin();
    configure_sys_tick_timer();

    for (;;)
    {
        // asm("WFI");
    }
}

static void toggle_pin(void);

void sys_tick_exception_handler(void)
{
    toggle_pin();
}

static void enable_port_clock(void)
{
    // enable I/O port C clock
    uint32_t rcc_base_address = 0x40021000;
    uint32_t rcc_apb2enr_address = rcc_base_address + 0x18;
    volatile uint32_t *rcc_apb2enr_pointer = (uint32_t *)rcc_apb2enr_address;
    uint32_t rcc_apb2enr_value = *rcc_apb2enr_pointer;
    rcc_apb2enr_value |= 0x00000010;
    *rcc_apb2enr_pointer = rcc_apb2enr_value;
}

static void configure_pin(void)
{
    // configure PC13 as open-drain output with 10 MHz speed
    uint32_t gpioc_base_address = 0x40011000;
    uint32_t gpioc_crh_address = gpioc_base_address + 0x04;
    volatile uint32_t *gpioc_crh_pointer = (uint32_t *)gpioc_crh_address;
    uint32_t gpioc_crh_value = *gpioc_crh_pointer;
    gpioc_crh_value |= 0x00600000;
    gpioc_crh_value &= ~0x00900000;
    *gpioc_crh_pointer = gpioc_crh_value;
}

static void configure_sys_tick_timer(void)
{
    uint32_t stk_base_address = 0xE000E010;
    uint32_t stk_ctrl_address = stk_base_address + 0x00;
    volatile uint32_t *stk_ctrl_pointer = (uint32_t *)stk_ctrl_address;
    uint32_t stk_load_address = stk_base_address + 0x04;
    volatile uint32_t *stk_load_pointer = (uint32_t *)stk_load_address;
    // enable systick exception, enable systick counter
    uint32_t stk_ctrl_value = *stk_ctrl_pointer;
    stk_ctrl_value = stk_ctrl_value | 0x00000003;
    *stk_ctrl_pointer = stk_ctrl_value;
    // set reload value to 500 ms
    *stk_load_pointer = 8000000 / 8 / 2;
}

static void toggle_pin(void)
{
    // toggle PC13
    uint32_t gpioc_base_address = 0x40011000;
    uint32_t gpioc_odr_address = gpioc_base_address + 0x0c;
    volatile uint32_t *gpioc_odr_pointer = (uint32_t *)gpioc_odr_address;
    uint32_t gpioc_odr_value;
    gpioc_odr_value = *gpioc_odr_pointer;
    gpioc_odr_value ^= 0x00002000;
    *gpioc_odr_pointer = gpioc_odr_value;
}

基本上,我配置外设,在 systick 异常处理程序中切换 LED,然后在主代码中运行无限循环。

这段代码工作得很好,但是我不喜欢在无限循环中浪费周期,所以我尝试插入

WFI
指令,该指令应该让 CPU 进入睡眠状态,直到下一个中断。好吧,使用未注释的 WFI 指令进行编程,工作正常,至少 LED 会闪烁。然而,在我刷新这个程序后,我无法再使用 ST-link 连接到我的 MCU。我必须将 BOOT0 引脚切换为“1”,然后才能再次连接到它。我用
WFI
WFE
指令尝试过,它们的作用相同。

我猜它破坏了某种调试功能,但是我不明白“永远睡觉”的正确方法是什么。

我使用的是带有 STM32F103 CPU 的“蓝色药丸”板和从 nucleo 板上拆下来的 ST-link 调试器。对于软件,我使用开源

st-flash
项目中的
stlink
实用程序。

将这个“有缺陷”的固件写入 MCU 后,甚至

st-info --probe
也不再显示已连接的 MCU。

实际上所有这些代码并不重要。我什至尝试注释掉除 WFI 循环之外的所有内容,它的作用是相同的。

我还尝试配置系统控制寄存器(SCB_SCR)并启用 SEVEONPEND 或 SLEEPONEXIT 位,但这没有什么区别。

stm32 sleep-mode
1个回答
0
投票

WFI 的作用是关闭处理器时钟(请参阅 RM0008 中 PWR 章节的低功耗模式子章)。片上调试器是处理器的一部分,因此此时它也无法工作。

可以设置DBGMCU_CR.DBG_SLEEP,这个有点是为了方便WFI调试。一些调试器允许从调试界面进行设置,IDE 通常有一些复选框。

顺便说一句。如果蓝色药丸很便宜,那么您“不太可能”拥有 STM32F103。 JW

© www.soinside.com 2019 - 2024. All rights reserved.