使用FreeRTOS在SD卡驅動使用非系統延時導致上電重啟不工作的情況


一、問題描述
在一個使用FreeRTOS的工程中,只做了SD卡的驅動,由於RTOS使用了Systick,故非系統延時函數使用的是 DWT中的時鍾周期(CYCCNT)計數功能,但是在SD卡驅動中使用了這個非系統延時導致,燒寫程序后板子工作正常,而下電再上電后板子無反應,分析排查去掉了這個非系統延時后工作正常。

二、使用環境
1)開發環境使用的是MDK5.20,下載器為JLINK;
2)軟件工程是V6的FreeRTOS模板工程,SD卡驅動也是V6的,非系統延時函數所在文件為V6的 bsp_dwt.c;
3)硬件板子是自己做的,MCU是STM32F429ZGT6;

三、問題分析
1)硬件板子已使用了一段時間,工作都正常包括下電再上電的情況,故該問題排出了硬件電路的問題;
2)由於之前也遇見過這樣的現象,再加之網絡查找,和代碼分析實驗,最后將問題定在了延時 bsp_DelayMS(100);
3)工程代碼

  1 int main(void)
  2 {
  3     /* 
  4       在啟動調度前,為了防止初始化STM32外設時有中斷服務程序執行,這里禁止全局中斷(除了NMI和HardFault)。
  5       這樣做的好處是:
  6       1. 防止執行的中斷服務程序中有FreeRTOS的API函數。
  7       2. 保證系統正常啟動,不受別的中斷影響。
  8       3. 關於是否關閉全局中斷,大家根據自己的實際情況設置即可。
  9       在移植文件port.c中的函數prvStartFirstTask中會重新開啟全局中斷。通過指令cpsie i開啟,__set_PRIMASK(1)
 10       和cpsie i是等效的。
 11      */
 12     __set_PRIMASK(1);  
 13     
 14     /* 硬件初始化 */
 15     bsp_Init(); 
 16     
 17     /* 創建任務 */
 18     AppTaskCreate();
 19     
 20     /* 啟動調度,開始執行任務 */
 21     vTaskStartScheduler();
 22 
 23     /* 
 24       如果系統正常啟動是不會運行到這里的,運行到這里極有可能是用於定時器任務或者空閑任務的
 25       heap空間不足造成創建失敗,此要加大FreeRTOSConfig.h文件中定義的heap大小:
 26       #define configTOTAL_HEAP_SIZE          ( ( size_t ) ( 30 * 1024 ) )
 27     */
 28     while(1);
 29 }
 30 
 31 /*
 32 *********************************************************************************************************
 33 *    函 數 名: vTaskTaskUserIF
 34 *    功能說明: 接口消息處理,這里用作LED閃爍    
 35 *    形    參: pvParameters 是在創建該任務時傳遞的形參
 36 *    返 回 值: 無
 37 *   優 先 級: 1  (數值越小優先級越低,這個跟uCOS相反)
 38 *********************************************************************************************************
 39 */
 40 static void vTaskTaskUserIF(void *pvParameters)
 41 {
 42     while(1)
 43     {
 44         bsp_LedToggle(1);
 45         vTaskDelay(500);
 46     }
 47 }
 48 
 49 /*
 50 *********************************************************************************************************
 51 *    函 數 名: vTaskLED
 52 *    功能說明: LED閃爍    
 53 *    形    參: pvParameters 是在創建該任務時傳遞的形參
 54 *    返 回 值: 無
 55 *   優 先 級: 2  
 56 *********************************************************************************************************
 57 */
 58 static void vTaskLED(void *pvParameters)
 59 {
 60     while(1)
 61     {
 62         bsp_LedToggle(2);
 63         vTaskDelay(1000);
 64     }
 65 }
 66 
 67 /*
 68 *********************************************************************************************************
 69 *    函 數 名: vTaskMsgPro
 70 *    功能說明: 信息處理,這里是用作LED閃爍    
 71 *    形    參: pvParameters 是在創建該任務時傳遞的形參
 72 *    返 回 值: 無
 73 *   優 先 級: 3  
 74 *********************************************************************************************************
 75 */
 76 static void vTaskMsgPro(void *pvParameters)
 77 {
 78     while(1)
 79     {
 80         DemoFatFS();
 81         vTaskDelay(300);
 82     }
 83 }
 84 
 85 /*
 86 *********************************************************************************************************
 87 *    函 數 名: vTaskStart
 88 *    功能說明: 啟動任務,也就是最高優先級任務,這里用作LED閃爍
 89 *    形    參: pvParameters 是在創建該任務時傳遞的形參
 90 *    返 回 值: 無
 91 *   優 先 級: 4  
 92 *********************************************************************************************************
 93 */
 94 static void vTaskStart(void *pvParameters)
 95 {
 96     while(1)
 97     {
 98         /* 按鍵掃描 */
 99         bsp_LedToggle(4);
100         vTaskDelay(400);
101     }
102 }
103 
104 /*
105 *********************************************************************************************************
106 *    函 數 名: AppTaskCreate
107 *    功能說明: 創建應用任務
108 *    形    參:無
109 *    返 回 值: 無
110 *********************************************************************************************************
111 */
112 static void AppTaskCreate (void)
113 {
114     xTaskCreate( vTaskTaskUserIF,       /* 任務函數  */
115                  "vTaskUserIF",         /* 任務名    */
116                  512,                   /* 任務棧大小,單位word,也就是4字節 */
117                  NULL,                  /* 任務參數  */
118                  1,                     /* 任務優先級*/
119                  &xHandleTaskUserIF );  /* 任務句柄  */
120     
121     
122     xTaskCreate( vTaskLED,            /* 任務函數  */
123                  "vTaskLED",          /* 任務名    */
124                  512,                 /* 任務棧大小,單位word,也就是4字節 */
125                  NULL,                /* 任務參數  */
126                  2,                   /* 任務優先級*/
127                  &xHandleTaskLED ); /* 任務句柄  */
128     
129     xTaskCreate( vTaskMsgPro,             /* 任務函數  */
130                  "vTaskMsgPro",           /* 任務名    */
131                  512,                     /* 任務棧大小,單位word,也就是4字節 */
132                  NULL,                   /* 任務參數  */
133                  3,                       /* 任務優先級*/
134                  &xHandleTaskMsgPro );  /* 任務句柄  */
135     
136     
137     xTaskCreate( vTaskStart,             /* 任務函數  */
138                  "vTaskStart",           /* 任務名    */
139                  512,                    /* 任務棧大小,單位word,也就是4字節 */
140                  NULL,                   /* 任務參數  */
141                  4,                      /* 任務優先級*/
142                  &xHandleTaskStart );   /* 任務句柄  */
143 }
  1 /*
  2 *********************************************************************************************************
  3 *    函 數 名: DemoFatFS
  4 *    功能說明: FatFS文件系統演示主程序
  5 *    形    參:無
  6 *    返 回 值: 無
  7 *********************************************************************************************************
  8 */
  9 void DemoFatFS(void)
 10 {
 11     uint8_t cmd;
 12 
 13     /* 打印命令列表,用戶可以通過串口操作指令 */
 14     DispMenu();
 15 //    while(1)
 16     {
 17         bsp_Idle();        /* 這個函數在bsp.c文件。用戶可以修改這個函數實現CPU休眠和喂狗 */
 18 
 19         if (comGetChar(COM1, &cmd))    /* 從串口讀入一個字符(非阻塞方式) */
 20         {
 21             printf("\r\n");
 22             switch (cmd)
 23             {
 24                 case '1':
 25                     printf("【1 - ViewRootDir】\r\n");
 26                     ViewRootDir();        /* 顯示SD卡根目錄下的文件名 */
 27                     break;
 28 
 29                 case '2':
 30                     printf("【2 - CreateNewFile】\r\n");
 31                     CreateNewFile();        /* 創建一個新文件,寫入一個字符串 */
 32                     break;
 33 
 34                 case '3':
 35                     printf("【3 - ReadFileData】\r\n");
 36                     ReadFileData();        /* 讀取根目錄下armfly.txt的內容 */
 37                     break;
 38 
 39                 case '4':
 40                     printf("【4 - CreateDir】\r\n");
 41                     CreateDir();        /* 創建目錄 */
 42                     break;
 43 
 44                 case '5':
 45                     printf("【5 - DeleteDirFile】\r\n");
 46                     DeleteDirFile();    /* 刪除目錄和文件 */
 47                     break;
 48 
 49                 case '6':
 50                     printf("【6 - TestSpeed】\r\n");
 51                     WriteFileTest();    /* 速度測試 */
 52                     break;
 53 
 54                 default:
 55                     DispMenu();
 56                     break;
 57             }
 58         }
 59         
 60 //        bsp_DelayMS(100);            /* 此延時將導致板子重新上電不工作 */
 61         
 62         /* 按鍵濾波和檢測由后台systick中斷服務程序實現,我們只需要調用bsp_GetKey讀取鍵值即可。 */
 63         switch (bsp_GetKey())    /* bsp_GetKey()讀取鍵值, 無鍵按下時返回 KEY_NONE = 0 */
 64         {
 65             case KEY_DOWN_K1:            /* K1鍵按下 */
 66                 break;
 67 
 68             case KEY_UP_K1:                /* K1鍵彈起 */
 69                 break;
 70 
 71             case KEY_DOWN_K2:            /* K2鍵按下 */
 72                 break;
 73 
 74             case KEY_UP_K2:                /* K2鍵彈起 */
 75                 break;
 76 
 77             case KEY_DOWN_K3:            /* K3鍵按下 */
 78                 break;
 79 
 80             case KEY_UP_K3:                /* K3鍵彈起 */
 81                 break;
 82 
 83             case JOY_DOWN_U:            /* 搖桿UP鍵按下 */
 84                 break;
 85 
 86             case JOY_DOWN_D:            /* 搖桿DOWN鍵按下 */
 87                 break;
 88 
 89             case JOY_DOWN_L:            /* 搖桿LEFT鍵按下 */
 90                 break;
 91 
 92             case JOY_DOWN_R:            /* 搖桿RIGHT鍵按下 */
 93                 break;
 94 
 95             case JOY_DOWN_OK:            /* 搖桿OK鍵按下 */
 96                 break;
 97 
 98             case JOY_UP_OK:                /* 搖桿OK鍵彈起 */
 99                 break;
100 
101             case KEY_NONE:                /* 無鍵按下 */
102             default:
103                 /* 其它的鍵值不處理 */
104                 break;
105         }
106     }
107 }

