当前位置: 首页 > news >正文

PCI9x5x驱动移植支持PCI9054在win7下使用3

接上文,本文章继续记录中泰联创的数据采集卡驱动翻新过程。

读写FPGA寄存器函数移植

将PCI8KPLX_IOCTL_BAR_RW改为PCI8KPLX_IOCTL_BAR_READ作为读FPGA寄存器命令,将PCI8KPLX_IOCTL_BAR_BULK_RW改为PCI8KPLX_IOCTL_BAR_BULK_WRITE作为写FPGA寄存器命令。
老驱动使用一个PCI8KPLX_IOCTL_BAR_RW命令作为内核通讯接口,没有利用到系统自身设计的便利,所以新驱动将读命令和写命令拆分成两个IOCTL操作。

之前的PCI8KPLX_IOCTL_OPEN_IRQ和PCI8KPLX_IOCTL_CLOSE_IRQ请求,都不需要返回给应用层数据,因此在PLxEvtIoDeviceControl函数中直接使用WdfRequestComplete函数设置请求完成即可;但是PCI8KPLX_IOCTL_BAR_READ需要返回给应用层寄存器读取结果,因此必须要设定返回字节数,可以通过WdfRequestCompleteWithInformation完成请求来设置返回字节数,但是这样就必须考虑其它不返回数据的函数,会增加编程复杂度,因此使用WdfRequestSetInformation函数在需要返回数据的函数里面设置返回字节数,不需要返回数据的函数,不调用这个函数,系统会默认返回0字节。

内核中添加代码如下:

VOID
PLxEvtIoDeviceControl(_In_ WDFQUEUE   Queue,_In_ WDFREQUEST Request,_In_ size_t     OutputBufferLength,_In_ size_t     InputBufferLength,_In_ ULONG      IoControlCode){...case PCI8KPLX_IOCTL_BAR_READ:status = PCI8KPLX_IOCTL_BAR_READ_Handler(Request, devExt);break;case PCI8KPLX_IOCTL_BAR_WRITE:status = PCI8KPLX_IOCTL_BAR_WRITE_Handler(Request, devExt);break;...}
/*** 功能:读回FPGA寄存器内容* 输入:ULONG[0],操作位宽;0对应32位,1对应16位,2对应8位*       ULONG[1],地址;0~255* 输出:ULONG[0],寄存器内容*/
NTSTATUS
PCI8KPLX_IOCTL_BAR_READ_Handler(_In_ WDFREQUEST Request,_In_ PDEVICE_EXTENSION DevExt
)
{NTSTATUS status = STATUS_SUCCESS;PULONG pBuff = NULL; // 指向输入缓冲区PULONG pOutBuff = NULL; // 指向输出缓冲区size_t bufferSize = 0;// 1. 获取输入缓冲区 status = WdfRequestRetrieveInputBuffer(Request, PCI8KPLX_IOCTL_BAR_READ_IN_SIZE, (PVOID*)&pBuff, &bufferSize);if (!NT_SUCCESS(status)) {return status;}ULONG type = pBuff[0];ULONG addr = pBuff[1];ULONG ret = 0;switch (type){case PORT_RW_32BIT:ret = READ_PORT_ULONG((PULONG)(DevExt->addrLocal + addr));break;case PORT_RW_16BIT:ret = READ_PORT_USHORT((PUSHORT)(DevExt->addrLocal + addr));break;case PORT_RW_8BIT:ret = READ_PORT_UCHAR((PUCHAR)(DevExt->addrLocal + addr));break;default:return STATUS_INVALID_PARAMETER;}//获取输出缓冲区status = WdfRequestRetrieveOutputBuffer(Request,PCI8KPLX_IOCTL_BAR_READ_OUT_SIZE,  // 要求至少能存 EVENT_COUNT 个 ULONG(PVOID*)&pOutBuff,&bufferSize);if (!NT_SUCCESS(status)) {return status;}pOutBuff[0] = ret;WdfRequestSetInformation(Request, (ULONG_PTR)PCI8KPLX_IOCTL_BAR_READ_OUT_SIZE);TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC,"%s:status %x", __FUNCDNAME__, status);return status;
}
/*** 功能:设置FPGA寄存器* 输入:ULONG[0],操作位宽;0对应32位,1对应16位,2对应8位*       ULONG[1],地址;0~255*       ULONG[2],数据* 输出:无*/
NTSTATUS
PCI8KPLX_IOCTL_BAR_WRITE_Handler(_In_ WDFREQUEST Request,_In_ PDEVICE_EXTENSION DevExt
)
{NTSTATUS status = STATUS_SUCCESS;PULONG pBuff = NULL; // 指向输入缓冲区size_t bufferSize = 0;// 1. 获取输入缓冲区 status = WdfRequestRetrieveInputBuffer(Request, PCI8KPLX_IOCTL_BAR_WRITE_IN_SIZE, (PVOID*)&pBuff, &bufferSize);if (!NT_SUCCESS(status)) {return status;}ULONG type = pBuff[0];ULONG addr = pBuff[1];ULONG data = pBuff[2];switch (type){case PORT_RW_32BIT:WRITE_PORT_ULONG((PULONG)(DevExt->addrLocal + addr), data);break;case PORT_RW_16BIT:WRITE_PORT_USHORT((PUSHORT)(DevExt->addrLocal + addr), (USHORT)data);break;case PORT_RW_8BIT:WRITE_PORT_UCHAR((PUCHAR)(DevExt->addrLocal + addr), (UCHAR)data);break;default:return STATUS_INVALID_PARAMETER;}TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC,"%s:status %x", __FUNCDNAME__, status);return status;
}

