我正在学习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 位,但这没有什么区别。