SylixOS x86 HPET 定时器驱动
HPET(High Precision Event Timer) 俗称高精度定时器,最低时钟频率为10MHZ,而且定义了比较严格的精确度(间隔 >= 1 毫秒的允许 +-0.05% 的误差,间隔 <=100 微妙的允许 +-0.2% 的误差)。x86 架构中一般支持 HPET 定时器。在 HPET 体系结构中规定 32 个定时器组成一个定时器块,最多可支持 8 个块,也就是 256 个定时器。实际设备中可使用的定时器数量可以从相关寄存器中查询。每个定时器均可以单独配置成一个中断。
在 x86 中使用 HPET 需要如下步骤:
1、在 _G_pAcpiHpet 结构中获取 HPET 寄存器操作地址操作地址;
2、在寄存器 General Capability 读取当前定时器的频率,这里的值表示每个时钟的周期,单位为飞秒(10^-15 秒);
3、配置中断,HPET 有三种中断模式:原始模式、标准模式、FSB 模式。这里我们使用标准模式,不对其他两种模式做过多解释。
在寄存器 Configuration Register 中通过配置 LEG_RT_CNF 控制关闭原始模式(默认关闭)
在具体的 Timer 配置寄存器中通过 TN_FSB_EN_CNF 位关闭 FSB 模式
标准模式下每个定时器的中断通过 Tn_INT_ROUTE_CNF 指定,Tn_INT_ROUTE_CAP 表示哪些中断号是有效的。
通过 Tn_INT_ENB_CNF 位使能定时器中断
4、配置比较寄存器 ,主计数器是 64 位的,会一直按照固定周期累加。若主计数器与比较寄存器中的值相同则会触发中断。通过调整比较寄存器的值可以调整中断触发周期。
例程:
hpet_drv.c
#define __SYLIXOS_KERNEL
#include <module.h>
#include "hpet_drv.h"
#include "arch/x86/common/x86Idt.h"
#include "arch/x86/acpi/x86AcpiLib.h"
/*********************************************************************************************************HPET 控制器定义
*********************************************************************************************************/
struct hpet_controller{LW_DEV_HDR HPET_devHdr; /* 必须是第一个结构体成员 */LW_LIST_LINE_HEADER HPET_fdNodeHeader; /* 表头 */UINT32 HPET_uiChannel; /* 通道号 */addr_t HPET_addrBase; /* 基址 */spinlock_t HPET_slSpinlock; /* 自旋锁 */LW_OBJECT_HANDLE HPET_ulMutex; /* 互斥锁 */LW_OBJECT_HANDLE HPET_ulSem; /* 信号量 */ULONG HPET_ulIrqNum; /* 定时器中断号 */UINT32 HPET_ulFsPerCnt; /* 时钟源周期 */HPET_CFG HPET_cfg; /* 配置 */
};
typedef struct hpet_controller HPET_CONTROLER;
typedef struct hpet_controller *PHPET_CONTROLER;
/*********************************************************************************************************HEPT 驱动号
*********************************************************************************************************/
static INT _G_iHpetDrvNum = PX_ERROR;
/*********************************************************************************************************HPET 宏配置
*********************************************************************************************************/
#define HPET_NUMBER (32) /* 32 路 HPET */
/*********************************************************************************************************HPET 寄存器定义
*********************************************************************************************************/
#define HPET_BASE (pHpetDev->HPET_addrBase)#define HPET_ID_LO (HPET_BASE + 0)
#define HPET_ID_HI (HPET_ID_LO + 4)#define HPET_CONFIG_LO (HPET_BASE + 0x10)
#define HPET_CONFIG_HI (HPET_CONFIG_LO + 4)#define HPET_STATUS_LO (HPET_BASE + 0x20)
#define HPET_STATUS_HI (HPET_STATUS_LO + 4)#define HPET_COUNTER_LO (HPET_BASE + 0xf0)
#define HPET_COUNTER_HI (HPET_COUNTER_LO + 4)#define HPET_TIMER_CONFIG_LO(t) (HPET_BASE + 0x100 + (t) * 0x20)
#define HPET_TIMER_CONFIG_HI(t) (HPET_TIMER_CONFIG_LO(t) + 4)
#define HPET_INT_ROUTE_MSK (0x1F)#define HPET_TIMER_COMPARATOR_LO(t) (HPET_BASE + 0x108 + (t) * 0x20)
#define HPET_TIMER_COMPARATOR_HI(t) (HPET_TIMER_COMPARATOR_LO(t) + 4)#define HPET_TIMER_FSB_INTR_LO(t) (HPET_BASE + 0x110 + (t) * 0x20)
#define HPET_TIMER_FSB_INTR_HI(t) (HPET_TIMER_FSB_INTR_LO(t) + 4)
/*********************************************************************************************************
** 函数名称: __acpiHpetMap
** 功能描述: 映射 ACPI HPET 表
** 输 入 : ulAcpiPhyAddr ACPI HPET 表物理地址
** ulAcpiSize ACPI HPET 表长度
** 输 出 : ACPI HPET 表虚拟地址
** 返 回 : ERROR_CODE
*********************************************************************************************************/
static VOID *__acpiHpetMap (addr_t ulAcpiPhyAddr, size_t ulAcpiSize)
{addr_t ulPhyBase = ROUND_DOWN(ulAcpiPhyAddr, LW_CFG_VMM_PAGE_SIZE);addr_t ulOffset = ulAcpiPhyAddr - ulPhyBase;addr_t ulVirBase;ulAcpiSize += ulOffset;ulAcpiSize = ROUND_UP(ulAcpiSize, LW_CFG_VMM_PAGE_SIZE);ulVirBase = (addr_t)API_VmmIoRemapNocache((PVOID)ulPhyBase, ulAcpiSize);if (ulVirBase) {return (VOID *)(ulVirBase + ulOffset);} else {return (VOID *)(LW_NULL);}
}
/*********************************************************************************************************
** 函数名称: __HpetIsrHandle
** 功能描述: HPET 中断处理
** 输 入 : pHpetDev HPET 结构
** 输 出 : NONE
** 返 回 : ERROR_CODE
*********************************************************************************************************/
static irqreturn_t __HpetIsrHandle (PHPET_CONTROLER pHpetDev)
{UINT64 u64Value;if (pHpetDev == LW_NULL) {return LW_IRQ_HANDLED;}if (read32(HPET_STATUS_LO) & (UINT32)(1 << pHpetDev->HPET_uiChannel)) {LW_SPIN_LOCK(&pHpetDev->HPET_slSpinlock);/** 清中断*/write32((UINT32)1 << pHpetDev->HPET_uiChannel, HPET_STATUS_LO);/** 重新计算比较值*/u64Value = read64(HPET_TIMER_COMPARATOR_LO(pHpetDev->HPET_uiChannel));if (pHpetDev->HPET_ulFsPerCnt != 0 && pHpetDev->HPET_cfg.uiHz != 0) {u64Value += 1000000000000000ULL / pHpetDev->HPET_ulFsPerCnt / pHpetDev->HPET_cfg.uiHz;}write64(u64Value, HPET_TIMER_COMPARATOR_LO(pHpetDev->HPET_uiChannel));/** 中断处理*/if (pHpetDev->HPET_cfg.hpetIntHandle) {pHpetDev->HPET_cfg.hpetIntHandle(pHpetDev->HPET_cfg.pIntArg);}/** 投递信号量*/API_SemaphoreBPost(pHpetDev->HPET_ulSem);LW_SPIN_UNLOCK(&pHpetDev->HPET_slSpinlock);}return (LW_IRQ_HANDLED);
}
/*********************************************************************************************************
** 函数名称: __hpetTimerInit
** 功能描述: 初始化 hpet 时钟
** 输 入 : pHpetDev HPET 结构
** pAcpiHpetPhy ACPI HPET 表
** 输 出 : NONE
** 返 回 : ERROR_CODE
*********************************************************************************************************/
static INT __hpetTimerInit (PHPET_CONTROLER pHpetDev, ACPI_TABLE_HPET *pAcpiHpetPhy)
{ACPI_TABLE_HPET *pAcpiHpet;UINT32 ulhpetTimerCfg;UINT32 ulIntRouteCap;if (!pHpetDev || !pAcpiHpetPhy) {return (PX_ERROR);}/** 映射 ACPI HPET 表*/pAcpiHpet = __acpiHpetMap((addr_t)pAcpiHpetPhy, LW_CFG_VMM_PAGE_SIZE);if (!pAcpiHpet) {return (PX_ERROR);}/** 映射 HPET 寄存器*/HPET_BASE = (addr_t)API_VmmIoRemapNocache((PVOID)(addr_t)(pAcpiHpet->Address.Address),LW_CFG_VMM_PAGE_SIZE);/** 解除映射 ACPI HPET 表*/API_VmmIoUnmap((PVOID)(((addr_t)pAcpiHpet) & LW_CFG_VMM_PAGE_MASK));if (!HPET_BASE) { /* 映射 HPET 寄存器失败 */return (PX_ERROR);}/** 读取时钟源周期*/pHpetDev->HPET_ulFsPerCnt = read32(HPET_ID_HI);/** 校验中断合法性*/ulIntRouteCap = read32(HPET_TIMER_CONFIG_HI(pHpetDev->HPET_uiChannel));if (!(ulIntRouteCap & (1 << pHpetDev->HPET_ulIrqNum))) {printk(KERN_ERR "[HPET] %s %d: IRQ NUM Check Error! INT_ROUTE_CAP = 0x%x\n",__func__, __LINE__, ulIntRouteCap);return (PX_ERROR);}/** 配置定时器模式*/ulhpetTimerCfg = read32(HPET_TIMER_CONFIG_LO(pHpetDev->HPET_uiChannel));ulhpetTimerCfg &= ~(1 << 15); /* 禁用 FSB INT */ulhpetTimerCfg &= ~(HPET_INT_ROUTE_MSK << 9);ulhpetTimerCfg |= pHpetDev->HPET_ulIrqNum << 9; /* 设置中断 */ulhpetTimerCfg &= ~(1 << 8); /* 64 位模式 */ulhpetTimerCfg &= ~(1 << 3); /* 单次触发模式 */ulhpetTimerCfg &= ~(1 << 2); /* 禁止中断 */ulhpetTimerCfg |= (1 << 1); /* 电平触发模式 */write32(ulhpetTimerCfg, HPET_TIMER_CONFIG_LO(pHpetDev->HPET_uiChannel));/* 配置定时器 */return (ERROR_NONE);
}
/*********************************************************************************************************
** 函数名称: __hpetTimerDeinit
** 功能描述: 解除初始化 hpet 时钟
** 输 入 : pHpetDev HPET 结构
** 输 出 : NONE
** 返 回 : ERROR_CODE
*********************************************************************************************************/
static INT __hpetTimerDeinit (PHPET_CONTROLER pHpetDev)
{if (!pHpetDev) {return (PX_ERROR);}LW_SPIN_LOCK(&pHpetDev->HPET_slSpinlock);write32(0, HPET_TIMER_CONFIG_LO(pHpetDev->HPET_uiChannel));bzero(&pHpetDev->HPET_cfg, sizeof(HPET_CFG));LW_SPIN_UNLOCK(&pHpetDev->HPET_slSpinlock);return (ERROR_NONE);
}
/*********************************************************************************************************
** 函数名称: __hpetTimerStart
** 功能描述: 启动 hpet 时钟
** 输 入 : pHpetDev HPET 结构
** 输 出 : NONE
** 返 回 : ERROR_CODE
*********************************************************************************************************/
static INT __hpetTimerStart (PHPET_CONTROLER pHpetDev)
{UINT32 ulhpetTimerCfg;UINT64 u64Value;if (!pHpetDev) {return (PX_ERROR);}/** 清除信号量信号*/API_SemaphoreBClear(pHpetDev->HPET_ulSem);/** 清中断*/write32((UINT32)1 << pHpetDev->HPET_uiChannel, HPET_STATUS_LO);/** 配置中断*/API_InterVectorConnect(pHpetDev->HPET_ulIrqNum,(PINT_SVR_ROUTINE)__HpetIsrHandle,pHpetDev,"hpetIsr");API_InterVectorEnable(pHpetDev->HPET_ulIrqNum); /* 使能中断 *//** 计算比较寄存器值*/LW_SPIN_LOCK(&pHpetDev->HPET_slSpinlock);u64Value = read64(HPET_COUNTER_LO);if (pHpetDev->HPET_ulFsPerCnt != 0 && pHpetDev->HPET_cfg.uiHz != 0) {u64Value += 1000000000000000ULL / pHpetDev->HPET_ulFsPerCnt / pHpetDev->HPET_cfg.uiHz;}write64(u64Value, HPET_TIMER_COMPARATOR_LO(pHpetDev->HPET_uiChannel));/** 开启定时器*/ulhpetTimerCfg = read32(HPET_TIMER_CONFIG_LO(pHpetDev->HPET_uiChannel));ulhpetTimerCfg |= (1 << 2); /* 使能中断 */write32(ulhpetTimerCfg, HPET_TIMER_CONFIG_LO(pHpetDev->HPET_uiChannel));LW_SPIN_UNLOCK(&pHpetDev->HPET_slSpinlock);return (ERROR_NONE);
}
/*********************************************************************************************************
** 函数名称: __hpetTimerStop
** 功能描述: 停止 hpet 时钟
** 输 入 : pHpetDev HPET 结构
** 输 出 : NONE
** 返 回 : ERROR_CODE
*********************************************************************************************************/
static INT __hpetTimerStop (PHPET_CONTROLER pHpetDev)
{UINT32 ulhpetTimerCfg;if (!pHpetDev) {return (PX_ERROR);}LW_SPIN_LOCK(&pHpetDev->HPET_slSpinlock);ulhpetTimerCfg = read32(HPET_TIMER_CONFIG_LO(pHpetDev->HPET_uiChannel));ulhpetTimerCfg &= ~(1 << 2); /* 禁止中断 */write32(ulhpetTimerCfg, HPET_TIMER_CONFIG_LO(pHpetDev->HPET_uiChannel));API_InterVectorDisable(pHpetDev->HPET_ulIrqNum); /* 禁止中断 */LW_SPIN_UNLOCK(&pHpetDev->HPET_slSpinlock);/** 清除信号量信号*/API_SemaphoreBClear(pHpetDev->HPET_ulSem);return (ERROR_NONE);
}
/*********************************************************************************************************
** 函数名称: __hpetIoctl
** 功能描述: 控制 HPET 设备
** 输 入 : pFdEntry 文件结构
** iCmd 命令
** lArg 参数
** 输 出 : NONE
** 返 回 : ERROR_CODE
*********************************************************************************************************/
static INT __hpetIoctl (PLW_FD_ENTRY pFdEntry, INT iCmd, LONG lArg)
{INT iRet = ERROR_NONE;PHPET_CONTROLER pHpetDev = (PHPET_CONTROLER)pFdEntry->FDENTRY_pdevhdrHdr;API_SemaphoreMPend(pHpetDev->HPET_ulMutex, LW_OPTION_WAIT_INFINITE);switch (iCmd) {case CMD_HPET_CONFIG:if (lArg) {LW_SPIN_LOCK(&pHpetDev->HPET_slSpinlock);pHpetDev->HPET_cfg = *(PHPET_CFG)lArg;LW_SPIN_UNLOCK(&pHpetDev->HPET_slSpinlock);} else {iRet = PX_ERROR;}break;case CMD_HPET_START:__hpetTimerStart(pHpetDev);break;case CMD_HPET_STOP:__hpetTimerStop(pHpetDev);break;case CMD_HPET_INT_WAIT:/** 等待中断信号量前先解互斥锁,防止造成死锁*/API_SemaphoreMPost(pHpetDev->HPET_ulMutex);API_SemaphoreBPend(pHpetDev->HPET_ulSem, LW_OPTION_WAIT_INFINITE);break;default:iRet = PX_ERROR;}if (iCmd != CMD_HPET_INT_WAIT) {API_SemaphoreMPost(pHpetDev->HPET_ulMutex);}return (iRet);
}
/*********************************************************************************************************
** 函数名称: __hpetOpen
** 功能描述: 打开 HPET 设备
** 输 入 : pFdEntry 文件结点
** pcName 设备名字
** iFlags 标志
** iMode 模式
** 输 出 : NONE
** 返 回 : 文件节点或者出错
*********************************************************************************************************/
static LONG __hpetOpen (PHPET_CONTROLER pHpetDev, PCHAR pcName, INT iFlags, INT iMode)
{PLW_FD_NODE pFdNode;BOOL bIsNew;if (pcName == LW_NULL) {_ErrorHandle(ERROR_IO_NO_DEVICE_NAME_IN_PATH);return (PX_ERROR);} else {API_SemaphoreMPend(pHpetDev->HPET_ulMutex, LW_OPTION_WAIT_INFINITE);pFdNode = API_IosFdNodeAdd(&pHpetDev->HPET_fdNodeHeader, (dev_t)pHpetDev, 0,iFlags, iMode, 0, 0, 0, LW_NULL, &bIsNew);if (pFdNode == LW_NULL) {API_SemaphoreMPost(pHpetDev->HPET_ulMutex);printk(KERN_ERR "[HPET] %s %d: failed to add fd node!\n", __func__, __LINE__);return (PX_ERROR);}if (LW_DEV_INC_USE_COUNT(&pHpetDev->HPET_devHdr) == 1) {}API_SemaphoreMPost(pHpetDev->HPET_ulMutex);return ((LONG)pFdNode);}
}
/*********************************************************************************************************
** 函数名称: __hpetClose
** 功能描述: 关闭 HPET 设备
** 输 入 : pFdEntry 文件结构
** 输 出 : NONE
** 返 回 : ERROR_CODE
*********************************************************************************************************/
static INT __hpetClose (PLW_FD_ENTRY pFdEntry)
{PLW_FD_NODE pfdnode = (PLW_FD_NODE)pFdEntry->FDENTRY_pfdnode;PHPET_CONTROLER pHpetDev = (PHPET_CONTROLER)pFdEntry->FDENTRY_pdevhdrHdr;if (!pFdEntry) {return (PX_ERROR);}if (pFdEntry && pfdnode) {API_SemaphoreMPend(pHpetDev->HPET_ulMutex, LW_OPTION_WAIT_INFINITE);API_IosFdNodeDec(&pHpetDev->HPET_fdNodeHeader, pfdnode, NULL);if (LW_DEV_DEC_USE_COUNT(&pHpetDev->HPET_devHdr) == 0) {__hpetTimerStop(pHpetDev);}API_SemaphoreMPost(pHpetDev->HPET_ulMutex);return (ERROR_NONE);} else {return (PX_ERROR);}
}
/*********************************************************************************************************
** 函数名称: hpetDrvInstall
** 功能描述: 安装 HPET 驱动
** 输 入 : NONE
** 输 出 : NONE
** 返 回 : ERROR_CODE
*********************************************************************************************************/
INT hpetDrvInstall (VOID)
{struct file_operations fileop;if (_G_iHpetDrvNum != PX_ERROR) {return (ERROR_NONE);}lib_memset(&fileop, 0, sizeof(struct file_operations));fileop.owner = THIS_MODULE;fileop.fo_create = __hpetOpen;fileop.fo_open = __hpetOpen;fileop.fo_close = __hpetClose;fileop.fo_ioctl = __hpetIoctl;_G_iHpetDrvNum = iosDrvInstallEx2(&fileop, LW_DRV_TYPE_NEW_1);DRIVER_LICENSE(_G_iHpetDrvNum, "Dual BSD/GPL->Ver 1.0");DRIVER_AUTHOR(_G_iHpetDrvNum, "WangJingshi");DRIVER_DESCRIPTION(_G_iHpetDrvNum, "HPET driver.");return (_G_iHpetDrvNum > 0) ? (ERROR_NONE) : (PX_ERROR);
}
/*********************************************************************************************************
** 函数名称: hpetDevCreate
** 功能描述: 创建 HPET 设备
** 输 入 : uiChannel HPET 通道
** cpcPath HPET 设备文件路径
** ulIrq HPET 分配中断号
** 输 出 : NONE
** 返 回 : ERROR_CODE
** 备 注 : 分配中断号注意不能与系统其他中断冲突
*********************************************************************************************************/
INT hpetDevCreate (UINT32 uiChannel, CPCHAR cpcPath, ULONG ulIrq)
{PHPET_CONTROLER pHpetDev;if (_G_iHpetDrvNum == PX_ERROR) {printk(KERN_ERR "[HPET] %s %d: driver number invalid!\n", __func__, __LINE__);return (PX_ERROR);}if (cpcPath == LW_NULL) {printk(KERN_ERR "[HPET] %s %d: device path invalid!\n", __func__, __LINE__);return (PX_ERROR);}if (uiChannel >= HPET_NUMBER) {printk(KERN_ERR "[HPET] %s %d: hpet channel invalid!\n", __func__, __LINE__);return (PX_ERROR);}/** 创建设备结构*/pHpetDev = (PHPET_CONTROLER)sys_zalloc(sizeof(HPET_CONTROLER));if (pHpetDev == LW_NULL) {printk(KERN_ERR "[HPET] %s %d: memory error!\n", __func__, __LINE__);errno = ENOMEM;return (PX_ERROR);}pHpetDev->HPET_uiChannel = uiChannel;pHpetDev->HPET_ulIrqNum = ulIrq;LW_SPIN_INIT(&pHpetDev->HPET_slSpinlock);pHpetDev->HPET_ulMutex = API_SemaphoreMCreate("hpet_lock",LW_PRIO_HIGH,LW_OPTION_WAIT_PRIORITY |LW_OPTION_OBJECT_GLOBAL|LW_OPTION_INHERIT_PRIORITY |LW_OPTION_ERRORCHECK,LW_NULL);if (pHpetDev->HPET_ulMutex == LW_OBJECT_HANDLE_INVALID) {printk(KERN_ERR "[HPET] %s %d: mutex create failed.\n", __func__, __LINE__);goto __error4;}pHpetDev->HPET_ulSem = API_SemaphoreBCreate("hpet_sem",LW_FALSE,LW_OPTION_WAIT_PRIORITY |LW_OPTION_OBJECT_GLOBAL,LW_NULL);if (pHpetDev->HPET_ulSem == LW_OBJECT_HANDLE_INVALID) {printk(KERN_ERR "[HPET] %s %d: sem create failed.\n", __func__, __LINE__);goto __error3;}/** 初始化 HPET 定时器*/if (__hpetTimerInit(pHpetDev, _G_pAcpiHpet) != ERROR_NONE) {printk(KERN_ERR "[HPET] %s %d: hpet %d init fail!\n",__func__, __LINE__, pHpetDev->HPET_uiChannel);goto __error2;}/** 向系统添加一个设备*/if (ERROR_NONE != API_IosDevAddEx(&pHpetDev->HPET_devHdr, cpcPath, _G_iHpetDrvNum, DT_CHR)) {printk(KERN_ERR "[HPET] %s %d: can not add device : %s\n", __func__, __LINE__, strerror(errno));goto __error1;}return (ERROR_NONE);__error1:__hpetTimerDeinit(pHpetDev);
__error2:API_SemaphoreBDelete(&pHpetDev->HPET_ulSem);
__error3:API_SemaphoreMDelete(&pHpetDev->HPET_ulMutex);
__error4:sys_free(pHpetDev);return (PX_ERROR);
}
/*********************************************************************************************************
** 函数名称: module_init
** 功能描述: 模块初始化
** 输 入 : NONE
** 输 出 : NONE
** 返 回 : ERROR_CODE
*********************************************************************************************************/
int module_init (void)
{hpetDrvInstall();hpetDevCreate(2, "/dev/hpet2", LW_IRQ_11);return (ERROR_NONE);
}
/*********************************************************************************************************
** 函数名称: module_exit
** 功能描述: 模块退出
** 输 入 : NONE
** 输 出 : NONE
** 返 回 : ERROR_CODE
*********************************************************************************************************/
void module_exit (void)
{
}
hpet_drv.h
#ifndef __HPET_DRV_H
#define __HPET_DRV_H#define __SYLIXOS_KERNEL
#include <SylixOS.h>
#include "sys/ioccom.h"/*********************************************************************************************************HPET 配置结构
*********************************************************************************************************/
struct hpet_cfg {UINT32 uiHz; /* 定时频率 */PVOID pIntArg; /* 中断处理参数 */PVOID (*hpetIntHandle) (PVOID); /* 中断处理 (注意:中断上下文) */
};
typedef struct hpet_cfg HPET_CFG;
typedef struct hpet_cfg *PHPET_CFG;/*********************************************************************************************************HPET ioctl 函数命令字
*********************************************************************************************************/#define CMD_HPET_CONFIG _IOW('h', 1, HPET_CFG) /* 配置定时器 */
#define CMD_HPET_START _IO('h', 2) /* 定时器启动 */
#define CMD_HPET_STOP _IO('h', 3) /* 定时器停止 */
#define CMD_HPET_INT_WAIT _IO('h', 4) /* 等待中断触发 *//*********************************************************************************************************函数声明
*********************************************************************************************************/
INT hpetDrvInstall(VOID);
INT hpetDevCreate(UINT32 uiChannel, CPCHAR cpcPath, ULONG ulIrq);#endif /* __HPET_DRV_H */
SylixOS x86 HPET 定时器驱动相关推荐
- SylixOS中APIC HPET定时器字符驱动实现
1.简介 1.1 APIC介绍 "APIC"是Advanced Programmable Interrupt Controller的缩写,即高级可编程中断控制器.引入APIC机制是 ...
- STM8单片机定时器驱动的深度解析
上一节给大家介绍了基于标准库STM8单片机GPIO的驱动,本节课主要给大家介绍一下STM8定时器的驱动. 我们先打开STM8L10x单片机的规格书,简单的了解一下STM8L10X单片机的定时器功能. ...
- HAL库配置STM32F1系列定时器驱动步进电机(三)
之前的电机成功地转了起来,但其噪音非常大,因为之前尝试过自带细分功能的优质驱动器,关于其具体原理我没有系统学习,在使用L298N驱动电机时就感觉到有些吃力,于是在这里补一下步进电机微步细分原理的功课, ...
- hpet 定时器中断 8259 linux,[OSDEV]编程高精度定时器(HPET)
高精度定时器HPET和I/O APIC一样,用的是内存映射,映射的地址保存在BIOS提供的ACPI表格中 我们首先来获取这个地址 获取HPET的I/O内存地址 先来看一下文档的30-31页: 关键就是 ...
- 由于高精度事件计时器(HPET)驱动过时导致AMD机器装Win10的卡死蓝屏问题记录
AMD机型最近频繁卡死,蓝屏,特征在于:打游戏等高负载条件,电脑没有问题:闲置一定时间之后蓝屏或者死机,鼠标键盘无反应,界面全部卡死,只能按开机键重启.未保存的数据全部丢失. 近日蓝屏代码 有两类,一 ...
- 【春节歌曲回味 | STM32小音乐盒 】PWM+定时器驱动无源蜂鸣器(STM32 HAL库)
l STM32通过PWM与定时器方式控制无源蜂鸣器鸣响 l STM32小音乐盒,歌曲进度条图形显示与百分比显示,歌曲切换 l 编程使用STM32 HAL库 l IIC OLED界面编程,动画实 ...
- 定时器驱动数码管c语言,第五章 定时器和数码管
1.1基本数字逻辑门电路 不管是数字电路,还是C语言,我们都会经常遇到逻辑运算和逻辑电路,在这里我介绍一下,大家先简单了解一下,知道有这么回事,回头遇到了,再详细研究. 首先,在"逻辑&qu ...
- 定时器驱动数码管c语言程序,74hc595驱动数码管时间程序
74hc595驱动数码管时间程序 这里是电路图: 下面是51单片机驱动74hc595芯片的程序: #include //包含51单片机的头文件 # ...
- 定时器驱动数码管c语言程序,用c语言编写,实用定时器实现数码管15倒计时
#include#define uchar unsigned char uchar miao,t0,flat,shiwei,gewei,; sbit dula = p2^6; sbit wela = ...
最新文章
- 设置 docker容器 禁用网络
- [杂笔]我的第一篇博客
- 在项目中使用JMail发送邮件
- java处理中文字符串_Java实现读取文章中重复出现的中文字符串
- Python 抓取图片
- efi引导文件_你们心心念念的oc通用EFI来了!
- wps计算机一级考试试题300,计算机一级考试WPS试题及答案
- python读音发音-python3 - 文本读音器
- C++笔试题整理(一)
- iOS-Senior19-FMDB第三方应用
- 基于SSM框架实现的房屋租赁管理系统
- Exif文件格式描述(转载)
- 视频下载软件Annie的安装及使用
- 当下的力量实践手册读书笔记(1.29)
- 机器学习笔记 十七:基于Gini Importance、Permutation Importance、Boruta的随机森林模型重要性评估的比较
- 手把手接入高德地图API——POI周边搜索功能实现
- R语言导入数据文件(数据导入、加载、读取)、使用read.table函数导入逗号分割文件CSV(Comma Delimited Text File)
- 2022Q4手机银行新版本聚焦提升客群专属、财富开放平台、智能化能力,活跃用户规模6.91亿人
- 软件编程学习网站汇总——持续更新中
- java.util.list源码_关于fest-util源码包Collections集合工具类过滤、判空、格式化及复制克隆处理...
热门文章
- 微信群发软件哪个好?好用的群发软件选择
- unity 3d iphone android 通用,在Unity3D中使用iPhone原生UI
- 微信小游戏 腾讯课堂《白鹭教育 - 成语大挑战小游戏开发》学习笔记
- (附源码)springboot基于微信小程序的高校计算机类课程思政库的设计与实现 毕业设计 271611
- 微信服务器 移动信号,微信消息延迟,只需更改手机这5个设置,效果“立竿见影”...
- java操作word,自动更新目录/域
- 【GD32F310开发板试用】编码器接口的使用
- iOS 一个带动画的等待指示器
- 使用Rust开发编译系统(C以及Rust编译的过程)
- Linux桌面基础:X Window System——Xorg