0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Linux系统下对硬件寄存器调试的应用设计研究

麦克泰技术 来源:嵌入式系统专家之声 2024-03-12 13:59 次阅读

0 引言

嵌入式系统广泛应用于生活中的各行各业,嵌入式硬件复杂度也在不断增加,嵌入式系统开发与维护变得越来越复杂,然而嵌入式系统的开发与维护工具发展相对很滞后。为了提高嵌入式系统开发与维护的效率,发展嵌入式开发与维护工具是非常重要的。通过基于 Qt 平台开发各种开发维护工具,实现嵌入式开发与维护的平台化,是当前嵌入式开发和维护的趋势[1-2]。当一款新的设备出厂之后,后期维护成了人们越来越关注的问题,为了延长设备使用周期,节约生产成本,使设备创造更大的价值,设备的操作与维护越来越受到人们的重视。

每当设备出现问题之后,就会调试底层驱动,这时可能需要调整寄存器的设置。面对这个问题,当前国内外开发与维护人员的通常做法是直接在程序里面修改硬件寄存器的数据,然后重新编译程序,下载到设备,以此来检验设备运行情况[3-4]。但是这种方法比较麻烦,效率低下,不利于维护。为了提高开发人员开发和维护设备的效率,需要设计一个可视化工具,从而可以直接方便地对硬件内部寄存器进行修改与调试。这个工具拥有图形化界面,可以直接读写下位机硬件寄存器的数值,首先输入硬件寄存器要传入的物理地址(这个物理地址可以通过芯片手册确定,在驱动程序里面要通过映射为虚拟地址才能使用),然后根据要求来读写下位机任意硬件寄存器的数值。

1 系统设计框架

该系统采用嵌入式Linux操作系统作为开发的核心,包括三部分,分别为客户端图形化界面、服务器端和硬件设备。客户端用来与用户进行交互,如输入下位机硬件寄存器地址和数据,服务器端用来接收上位机客户端用户传来的数据或者向客户端发送数据,底层驱动用来操作硬件设备内部寄存器的数值。本系统采用Linux 网络通信的方式连接上位机和下位机,使交互更加方便和高效。整个系统框架如图1所示。

a3800a6a-e023-11ee-a297-92fbcf53809c.png

图1系统框架

2 Linux 网络通信设计

该网络通信系统包括服务器端和客户端两个部分。服务器端实现对数据的采集和发送,以及通过TCP协议进行网络传输;客户端主要是接收服务器传输过来的数据并进行图形化显示。服务器端和客户端使用 TCP协议进行网络通信的具体流程图如图2所示。

a3b41b84-e023-11ee-a297-92fbcf53809c.png

图2TCP网络通信流程图

客户端和服务器端的交互过程如下:服务器端先初始化socket,分配文件描述符;然后调用bind() 将套接字与本地IP地址和端口绑定;接着调用listen()对端口进行监听,并设置监听队列的大小;继续调用accept()阻塞,等待客户端连接[5]。如果有客户端初始化一个socket()后调用connect()向服务器端发送连接请求,若经过三次握手,则连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后调用close() 关闭连接,一次交互结束。

2.1服务器端设计

服务器端通过三次握手与客户端建立连接之后,将驱动端映射到内核空间的数据读取出来并且发送到客户端,或者将客户端要发送的数据接收到服务器端并发送给驱动端。

下位机服务器端的部分程序如下:

