28388_USB

1. 如何找到libusb源码

仅供参考
找到该路径:C:\ti\c2000\C2000Ware_3_03_00_00\libraries\communications\usb\f2838x\source
在这里插入图片描述

2. C2000_Ware中的usb_ex4_dev_bulk例程

例程中代码开头有介绍一个调试上位机软件,如图所示:
在这里插入图片描述

3. 使用LIBUSB来安装驱动

4. 28388中的USB接口的硬件位置

在这里插入图片描述

5. USB_C++ HID设备上位机源码:

// ConsoleApplication2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include<Windows.h>
#include<setupapi.h>
#include<hidsdi.h>
#include <initguid.h>
using namespace std;
BOOL find_device(uint32_t PID, uint32_t VID);
HANDLE userHidFileHandle;
int main()
{
    BOOL isReadFile = false;
    uint8_t readbuf[3];
    DWORD numberOfBytesRead;
    cout << "*****************User Hid Device Software!*****************\n";
    if (find_device(0x0001, 0x1cbe)) {
        while (true) {
            Sleep(1);
            isReadFile =  ReadFile(userHidFileHandle,
                readbuf,3,
                &numberOfBytesRead,
                NULL
                );
            if (isReadFile) {
                cout << "numberOfBytesRead:" << numberOfBytesRead;
                for (int i = 0; i < numberOfBytesRead;i++) {
                    cout << "   0x:" << hex << (uint32_t)readbuf[i] << endl;
                }
            }
        }
    }
    else {
        cout << "你没了" << endl;
    }

}
void show_guid(LPGUID HidGuid) {
    cout << hex << HidGuid->Data1 << "-";
    cout << hex << HidGuid->Data2 << "-";
    cout << hex << HidGuid->Data3 << "-";

    for (int i = 0; i < 8;  i++) {
        cout << hex << (uint32_t)(HidGuid->Data4[i]);
    }
    cout << endl;
}
BOOL find_device(uint32_t PID,uint32_t VID) {
    BOOL isFind = false;
    GUID hid_guid;
    
    
    HDEVINFO device_info;
    uint32_t deviceIndex = 0;
    SP_DEVICE_INTERFACE_DATA device_interface_data;
    BOOL isGetDeviceInterfaces = false;
    BOOL isGetDeviceInterfaceDetail = false;
    DWORD requiredSize = 0;
    PSP_DEVICE_INTERFACE_DETAIL_DATA p_device_interface_detail_data;
    HANDLE fileHandle;
    BOOL isGetAttributes = false;
    HIDD_ATTRIBUTES hid_attribute;


    HidD_GetHidGuid(&hid_guid);
    show_guid(&hid_guid);

    device_info = SetupDiGetClassDevs(
        &hid_guid,
        NULL,
        NULL,
        DIGCF_INTERFACEDEVICE | DIGCF_PRESENT
    );

    do {
        device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
        isGetDeviceInterfaces = SetupDiEnumDeviceInterfaces(
            device_info,
            NULL,
            &hid_guid,
            deviceIndex,
            &device_interface_data);
        deviceIndex++;
        if (isGetDeviceInterfaces) {
            cout << "GetDviceInterface success" << endl;
            //获取 requiredSize
            SetupDiGetDeviceInterfaceDetail(
                device_info,
                &device_interface_data,
                NULL,
                0,
                &requiredSize,
                NULL
            );
            p_device_interface_detail_data = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(requiredSize);
            p_device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

            isGetDeviceInterfaceDetail = SetupDiGetDeviceInterfaceDetail(
                device_info,
                &device_interface_data,
                p_device_interface_detail_data,
                requiredSize,
                NULL,
                NULL
            );
            if (isGetDeviceInterfaceDetail) {
                cout << "GetDeviceInterfaceDetail success" << endl;
                fileHandle = CreateFile(p_device_interface_detail_data->DevicePath,
                    GENERIC_READ | GENERIC_WRITE,
                    FILE_SHARE_READ | FILE_SHARE_WRITE,
                    NULL,
                    OPEN_EXISTING,
                    FILE_ATTRIBUTE_NORMAL,
                    NULL
                    );

                //键盘鼠标是会打开ERROR的,只有我们自定义的HID设备可以打开成功
                if (fileHandle == INVALID_HANDLE_VALUE) {
                    cout << "CreateFile ERROR" << endl;
                }
                else {
                    cout << "CreateFile SUCCESS" << endl;
                    isGetAttributes = HidD_GetAttributes(fileHandle,&hid_attribute);
                    if (isGetAttributes) {
                        cout << "PID: 0x" << hex << hid_attribute.ProductID << endl;
                        cout << "VID: 0x" << hex << hid_attribute.VendorID << endl;
                        if (hid_attribute.ProductID == PID && hid_attribute.VendorID == VID) {
                            userHidFileHandle = fileHandle;
                            
                            return true;
                        }
                    }
                }
            }
            else {
                cout << "GetDeviceInterfaceDetail fail" << endl;
            }

            cout << "requiredSize is: " << requiredSize << endl;
        }
        else {
            cout << "GetDviceInterface fail" << endl;
        }

    } while (isGetDeviceInterfaces);
    

    return isFind;
}





















// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门使用技巧: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件

6. USB数据收发调试过程

  1. 关闭BitLocker功能(自行百度)
    在这里插入图片描述
  2. 禁止驱动程序强制签名(自行百度)
  3. 通过libusb安装bulk device(USB设备)的驱动(自行百度)
    在这里插入图片描述
  4. 通过上位机与28388进行调试
    NOTE: 28388使用的例程为:usb_ex4_dev_bulk
    在这里插入图片描述

7. 与普通USB设备通信上位机源码:

参考b站视频:基于STM32的高速USB开发视频教程——手把手教你玩开发

// USB_HSPeed_device.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include "lusb0_usb.h"
#include <time.h>
#define WRITE_DATA_SIZE 4096     //实际可用
#define READ_DATA_SIZE 4096      //实际可用
#define DEBUG_ENABLE FALSE


using namespace std;
BOOL find_my_device(UINT32 PID, UINT32 VID);
usb_dev_handle* my_device;
char receviceBytes1[12];
char receviceBytes2[READ_DATA_SIZE];
char writeBytes[WRITE_DATA_SIZE];



int main()
{
    std::cout << "Hello USB asldkfjsjakdjfljsadjfkjsadkl!\n";
    //usb_init();

    for (int i = 0; i < WRITE_DATA_SIZE; i++) {
        writeBytes[i] = 'D';
    }


    if (find_my_device(0x0003, 0x1cbe)) {//0x0003
        cout << "NB" << endl;
        while (true) {
            char op = getchar();
            if (op == 'w') {
                //int count = usb_bulk_write(my_device, 0x01, (char*)"Hello caonima!", 12, 500);
                int count = usb_bulk_write(my_device, 0x01, (char*)writeBytes, WRITE_DATA_SIZE, 500);
                cout << "usb wite bytes: " << count << endl;
            }
            SYSTEMTIME time1, time2;
            if (op == 'r') {
                GetLocalTime(&time1);
                int count = usb_bulk_read(my_device, 0x81, receviceBytes2, READ_DATA_SIZE, 500);
#if DEBUG_ENABLE
                if (count == READ_DATA_SIZE) {
                    for (int i = 0; i < READ_DATA_SIZE;i++) {
                        cout << "revicedata[ " << i << "]: "<< receviceBytes2[i] << endl;
                    }
                   
                }
                else {
                    cout << "ERROR count: " << count << endl;
                }
#else
                if (count < READ_DATA_SIZE) {
                    cout << "ERROR count: " << count << endl;
                }
#endif
                GetLocalTime(&time2);
                cout << "read 1kb data time: " << time2.wMilliseconds - time1.wMilliseconds << "ms" << endl;
                /*
                    USB Speed = 字节数(kb)/时间 = 1kb/ms = 1kb/(ms/1000) = 1000/ms   //这里假设传输的是1kb的数据
                */
                cout << "USB Speed: " << (READ_DATA_SIZE*1.0f) /(time2.wMilliseconds - time1.wMilliseconds) << "kb/s" << endl;
            }

        }
    }
    else {
        cout << "未能找到设备" << endl;
    }



}

