SylixOS BSP tick驱动流程

SylixOS BSP tick驱动流程

1. 开发环境

- 操作系统:SylixOS
- 编程环境:RealEvo-IDE3.1
- 硬件平台:IMX6Q实验箱

2.技术实现

时钟节拍(clock tick)是特定的周期性中断。这个中断可以看做是系统心脏的脉动。时钟的节拍式中断使得内核可以将任务延时若干个整数时钟节拍,同时当任务等待事件发生时,提供等待超时的依据。

2.1 Tick的频率设置
Tick的频率需要根据具体的硬件性能来设置。频率越快,系统的额外开销也会越大。SylixOS中频率通 过bspInit.c文件中的halPrimaryCpuMain函数设置,如程序清单 2-1 所示。

                                 程序清单 2-1 tick频率设置
/***************************************************************************************************
** 函数名称: halPrimaryCpuMain
** 功能描述: Primary CPU C 入口
** 输 入  : NONE
** 输 出  : 0
** 全局变量:
** 调用模块:
***************************************************************************************************/
INT  halPrimaryCpuMain (VOID)
{
    /*
     *  系统内核堆与系统堆
     */
    extern UCHAR  __heap_start, __heap_end;

    bspOpenocdInit();                                              /*  初始化 openocd              */

    halModeInit();                                                 /*  初始化硬件                  */

    /*
     *  这里的调试端口是脱离操作系统的, 所以它应该不依赖于操作系统而存在.
     *  当系统出现错误时, 这个端口显得尤为关键. (项目成熟后可以通过配置关掉)
     *  (!!当前串口已经由bootloader初始化了, 这里无需处理.)
     */

    /*
     *  这里使用 bsp 设置启动参数, 如果 bootloader 支持, 可使用 bootloader 设置.
     *  为了兼容以前的项目, 这里 kfpu=yes 允许内核中(包括中断)使用 FPU.
     */

#if (BOARD_MARSBOARD == 1)
    API_KernelStartParam("ncpus=2 kdlog=no kderror=yes kfpu=no heapchk=yes hz=1000 hhz=1000");
#else
    API_KernelStartParam("ncpus=4 kdlog=no kderror=yes kfpu=no heapchk=yes hz=1000 hhz=1000");
#endif
                                                                   /*  操作系统启动参数设置        */
    API_KernelStart(usrStartup,
                    (PVOID)&__heap_start,
                    (size_t)&__heap_end - (size_t)&__heap_start,
                    LW_NULL, 0);                                   /*  启动内核                    */

    return  (0);                                                   /*  不会执行到这里              */
}

在代码中,调用了API_KernelStartParam函数,函数参数是字符串类型,字符串里的“hz”参数选项后面的数值是需要设置的频率,调用API_KernelStartParam之后,系统的宏LW_TICK_HZ也会被设置为对应的频率,这里的代码运行后LW_TICK_HZ被设置为1000。

2.2 tick初始化

一般选用硬件定时器来实现系统tick功能,因此tick的初始化其实就是IMX6Q实验箱定时器的初始化。
SylixOS中通过bsplib.c文件里的bspTickInit函数实现tick的初始化。
Imx6Q实验箱的tick初始化代码如程序清单 2 2 所示,流程见代码中的注释。

                                     程序清单 2-2 tick 初始化
/***************************************************************************************************
** 函数名称: bspTickInit
** 功能描述: 初始化 tick 时钟
** 输  入  : NONE
** 输  出  : NONE
** 全局变量:
** 调用模块:
***************************************************************************************************/
VOID  bspTickInit (VOID)
{
    REGISTER UINT32      uiIncrementValue, uiPrescaler;

#if TICK_IN_THREAD > 0
    LW_CLASS_THREADATTR  threakattr;

    API_ThreadAttrBuild(&threakattr, (8 * LW_CFG_KB_SIZE),
                        LW_PRIO_T_TICK,
                        LW_OPTION_THREAD_STK_CHK |
                        LW_OPTION_THREAD_UNSELECT |
                        LW_OPTION_OBJECT_GLOBAL |
                        LW_OPTION_THREAD_SAFE, LW_NULL);

    htKernelTicks = API_ThreadCreate("t_tick", (PTHREAD_START_ROUTINE)__tickThread,
                                     &threakattr, LW_NULL);
#endif                                                             /*  TICK_IN_THREAD > 0          */

    /*
     *                          (PRESCALER_value+1) x (Load_value+1) x 2
     * The timer interval = ---------------------------------------------
     *                                          PERIPHCLK
     */
    uiIncrementValue = ((imx6qMainClkGet(CPU_CLK) / 2) / LW_TICK_HZ);
    uiPrescaler      = 0;

    /*
     * 1.设置定时器分频系数,根据LW_TICK_HZ和分频系数计算出定时器的比较数值;
     */
    _G_uiFullCnt       = uiIncrementValue;
    _G_ui64NSecPerCnt7 = ((1000 * 1000 * 1000 / LW_TICK_HZ) << 7) / _G_uiFullCnt;

    /*
     * 2.初始化硬件定时器,设置为对应的计数模式;
     */
    armGlobalTimerInit(LW_TRUE, uiIncrementValue, uiPrescaler, LW_TRUE);

    /*
     * 3.将定时器当前的计数值,和比较值写入对应的寄存器;
     */
    armGlobalTimerCounterSet(0);
    armGlobalTimerComparatorSet(uiIncrementValue);
    _G_ui64ComparatorCur = 0;

    /*
     * 4.绑定定时器的中断服务函数(__tickTimerIsr),设置中断优先级;
     */
    API_InterVectorConnect(ARM_TICK_INT_VECTOR,
                           (PINT_SVR_ROUTINE)__tickTimerIsr,
                           LW_NULL,
                           "tick_isr");

    API_InterVectorEnable(ARM_TICK_INT_VECTOR);

    armGicIrqPrioritySet(ARM_TICK_INT_VECTOR, ARM_TICK_INT_PRIORITY);

    /*
     * 5.使能定时器,开始计数。
     */
    armGlobalTimerStart();
}

2.3 tick中断服务函数

SylixOS里tick中断服务函数为__tickTimerIsr,在2.2节的tick初始化过程中已经绑定,对于bsp开发,只需要在__tickTimerIsr函数内,清除tick使用的定时器的中断位。其余的不需要修改。如程序清单 2-3 所示。

                       程序清单 2-3 tick 中断服务函数
/***************************************************************************************************
** 函数名称: __tickTimerIsr
** 功能描述: tick 定时器中断服务例程
** 输  入  : NONE
** 输  出  : 中断返回值
** 全局变量:
** 调用模块:
***************************************************************************************************/
static irqreturn_t  __tickTimerIsr (VOID)
{
    armGlobalTimerIntClear();                                      /*  清除中断                    */

    API_KernelTicksContext();                                      /*  保存被时钟中断的线程控制块    */

#if TICK_IN_THREAD > 0
    API_ThreadResume(htKernelTicks);
#else
    API_KernelTicks();                                             /*  内核 TICKS 通知             */
    API_TimerHTicks();                                             /*  高速 TIMER TICKS 通知       */
#endif                                                             /*  TICK_IN_THREAD > 0         */

    return  (LW_IRQ_HANDLED);
}

3.参考资料

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值