while(1){

//服务器阻塞,直到获得连接请求并建立连接

int socklis=accept(sock,(struct sockaddr *)&.clientAddr,

&.len);

if(socklis<0){

perror("accept")

exit(1);

}

While(1){// 清空数组

memset(buff,0,1024);

//从客户端接收数据

n=recv(socklis,buff,1024,0);

if(n<0){

perror("recv");

return—1

}

msgtype=*(unsigned int *)buff;

switch(msgtype){

case REGISTER_CTRL:{

structregister_ctrlregmsg;

structregister_info reg;

//内存拷贝

memcpy(&.regmsg,buff,sizeof(regmsg));

reg.addr=regmsg.addr;

reg.data=regmsg.data;

if(regmsg.cmd==1){

ioctl(fd_reg,REG_READ,);

printf("read reg:addr=%#x,data=%#x ",reg.

addr,reg.data);

//发送数据到客户端

send(socklis,&.reg,sizeof(reg),0);

}else if(regmsg.cmd==0){

printf("write reg:addr=%#x,data =%#x ",reg.addr,

reg.data);

ioctl(fd_reg,REG_WRITE,&.reg);

}

break;

}

}

}

}

2.2客户端设计

为了满足人性化要求,本文设计了一个Qt客户端图形化界面,从而方便用户操作和读写数据。Qt是一个跨平台的C++图形用户界面应用程序框架,由挪威Troll- Tech公司出品,目前包括 QtCreator、Qt Embedded、Qt Designer等快速开发工具[6]。其中 Qt Creator是一个全新的、完整的、轻量级的图形开发平台,它可以按照设计人员的意愿建立图形用户界面,随时进行显示和修改,具有良好的适应性,保证了不同平台之间设计的兼容性[7]。

在客户端图形化界面中,首先设计一个“寄存器地址”输入框,用来输入用户需要操作的下位机寄存器物理地址;然后设计一个“寄存器数据”输入框,用来显示从下位机读取的存储在该寄存器里面的数据,或者向下位机发送用户需要写入到该寄存器中的数据;接着在旁边设计一个“读”数据复选框和一个“写”数据复选框,用来发送“读”或者“写”命令;最后在界面下端设计一个“确定”按钮,来确认需要执行的操作。Qt图形化界面如图3所示。该界面清晰明确、步骤简单、操作方便、简洁高效,大大缩短了用户查看和编辑下位机设备硬件寄存器中数据的时间,提高了用户调试和维护设备的效率。

a3d72fac-e023-11ee-a297-92fbcf53809c.png

图3Qt图形化界面

在Qt中通过使用Linux系统调用中的 TCP协议实现客户端与服务器端的连接,并进行数据读取、发送以及显示,按下“确定”按钮,建立网络通信,开始进行数据的读取、发送和显示。

上位机客户端部分应用程序如下:

void MainWindow::on_send_clicked(){

struetregister_ctrlreg;

structregister_inforeg_rsp;

reg.msgtype=REGISTERCTRL;

reg.addr=ui->addr->text().toUInt(NULL,16);

reg.data=ui->data->text().toUInt(NULL,16);

if(ui->read->isChecked()){

reg.cmd=1;

qDebug("read");

}

if(ui->write->isChecked()){

reg.cmd=0;

qDebug("write");

}

//发送数据到服务器端

send(m_fd_client,&.reg,sizeof(reg),0);

if(reg.cmd ==1){

//从服务器端接收数据

recv(m_fd_client,&.reg_rsp,sizeof(reg_rsp),0);

ui->data->setText(QString::number(reg_rsp.data,

16)):

}

}

3 底层驱动端设计

系统在运行时,外设的I/O内存资源的物理地址是已知的,由硬件设计决定,但是 CPU 通常并没有为这些已知的外设I/O内存资源物理地址预定义虚拟地址范围,驱动程序并不能直接通过物理地址访问I/O内存资源,而必须将它们映射到核心虚地址空间内(通过页表),然后根据映射所得到的核心虚拟地址范围通过访内指令访问这些I/O内存资源[8]。

