出问题的函数如下:

1 char *calc_file_md5(const char* fw_name) 2 { 3 FRESULT result; 4 FIL File; 5 uint32_t BytesRead = 0,offset = 0,file_size = 0; 6 MD5_CTX context; //MD5 7 unsigned char digest[16]; 8 uint8_t i = 0; 9 10 result = f_open(&File,fw_name,FA_OPEN_EXISTING|FA_READ); //打开文件 11 if(FR_OK != result) 12 { 13 DEBUG_LOG(DEBUG_FW,("Not Find %s\n",fw_name)); 14 return 0; 15 } 16 file_size = File.obj.objsize;//结束地址为起始地址加上文件大小。 17 MD5Init(&context); 18 while(1) 19 { 20 f_lseek(&File,offset); 21 result = f_read(&File,file_buffer,2048,&BytesRead); 22 if(result || BytesRead==0) 23 { 24 DEBUG_LOG(DEBUG_FW,("read %s error!\n",fw_name)); 25 return 0; 26 } 27 MD5Update(&context, file_buffer, BytesRead); 28 29 offset+=BytesRead; 30 if(offset==file_size) 31 break; 32 } 33 34 MD5Final(digest, &context); 35 f_close(&File); 36 for (i = 0; i < 16; i++) 37 rt_sprintf(cal_md5_str+(i*2),"%02X",digest[i]); 38 39 DEBUG_LOG(DEBUG_FW,("cal_md5:%s\n",cal_md5_str)); 40 41 return cal_md5_str; 42 }
就计算个MD5值的代码,计算不对。不知道问题出在哪里,MD5算法是之前移植好,实验无误的。就吧这个函数有关的,全部弄到我的另一个工程,实验计算正确!这就纳闷了呀。工程本身的问题?玄学?
于是,(我在这个函数,又添加了些代码,试图读回读出的文件。结果MD5计算值变了,但不对。——以上为胡乱尝试,无头苍蝇,瞎试)。我把第4行 弄到外边 让File作为全局变量,竟然正确了。
再次弄进来让它作为局部变量,还是错误。立刻认识到可能是Stack_size设置小了,导致File里的数据在入栈出栈的时候发生错误了。于是我把Statck_size由0x400改为0x800,于是就好了。
还有一次,同事调用了文件系统的API,导致莫名进入硬件错误中断,查找一番,找不到哪里硬件操作不当,于是想到了可能stack不够用,于是把stack_size调大后,就正常了。
这里引出几个问题:
1 描述stm32的Stack_Mem,Heap_Mem的作用。
栈(stack)空间,用于局部变量,函数调时现场保护和返回地址,函数的形参等。
堆(heap)空间,主要用于动态内存分配,也就是说用 malloc,calloc, realloc 等函数分配的变量空间
2 怎么在早期意识到Stack_size可能不够用,即怎么估计我最大要用到的Stacks_size的大小?
首先,使用GUI和文件系统的时候,是要调大stack_size的。这些是定性的经验之谈,那么怎么定量呢?
工程全编译,且无误后,到obj文件夹找到与工程同名的.htm文件。
开头就有最大栈深度的大小
继续往下翻,还可以看到具体的每个函数用到的栈的大小。
3 用rtos加持的stm32的Stack_Mem,Heap_Size的作用。
RTOS有自己的任务栈,不再使用这里,仅RTOS启动前和中断以及中断嵌套才使用这里,这里的栈被称为系统栈,而uCOS又略有不同,uCOS把系统栈也接管了。
Heap_Size作为裸机时,malloc,calloc, realloc 等函数用于分配动态内存。如果RTOS有自己的一套动态内存机制,这不受这个Heap_Size限制,而由那套机制限定。