出問題的函數如下:

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限制,而由那套機制限定。