嵌入式处理器访问外设都是以地址指针的形式访问,也就是说要想访问外设,必须知道这个外设的物理地址。在Linux系统中,不管是在用户空间还是内核空间,一律不允许直接访问外设的物理地址,要想访问需要提前将物理地址映射到内核虚拟地址或者用户虚拟地址上,将来程序访问用户虚拟地址或者内核虚拟地址就是在访问物理地址[9]。将Linux系统4G虚拟地址空间划分如下,用户虚拟地址为0x00000000~0xBFFF FFFF(0G~3G),内核虚拟地址为0xC0000000~0xFFFF FFFF(3G~4G)[10]。一个物理地址可以有多个虚拟地址,一个虚拟地址不能对应多个物理地址。如果要将物理地址映射到内核虚拟地址上,可以使用ioremap()函数;若要解除地址映射,可以使用iounmap() 函数。Linux地址映射机制如图4所示。

a3eda43a-e023-11ee-a297-92fbcf53809c.png

图4Linux 地址映射机制

驱动端部分程序如下:

staticlongreg_ioctl(structfile*file,unsignedintemd,unsigneclongarg){

//定义内核缓冲区

structreg_infokreg;

unsignedlong*gpiobase;

//拷贝用户缓冲区到内核

copy_to_user((structreg_info *)arg,&kreg,sizeof

(kreg));

//将外设的物理地址映射到内核虚拟地址上

gpiobase=ioremap(kreg.addr,4);

//解析命令,操作硬件

switch(cmd){

case REG_READ:

kreg.data=*gpiobase;

copy_to_user((structreg_info *)arg,&kreg,sizeof

(kreg));

break;

case REG_WRITE:

*gpiobase=kreg.data;

break;

}

//解除地址映射

iounmap(gpiobase);

return0;

}

4 实验结果

本系统使用基于Cortex-A53架构处理器的S5P6818开发板上面的点阵LED灯来验证实验结果。首先在下位机运行Linux系统,点亮第一个LED灯,将第二个和第三个LED灯关闭。然后查看芯片手册,将物理地址为0xC001C000的32位寄存器的bit[12]、设为低电平,bit[11]和bit[7]设为高电平。对此,向该寄存器写入数据0x880,并选中右边的“写”复选框,点击“确认”按钮(如图5所示)后,发现开发板第一个LED灯被点亮,验证成立,如图6所示。接着选中右边的“读”复选框,再次点击“确认”按钮,发现寄存器数据显示为0x880(如图7所示),因为读取的正是刚才写入到该寄存器的数值。

a3f863e8-e023-11ee-a297-92fbcf53809c.png

图5向寄存器写数据

a3fc3a86-e023-11ee-a297-92fbcf53809c.png

图6点阵LED被点亮

a40f6f48-e023-11ee-a297-92fbcf53809c.png

图7 从寄存器读数据

结语

本文所设计的寄存器读写器工具,只需知道设备的硬件寄存器物理地址就能快速准确地读写任意硬件寄存器的数值,操作简单方便,快速高效,为设备操作与维护提供了一种有效的解决方案。特别是当系统逻辑比较复杂时,图形化界面的调试工具可以大大节省用户发现问题的时间,能够让用户方便快速地处理设备中出现的各种问题,从而更好地维护产品和设备。




审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式
    +关注

    关注

    4983

    文章

    18291

    浏览量

    288566
  • 寄存器
    +关注

    关注

    30

    文章

    5036

    浏览量

    117762
  • Linux系统
    +关注

    关注

    4

    文章

    567

    浏览量

    26923
  • 上位机
    +关注

    关注

    26

    文章

    861

    浏览量

    54049
  • TCP通信
    +关注

    关注

    0

    文章

    145

    浏览量

    4138

原文标题:Linux 系统下对硬件寄存器调试的应用研究

