OpenHarmony(4) —— system counter

    科技2022-07-13  145

        进入多核时代后,ARM公司提供了timer的硬件设计,集成在了自己的多核结构中。例如:在Cortex A15 MPcore的硬件体系结构中有一个HW block叫做Generic Timer(该硬件取代了A9中的global timer、private timer的功能),为系统提供了计时以及触发timer event的功能。

        ARM generic timer的硬件block主要是SOC上的System counter(多个process共享,用来记录时间的流逝)以及附着在各个processor上的Timer(用于触发timer event)组成,其他的generic timer的硬件电路主要是用来进行交流generic time event的。例如各个processor中的timer和system counter外设进行交互,各个processor中的timer进行信息交互。System counter的功能很简单,就是计算输入时钟已经过了多少个clock,开始的时候是0,每一个clock,System counter会加一。System counter的counter value需要分发到各个timer中,也就是说,从各个timer的角度看,system counter value应该是一致的。Timer其实就是定时器,它可以定义一段指定的时间,当时间到了,就会assert一个外部的输出信号(可以输出到GIC,作为一个interrupt source)。

        除了基本的计时功能,system count还提供了event stream的功能。我们知道,ARMv7的处理器提供了wait for event的机制,该机制允许processor进入low power state并等待event的到来。这个event可能是来自另外的process的send event指令,也可能是外部HW block产生的event,比如来自system counter的wake-up event。

    选自《Linux时间子系统之(十七):ARM generic timer驱动代码分析》

     

    代码仓:https://codechina.csdn.net/fu851523125/rtos

    main()

    {

    HalClockFreqWrite(OS_SYS_CLOCK);

    。。。

    OsMain() {

    。。。

    ret = OsTickInit(g_sysClock, LOSCFG_BASE_CORE_TICK_PER_SECOND) {

    HalClockInit(){

        g_sysClock = HalClockFreqRead();     ret = LOS_HwiCreate(OS_TICK_INT_NUM, MIN_INTERRUPT_PRIORITY, 0, OsTickEntry, 0);     if (ret != LOS_OK) {         PRINT_ERR("%s, %d create tick irq failed, ret:0x%x\n", __FUNCTION__, __LINE__, ret);     }

    }

    }

    。。。

    }

    。。。

        OsStart() {

             OsTickStart() {

                HalClockStart() {

                    HalIrqUnmask(OS_TICK_INT_NUM);

                    /* triggle the first tick */                 TimerCtlWrite(0);                 TimerTvalWrite(OS_CYCLE_PER_TICK);                 TimerCtlWrite(1);

                }

             }

            。。。

        }

        while (1) {         __asm volatile("wfi");     }

    }

     

        测试:

        ARCH_ClockStart() {

            /* set smp system counter freq */         WRITE_TIMER_REG32(TIMER_REG_CNTFRQ, OS_SYS_CLOCK);

            WRITE_TIMER_REG32(TIMER_REG_CTL, 0);         WRITE_TIMER_REG32(TIMER_REG_TVAL, 0);         WRITE_TIMER_REG64(TIMER_REG_CVAL, 0);         WRITE_TIMER_REG32(TIMER_REG_CTL, 1);

        }          ret = RTOS_HAL_HwiCreate(OS_TICK_INT_NUM, OS_TickHandler, OS_NULL) {

            。。。

            ARCH_IrqUnmask(no);

            。。。

        }     if (ret != OS_ERR_NOERR) {         EPRINTK_ERR("create HWI os tick irq failed, ret:0xX\n", ret);         RTOS_Hang();     }

        eprintk("CPU#%u: releasing %u secondary cores ...\n", cpuId, CORE_NUM - 1);     //ARCH_ReleaseSecondaryCores();     /* wait until all APs are ready */     //while (RTOS_ATOMIC_Read(&cpus) < CORE_NUM) {     //    ARCH_WFE();     //}

        //OS_Start();

        while(1) {         uss = ARCH_ClockGetUs();

            s = uss / 1000000;         m = s / 60;         h = m / 60;         m = m % 60;         s = s % 60;

            uss = uss % 1000000;

            ms = uss / 1000;         us = uss % 1000;                  eprintk("\rCPU#%u: %u:u:u.u.u WFI",                 cpuId, h, m, s, ms, us);         ARCH_WFI();     }

        呈现时钟效果

        CPU#0: 0:08:35.210.000 WFI

     

    但是呢,中断没有,一直在找原因,为什么呢没有中断产生,

    然后各种找,各种想,某一刻看到

    /* arch/hw.S */ os_base_t ARCH_HW_InterruptDisable(void); void ARCH_HW_InterruptEnable(os_base_t level);

    ARCH_HW_InterruptDisable()在一开始执行了,那就要调用ARCH_HW_InterruptEnable()?

    一试,还真可以了。

    修改,

    static void OS_TickHandler(void *param) {     u32 cpuId = ARCH_CurCpuId();     u32 intSave;

        ARCH_ClockStop();

        //TICK_LOCK(intSave);     ++gTickCount[cpuId];     eprintk("CPU#%u: tick %u\n", cpuId, gTickCount[cpuId]);     //TICK_UNLOCK(intSave);

        //OsTimesliceCheck();     //OsTaskScan(); /* task timeout scan */     //OsSwtmrScan();

        ARCH_ClockContinue(); }

    void RTOS_Main(os_base_t osMemStart) {     s32 ret = 0;     //u32 cpuId = ARCH_CurCpuId();

        ARCH_HW_InterruptDisable();

        RTOS_HAL_Init();

        eprintk("\nRTOS SMP %s*%d [v%d.%d.%d %s %s]\n",             ARCH_GetCpuInfo(), CORE_NUM,              KERNEL_MAJOR, KERNEL_MINOR, KERNEL_PATCH,             __DATE__, __TIME__);

        RTOS_MEM_Init(osMemStart, KERNEL_VADDR_SIZE - (osMemStart - KERNEL_VADDR_BASE));

        ARCH_ClockInit();          ret = RTOS_HAL_HwiCreate(OS_TICK_INT_NUM, OS_TickHandler, OS_NULL);     if (ret != OS_ERR_NOERR) {         EPRINTK_ERR("create HWI os tick irq failed, ret:0xX\n", ret);         RTOS_Hang();     }

        ARCH_ClockStart(OS_TICK_INT_NUM);

        //eprintk("CPU#%u: releasing %u secondary cores ...\n", cpuId, CORE_NUM - 1);     //ARCH_ReleaseSecondaryCores();     /* wait until all APs are ready */     //while (RTOS_ATOMIC_Read(&cpus) < CORE_NUM) {     //    ARCH_WFE();     //}

        //OS_Start();

        while(1) {         ARCH_WFI();     } }  

    运行,

    hisilicon # go 0x80000000 ## Starting application at 0x80000000 ...

    RTOS SMP Cortex-A7*2 [v0.1.0 Oct  4 2020 17:01:51] [DBG]{ARCH_IrqUnmask() L335} enable irq 29 CPU#0: tick 1 CPU#0: tick 2 CPU#0: tick 3 CPU#0: tick 4 CPU#0: tick 5 CPU#0: tick 6 CPU#0: tick 7 CPU#0: tick 8 CPU#0: tick 9 CPU#0: tick 10 CPU#0: tick 11 CPU#0: tick 12 CPU#0: tick 13 CPU#0: tick 14 CPU#0: tick 15 CPU#0: tick 16 CPU#0: tick 17 CPU#0: tick 18 CPU#0: tick 19 CPU#0: tick 20

    Processed: 0.012, SQL: 8