• 从零开始操作系统-08:计时器


    这一节主要主要是计时器。

    所需要的文件在Github:https://github.com/yongkangluo/Ubuntu20.04OS/tree/main/Files/Lec7-ExternalInterrupt

    计时器:

    可编程间隔计时器:PIT(Programmalbe Interval Timer)8254

    使用APIC自带的Timer:
    更高精度并且能对CUP单独设置;

    概述而言就是:
    使用 两个Count来做计时:
    FEE0 0380H :Initial Count;
    FEE0 0390H :Current Count

    if(ICR){
    	do{
    		CCR = ICR;
    		while(CCR--);
    		Interrput;
    	} while(Timer Model)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    计数器的行为设置:
    在这里插入图片描述

    手动测量频率
    使用一个固定已知频率的时钟做参考:
    Lapic 计时器发生中断时,经过了多少的间隔:
    F t i m e r = F C P U / k I C R / F t i m e r = t / F R T C F_{timer} = F_{CPU} / k\\ ICR / F_{timer} = t / F_{RTC} Ftimer=FCPU/kICR/Ftimer=t/FRTC
    使用CPU来计算是不准确的,可能存在超频的可能。所以需要用手动测量。使用主板上的COMS来作为时间参考。

    步骤如下:

    1. 安装RTC和Lapic Timer 的临时中断服务例程
    2. 配置RTC的频率(1024赫兹)
    3. 打开中断
    4. 写入ICR
    5. PIE置位
    6. 阻塞
    7. 党LAPIC Timer触发之后,计算频率并关闭RTC
    8. 清楚临时例程
    Code
    void
    timer_init(uint32_t frequency)
    {
        timer_init_context();
        cpu_disable_interrupt();
        // 配置LAPIC中的中断寄存器; One shot, 中断号是202
        apic_write_reg(APIC_TIMER_LVT,
                       LVT_ENTRY_TIMER(APIC_TIMER_IV, LVT_TIMER_ONESHOT));
        // Time Driver设置为64
        apic_write_reg(APIC_TIMER_DCR, APIC_TIMER_DIV64);
        timer_ctx->base_frequency = 0;
        rtc_counter = 0;
        apic_timer_done = 0;
        // 安装APIC对一个的中断程序
        intr_subscribe(APIC_TIMER_IV, temp_intr_routine_apic_timer);
        intr_subscribe(RTC_TIMER_IV, temp_intr_routine_rtc_tick);
        // 开启RTC计时器
        rtc_enable_timer();    
        // 在APIC中写一个很大的常数                              
        apic_write_reg(APIC_TIMER_ICR, APIC_CALIBRATION_CONST); 
        // 开启中断
        cpu_enable_interrupt();
        wait_until(apic_timer_done);
        assert_msg(timer_ctx->base_frequency, "Fail to initialize timer (NOFREQ)");
        kprintf(KINFO "Base frequency: %u Hz\n", timer_ctx->base_frequency);
        timer_ctx->running_frequency = frequency;
        timer_ctx->tick_interval = timer_ctx->base_frequency / frequency;
        
        intr_unsubscribe(APIC_TIMER_IV, temp_intr_routine_apic_timer);
        intr_unsubscribe(RTC_TIMER_IV, temp_intr_routine_rtc_tick);
        apic_write_reg(APIC_TIMER_LVT,
                       LVT_ENTRY_TIMER(APIC_TIMER_IV, LVT_TIMER_PERIODIC));
        intr_subscribe(APIC_TIMER_IV, timer_update);
        apic_write_reg(APIC_TIMER_ICR, timer_ctx->tick_interval);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    在这里插入图片描述

    方法主要跟着B站Up主做的,B站视频链接在:https://www.bilibili.com/video/BV1jL4y1s7X6/?spm_id_from=333.788&vd_source=72ce864f895f9fbf22b81450817f2875

  • 相关阅读:
    【Linux】进程概念
    基础算法练习200题06、分练习本
    SOCKS5代理(源码)
    搜索技术【深度优先搜索】 - m 叉树
    论文解析——AMD EPYC和Ryzen处理器系列的开创性的chiplet技术和设计
    ESP32 之 ESP-IDF 教学(二十)—— SNTP校时
    基于Java+SpringBoot+Vue宠物咖啡馆平台设计和实现
    【Matplotlib绘制图像大全】(三):水平柱状图
    新零售SaaS架构:什么是订单履约系统?
    程序员造轮子:一个基于posix线程库的互斥类(源码)
  • 原文地址:https://blog.csdn.net/lyk82698/article/details/127985458