BOOL find_my_device(UINT32 PID, UINT32 VID) {
    bool isFind = false;
    usb_init();
    usb_find_busses();
    usb_find_devices();


    struct usb_bus* bus;
    for (bus = usb_busses; bus; bus->next) {
        struct usb_device* device;
        for (device = bus->devices; device; device->next) {
            if (device->descriptor.idProduct == PID && device->descriptor.idVendor == VID) {
                cout << "find my device" << endl;
                my_device = usb_open(device);

                //接口声明,第二个参数要看单片机中的interface参数,返回值为0则声明成功
                int ret = usb_claim_interface(my_device, 0);//
                cout << "接口声明结果: " << ret << endl;
                return true;
            }
        }
    }

    return isFind;
}

// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门使用技巧: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件


上述C++程序需要现在VS中导入libusb相关库
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

libusb例程bulk.c代码移植

首先需要根据上面的步骤导入相关libusb.lib和lusb0_usb.h文件到VS中

  1. 导入相关库文件之后还需要修改PID VID的值
    在这里插入图片描述
  2. 需要定义#define TEST_BULK_WRITE,因为该例程中直接读了,要跟没有写操作,会导致读操作失败。
    #define TEST_BULK_WRITE
  3. 该例程中读写的数据buffer,即:char tmp[BUF_SIZE]并没有填充任何数据,如果想要看到数据收发的过程,需自行填充数据。如下所示我给他填充了一些字符串:
    char tmp[BUF_SIZE] = "This is a test for you";
  4. 【重要】交互的数据长度问题
    上位机BUF_SIZE <= 下位机BUF_SIZE-1
    在这里插入图片描述

8. USB buffer实际可用空间

在这里插入图片描述

9. USB速度测试

在这里插入图片描述

补充:

上述方法测试通信速度具有很大的误差,因为测试的数据太小(1M),基本上在1~2ms就发送完了,而C++的这种计时方式最多精确到1ms,所以这样测试的误差就会很大

解决方案
  1. 连续收发较大的数据量来进行测试
    • 关于如何通过上位机进行连续的USB数据收发测试,可以参考:
      在这里插入图片描述
  1. 尽量不要使用C++的这种计时方式,看能否使用DSP中的定时器来进行精确的计时,然后将计数器的值通过USB发送给上位机进行通信速度的计算。

10. USBHost与28388数据收发问题

问题描述:DSP会将接收到的1个字节数据全部转换成2个字节的数据
在这里插入图片描述

问题分析:

DSP中char类型数据长度问题
参考来自:https://blog.youkuaiyun.com/zyboy2000/article/details/8307045
在这里插入图片描述
下面是28388的CPU1中char类型变量的赋值与仿真结果,结果证明在28388的CPU1中char类型变量为2个字节
在这里插入图片描述
下面是CM中char类型变量的赋值与仿真结果,结果证明CM中char类型为1字节
在这里插入图片描述

下面是我实验并总结的在28388 CPU1程序中各个数据类型变量所占的字节大小
在这里插入图片描述

10.USB Bulk device向USB Host发送数据

在这里插入图片描述

11. USB Device中接收Buffer存储机制

上位机的测试代码:
其中tmp发送数组的长度为60(即:60个char)
在这里插入图片描述

上述代码的功能:写数据-》读数据 循环两次

