title: 踩坑记 BSS段的初始化
category_bar: true
categories:
- blog
tags: - embedded
date: 2023-10-20 19:23:05
前言
接手一个项目,调试全靠串口日志,测试同事测试产品的时候无法拿到日志,刚好产品RAM够大,且刚好有SD卡。所以就诞生了将日志缓存在RAM上,在特定条件下将它写到SD卡上的想法。
.
.
.
开工。
.
.
.
写完代码之后发现机器偶尔会无法启动,无法开机,无任何日志。
.
有的时候是烧录完成代码后重启无法启动,有些情况下是烧录完成代码后运行正常,放置一段时间后无法启动。
.
有时候有些无法启动的机器放置一段时间又成功启动。
.
.
.
一段一段代码,屏蔽,编译,验证,发现一个非常无法理解的事,TFCardLogBufferPut
函数注释后设备可以正常启动。
.
.
.
看代码:
#define TF_CARD_LOG_BUFFER_SIZE (64*1024ul)
uint8_t tfCardLogBuffer[TF_CARD_LOG_BUFFER_SIZE] = {0};
uint32_t tfCardLogBufferIndex = 0;
void TFCardLogBufferPut(uint8_t data) {
tfCardLogBuffer[tfCardLogBufferIndex] = data;
tfCardLogBufferIndex++;
if( tfCardLogBufferIndex>=(sizeof(tfCardLogBuffer)/sizeof(tfCardLogBuffer[0]))-1 ) {
tfCardLogBufferIndex = 0;
}
}
.
.
.
我实在无法理解,这段代码是如何导致设备无法启动的,后面搁置了一段时间,遂归结于小众芯片不完善导致。
.
.
.
但是后面这个需求实在是过于旺盛,遂重新开始验证代码。
当时代码是这样的:
// main.c
int main(int argc, char **argv) {
hal_uartInit();
ax32xx_uart0SendByte('a');
ax32xx_uart0SendByte('b');
hal_uartSendData('1');
hal_uartSendData('2');
ax32xx_uart0SendByte('c');
hal_sysInit();
//.... some code here
}
// uart.c
void hal_uartSendData(u8 data)
{
ax32xx_uart0SendByte(data);
TFCardLogBufferPut(data);
}
void ax32xx_uart0SendByte(u8 data)
{
R_UART_DATA0 = data;
while((R_UART_PEND0 & 0x2)==0);
R_UART_PEND0 |= 1;
}
#define TF_CARD_LOG_BUFFER_SIZE (64*1024ul)
uint8_t tfCardLogBuffer[TF_CARD_LOG_BUFFER_SIZE] = {0};
uint32_t tfCardLogBufferIndex = 0;
void TFCardLogBufferPut(uint8_t data) {
tfCardLogBuffer[tfCardLogBufferIndex] = data;
tfCardLogBufferIndex = (tfCardLogBufferIndex>=(sizeof(tfCardLogBuffer)/sizeof(tfCardLogBuffer[0]))-1) ? 0 : tfCardLogBufferIndex+1;
}
运行后日志是这样的:
# 正常运行 的日志
ab12c ...
# 无法启动 的日志
ab1
.
.
.
后面我就猜想了很多:
- 这个soc不能支持这么大的数值 64KB
- 这个位置的内存被改写了
- 和冷启动热启动有关
- 芯片异常
.
.
.
后面我猜想,试试把TFCardLogBufferPut
函数里面的tfCardLogBufferIndex
的数值和data
数值输出出来看看。
.
.
这一看不得了,越界了!
代码:
输出日志:
ab1z31m00327300
.
.
.
这个tfCardLogBufferIndex
越界了啊!而且初始化赋0并没有成功!这就非常坑爹了!
.
.
.
后面尝试在调用这个函数之前再次赋0,发现程序运行正常,设备也正常启动。
查看map文件这个数组和变量也是存放在BSS段的,这就非常令人费解了。
.
.
.
.
.
看到这里我直接就怀疑,就是这个芯片的锅。
但是别急这还不是让人最震惊的!后面还有让人更加鼻血飙升的。
.
.
.
.
.
.
.
.
.
.
.
.
.
最后找FAE排查问题很久,最后发现BSS段在hal_sysInit
函数内初始化。
看代码:
void ax32xx_sysInit(u32 *saddr,u32 *eaddr)
{
debg("sys init\n"); // 这个debg会调用 hal_uartSendData 函数输出日志
//...
ax32xx_wdtClear();
//-----cache set
ax32xx_sysIcacheInit();
ax32xx_sysDcacheInit();
//-----bss clear
ax32xx_sysBSSClear();
// ...
}
.
.
.
实在是震惊,无法理解这个RAM的初始化为什么放在main函数里面,实在无法理解进入main函数了,c语言环境都没有OK。
最烦的就是这种xx芯片,总是会有一些让人血压飙升的操作。
.
.
.
.
.
教训
在对数组进行访问的时候一定要先检查范围。
// 原函数
void TFCardLogBufferPut(uint8_t data) {
tfCardLogBuffer[tfCardLogBufferIndex] = data;
tfCardLogBufferIndex = (tfCardLogBufferIndex>=(sizeof(tfCardLogBuffer)/sizeof(tfCardLogBuffer[0]))-1) ? 0 : tfCardLogBufferIndex+1;
}
// 改后
void TFCardLogBufferPut(uint8_t data) {
if( tfCardLogBufferIndex>=(sizeof(tfCardLogBuffer)/sizeof(tfCardLogBuffer[0]))-1 ) {
tfCardLogBufferIndex = 0;
}
tfCardLogBuffer[tfCardLogBufferIndex] = data;
tfCardLogBufferIndex++;
}