应用层代码移植,打算尝试直接用 Qoder 修改,看能否成功,下达下面的指令:“zt9054/sys/dll目录下的程序原来是调用sys目录下的驱动,现在改成调用zt9054/sys/sys目录下的驱动,现在要把TK3000_WriteD调用PCI8KPLX_IOCTL_BAR_WRITE,TK3000_ReadD调用PCI8KPLX_IOCTL_BAR_READ实现,请修改zt9054/sys/dll目录下这两个函数的相关代码”

代码加上了,但是所有中文都变成了乱码。接下来为了编码问题又和Qoder斗争了半天,最后总算是搞定,和自己写时间也差不多,但是如果没有编码问题还是会节约不少时间的。
以下是Qoder修改的部分代码

long CZTCARD::WriteD(ULONG cardNO, ULONG nOffset, ULONG dataDoubleWord)
{
//函数名称:
//函数功能:以IO方式,对板卡寄存器进行32位写
//入口参数:
//          baseAddr:板卡基地址
//         nOffset:偏移地址,在硬件说明书上可以查到
//  dataDoubleWord:要写入寄存的值
//返回值:  0  表成功
//         -1  表失败,应该进一步调用 ZT511PF_GetLastErr 判断出错原因CHECK_CARDNO(cardNO); //检查板卡号CHECK_ERRNO; //若用户参数错,不继续执行ULONG inBuffer[3];inBuffer[0] = PORT_RW_32BIT;  // New protocol: specify 32-bit writeinBuffer[1] = nOffset;inBuffer[2] = dataDoubleWord;//  ULONG outBuffer[1];ULONG nOutput;if (!DeviceIoControl(g_ztpciHandle[cardNO-g_baseNO],PCI8KPLX_IOCTL_BAR_WRITE,  // Use new control codeinBuffer,sizeof(inBuffer),NULL,0,&nOutput,NULL)){g_errorLevel = ERR_EXCHANGE_DATA; //与底层驱动之间交换数据出错return -1;}return ZT_SUCCESS;
}

修改启动和停止AD采集对应代码

主要是需要将内核寄存器操作部分移植到应用层,让Qoder仿照我之前写好的中断初始化相关代码,结果他直接把我一个文件大部分代码都删除了,幸亏有git,还得随时盯着才能不出错。
经过多次沟通调整,Qoder 生成的代码仍频繁出错,最后还是我自己修改代码,Qoder反倒是浪费了时间。
最后把通道号缓存变量转移到了dll中:

// AD通道相关全局变量
ULONG g_adEndChCache[MAX_CARD_COUNT + 1];
void SetAdEndChCache(ULONG cardNo, ULONG ulCh) {if (cardNo > MAX_CARD_COUNT)return;g_adEndChCache[cardNo] = ulCh;
}ULONG GetAdEndChCache(ULONG cardNo) {if (cardNo > MAX_CARD_COUNT)return 0;return g_adEndChCache[cardNo];
}

两个核心函数的修改内容如下:

long CROMAD::EnableAD(ULONG cardNO, unsigned long ulCh, unsigned long ulADFreqFlag)
{CHECK_CARDNO(cardNO); //检查板卡号CHECK_ERRNO; //若用户参数错,不继续执行// 设置本地缓存的通道号SetAdEndChCache(cardNO, ulCh);//设置控制字//设置频率// 从本地缓存读取控制字ULONG ulCtrlWord = GetCtrlWord(cardNO); // 使用tk2000.CPP中定义的函数	ulCtrlWord = SET_ULONG_BITS( ulCtrlWord, TK3000_ADFREQ_MASK, TK3000_ADFREQ, ulADFreqFlag );//将设备数据线设成输入状态(D0~D15)ulCtrlWord = SET_ULONG_BITS( ulCtrlWord, TK3000_DIR_MASK, TK3000_DIR, TK3000_D_IN );//将控制字写到本地缓存中SetCtrlWord(cardNO, ulCtrlWord);//实际写AD通道和控制寄存器,AD采集开始WRITED(cardNO, OFF_AD_END_CH, GetAdEndChCache(cardNO)); WRITED(cardNO, OFF_CTRLWORD, (USHORT)(GetCtrlWord(cardNO)));return (g_errorLevel != ZT_SUCCESS) ? -1 : ZT_SUCCESS; //调过别的函数,要重新判断是否出错
}long CROMAD::DisableAD(ULONG cardNO)
{CHECK_CARDNO(cardNO); //检查板卡号CHECK_ERRNO; //若用户参数错,不继续执行//停止AD采集,将频率设成0即可// 从本地缓存读取控制字ULONG ulCtrlWord = GetCtrlWord(cardNO);	ulCtrlWord = SET_ULONG_BITS( ulCtrlWord, TK3000_ADFREQ_MASK, TK3000_ADFREQ, ADFREQ_0 );SetCtrlWord(cardNO, ulCtrlWord);//更新控制字中的通道状态ulCtrlWord = GetCtrlWord(cardNO);ulCtrlWord = SET_ULONG_BITS( ulCtrlWord, TK3000_ADFREQ_MASK, TK3000_ADFREQ, 0 );SetCtrlWord(cardNO, ulCtrlWord);WRITED(cardNO, OFF_CTRLWORD, (USHORT)(GetCtrlWord(cardNO)));return (g_errorLevel != ZT_SUCCESS) ? -1 : ZT_SUCCESS; //调过别的函数,要重新判断是否出错
}
http://www.jsqmd.com/news/293782/

相关文章:

  • 数字孪生应用于特种设备领域的技术难点
  • 2026年1月工程管理系统推荐榜:五大平台深度对比与客观评测
  • 2026年1月工程管理系统推荐排行榜单深度对比评测:聚焦中小企业数字化实践
  • 英语_固定短语
  • 2025新中式高定风潮来袭,加盟这些品牌准没错!评价好的新中式高定服装加盟创业优选品牌推荐与解析
  • 外用贴敷膏厂家直销采购指南排行,外用贴剂/外用贴敷膏/定制化贴敷膏/靶向贴敷膏/中医穴位贴敷/经皮给药贴外用贴敷膏供应商有哪些
  • 京东e卡回收怕被骗?京顺回收带你避开三大陷阱
  • 2026年1月包装机品牌推荐排行榜单:五大品牌客观对比与深度评测分析,
  • 封边机怎么选?三大核心维度 + 需求匹配指南,家具厂避坑必看
  • 2026年1月补水修复面膜品牌推荐与评测榜:医用级与日常修复面膜深度对比分析
  • 基于S7 - 300 PLC和Wincc的三路抢答器控制系统实现
  • 2026年1月补水修复面膜品牌推荐排行榜单:十款产品深度对比与评测
  • 2026年1月补水修复面膜品牌推荐榜:十大品牌深度对比与选购评测指南
  • 2026年1月补水修复面膜品牌推荐榜:十款产品深度对比与选购评测分析
  • 2026年1月补水修复面膜品牌推荐排行榜单:十款产品深度对比与评测分析
  • 2026年性价比高的粮食钢板仓成型设备制造企业排名
  • 2026年深圳GEO源头工厂排名,哪家性价比高?南方网通了解下
  • 一铭教育的教学理念领先吗?天津市内六区教育品牌盘点
  • 讲讲来图定制意大利进口岩板品牌,哪家性价比高
  • 2026年1月补水修复面膜品牌推荐排行榜单:十大品牌深度对比与选购评测
  • 【收藏版】LangGraph智能体开发核心三板斧:3种工作流模式(附完整代码+实战解析)
  • 提升多尺度检测能力:YOLOv8 中 P2 小目标与 P6 超大目标检测头添加方法解析
  • 从零开始玩转边缘 AI:Jetson Nano 深度学习环境搭建与 YOLOv5 部署指南
  • 融合 Dual‑ViT 的 YOLOv5 改进方案:注意力机制带来的性能与效率优化
  • YOLOv13 新思路解析:SFHF + 傅里叶频域特征融合实现 mAP 提升 7.66%
  • YOLOv8 实战进阶:RepNCSPELAN_CAA 模块的集成方法与性能提升分析(mAP +3.3)
  • YOLOv8 中 SEAM 注意力机制的融合方法解析与遮挡场景下的性能分析
  • 从 Transformer 到 Mamba:YOLOv8 中 VSSBlock(MambaLayer)的核心原理解析与结构演进
  • 【柔性作业车间调度】多目标应用:四种多目标优化算法(NSOOA、NSGA2、NSDBO、NSCOA)求解柔性作业车间调度问题(FJSP)研究附Matlab代码
  • 2025年AI超级员工品牌口碑排行分析,AI超级员工/AI员工/AI企业员工/AI智能员工供应商推荐排行