RTK


1. 概述

RTK全称Real Time Kernel。它是一个多任务,基于优先级调度服务的系统。它提供临界段代码管理(critical section management),通过semaphore, mutex, flag, timer来实现各任务间的通讯和同步。

2. 系统初始化

图 2‑1 RTK系统初始化

3. 任务(task)

RTK Task中,Priority 0为最低优先级。在SDK中被定义为TASK_IDLE_PRIO。

设定为高优先级的任务,必须保证其执行时间越短越好。耗时的部分,需要拉到低优先级去做,避免低优先级的任务被卡死而导致系统不正常。

不要创建相同优先级的任务。

3.1. 系统任务

系统任务优先级最高为50,最低为0。(新SDK 更新到54 - 0)

图 3‑1 系统任务优先级

系统任务放在cus_InitTask[]中,开机时由RtkCreateSystemTask创建。

图 3‑2 新建系统任务

除了TASK_IDLE_PRIO,其它系统任务优先级必须超过自定义优先级。软件中我们会对系统任务优先级作一个偏移。

图 3‑3 系统任务优先级偏移

3.2. 自定义任务

自定义任务优先级最高为200,最低为1。任务由AHC_OS_CreateTask()创建。

3.2.1. 任务状态机

图 3‑4 任务状态

当某个任务状态满足 "(state & RTK_NON_OPERATIONAL) = RTK_READY" 条件时,意味该任务现在可以被调度,无需等待其它额外事件。

图 3‑5 任务状态

3.2.2. 调度方案

  • 多级队列调度

  • 抢占式,基于优先级

  • 相同优先级任务,先准备好的先处理

图 3‑6 调度方案

4. 临界段代码管理(Critical Section)

  • MsEnterRegion() / MsLeaveRegion()

    • 任务能够被中断但是不可以被抢占

    • 由Rtk_RegionCount计数器控制,0 \<= Rtk_RegionCount \<= 255

      图 4‑1 临界段代码管理1

  • MsEnableInterruptUser() / MsDisableInterruptUser()

    • User mode中断获取锁

    • 操作INTC(System Interrupt Controller)掩码

      图 4‑2 临界段代码管理2

  • MsEnableInterrupt() / MsDisableInterrupt()

    • Kernel mode 中断获取锁

    • 操作ARM CPSR IRQ 位

      图 4‑3 临界段代码管理3

5. 信号量(Semaphore)

  • Semaphore通常用在任务同步,临界段代码管理,事件通知等情况

  • 每一个semaphore包含一个令牌(token)和一个任务队列(task queue)

  • 等待中的任务按照优先级顺序激活

  • Semaphore必须在启动任务时创建

图 5‑1 任务优先级

6. 互斥(Mutual Exclusion Object)

  • 通常用于保护关键区域的访问

  • 等待中的任务按照优先级顺序激活

  • Mutex 必须在启动任务时创建

  • Mutex 必须要由获得锁的任务来释放

  • 支持优先级继承协议

图 6‑1 优先级继承

7. 标志(Flag)

  • Flag是由一个字(word)32位(bits)数据表示的任务同步机制

  • Flag中的每一位表示一个条件,而线程在等待单个条件或条件组合被满足

  • 当规定的所有条件或者条件组合满足时,等待中的线程将会被唤醒

  • 信令线程可以根据特定条件设置或重置位,以便执行适当的线程

  • Flags可以在应用程序运行时随时创建

8. 中断

  • 只有一级中断服务程序

  • 所有的RTK 服务都允许中断

9. 定时器

  • 支持两类定时器服务

    • 消息类型

      在接收任务解析器中完成

    • 回调类型

      在最高定时器任务中完成

      必须避免复杂的处理程序

  • 时钟精度为4.6 毫秒

  • 支持一次性和周期性计时

10. 内存

10.1.1. Pool和Heap的区别

  • 两种类型的动态内存管理

    • 固定大小: pool

    • 可变大小: heap

  • Pool

    • 可以调整内存池和簇数量

    • 从Heap中获取空间并在启动时创建

    • 速度快,没有碎片,但灵活性低(适合实时)

  • Heap

    • Heap大小等于 "total physical ram" 减去"static memory"

    • Validated GKI algorithm to achieve defragmentation

    • 每个Block需要32字节对齐。

    • RTK heap 比较低效,它总是从heap 顶端开始线性查找第一个合适的可用内存。

      图 10‑1 RTK系统Heap

  • 一般的malloc调用

    • 8x39目前只用"heap"。

    • Malloc的地址需要对齐,比如32字节。

11. Cache和 Non Cache

RTK中,当CPU要写东西到DRAM时,会先进入Write Buffer,而不是直接进DRAM的物理地址。就算用的Buffer是Non Cache也一样。

例如,

  • UI画图 --DRAM,GOP ENGINE拿DRAM叠图。图画完时,物理内存内的数据可能还没有更新。

  • CPU写I2C的命令进DRAM,透过I2C DMA去拿DRAM数据,物理内存内的数据可能还没有更新。

这个时候需要调用下面函数去刷掉(Flush) Write Buffer,避免出现问题。

DrvChipFlushMiuPipe()

即当我们通过CPU向DRAM存取数据,然后又需要HW ENGINE去存取DRAM中的这一些数据时,就需要调用上面的函数。

注:RIU (register fifo)模式不包括在内。

12. RTK内存分配

12.1. RTK中存储管理单元(MMU)设定

0x20000000 ~ 0x28000000 属于CACHE //833x

0x90000000 ~ 0x98000000 属于NON CACHE

12.2. 内存分配函数

图 12‑1 内存分配函数

在图12-1中,ppUserPtr为虚拟地址,CPU 读写或memset / memcpy都是用这个地址。pMiuAddr为MIU地址,HW ENGINE使用这个地址。

图 12‑2 虚拟地址和物理地址互转

图 12‑3 物理地址转为MIU地址