下位机中g_pui8USBRxBuffer实际可用空间为63
在这里插入图片描述
程序中记录一下g_sRxBuffer的space
在这里插入图片描述
假如上位机改为这样:
只写数据不读数据
在这里插入图片描述
很明显只有前面3次写成功了
在这里插入图片描述

那么Rxbuffer的space是这样的
在这里插入图片描述

结论:

如何USB host只写不读,那么USB Device中的Rxbuffer空间会逐次减少,用完之后将无法成功写数据。
但是如果写多少读多少那么Rxbuffer的空间又会被重新释放出来。
具体原因可能要看看源码了。

12. 接收Rxbuffer如果space不够下一次的数据了怎么办?

space总共是63个字节,第一次接收了60个字节的数据,然后主机读走数据,RxBuffer空间又重新拥有了63个字节,,如果主机再一次写60个字节,那么数据并不会从RxBuffer的第一个字节开始存,而是接着上一次的第60个字节开始,61,62,63,再往后没有了,就会重新从第一个字节开始写入,说白了又回头了。
在这里插入图片描述

13. Bulk Transfer

Bulk transfer 由多个事务组成。
在这里插入图片描述

Bulk Transaction

顾名思义,改种事务传输主要是大块的数据,传送这种事务的管道叫做Bulk管道,这种事务传输的时候分为三部分.

第一部分:

令牌包(Token)

是Host端发出一个Bulk的令牌请求,如果令牌是IN请求则是从Device到Host的请求,
如果是OUT令牌,则是从Host到Device端的请求。

第二部分:

数据包(data)

是传送数据的阶段,根据先前请求的令牌的类型,数据传输有可能是IN方向.
也有可能是OUT方向。传输数据的时候用DATA0和DATA1令牌携带着数据交替传送。

第三部分:

握手(handshake)

是握手信号。如果数据是IN方向,握手信号应该是Host端发出,如果是OUT方向,
握手信号应该是Device端发出。
握手信号可以为:
1. ACK,表示正常响应,
2. NAK表示没有正确传送。
3. STALL表示出现主机不可预知的错误。

14. How to send USB bulk transfer requests

This topic provides a brief overview about USB bulk transfers. It also provides step-by-step instructions about how a client driver can send and receive bulk data from the device.
About bulk endpoints
Bulk transactions
USB client driver tasks for a bulk transfer
Bulk transfer request example
Prerequisites
Step 1: Get the transfer buffer.
Step 2: Format and send a framework request object to the USB driver stack.
Step 3: Implement a completion routine for the request.

About bulk endpoints

A USB bulk endpoint can transfer large amounts of data. Bulk transfers are reliable that allow hardware error detection, and involves limited number of retries in the hardware. For transfers to bulk endpoints, bandwidth is not reserved on the bus. When there are multiple transfer requests that target different types of endpoints, the controller first schedules transfers for time critical data, such as isochronous and interrupt packets. Only if there is unused bandwidth available on the bus, the controller schedules bulk transfers. Where there is no other significant traffic on the bus, bulk transfer can be fast. However, when the bus is busy with other transfers, bulk data can wait indefinitely.

Here are the key features of a bulk endpoint:

  • Bulk endpoints are optional. They are supported by a USB device that wants to transfer large amounts of data. For example, transferring files to a flash drive, data to or from a printer or a scanner.

  • USB full speed, high speed, and SuperSpeed devices support bulk endpoints. Low speed devices do not support bulk endpoints.

  • The endpoint is a unidirectional and data can be transferred either in an IN or OUT direction. Bulk IN endpoint is used to read data from the device to the host and bulk OUT endpoint is used to send data from the host to the device.
    The endpoint has CRC bits to check for errors and thus provides data integrity. For CRC errors, data is retransmitted automatically.

  • A SuperSpeed bulk endpoint can support streams. Streams allow the host to send transfers to individual stream pipes.

  • Maximum packet size of a bulk endpoint depends on the bus speed of the device. For full speed, high speed, and SuperSpeed; the maximum packet sizes are 64, 512, and 1024 bytes respectively.

