使用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);
四、解决过程
把你函数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开发板上运行正常,所以原因不是不能使用,应该是我的使用方式有问题,或是有些地方未注意到,恳请帮忙分析教导
1. 这个是阻塞式的延迟,这个任务阻塞后,低于此优先级的任务将得不到执行。
2. 那个是驱动,驱动仅调用一次,在bsp_Init初始化的时候仅调用一次,任务执行的时候不会再使用。
me
1. 可以理解为任务中不可以使用非系统延时函数?
2. 我做了如下实验
上表中包括我的测试条件及个人一些理解,和最终的疑问。
3.为了规避这样的事情发生,在任务中只使用系统延时函数即可,但有些情况使用非系统延时函数较为方便,比如某些设备的Demo,因为这些设备Demo程序会单独存在于文件中,或是在不考虑操作系统时而写的一些应用程序等。为了研究本质刨根问底,个人觉得还是有必要知晓其中机理,在此感谢大家了。
1. 可以加,比如DS18B20这种,是要加的微妙延迟的。
2. 以系统断电后重新上电为准。关于这个第2个问题,后面还是需要深入学习下RTOS工作原理。通过本质理解现象的效率更高些。
3. 这种大延迟,死等的程序一定要修改,最好改成事件触发的方式,后面你改的多了就熟练了。需要慢慢从裸机的编程思想转换到RTOS上面来。
me
好的 多谢
暂且如此吧 待深入后续贴