linux嵌入式开发-Zynq开发板配置usb_gadget模拟HID鼠标

这篇具有很好参考价值的文章主要介绍了linux嵌入式开发-Zynq开发板配置usb_gadget模拟HID鼠标。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


前言

本实验基于alinx Zynq 7010开发板。目的是通过usb_slave连接到PC上,让开发板作为一个鼠标从设备接入电脑,并可以通过linux上命令操作移动、点击鼠标等。

一、内核配置

1.petalinux

在PC上使用VMWare,在ubuntu下创建petalinux工程,编译内核,vmware、vivdado、petalinux的安装详见alinx官方教程course4-linux实验中的步骤
创建petalinux工程,在工程目录下打开终端,输入命令准备编译内核

source /opt/pkg/petalinux/settings.sh
source /opt/Xilinx/Vivado/2017.4/settings64.sh

alinx 配置usb,linux嵌入式开发,zynq,linux,计算机外设,运维,python,开发语言
然后编译内核:

petalinux-config -c kernel

alinx 配置usb,linux嵌入式开发,zynq,linux,计算机外设,运维,python,开发语言
进入Devicedrivers -> USB Support,勾选USB Gadget Support(按Y)
alinx 配置usb,linux嵌入式开发,zynq,linux,计算机外设,运维,python,开发语言
进入USB Gadget Support,开启选项如下:
alinx 配置usb,linux嵌入式开发,zynq,linux,计算机外设,运维,python,开发语言
编译内核:

petalinux-build

生成镜像

petalinux-package --boot --fsbl ./images/linux/zynq_fsbl.elf --fpga --u-boot --force

将SD卡插入电脑连接到VMWare虚拟机,把petalinux工程中的images/linux中的BOOT.BIN和image.ub拷入SD卡的FAT分区中即可
alinx 配置usb,linux嵌入式开发,zynq,linux,计算机外设,运维,python,开发语言
将SD卡插入开发板,开机进入linux,检查有无usb_gadget配置项

ls /sys/kernel/config

如果出现usb_gadget,说明配置成功,可以进行后续步骤

2.修改设备树

我在linux上进行ls /sys/class/udc时遇到问题,没有udc,因此又在网上查找资料,重新回去弄了半天,最后发现的解决办法是在devicetree中,把usb0的dr_mode=“host”改为peripheral,该方法来自AMD xilinx论坛,原问题petalinux-20164-usb-failed?
devicetree文件在(petalinux项目名)/project-spec/meta-user/recipes-bsp/device-tree/files里:
alinx 配置usb,linux嵌入式开发,zynq,linux,计算机外设,运维,python,开发语言
修改:
alinx 配置usb,linux嵌入式开发,zynq,linux,计算机外设,运维,python,开发语言

二、鼠标配置

1.创建配置

cd到usb_gadget的目录下

cd /sys/kernel/config/usb_gadget/

使用mkdir方法创建一项配置

mkdir xjs_gadget

进入创建的配置中查看

cd xjs_gadget
ls

可以看到如下结果:
alinx 配置usb,linux嵌入式开发,zynq,linux,计算机外设,运维,python,开发语言

2.配置字符串

字符串是当设备连接到主机上时,主机上显示的设备名称、生产商之类的信息。

以下是需要配置的部分字符串参数及其含义。其中idProduct和Vendor必须是4位十六进制数,如果想要开发的USB设备在连接主机时具有专属名称,可以向USB协会提交申请。如果只是用来测试也可以填我用的这个。而strings下的字符串可以按自己的需要填写。

xjs_gadget
├── idProduct=0xa4ac# 产品id
├── idVendor =0x03FD# 产品厂商id
└── strings  # 用于主机显示的相关文本
	└── 0x409# 语言标识符(EN)
		├── manufacturer ="flyingrt" #生产商名称
        ├── product      ="flyingrt_mouse"   #产品名称
        └── serialnumber ="0001"       #产品序列号

我的命令如下:

echo "0x03FD" > idVendor
echo "0xa4ac" > idProduct
mkdir strings/0x409
echo "flyingrtx" > strings/0x409/manufacturer 
echo "0001" > strings/0x409/serialnumber 