不想抄了,自行参考:
How to send USB bulk transfer requests

15. Bulk Device Class Event

参考来源:F2838x USB Library User’s Guide.pdf 19 / 214

Receive Channel Events

USB_EVENT_RX_AVAILABLE
USB_EVENT_ERROR
USB_EVENT_CONNECTED
USB_EVENT_DISCONNECTED
USB_EVENT_SUSPEND
USB_EVENT_RESUME

Note: The USB_EVENT_DISCONNECTED event will not be reported to the application if the
MCU’s PB1/USB0VBUS pin is connected to a fixed +5 Volts rather than directly to the VBUS pin on
the USB connector or if the USB controller is configured to force device mode.

Transmit Channel Events

USB_EVENT_TX_COMPLETE

16. 关于一个BULK传输结束标志的思考:

A bulk transfer is complete when the endpoint does one of the following:
• Has transferred exactly the amount of data expected
• Transfers a packet with a payload size less than wMaxPacketSize or transfers a zero-length packet

When a bulk transfer is complete, the Host Controller retires the current IRP and advances to the next IRP.If a data payload is received that is larger than expected, all pending bulk IRPs for that endpoint will be aborted/retired

Data In Transport

If the device supplies a zero-length or short packet, the host should consider the transport of data for the current command block to have ended, and send no more IN PID(不再发送PID为IN的令牌包)

Status by Bulk In Pipe

The device may STALL the Bulk In pipe to indicate a command block has failed.

17. USB endpoints and their pipes

摘自:Universal Serial Bus (USB).pdf 33 / 736

Summar y

  • Endpoint is hardware on the device; pipe is software on the host side.
  • Endpoint is not configured; pipe is configured for transfers
  • The host sends or receives data to or from a pipe.
    A USB device has endpoints that are used to for data transfers. On the host side, endpoints are represented by
    pipes. This topic differentiates between those two terms.

USB endpoint

An endpoint is a buffer on a USB device. Endpoint is a term that relates to the hardware itself, independent of the
host operating system. The host can send and receive data to or from that buffer. Endpoints can be categorized into
control and data endpoints.
Every USB device must provide at least one control endpoint at address 0 called the default endpoint or Endpoint0.
This endpoint is bidirectional. that is, the host can send data to the endpoint and receive data from it within one
transfer. The purpose of a control transfer is to enable the host to obtain device information, configure the device,
or perform control operations that are unique to the device.
Data endpoints are optional and used for transferring data. They are unidirectional, has a type (control, interrupt,
bulk, isochronous) and other properties. All those properties are described in an endpoint descriptor (see Standard
USB descriptors)
In USB terminology, the direction of an endpoint ( and transfers to or from them) is based on the host. Thus, IN
always refers to transfers to the host from a device and OUT always refers to transfers from the host to a device.
USB devices can also support bi-directional transfers of control data.
The endpoints on a device are grouped into functional interfaces, and a set of interfaces makes up a device
configuration. For more information, see USB device layout.
The host software can look at endpoint information, before the device has been configured or during selection of
an alternate setting. You will iterate through all of the interfaces, then through each interfaces list of settings, and
look at the properties of each endpoint or the entire set of endpoints in the setting. Looking at the endpoint
information does not affect the configured state of the device.

USB pipes

Data is transferred between a USB device and the USB host through an abstraction called a pipe. Pipes is purely a
software term. A pipe talks to an endpoint on a device, and that endpoint has an address. The other end of a pipe is
always the host controller.
A pipe for an endpoint is opened when the device is configured either by selecting a configuration and an
interface’s alternate setting. Therefore they become targets for I/O operations. A pipe has all the properties of an
endpoint, but it is active and be used to communicate with the host.
An unconfigured endpoint is called an endpoint while a configured endpoint is called a pipe.
在这里插入图片描述

28388 USB例程分析

例程: udma_ex2_scatter_gather_mode
例程功能:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值