OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 13305|回复: 16

FreeRTOS使用delay_ms()作为系统延时、任务调度

[复制链接]

12

主题

336

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1571
金钱
1571
注册时间
2015-8-9
在线时间
624 小时
发表于 2016-10-8 22:33:25 | 显示全部楼层 |阅读模式
5金钱
请教一个问题,最近在学习使用FreeRTOS,想像原子一样在delay.c里添加RTOS的系统支持,即使用tick时钟作延时。现在有几个问题:
1、在启动任务调度器前,如果调用了delay_ms()或者printf()(LCD_Init函数会用到这两个函数),系统就会进入HardFault_Handler状态
2、但当启动了vTaskStartScheduler()调度器后,延时和串口函数都能正常工作
3、相比ucosii,在初始化os前,调用了延时和串口打印却等正常运转。。。

以上初步怀疑是FreeRTOS的中断处理没配置好,系统的源代码、某开发板的FreeRTOS教程也看过好几遍,没找到办法。。
支招!!!
附:自己移植的工程代码,使用的是f103

FreeRTOS.rar

337.08 KB, 下载次数: 354

最佳答案

查看完整内容[请看2#楼]

这是你没移植好延时。跟FreeRTOS没关系。给你发一份我们自己F429的的FreeRTOS版本的SYSTEM文件夹,你可以参考一下。F429用的HAL库。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

88

主题

7377

帖子

5

精华

资深版主

Rank: 8Rank: 8

积分
14980
金钱
14980
注册时间
2013-11-13
在线时间
1823 小时
发表于 2016-10-8 22:33:26 | 显示全部楼层
这是你没移植好延时。跟FreeRTOS没关系。给你发一份我们自己F429的的FreeRTOS版本的SYSTEM文件夹,你可以参考一下。F429用的HAL库。

SYSTEM.rar

8.88 KB, 下载次数: 572

回复

使用道具 举报

27

主题

711

帖子

0

精华

版主

Rank: 7Rank: 7Rank: 7

积分
11922
金钱
11922
注册时间
2015-11-5
在线时间
2086 小时
发表于 2016-10-9 07:53:21 | 显示全部楼层
调度器没启动前是不能调用系统延时的,因为调度器在启动时才开始初始化SysTick,也就是说系统定时器在调度器启动后才开始运行
回复

使用道具 举报

12

主题

336

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1571
金钱
1571
注册时间
2015-8-9
在线时间
624 小时
 楼主| 发表于 2016-10-9 08:04:24 | 显示全部楼层
FreeRTOS 发表于 2016-10-9 07:53
调度器没启动前是不能调用系统延时的,因为调度器在启动时才开始初始化SysTick,也就是说系统定时器在调度 ...

这样说来,串口中断处理等操作也是要调度器启动了才能开始运行?
回复

使用道具 举报

27

主题

711

帖子

0

精华

版主

Rank: 7Rank: 7Rank: 7

积分
11922
金钱
11922
注册时间
2015-11-5
在线时间
2086 小时
发表于 2016-10-9 09:54:15 | 显示全部楼层
Akatsuki_lim 发表于 2016-10-9 08:04
这样说来,串口中断处理等操作也是要调度器启动了才能开始运行?

根据FreeRTOS的设计,几乎可以认为系统没开跑前系统API都不能用
因为不管是信号量、队列、互斥锁还是任务结构体,使用前必须要创建,创建时一定会调用系统自带的内存管理,例如 heap_4只要调用了内存分配,必然会调用 vTaskSuspendAll(); 跟 xTaskResumeAll();
xTaskResumeAll() 最后调用了 taskEXIT_CRITICAL();
[mw_shl_code=applescript,true]void vPortExitCritical( void )
{
        configASSERT( uxCriticalNesting );
        uxCriticalNesting--;
        if( uxCriticalNesting == 0 )
        {
                portENABLE_INTERRUPTS();
        }
}[/mw_shl_code]仔细看有一个操作系统的嵌套层数计数器进行了自减操作:uxCriticalNesting--;
这个变量在操作系统没开跑前的初始值并不是0: static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
问题就出在这了,因为初始值并不是0,所以 portENABLE_INTERRUPTS(); 是不会被执行的!!!
portENABLE_INTERRUPTS() 是啥?这是使能系统中断的接口,内存分配前系统屏蔽了中断,在操作系统启动后,内存分配完毕会重新开启中断
反之,在FreeRTOS的调度器没启动前,只要你调用了系统的内存管理,中断就会被关闭,而且关闭之后不会被打开!

我们一般都在串口中断里面调用了信号量API来通知APP,但信号量创建后中断就被关闭了,如果串口中断也在操作系统的管辖范围内
那么意味着串口中断也被屏蔽了,你说还能正常使用么?

拿来长岛冰茶换我半晚安睡
回复

使用道具 举报

12

主题

336

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1571
金钱
1571
注册时间
2015-8-9
在线时间
624 小时
 楼主| 发表于 2016-10-9 10:43:50 | 显示全部楼层
zuozhongkai 发表于 2016-10-8 22:33
这是你没移植好延时。跟FreeRTOS没关系。给你发一份我们自己F429的的FreeRTOS版本的SYSTEM文件夹,你可以参 ...

十分感谢,还没看过F429的资料,想不到已经做出来了
回复

使用道具 举报

12

主题

336

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1571
金钱
1571
注册时间
2015-8-9
在线时间
624 小时
 楼主| 发表于 2016-10-9 10:47:59 | 显示全部楼层
FreeRTOS 发表于 2016-10-9 09:54
根据FreeRTOS的设计,几乎可以认为系统没开跑前系统API都不能用
因为不管是信号量、队列、互斥锁还是任 ...

原来是自己没有深入理解FreeRTOS,感谢版主耐心回答
回复

使用道具 举报

12

主题

336

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1571
金钱
1571
注册时间
2015-8-9
在线时间
624 小时
 楼主| 发表于 2016-10-9 19:32:51 | 显示全部楼层
感谢@zuozhongkai @FreeRTOS 的提示和解答,今天再修改了一下delay.c函数,在SysTick_Handler()里加入系统启动判断:
[mw_shl_code=applescript,true]//systick中断服务函数,使用ucos时用到
void SysTick_Handler(void)
{                                  
#ifdef OS_CRITICAL_METHOD         //如果OS_CRITICAL_METHOD定义了,说明使用ucosII了.       
        OSIntEnter();                //进入中断
    OSTimeTick();       //调用ucos的时钟服务程序               
    OSIntExit();        //触发任务切换软中断
#endif       
#ifdef FreeRTOS
        if(OSRunning==1)        //系统在运行
        {
                xPortSysTickHandler();       
        }
#endif
}
[/mw_shl_code]
这样系统就能在没有启动调度器的情况下,调用延时和串口打印函数也能正常运行。

新的问题又来了:
USART1_IRQHandler()里模仿ucos调用了taskENTER_CRITICAL_FROM_ISR(),taskEXIT_CRITICAL_FROM_ISR()作为中断屏蔽,追踪源码,是一段汇编,,,
[mw_shl_code=applescript,true]//taskENTER_CRITICAL_FROM_ISR()
__asm uint32_t ulPortSetInterruptMask( void )
{
        PRESERVE8

        mrs r0, basepri
        mov r1, #configMAX_SYSCALL_INTERRUPT_PRIORITY
        msr basepri, r1
        bx r14
}
/*-----------------------------------------------------------*/
//portCLEAR_INTERRUPT_MASK_FROM_ISR()
__asm void vPortClearInterruptMask( uint32_t ulNewMask )
{
        PRESERVE8

        msr basepri, r0
        bx r14
}
/*-----------------------------[/mw_shl_code]
能指点迷津?

附:修正后的工程

FreeRTOS V2.rar

337.33 KB, 下载次数: 576

回复

使用道具 举报

27

主题

711

帖子

0

精华

版主

Rank: 7Rank: 7Rank: 7

积分
11922
金钱
11922
注册时间
2015-11-5
在线时间
2086 小时
发表于 2016-10-9 19:56:27 | 显示全部楼层
Akatsuki_lim 发表于 2016-10-9 19:32
感谢@zuozhongkai @FreeRTOS 的提示和解答,今天再修改了一下delay.c函数,在SysTick_Handler()里加入系统 ...

关于 configMAX_SYSCALL_INTERRUPT_PRIORITY 和 BASEPRI 寄存器的用法请参考我的另一个帖子:
http://www.openedv.com/thread-77593-1-1.html
帖子中间部分对这两者进行了一个比较详细的解释
拿来长岛冰茶换我半晚安睡
回复

使用道具 举报

35

主题

106

帖子

0

精华

高级会员

Rank: 4

积分
546
金钱
546
注册时间
2016-4-20
在线时间
181 小时
发表于 2016-10-25 17:23:09 | 显示全部楼层
请问楼主问题解决了吗?
回复

使用道具 举报

12

主题

336

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1571
金钱
1571
注册时间
2015-8-9
在线时间
624 小时
 楼主| 发表于 2016-10-25 17:28:03 | 显示全部楼层
wangjun110 发表于 2016-10-25 17:23
请问楼主问题解决了吗?

嗯?是指哪方面问题?
回复

使用道具 举报

35

主题

106

帖子

0

精华

高级会员

Rank: 4

积分
546
金钱
546
注册时间
2016-4-20
在线时间
181 小时
发表于 2016-10-25 17:31:53 | 显示全部楼层
Akatsuki_lim 发表于 2016-10-25 17:28
嗯?是指哪方面问题?

没启用调度前delay_ms和串口不能打印的问题。
回复

使用道具 举报

12

主题

336

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1571
金钱
1571
注册时间
2015-8-9
在线时间
624 小时
 楼主| 发表于 2016-10-25 17:33:19 | 显示全部楼层
wangjun110 发表于 2016-10-25 17:31
没启用调度前delay_ms和串口不能打印的问题。

解决了,工程代码已共享。代码在第8楼
不过启动任务调度前的delay_ms()可能会不太准
回复

使用道具 举报

35

主题

106

帖子

0

精华

高级会员

Rank: 4

积分
546
金钱
546
注册时间
2016-4-20
在线时间
181 小时
发表于 2016-10-25 17:45:03 | 显示全部楼层
本帖最后由 wangjun110 于 2016-10-25 18:03 编辑
Akatsuki_lim 发表于 2016-10-25 17:33
解决了,工程代码已共享。代码在第8楼
不过启动任务调度前的delay_ms()可能会不太准

嗯。看到了,我很喜欢你的代码风格。
你说的延时可能不太准,能否解释下原因呢?呵呵
123123123123213.jpg
2222.jpg
回复

使用道具 举报

12

主题

336

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1571
金钱
1571
注册时间
2015-8-9
在线时间
624 小时
 楼主| 发表于 2016-10-26 08:10:39 | 显示全部楼层
wangjun110 发表于 2016-10-25 17:45
嗯。看到了,我很喜欢你的代码风格。
你说的延时可能不太准,能否解释下原因呢?呵呵

1、delay_ms 函数里有一个 OSRunning==1 的判断,它是启用了任务调度函数才为真。在调度使用前,延时都用 delay_us 来实现。比如说 delay_ms(2) 实际就是 delay_us(2000) 。
2、中断使用的4组,4位抢占优先级,0位响应优先级。然后抢占优先级的范围是0~2^4-1,就是0~15。数值越小越优先,所以设一个15
回复

使用道具 举报

35

主题

106

帖子

0

精华

高级会员

Rank: 4

积分
546
金钱
546
注册时间
2016-4-20
在线时间
181 小时
发表于 2016-10-26 09:02:02 | 显示全部楼层
Akatsuki_lim 发表于 2016-10-26 08:10
1、delay_ms 函数里有一个 OSRunning==1 的判断,它是启用了任务调度函数才为真。在调度使用前,延时都用 ...

多谢谢指教,从回贴的时间不难看出你是8点上班然后5:30下班,我猜的没错吧。
回复

使用道具 举报

12

主题

336

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1571
金钱
1571
注册时间
2015-8-9
在线时间
624 小时
 楼主| 发表于 2016-10-26 09:41:08 | 显示全部楼层
wangjun110 发表于 2016-10-26 09:02
多谢谢指教,从回贴的时间不难看出你是8点上班然后5:30下班,我猜的没错吧。

哈哈,这都可以看出来。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-22 23:13

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表