問題就在上段代碼第60行的延時函數 bsp_DelayMS(100); 

 

四、解決過程

eric2013

把你函數void DemoFatFS(void)里面的while大循環加上,不要注釋,而函數static void vTaskMsgPro(void *pvParameters)里面的  vTaskDelay(300);注釋掉。

並將你的 bsp_DelayMS(100);   函數所在位置修改為 vTaskDelay(100);就行。

 

me

1. 將函數void DemoFatFS(void)里面的while大循環加上,將導致系統其他3個任務不執行,一直執行 DemoFatFS任務,我之所以注釋是因為任務本身已有while循環;

2. 將非系統延時函數bsp_DelayMS(100)替換為系統延時函數vTaskDelay(100),經測試工作正常,我想問的是非系統延時函數bsp_DelayMS(100)為什么會導致這樣的問題產生,難道FreeRTOS系統中不支持非系統延時函數,但我在學習V6-349-FreeRTOS實驗_FreeRTOS+STemWin+FatFS+USB Devicet綜合例程時,看到在觸摸屏驅動和外部SDRAM驅動文件中多次使用了非系統延時函數bsp_DelayMS(),這也是我在本工程中加入bsp_dwt.c文件使用非系統延時函數bsp_DelayMS()的緣由,該綜合例程經我在V6開發板上運行正常,所以原因不是不能使用,應該是我的使用方式有問題,或是有些地方未注意到,懇請幫忙分析教導

 

 

