|
楼主 |
发表于 2023-4-8 22:15:25
|
显示全部楼层
本帖最后由 tomzbj 于 2023-4-8 22:29 编辑
4.7课程更新:
0. 在上次的基础上, Makefile前面加一行:- STLINK := "C:/Program Files (x86)/STMicroelectronics/STM32 ST-LINK Utility/ST-LINK Utility/ST-LINK_CLI.exe"
复制代码
后面加两行:- flash:
- $(STLINK) -c SWD freq=4000 -P $(TARGET).hex -V -Rst
- reset:
- $(STLINK) -c SWD -Rs
复制代码
于是在命令行执行make flash和make reset就可以实现下载和复位了.
1. main.c, 把闪灯的部分单独拿出来做成一个函数gpio_toggle, 在main函数里调用, 再在这个函数里加个while(1); 于是程序运行到这里就卡死了.
2. 用stlink连接, MCU Core, 单步运行, PC寄存器的值一直不动, 说明死循环了.
3. 但是怎么从PC的值知道卡在哪里? 首先在Makefile里加一行:
- LDFLAGS += -Wl,-Map=$(TARGET).map,--cref,--no-warn-mismatch
复制代码
4. 再编译运行, 多了一个main.map, 在里面查找PC寄存器对应的地址, 于是可以知道是卡在哪个函数里了.
5. 在gpio_toggle函数里加个void (*func)(void), 让它指向NULL, 然后直接调用这个函数指针, 于是又卡死了.
6. 再用stlink连接, 检查PC寄存器, 再对照main.map, 这次卡在Default_Handler了. 这是因为没有明确给出HardFault_Handler, 而启动文件里有个弱符号HardFault_Handler是Default_Handler的别名.
7. main.c里再加一段:
- void HardFault_Handler(void)
- {
- while(1);
- }
复制代码
8. 再编译运行, stlink检查PC寄存器, 这次确定是卡在HardFault_Handler了. 但是怎么知道是从哪掉进HardFault的?
9. 查R13寄存器, 把里面的值复制到addr里, 读取几十字节, 再看第6或第7个32位值, 这是掉进HardFault之前的地址, 再对照main.map检查, 这次知道是在gpio_toggle函数里出错了.
10. 查map文件还是嫌太麻烦怎么办? 再在Makefile里给CFLAGS加一行 -Wa,-ahlms=$(<:.c=.lst), 编译运行, 这次又多了main.lst文件.
11. 卡住了, 用stlink知道了地址, 命令行执行- arm-none-eabi-addr2line 地址 -e main.elf
复制代码 , 这次直接给了出错的文件名和行号.
12. 小弟们大概知道调试流程了. 最后在之前空白的SystemInit函数里加上配置时钟的内容:
- RCC_DeInit();
- FLASH_SetLatency(FLASH_Latency_0);
- RCC_HSEConfig(RCC_HSE_ON);
- int ret = RCC_WaitForHSEStartUp();
- if(ret == 0x01) {
- FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
- FLASH_SetLatency(FLASH_Latency_2);
-
- RCC_HCLKConfig(RCC_SYSCLK_Div1);
- RCC_PCLK2Config(RCC_HCLK_Div1);
- RCC_PCLK1Config(RCC_HCLK_Div2);
- RCC_PLLConfig(RCC_PLLSource_HSE_Div2, RCC_PLLMul_9);
- RCC_PLLCmd(ENABLE);
- while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
- RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
- while(RCC_GetSYSCLKSource() != 0x08);
- }
复制代码
13. 上面这个SystemInit相比system_stm32f10x.c里的版本相对简单明了一些. 给他们讲清楚, 每一行起什么作用, 为什么网上各种例子是RCC_PLLSource_HSE_Div1而我们这个是Div2, 因为各种STM32开发板一般用8M晶振而我们这个是16M的, 因此需要预先把HSE时钟二分频再进PLL.
14. 编译运行, 这次LED闪烁频率果然比之前快多了.
15. 指导他们实现简单的延时函数, 顺便说明, 初始化阶段可以使用ms级延时, 进入主循环之后只允许使用us级延时. 调度器之类以后再讲. 参数加volatile则是为了避免被编译器给优化掉.
- void _delay_us(volatile int nus)
- {
- nus *= 7;
- while(nus > 0) {
- nus--;
- }
- }
- void _delay_ms(volatile int nms)
- {
- while(nms > 0) {
- _delay_us(1000);
- nms--;
- }
- }
复制代码
|
|