3.配置功能项functions

USB Gadget通过function配置实际的功能。每个function由protocol、subclass、report_desc、report_length这四项组成1。同一个USB Gadget可以通过一条线同时支持多个function(例如同时模拟鼠标和键盘)
首先建立功能项:

mkdir functions/hid.ms

使用ls查看,可以看到下面目录:
alinx 配置usb,linux嵌入式开发,zynq,linux,计算机外设,运维,python,开发语言

protocol

protocol指定HID设备使用的协议,对于键盘设备其值为1,鼠标设备其值为2。subclass指定子类。

report_desc

USB-IF官网
USB-IF官网提供了HID description Tool可以编辑和生成描述符文件,并且附带了许多常见设备的示例。下载其网站提供的工具dt2_4.zip
alinx 配置usb,linux嵌入式开发,zynq,linux,计算机外设,运维,python,开发语言
解压后运行Dt.exe
选择file -> open ,打开其提供的mouse文件,即可查看:
alinx 配置usb,linux嵌入式开发,zynq,linux,计算机外设,运维,python,开发语言
可以使用file -> save as 保存为一个txt文件
我这里通过下面这段c代码向report_desc和report_length中写入二进制数据

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#define REPORT_DESC_SIZE 50

int main() {
    int fd;
    char *device = "/sys/kernel/config/usb_gadget/xjs_gadget/functions/hid.ms/report_desc";
    char report_desc[REPORT_DESC_SIZE];

    // 鼠标报告描述,这是一个示例,请根据你的设备规范修改
    unsigned char mouse_report_desc[] = {
        0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
        0x09, 0x02,        // Usage (Mouse)
        0xa1, 0x01,        // Collection (Application)
        0x09, 0x01,        //   Usage (Pointer)
        0xa1, 0x00,        //   Collection (Physical)
        0x05, 0x09,        //     Usage Page (Button)
        0x19, 0x01,        //     Usage Minimum (0x01)
        0x29, 0x03,        //     Usage Maximum (0x03)
        0x15, 0x00,        //     Logical Minimum (0)
        0x25, 0x01,        //     Logical Maximum (1)
        0x95, 0x03,        //     Report Count (3)
        0x75, 0x01,        //     Report Size (1)
        0x81, 0x02,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
        0x95, 0x01,        //     Report Count (1)
        0x75, 0x05,        //     Report Size (5)
        0x81, 0x03,        //     Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
        0x05, 0x01,        //     Usage Page (Generic Desktop Ctrls)
        0x09, 0x30,        //     Usage (X)
        0x09, 0x31,        //     Usage (Y)
        0x09, 0x38,        //     Usage (Wheel)
        0x15, 0x81,        //     Logical Minimum (-127)
        0x25, 0x7f,        //     Logical Maximum (127)
        0x75, 0x08,        //     Report Size (8)
        0x95, 0x03,        //     Report Count (3)
        0x81, 0x06,        //     Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
        0xc0,              //   End Collection
        0xc0               // End Collection
    };

    // 打开报告描述文件
    fd = open(device, O_WRONLY);
    if (fd < 0) {
        perror("Unable to open report_desc file");
        return 1;
    }

    // 将鼠标报告描述写入文件
    int desc_size = sizeof(mouse_report_desc);
    int res = write(fd, mouse_report_desc, desc_size);
    if (res < 0) {
        perror("Error writing report_desc file");
        close(fd);
        return 1;
    }

    // 关闭文件
    close(fd);

    // 设置报告描述长度
    fd = open("/sys/kernel/config/usb_gadget/xjs_gadget/functions/hid.ms/report_length", O_WRONLY);
    if (fd < 0) {
        perror("Unable to open report_length file");
        return 1;
    }

    // 将报告描述长度写入文件
    char length_str[10];
    snprintf(length_str, sizeof(length_str), "%d", desc_size);
    res = write(fd, length_str, strlen(length_str));
    if (res < 0) {
        perror("Error writing report_length file");
        close(fd);
        return 1;
    }

    // 关闭文件
    close(fd);

    return 0;
}

