stm32L0使用arduino
絮絮叨叨:
在做一个无线姿态传感器的小项目时,看中了 arduino 强大的第三方库,于是选型使用了 arduino 进行开发。
可是在第一步时就踩坑了。。。。
问题简述
我硬件使用 STM32L051K8U6 + NRF24L01 + MPU6050,准备用来做一个无线的姿态传感器。
在使用 arduino 对 stm32 时,烧录的 Demo 程序没有任何反应,而使用之前 keil 编译的程序则可以正常运行。
在简化程序后,发现 LED 可以正常运行,但是串口不能工作。于是开始排查问题
问题排查
在我使用 STM32F103C8T6 烧录相同的 Demo 程序后,可以正常运行。于是问题被锁定在 STM32L051 上。
串口波特率异常
在测试时,发现 L051 的板子,LED 可以运行,但是串口不能接受数据,于是首先怀疑波特率是否正确。但是手头暂时没有逻辑分析仪,只能通过软件测试。
使用 Keil 配置工程测试,串口 TX、RX 接线正常,芯片功能正常。由于我使用内部时钟源,而 F103 板子使用外部晶振,于是开始确认系统时钟频率是否正确。
好在 arduino 中可以直接使用 HAL 库的函数, 调用 HAL_RCC_GetSysClockFreq
函数读取判断系统时钟。
#define LED PB3
int ms = 200;
uint32_t sysclock = 0;
void setup() {
sysclock = HAL_RCC_GetSysClockFreq();
if (sysclock == 32000000){
ms = 1000;
}
pinMode(LED, OUTPUT);
Serial.begin(115200);
Serial.println("system init\n");
}
void loop() {
digitalWrite(LED, HIGH);
delay(ms);
digitalWrite(LED, LOW);
delay(ms);
}
经过测试,芯片的时钟配置也是正常,此路不通。。
串口配置
在检查时钟正常后,开始怀疑串口配置是否正常。于是修改默认串口 Serial
为 Serial1
编译失败,提示未定义引用。
修改为 Serial2
,串口同样无输出。。。
既然可以使用 HAL 库进行配置,那就使用 HAL 库初始化串口,进行测试,失败。。。
在使用 HAL 库配置完串口后顺手使用 HAL 库的串口发送函数进行测试。
HAL_UART_Transmit(&huart1, (uint8_t *)"hello\n", 6, 1000 );
竟然可以用?!!!
arduino 移植调试
于是问题确认在 arduino 内部的代码中,奈何在 arduino 中无法进行调试,于是尝试将 arduino 的代码移植到 makefile 中编译,方便进行调试。
不过之前也移植过,这个好说,然后开始各种折腾,离初始目标越来越远。。。
在移植 arduino 到 makefile 的过程中,想到查看一下符号表,只需要把用到的文件进行编译调试即可。
于是 objdump 查看了一下,在查看符号表的时候发现一个奇怪的问题,引起我的注意:
在符号表中出现的怎么都是 Serial
2 的配置,没有关于 ``````Serial1
的初始化,所以 Serial
的宏是指向 Serial
2 ?
于是查看了一下 variant 中 IO 的配置,不看不知道,一看吓一跳。。。。
// UART Definitions
#ifndef SERIAL_UART_INSTANCE
#define SERIAL_UART_INSTANCE 2
#endif
// Default pin used for generic '```Serial```' instance
// Mandatory for Firmata
#ifndef PIN_SERIAL_RX
#define PIN_SERIAL_RX PA3
#endif
#ifndef PIN_SERIAL_TX
#define PIN_SERIAL_TX PA2
#endif
在配置文件中赤裸裸的使用着串口2 🤦♂️
问题解决
找到问题后,就很好解决了。既然 Serial
使用的是 Serial2
,那我初始化 Serial1
然后将这个宏重新定义到 Serial1
不就解决问题了。
上面的代码变为:
#undef Serial
#define Serial Serial1
HardwareSerial Serial(USART1);
#define LED PB3
int ms = 200;
void setup() {
pinMode(LED, OUTPUT);
Serial.begin(115200);
Serial.println("system init");
}
void loop() {
digitalWrite(LED, HIGH);
delay(ms);
digitalWrite(LED, LOW);
delay(ms);
}
下载运行,完美解决~
复盘分析
其实在最开始在怀疑串口配置的时候,已经想到了是否是串口号配置不对,而且编译报错信息已经提示了 Serial1
未定义,只是在当时未引起注意。
在经过一番折腾后,发现还是串口号配置错误导致的。
在 debug 的过程中应该本着 “大胆假设,小心求证” 的心态去排查问题。
虽然分析问题时想到这个原因,但是在求证的过程中却忽略了这个重要信息,导致后面走了不少弯路。
如果这是一个复杂代码的 debug , 同样不能运行调试,那问题应该怎么被发现解决呢?
这种情况在之前 debug 时已经碰到过了,最后的结果是花费大量时间和精力,最后发现问题原因早被猜想中了,只是在验证时被忽略一些细节而放过。