eric2013

1. 這個是阻塞式的延遲,這個任務阻塞后,低於此優先級的任務將得不到執行。
2. 那個是驅動,驅動僅調用一次,在bsp_Init初始化的時候僅調用一次,任務執行的時候不會再使用。

 

me

1. 可以理解為任務中不可以使用非系統延時函數?
2. 我做了如下實驗

上表中包括我的測試條件及個人一些理解,和最終的疑問。
3.為了規避這樣的事情發生,在任務中只使用系統延時函數即可,但有些情況使用非系統延時函數較為方便,比如某些設備的Demo,因為這些設備Demo程序會單獨存在於文件中,或是在不考慮操作系統時而寫的一些應用程序等。為了研究本質刨根問底,個人覺得還是有必要知曉其中機理,在此感謝大家了。

 

eric2013

 

1. 可以加,比如DS18B20這種,是要加的微妙延遲的。
2. 以系統斷電后重新上電為准。關於這個第2個問題,后面還是需要深入學習下RTOS工作原理。通過本質理解現象的效率更高些。
3. 這種大延遲,死等的程序一定要修改,最好改成事件觸發的方式,后面你改的多了就熟練了。需要慢慢從裸機的編程思想轉換到RTOS上面來。

 

me

好的 多謝
暫且如此吧 待深入后續貼


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM