一、背景:
应用实时性:应用程序1以固定周期执行实时算法;
应用程序2以固定周期,执行串口收发;
驱动实时性:驱动sdio接口,实现与FPGA数据交互,实现串口数据收发。
二、实时性保证:
1、linux系统:
打上rt_preempt补丁,早起的内核版本支持CONFIG_RT_BASE内核配置,后来的内核版本直接去掉了,只存在CONFIG_RT_FULL内核配置;前者表示只把中断函数线程化,后者表示原子锁互斥化+中断函数线程化。
被线程化的中断函数,使用一个内核线程来实现中断下半部处理,调度策略为RR,优先级为50。
2、linux驱动:
sdio以工作队列方式发起sdio请求,工作队列选取hi优先级,绑定固定core3;并且通过bootargs参数中增加isolate=8方式隔离core3。然后通过中断和workqueue绑定到core3,以保证底层的数据收发不被应用干扰。
3、linux应用:
deadline调度策略,保证应用程序的实时调度。
sysctl -w kernel.sched_rt_runtime_us=-1
#include <linux/sched.h>
#include <sys/types.h>
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sched.h>
#include <linux/sched.h>
#include <sys/types.h>
struct sched_attr {
uint32_t size;
uint32_t sched_policy;
uint64_t sched_flags;
/* SCHED_NORMAL, SCHED_BATCH */
int32_t sched_nice;
/* SCHED_FIFO, SCHED_RR */
uint32_t sched_priority;
/* SCHED_DEADLINE (nsec) */
uint64_t sched_runtime;
uint64_t sched_deadline;
uint64_t sched_period;
};
int sched_setattr(pid_t pid, const struct sched_attr *attr, unsigned int flags)
{
return syscall(__NR_sched_setattr, pid, attr, flags);
}
pthread1_main()
{
struct sched_attr attr;
attr.size = sizeof(attr);
attr.sched_flags = 0;
attr.sched_nice = 0;
attr.sched_priority = 0;
/* This creates a 300us/500us reservation */
attr.sched_policy = SCHED_DEADLINE;
attr.sched_runtime = 300 * 1000;
attr.sched_period = attr.sched_deadline = 500 * 1000;
tid = syscall(SYS_gettid);
ret = sched_setattr(tid, &attr, 0);
if (ret != 0)
{
perror("sched_setattr");
printf("exit!\n");
exit(-1);
}
while(1)
{
..........
sched_yield();
}
}
4、系统接口:
使用异步接口,mmap方式共享内核内存。
三、场景复杂性:
实时的应用程序占用CPU会比较高,特别是应用中的实时任务比较多,会占用CPU大概到60%左右,导致系统负载过大。基于RT_FULL的kernel_patch,甚至会导致cpu stall现象出现。