首先新建一个.c文件,将上面代码拷入其中

nano gen.c

然后编译c文件

gcc gen.c -o gen

最后运行

./gen

还需要写入protocol

echo "2" > functions/hid.ms/protocol

4.配置config

在configs目录下可以通过mkdir $configName创建Gadget的一个配置目录,名称可自定义。

mkdir c.1
root@zynq:/sys/kernel/config/usb_gadget/xjs_gadget/configs# cd c.1
root@zynq:/sys/kernel/config/usb_gadget/xjs_gadget/configs/c.1# ls

可以看到如下结果:
alinx 配置usb,linux嵌入式开发,zynq,linux,计算机外设,运维,python,开发语言
配置信息及其目录结构如下,其中string也是支持多语言的字符串。

configs
└── ${configName}
	├──MaxPower=120 #最大电流,120mA
    └── strings
        └── 0x409
        	└── configuration "config1" #配置描述字符串
echo "120" > configs/c.1/MaxPower 
mkdir  configs/c.1/strings/0x409
echo "this is conf" > configs/c.1/strings/0x409/configuration 

然后对于每个需要启用的function创建软链接,将配置的functions链接到当前使用的config,这样才能使用其功能:

ln -s functions/hid.ms/ configs/c.1/

5.启用Gadget

这里需要用到udc,通过下面命令查看当前有多少个udc。我遇到的问题见内核配置。

ls /sys/class/udc

写入UDC即可开启运行。

echo ci_hdrc.0 >UDC

6.查看结果

ls /dev/hid*

7.一键脚本

由于基于configs的配置,在系统重启后就会重置,所以可以把这些写成一个脚本,每次开机运行后就可以激活hid鼠标

nano start_mouse.sh

脚本内容如下,即上述所有操作:

#!/bin/bash

cd /sys/kernel/config/usb_gadget/
mkdir xjs_gadget
cd xjs_gadget/
echo "0x03FD" > idVendor
echo "0xa4ac" > idProduct
mkdir strings/0x409
echo "flyingrtx" > strings/0x409/manufacturer 
echo "0001" > strings/0x409/serialnumber 
mkdir functions/hid.ms
echo "2" > functions/hid.ms/protocol 
echo "3" > functions/hid.ms/report_length 
mkdir configs/c.1
echo "120" > configs/c.1/MaxPower 
mkdir  configs/c.1/strings/0x409
echo "this is conf" > configs/c.1/strings/0x409/configuration
cd /home
./gen
cd /sys/kernel/config/usb_gadget/xjs_gadget/
cd /sys/kernel/config/usb_gadget/xjs_gadget/
ln -s functions/hid.ms/ configs/c.1/
echo ci_hdrc.0 >UDC
ls /dev/hid*
chmod 666 /dev/hidg0
cd /home

8.连接电脑

使用usb_slave口连接电脑,设备管理器中应当可以看到一个hid鼠标出现
alinx 配置usb,linux嵌入式开发,zynq,linux,计算机外设,运维,python,开发语言

三、操作鼠标

我们通过往/dev/hidg0文件中写入二进制数据实现鼠标操作
鼠标发送给PC的数据每次4个字节
BYTE1 BYTE2 BYTE3 BYTE4
定义分别是:
BYTE1 –

   |--bit7:   1   表示   Y   坐标的变化量超出-256   ~   255的范围,0表示没有溢出  
   |--bit6:   1   表示   X   坐标的变化量超出-256   ~   255的范围,0表示没有溢出  
   |--bit5:   Y   坐标变化的符号位,1表示负数,即鼠标向下移动  
   |--bit4:   X   坐标变化的符号位,1表示负数,即鼠标向左移动  
   |--bit3:     恒为1  
   |--bit2:     1表示中键按下  
   |--bit1:     1表示右键按下  
   |--bit0:     1表示左键按下  

BYTE2 – X坐标变化量,与byte的bit4组成9位符号数,负数表示向左移,正数表右移。用补码表示变化量
BYTE3 – Y坐标变化量,与byte的bit5组成9位符号数,负数表示向下移,正数表上移。用补码表示变化量
BYTE4 – 滚轮变化。
可以这样调试:

echo -e -n "\x02\xa0\x00\x00" > /dev/hidg0  # 第一个00000010右键按下,x移动
echo -e -n "\x00\xa0\x00\x00" > /dev/hidg0  # 仅x移动,byte1 00000000无操作,从而释放右键,完成一次右击

对于坐标移动,当其最高位为1时,向负方向移动
例如下面两个x坐标的移动数值:

00001000 "\x08\xd0\x00\x00" \xd0是1101 0000,鼠标左移, 不点击,不滚轮
00001000 "\x08\x50\x00\x00" \x50是0101 0000,鼠标右移, 不点击,不滚轮

使用python进行写入hidg0的操作:

data = b"\x02\xa0\x00\x00"

with open('/dev/hidg0', 'wb') as f:
    f.write(data)

data = b"\x00\xa0\x00\x00"

with open('/dev/hidg0', 'wb') as f:
    f.write(data)

此时应该可以看到电脑上的鼠标向左移动,并且点击了一次右键

四、鼠标操作封装

1.使用C语言进行封装

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
uint8_t byte1(int mid, int left, int right) {
    uint8_t result = 0x00;
    if (left) {
        result += 0x01;
    }
    if (right) {
        result += 0x02;
    }
    if (mid) {
        result += 0x04;
    }
    return result;
}

int8_t byte2(int x) {
    if (x >= 128) {
        x = 127;
    }
    else if (x <= -128) {
        x = -127;
    }
    return (int8_t)x;
}

int8_t byte3(int y) {
    if (y >= 128) {
        y = 127;
    }
    else if (y <= -128) {
        y = -127;
    }
    return (int8_t)y;
}


void data_gen(int x, int y, int left, int mid, int right, uint8_t* result) {
    result[0] = byte1(mid, left, right);
    result[1] = byte2(x);
    result[2] = byte3(y);
    result[3] = 0x00;
}

int main(int argc, char* argv[]) {

    int x = 0, y = 0, left = 0, mid = 0, right = 0;

    if (argc > 1) {
        x = atoi(argv[1]);
    }
    if (argc > 2) {
        y = atoi(argv[2]);
    }
    if (argc > 3) {
        left = atoi(argv[3]);
    }

    uint8_t result[4];

    data_gen(x, y, left, mid, right, result);

    FILE* filePointer;

    filePointer = fopen("/dev/hidg0", "wb");

    if (filePointer == NULL) {
        printf("无法打开文件或创建文件。\n");
        return 1;
    }
    fwrite(result, sizeof(uint8_t), sizeof(result), filePointer);

    // 关闭文件
    fclose(filePointer);

    return 0;
}

这段代码实现的意思是move x y left(是否点击左键, 1点击, 0不点击),默认0,0,0
使用示例:

g++ move.cpp -o move  # 编译
./move 50 0  # 鼠标左移50,y轴不移动,不点左键

总结

通过上述操作,可以实现一个简易的鼠标操作。后续会进行更加完善的python操作封装。文章来源地址https://www.toymoban.com/news/detail-762270.html

