ST意法半导体
直播中

张莉

8年用户 1339经验值
私信 关注
[问答]

stm32f401rct6寄存器配置HSE PLL作为系统时钟,系统锁死怎么解决?

loop{        let mut cr_value =unsafe{ptr::read_volatile(register_rcc_cr).read()};        let is_25_bit_set = (cr_value & (1 << 25)) != 0;        let is_17_bit_set = (cr_value & (1 << 17)) != 0;        if is_25_bit_set && is_17_bit_set{            break;        }    }    let mut cr_value =unsafe{ptr::read_volatile(register_rcc_cr).read()};    defmt::println!("afterloop value: {:b}",cr_value);    let register_rcc_cfgr = unsafe{(RCC_BASE as *mut RW).offset(0x08 / 4)}; // GPIOC_MODER    let mut cfgr_sys_value = unsafe{ptr::read_volatile(register_rcc_cfgr).read()};    // cfgr_value &= !(0b11111 << 16); // 清除第 0 个引脚的配置    // cfgr_value |= 0b01000 << 16; // 设置为rtc_pre    // cfgr_value &= !(0b111 << 13); // 清除第 0 个引脚的配置    // cfgr_value |= 0b000 << 13; // 设置为rtc_apb2    cfgr_sys_value &= !(0b111 << 10); // 清除第 0 个引脚的配置    cfgr_sys_value |= 0b100 << 10; // 设置为rtc_apb2    cfgr_sys_value &= !(0b11 << 0); // 清除第 0 个引脚的配置    cfgr_sys_value |= 0b10 << 0; // 设置SYS_CLK    cfgr_sys_value &= !(0b1111 << 4); // 清除第 0 个引脚的配置    cfgr_sys_value |= 0b0000 << 4; // 设置SYS_CLK PRE    unsafe{ptr::write_volatile(register_rcc_cfgr as *mut u32, cfgr_sys_value)};具体报错如下:
ERROR probe_rs::architecture::arm::core::armv7m: The core is in locked up status as a result of an unrecoverable exceptionERROR probe_rs::architecture::arm::core::armv7m: The core is in locked up status as a result of an unrecoverable exceptionError: The core is locked up.
Stack backtrace:0: 1: 2: hid_write3: 4: 5: 6: 7: 8: 9: 10: hid_write11: BaseThreadInitThunk12: RtlUserThreadStarterror: process didn't exit successfully: probe-rs run --chip STM32F401RCTx targetthumbv7em-none-eabihfdebughello (exit code: 1)

回帖(3)

王璐

2025-3-3 11:55:23

在配置STM32F401RCT6的HSE和PLL作为系统时钟时,若系统锁死,通常是由于时钟就绪标志未正确检测或配置错误导致的。以下是分步解决方案:




1. 确认寄存器位定义



  • RCC_CR寄存器关键位

    • HSEON (Bit 16): 使能HSE时钟。

    • HSERDY (Bit 17): HSE时钟就绪标志。

    • PLLON (Bit 24): 使能PLL。

    • PLLRDY (Bit 25): PLL时钟就绪标志。


  • 代码问题:用户代码混淆了HSERDYPLLRDY的位位置,导致死循环。

    • 错误代码is_25_bit_set检查的是PLLRDY,is_17_bit_set检查的是HSERDY。

    • 正确逻辑:应先等待HSERDY(Bit 17),再启用并等待PLLRDY(Bit 25)。





2. 修复代码逻辑


修改轮询部分的逻辑,确保正确检测标志位:


loop {
    let cr_value = unsafe { ptr::read_volatile(RCC_CR_ADDR) };
    let hse_ready = (cr_value & (1 << 17)) != 0;  // HSERDY在Bit 17
    let pll_ready = (cr_value & (1 << 25)) != 0;  // PLLRDY在Bit 25

    if hse_ready && pll_ready {
        break;
    }
    // 添加超时处理避免死锁
}



3. 添加超时机制


避免因硬件故障导致无限等待:


let mut timeout = 1_000_000; // 根据实际情况调整超时值
loop {
    let cr_value = unsafe { ptr::read_volatile(RCC_CR_ADDR) };
    if (cr_value & (1 << 17)) != 0 && (cr_value & (1 << 25)) != 0 {
        break;
    }
    timeout -= 1;
    if timeout == 0 {
        // 触发错误处理(如切回HSI)
        panic!("HSE/PLL启动超时!");
    }
}



4. 检查时钟配置步骤


确保按顺序配置时钟:


(1) 使能HSE并等待就绪


unsafe {
    // 启动HSE
    ptr::write_volatile(RCC_CR_ADDR, ptr::read_volatile(RCC_CR_ADDR) | (1 << 16));
    // 等待HSERDY
    while (ptr::read_volatile(RCC_CR_ADDR) & (1 << 17)) == 0 {}
}

(2) 配置PLL参数



  • 假设HSE频率为8MHz,目标系统时钟为84MHz:
    // 配置PLL参数:HSE作为PLL输入,分频系数M=8,倍频系数N=168,分频P=2
    unsafe {
    // PLLM: 分频M=8 → 8MHz / 8 = 1MHz
    // PLLN: 倍频N=168 → 1MHz * 168 = 168MHz
    // PLLP: 分频P=2 → 168MHz / 2 = 84MHz
    ptr::write_volatile(RCC_PLLCFGR_ADDR,
        (8 << 0) |    // PLLM
        (168 << 6) |  // PLLN
        (0 << 16) |   // PLLP (0表示分频系数2)
        (1 << 22)     // PLLSRC (选择HSE)
    );
    }


(3) 使能PLL并等待就绪


unsafe {
    // 启动PLL
    ptr::write_volatile(RCC_CR_ADDR, ptr::read_volatile(RCC_CR_ADDR) | (1 << 24));
    // 等待PLLRDY
    while (ptr::read_volatile(RCC_CR_ADDR) & (1 << 25)) == 0 {}
}

(4) 配置Flash等待周期


确保Flash访问速度匹配时钟:


unsafe {
    // 设置FLASH等待周期为2WS(适用于84MHz)
    ptr::write_volatile(FLASH_ACR_ADDR,
        (2 << 0) |   // LATENCY
        (1 << 8) |   // PRFTEN
        (1 << 9)     // ICEN
    );
}

(5) 切换系统时钟到PLL


unsafe {
    // 切换时钟源到PLL
    ptr::write_volatile(RCC_CFGR_ADDR, ptr::read_volatile(RCC_CFGR_ADDR) | (0b10 << 0));
    // 等待切换完成
    while (ptr::read_volatile(RCC_CFGR_ADDR) & (0b11 << 2)) != (0b10 << 2) {}
}



5. 硬件检查



  • HSE晶体/振荡器:确认焊接良好,负载电容匹配(如8MHz晶体常用20pF)。

  • 电源和地:确保VDD稳定,噪声干扰小。

  • 启动配置:检查BOOT引脚是否设置为从Flash启动。




6. 常见错误



  • 位混淆:误用寄存器位偏移(如将HSERDY和PLLRDY位颠倒)。

  • 超时缺失:未处理时钟启动失败导致死循环。

  • 频率超限:PLL输出超过84MHz(STM32F401最高频率)。

  • Flash未配置:未设置正确的等待周期导致总线错误。




通过以上步骤,可解决HSE/PLL配置导致的系统锁死问题。确保代码逻辑、硬件连接和参数配置正确,并始终添加超时处理机制。

举报

李鸾

2025-3-13 15:23:41
楼主最好使用官方的而且现在非常流行的HAL 库,可以在官网上找到 STM32Cbue以及强大的生态系统。


在库中有相关配置的源码,感兴趣的话可以仔细研读,这样大幅度提高效率。

在32位单片机中,已经极少用户去配置寄存器了,不利于阅读和移植,并且已经有些过时了。

随着芯片不断的推陈出新,芯片越来越强大,细节无数,分工也会越来越细,使用HAL 驱动库效率更高,管理更方便。
举报

云甫太

2025-3-13 15:23:45
如果你确认HSE的振荡稳定、PLL也能Ready,


建议你检查下从HSE到最终系统时钟的形成所涉及到各个参数,主要是那些分频、倍频参数,


不要配置出超出数据手册约定之外的更高时钟频率了。


你可以基于CbueMx配置生成相应代码后,你相应移植过来。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分