鸿蒙Harmony系统时钟源码解析 - HarmonyOS技术社区 - 电子技术论坛 - 广受欢迎的专业电子论坛
分享 收藏 返回

Bright_ML 关注 私信
[文章]

鸿蒙Harmony系统时钟源码解析

一.系统时钟初始化1.main函数的各种调用,验证参数
kernelliteos_aplatformmain.c->main()
        kernelliteos_akernelcommonlos_config.c->OsMain()
                kernelliteos_aarcharmarmsrclos_hw_tick.c->OsTickInit()
  1. systemClock     //vendor里设置的是50000000
  2. tickPerSecond   //鸿蒙默认设置的是100
  3. LITE_OS_SEC_TEXT_INIT UINT32 OsTickInit(UINT32 systemClock, UINT32 tickPerSecond)
  4. {    //只是验证了下传入的这两个参数,并未使用
  5.     HalClockInit();
  6.     return LOS_OK;
  7. }
2.先获取当前时钟频率,注册中断
kernelliteos_aplatformhwarmtimerarm_genericarm_generic_timer.c
  1. OS_TICK_INT_NUM//中断号,在vendor******boardincludeasmhal_platform_ints.h下定义,查手册确定
  2. MIN_INTERRUPT_PRIORITY//优先级
  3. OsTickEntry//中断函数
  4. LITE_OS_SEC_TEXT_INIT VOID HalClockInit(VOID)
  5. {   ...
  6.     g_sysClock = HalClockFreqRead(); //先获取当前时钟频率
  7.    
  8.     //调用LOS_HwiCreate函数新建中断,系统中断由它注册
  9.     ret = LOS_HwiCreate(OS_TICK_INT_NUM, MIN_INTERRUPT_PRIORITY, 0, OsTickEntry, 0);//参数1:中断号、参数4:执行函数
  10.     //这个函数就不深入了,大体就是将中断号好和对应的执行函数放到一个数组
  11.     //比如这里就是,当发生OS_TICK_INT_NUM这个中断时,执行OsTickEntry()函数
  12.     ...
  13. }
二.时钟中断的执行函数OsTickEntry()
kernelliteos_aplatformhwarmtimerarm_genericarm_generic_timer.c
不过此时这是注册了这个函数,时钟并未启动,得执行了(三.启动时钟)之后才会调用这个函数
  1. LITE_OS_SEC_TEXT VOID OsTickEntry(VOID)
  2. {
  3.     TimerCtlWrite(0);
  4.     OsTickHandler();
  5.     TimerCvalWrite(TimerCvalRead() + OS_CYCLE_PER_TICK);
  6.     TimerCtlWrite(1);
  7.     //使用最后一个cval生成下一个tick的时间是绝对和准确的。不要使用tval来驱动一般时间,在这种情况下tick会变慢。
  8. }
三.启动时钟
main() => OsStart(VOID) => OsTickStart() => HalClockStart(VOID)
kernelliteos_aplatformhwarmtimerarm_genericarm_generic_timer.c => HalClockStart(VOID)
  1. //树莓派2b没有GIC所以这个函数要爆改
  2. LITE_OS_SEC_TEXT_INIT VOID HalClockStart(VOID)
  3. {
  4.     HalIrqUnmask(OS_TICK_INT_NUM);  //wendor里定义的 OS_TICK_INT_NUM = 29
  5.     TimerCtlWrite(0);
  6.     TimerTvalWrite(OS_CYCLE_PER_TICK);
  7.     TimerCtlWrite(1);
  8. }
1. HalIrqUnmask; //接收中断(通过设置寄存器,允许CPU响应该中断)
  1. HalIrqUnmask(OS_TICK_INT_NUM);
  2. HalIrqUnmask(29);
  3. GIC_REG_32(GICD_ISENABLER(29 >> 5)) = 1U << (29 % 32);

  4. (GICD_ISENABLER(29 >> 5))拆开
  5. GIC_REG_32(GICD_OFFSET + 0x100 + (29 >> 5) * 4) = 1U << (29 % 32);/* 中断使能 Registers */

  6. GIC_REG_32拆开,(29 % 32)=1D
  7. GIC_BASE_ADDR + (GICD_OFFSET + 0x100 + (29 >> 5) * 4) = 1U << (29 % 32)

  8. #define GIC_BASE_ADDR             IO_DEVICE_ADDR(0x3F00A100)
  9. #define GICD_OFFSET               0x1000     /* interrupt distributor offset */
2.TimerCtlWrite(0); //关闭Timer
  1. WRITE_TIMER_REG32(TIMER_REG_CTL, 0);

    ARM_SYSREG_WRITE(TIMER_REG_CTL, 0)
  2. ARM_SYSREG_WRITE(TIMER_REG(_CTL), 0)
  3. ARM_SYSREG_WRITE(CP15_REG(c14, 0, c2, 1)), 0)
  4. "mcr " (CP15_REG(c14, 0, c2, 1) :: "r" (val)
  5. 反汇编
  6. r8 0
  7. mcr p15, #0, r8, c14, c2, #1    CNTP_CTL,PL1物理定时器控制寄存器
3.TimerTvalWrite(OS_CYCLE_PER_TICK); //设置Tval
  1. 反汇编
  2. r0 192000
  3. mcr p15, #0, r0, c14, c2, #0    CNTP_TVAL,PL1物理时间值寄存器
4.TimerCtlWrite(1);        //再开启Timer
  1. 反汇编
  2. r5 1
  3. mcr p15, #0, r5, c14, c2, #1    CNTP_CTL,PL1物理定时器控制寄存器
代码移植
Z:brightharmony-100askkernelliteos_aplatformhwarminterruptgicgic_v2.c
  1. VOID HalIrqUnmask(UINT32 vector)
  2. {
  3.     if ((vector > OS_USER_HWI_MAX) || (vector < OS_USER_HWI_MIN)) {
  4.         return;
  5.     }
  6.     //GIC_REG_32(GICD_ISENABLER(vector >> 5)) = 1U << (vector % 32);  //替换
  7.     *(volatile UINT32 *)((UINTPTR)IO_DEVICE_ADDR(0x3F00B218)) = 1; //使能ARM Timer IRQ   

  8. }
Z:brightharmony-100askkernelliteos_aplatformhwarmtimerarm_genericarm_generic_timer.c
  1. STATIC_INLINE VOID TimerCtlWrite(UINT32 cntpCtl)
  2. {
  3.     //WRITE_TIMER_REG32(TIMER_REG_CTL, cntpCtl);//替换
  4.     if(cntpCtl == 0){
  5.         *(volatile UINT32 *)((UINTPTR)IO_DEVICE_ADDR(0x3F00B408)) = 0x003E0000;
  6.         }
  7.     else
  8.     {
  9.         *(volatile UINT32 *)((UINTPTR)IO_DEVICE_ADDR(0x3F00B408)) = 0x003E00A2;
  10.     }
  11. }
Z:brightharmony-100askkernelliteos_aplatformhwarmtimerarm_genericarm_generic_timer.c
  1. STATIC_INLINE VOID TimerTvalWrite(UINT32 tval)
  2. {
  3.     //WRITE_TIMER_REG32(TIMER_REG_TVAL, tval);//替换
  4.     *(volatile UINT32 *)((UINTPTR)IO_DEVICE_ADDR(0x3F00B400)) = tval;  //设置倒计时时间,鸿蒙是10ms   
  5. }



更多回帖

×
发帖