到了这里,关于linux嵌入式开发-Zynq开发板配置usb_gadget模拟HID鼠标的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 嵌入式开发:单片机嵌入式Linux学习路径

    SOC(System on a Chip)的本质区别在于架构和功能。低端SOC如基于Cortex-M架构的芯片,如STM32和NXP LPC1xxx系列,不具备MMU(Memory Management Unit),适用于轻量级实时操作系统如uCOS和FreeRTOS。高端SOC如基于Cortex-A架构的芯片,如三星、高通、飞卡、全志和瑞芯微等,具备MMU,支持虚拟内

    2024年02月15日
    浏览(37)
  • 嵌入式Linux开发教程汇总

    野火:https://doc.embedfire.com/products/link/zh/latest/linux/index.html 正点原子:http://47.111.11.73/docs/boards/arm-linux/index.html 百问网:http://download.100ask.net/books/Linux/ELADCM1/index.html 百问网:https://space.bilibili.com/275908810/channel/seriesdetail?sid=1714177 野火:https://space.bilibili.com/356820657/channel/seriesdeta

    2024年02月10日
    浏览(44)
  • 嵌入式Linux开发-USB驱动

    哥们马上就要被裁了,总得整理一下技术方面的积累,准备开始下一轮的面试和找工作之旅了。。。。 通用串行总线(USB)是主机和外围设备之间的一种连接。 从拓扑上来看,是一颗由几个点对点的连接构建而成的树。这些连接是连接设备和集线器(hub)的四线电缆(底线、电源线

    2024年02月20日
    浏览(56)
  • 嵌入式开发之linux内核移植

    目录  前言 一、下载内核源码 1.1 下载linux-3.0.1 1.2 解压源码文件 二、 内核添加yaffs2文件系统支持 2.1 下载yaffs2 2.2 内核添加yaffs2文件补丁 三、配置开发板 3.1 修改机器ID 3.2 添加开发板初始化文件 3.3 配置NandFalsh 3.3.1 添加NandFlash设备 3.3.2 添加NandFlash驱动 3.3 修改Kconfig(支持

    2024年02月07日
    浏览(78)
  • 嵌入式Linux驱动开发之点灯

      使用驱动开发的方式点亮一个LED灯。看看两者有啥区别不? 首先查看原理图,看看我们的板子上的LED等接在哪一个IO口上面。 好了,看原理图我们知道LED灯接在芯片的GPIO1的第三个引脚上面,也就是GPIO1_IO03。 先掌握三个名词 CCM: Clock Controller Module (时钟控制模块) IOMUXC : I

    2024年02月01日
    浏览(84)
  • 嵌入式Linux应用开发笔记:串口

    串口(UART)是嵌入式设备中比较常用的功能。这篇文章将记录下应用程序中串口操作相关内容。 这篇文章中内容均在下面的开发板上进行测试: 《新唐NUC980使用记录:自制开发板(基于NUC980DK61YC)》 这篇文章是在下面文章基础上进行的: 《新唐NUC980使用记录(5.10.y内核)

    2024年02月09日
    浏览(35)
  • 嵌入式Linux驱动开发——常见框架梳理

    本文主要介绍了Linux驱动开发中一些常用的驱动框架,platform、input、iic、spi等,硬件平台使用的是正点原子的imx6ull开发板。 不管什么框架最后都是要追溯到配置IO的电气属性和复用功能 如果要使用外部中断,设备树节点中还需添加相关信息,什么边沿触发 1:module_init和mod

    2024年02月15日
    浏览(52)
  • 嵌入式Linux开发实操(八):UART串口开发

    串口可以说是非常好用的一个接口,它同USB、CAN、I2C、SPI等接口一样,为SOC/MCU构建了丰富的接口功能。那么在嵌入式linux中又是如何搭建和使用UART接口的呢? 一、Console接口即ttyS0 ttyS0通常做为u-boot(bootloader的一种,像是Windows的BIOS),它需要一个交互界面,一般使用ttyS0,即可

    2024年02月12日
    浏览(29)
  • 嵌入式Linux驱动开发系列六:Makefile

    Makefile是什么? gcc hello.c -o hello gcc aa.c bb.c cc.c dd.c ... make工具和Makefile make和Makefile是什么关系? make工具:找出修改过的文件,根据依赖关系,找出受影响的相关文件,最后按照规则单独编译这些文件。 Makefile文件:记录依赖关系和编译规则。 必须要学精Makefile吗? 怎么学习Makefi

    2024年02月13日
    浏览(46)
  • 嵌入式开发--电子钢琴项目(Linux+C开发)附上源码

    复盘一下之前做的一个小项目,温习一下c语言和Linux的知识,唔,就是这样子。 所用软件以及工具如下: 1、VMware-workstation-full搭配Ubuntu18.04的Linux操作系统,VMware是桌面虚拟计算机软件,提供用户可在单一的桌面上同时运行不同的操作系统和进行开发、测试 、部署新的应用程

    2024年02月08日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包