STM32程序死机问题分析过程- printf导致死机的解决方法。

版权声明:转载请标明出处 https://blog.csdn.net/networkhunter/article/details/83959254

问题的背景:公司的一个客户,应该算是一家创业企业,偶尔会让我们帮他们下stm32的驱动程序,具体的应用产需还是在自己写的。驱动基本都写好了,也都交付给他们了。最近他们在写应用程序的使用遇到了一个问题。

问题描述:申请了一个很大的全局数组,如下:

#define MAXDOORNUMBER  220
DOOR_INFO doorInfo[MAXDOORNUMBER];

程序运行起来会莫名死机,或者会被看门狗咬死。

开始分析:

1,怀疑程序内存不足,留给静态存储区的空间不足导致。

内存会划分几个区,该程序中回涉及到三个,静态存储区,堆区,栈区。静态存储区主要存放程序的全局变量,例如上边代码里的全局数组就存放在该区中,堆里存放的是程序动态分配的内存,例如用malloc分配的;栈里存放的是局部变量,函数调用现场的保存。从本例的map文件中,的Global Symbols中可以看出,全局数据区到0x20003090+2070,堆是从0x200038a8到0x20004aa8(堆是从小内存往大内存地址增长的),栈是从0x20006aa8开始到0x20004aa8,(栈是从小内存空间往大内存空间增长的,0x20006aa8为栈顶,入栈数据会向4aa8方向增长)。

对于本例来说,103vct6 的总内存大小为48K,就是从20000000-2000C000一个空间内,在魔术棒的target RAM1的设置里也可以看到。对于这个内存空间中的区域是如何分配和使用的在编译生成的map文件中都有详细的描述。本例可以查看 map文件中的 Global Symbols 中 看到全局变量doorInfo 从内存0x20000ff4开始,占用了3080个字节。

理论上说,不存在内存不够的问题,难道是全局数组的大小编译器有限制?

2,从改变数据存储区的方向来解决问题,

扫描二维码关注公众号,回复: 4042826 查看本文章

DOOR_INFO * doorInfo = NULL;  //不用数组了,将其定义为指针。

doorInfo = (DOOR_INFO *)malloc(MAXDOORNUMBER*sizeof(DOOR_INFO));  //在程序开始的时候用malloc来分配空间。

经过以上的修改,相当于将该数据存储区域从内存中的全局数据区,移到了堆里边存储了,并在*.s文件中将堆的大小进行适当的增大。这是一种方法,但是并不能解决问题,只是往这个方向上做了研究。

3,客户那边的开发领导也找到了一种方法,就是将大的全局数组一分为二,这样也避免了问题,程序也不会死了,真没想通是什么原因。

4,最后的尝试找到了解决方法,用keil 5的debug功能,执行代码发现是卡在了如下的地方:

int fputc(int ch, FILE *f)
{
    USART_SendData(DEBUG_USARTx, (uint8_t) ch);
    //利用keil的debug功能,卡在了这一句,是printf的相应中断没有清导致的。
    while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);	
    return (ch);
}

终于发现是死在printf里边了,可以知道应该是打印中断的标志没有清对,在如下的函数中添加清除标志的处理,如下所示。

void USART3_IRQHandler(void)
{
  uint8_t ucTemp;
  if(USART_GetITStatus(USART3,USART_IT_RXNE)!=RESET)
  {		
    USART_ClearITPendingBit(USART3,USART_IT_RXNE); //收的地方可能会遇到相同问题,同样需要清标志。
    ucTemp = USART_ReceiveData(USART3);
    UARTIOInfo[2].buf[UARTIOInfo[2].write_pos++] = ucTemp;		  	
    UARTIOInfo[2].write_pos %= RB_BUFFER_SIZE;											
    UARTIOInfo[2].data_count ++;
    UARTIOInfo[2].bUartRcvActing   = 1U;
    UARTIOInfo[2].u16UartRcvTimer  = u16_UART_FRAME_INTERVAL_MS;
  }
  //发的地方清标志
  if(USART_GetFlagStatus(USART3,USART_FLAG_ORE) == SET) 
  {
    USART_ClearFlag(USART3,USART_FLAG_ORE);
    USART_ReceiveData(USART3);
  }
}

标记上边的代码,红框里的代码就是为了清标志所添加的代码。

添加后问题解决

参考链接:

https://blog.csdn.net/aichirourou_66/article/details/79401243

猜你喜欢

转载自blog.csdn.net/networkhunter/article/details/83959254