文章出处:【微信号:麦克泰技术,微信公众号:麦克泰技术】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    如何根据自己设计中的寄存器配置总线定义来生成一套寄存器配置模版

    无论是FPGA还是ASIC,系统设计中总会存在配置寄存器总线的使用,我们会将各种功能、调试寄存器挂载在寄存器总线上使用。
    的头像 发表于 03-04 13:56 402次阅读
    如何根据自己设计中的<b class='flag-5'>寄存器</b>配置总线定义来生成一套<b class='flag-5'>寄存器</b>配置模版

    linux寄存器概念

    linux寄存器简介
    发表于 05-11 14:33

    Hyp调试控制寄存器配置

    是:一个 Banked EL2 寄存器。在架构上映射到 AArch64 MDCR_EL2 寄存器。属性请参阅 表 4-85 c1 寄存器摘要中的寄存器摘要。下图显示了 HDCR 位分
    发表于 06-08 18:04

    简单研究一下Armv8-A的AArch64寄存器

    的指令系统主要是寄存器-寄存器型。说了这么多,就是想强调一在Armv8-A中寄存器的重要性。在AArch64应用级角度,一个PE(Proc
    发表于 09-20 14:54

    寄存器与移位寄存器

    寄存器与移位寄存器 寄存器是用来寄存数码的逻辑部件,所以必须具备接收和寄存数码的功能。任何一种触发器都可以构成
    发表于 03-12 15:19 59次下载

    寄存器,寄存器是什么意思

    寄存器,寄存器是什么意思 寄存器定义  寄存器是中央处理器内的组成部分。寄存器是有限存贮容量的高速存贮部件,它们可用
    发表于 03-08 14:26 2.1w次阅读

    数据寄存器,数据寄存器是什么意思

    数据寄存器,数据寄存器是什么意思 数据寄存器数据寄存器包括累加器AX、基址寄存器BX、计数寄存器
    发表于 03-08 14:38 1.2w次阅读

    32位寄存器,32位寄存器是什么意思

    32位寄存器,32位寄存器是什么意思  从X8086开始学了一年,第一个ASM的程序就是变32换16进制的程序,不过现在叫我从新开始写ASM程
    发表于 03-08 17:26 1.7w次阅读

    寄存器与移位寄存器

    寄存器与移位寄存器:介绍寄存器原理和移位寄存器的原理及实现。
    发表于 05-20 11:47 0次下载

    微控制器的寄存器调试

      嵌入式系统的软件调试通常侧重于代码执行、存储器的值、堆栈指针、中断时间和寄存器的值。在这篇文章中,我们将向你展示如何使用ARM版的IAREmbeddedWorkbench调试
    发表于 09-20 17:24 5次下载
    微控制器的<b class='flag-5'>寄存器</b>的<b class='flag-5'>调试</b>

    开发一个Linux调试器就必须要知道寄存器和内存!

    在我们正真的读取寄存器前,调试器需要知道一些关于x8664架构的相关知识。包括通用寄存器,专用寄存器以及浮点寄存器和向量
    发表于 05-14 17:28 1367次阅读

    新版IAR调试查看寄存器问题 STM8代码大小优化问题

    新版IAR调试查看寄存器问题、STM8代码大小优化问题
    的头像 发表于 03-07 16:13 3342次阅读

    深度学习_硬件知识_上拉寄存器与下拉寄存器

    上拉寄存器上拉寄存器是控制对应端口上拉使能的。当对应位为0时,设置对应引脚上拉使能,对应位为1时,禁止对应引脚上拉使能。如果上拉寄存器使能,无论引脚功能寄存器如何设置(输入、输出、数据
    发表于 01-14 14:31 10次下载
    深度学习_<b class='flag-5'>硬件</b>知识_上拉<b class='flag-5'>寄存器</b>与下拉<b class='flag-5'>寄存器</b>

    Linux应用层操作寄存器

    --- > [*] /dev/mem virtual device support Linux应用层操作寄存器 除了直接使用devmem,我们也可以在Linux应用层自己实现一个devmem
    的头像 发表于 10-08 15:16 588次阅读
    <b class='flag-5'>Linux</b>应用层操作<b class='flag-5'>寄存器</b>

    arm三个寄存器在gdb调试时的作用

    arm三个寄存器在gdb调试时作用  ARM是一种广泛使用的微处理器架构,它广泛应用于移动设备、嵌入式系统和其他高性能计算设备。当我们在使用gdb(GNU调试器)
    的头像 发表于 01-31 10:44 214次阅读