NU_LB_NUC140 USB HID设备

##问题1:USB设备 通信管道

Nu_LB_NUC140_BSP\SampleCode\Nu-LB-NUC140\USBD_HID_Transfer 上行有点问题
NUC100_120BSPv3.00.002\SampleCode\StdDriver\USBD_HID_Transfer\WindowsTool\debug 可以使用

##问题2:USB 设备 例子习题,验证对USB的理解

##3 usb设备接口
这里写图片描述

##4 函数调用关系---- 下行
USBD_IRQHandler

EP3_Handler

HID_GetOutReport

##5 中断输入端点

##6 程序协议


#pragma pack(push)  /* push current alignment to stack */
#pragma pack(1)     /* set alignment to 1 byte boundary */

typedef struct
{
    unsigned char cmd;
    unsigned char len;
    unsigned int arg1;
    unsigned int arg2;
    unsigned int signature;
    unsigned int checksum;
} CMD_T;

#pragma pack(pop)   /* restore original alignment from stack */

len 不包括checksum的长度

#define USB_VID         0x0416  /* Vendor ID */
#define USB_PID         0x5020  /* Product ID */

#define HID_CMD_SIGNATURE   0x43444948

#define HID_CMD_NONE     0x00
#define HID_CMD_ERASE    0x71
#define HID_CMD_READ     0xD2
#define HID_CMD_WRITE    0xC3
#define HID_CMD_TEST     0xB4


#define PAGE_SIZE       256
#define SECTOR_SIZE     4096
#define HID_PACKET_SIZE 64


#define USB_TIME_OUT    100

##6 log

Device  Phase  Data                                                                                                    
------  -----  ------------------------------------------------------------------------------------------------------  
  26    OUT    00 71 0e 10  00 00 00 40  00 00 00 48  49 44 43 e7  01 00 00 cc  cc cc cc cc  cc cc cc cc  cc cc cc cc  
               cc cc cc cc  cc cc cc cc  cc cc cc cc  cc cc cc cc  cc cc cc cc  cc cc cc cc  cc cc cc cc  cc cc cc cc  
               cc                                                                                                      
  26    OUT    00 d2 0e 00  01 00 00 00  04 00 00 48  49 44 43 fd  01 00 00 cc  cc cc cc cc  cc cc cc cc  cc cc cc cc  
               cc cc cc cc  cc cc cc cc  cc cc cc cc  cc cc cc cc  cc cc cc cc  cc cc cc cc  cc cc cc cc  cc cc cc cc  
               cc                                                                                                      

##7 遇到问题

不正确 应为是程序的问题。

USB HID Device VID[0416] PID[5020] Open Success.
>>> Erase sectors: 16 - 17
USB HID Device VID[0416] PID[5020] Open Success.
>>> Read pages: 32 - 35
USB HID Device VID[0416] PID[5020] Open Success.
>>> Write pages: 32 - 35
USB HID Device VID[0416] PID[5020] Open Success.
>>> Read pages: 32 - 35
USB HID Device VID[0416] PID[5020] Open Success.
>>> Erase sectors: 17 - 17
USB HID Device VID[0416] PID[5020] Open Success.
>>> Read pages: 32 - 35
ERROR: Single sector erase test fail!

8 HID.hpp 源码 简体字 GB2312编码

来自:
Nu_LB_NUC140_BSP\SampleCode\Nu-LB-NUC140\USBD_HID_Transfer\WindowsTool\HIDTransferTest\

#ifndef INC__HID_HPP__
#define INC__HID_HPP__

#include "stdafx.h"
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>
#include <string.h>
#include "dbt.h"

extern "C" {
#include "setupapi.h"
#include "hidsdi.h"
}


#define HID_MAX_PACKET_SIZE_EP 64
#define V6M_MAX_COMMAND_LENGTH (HID_MAX_PACKET_SIZE_EP - 2)

class CHidIO
{
protected:
	HANDLE m_hReadHandle;
	HANDLE m_hWriteHandle;
	HANDLE m_hReadEvent;
	HANDLE m_hWriteEvent;
	HANDLE m_hAbordEvent;
public:
	CHidIO()
		: m_hReadHandle(INVALID_HANDLE_VALUE)
		, m_hWriteHandle(INVALID_HANDLE_VALUE)
		, m_hAbordEvent(CreateEvent(NULL,TRUE,FALSE,NULL))
		, m_hReadEvent(CreateEvent(NULL,TRUE,FALSE,NULL))
		, m_hWriteEvent(CreateEvent(NULL,TRUE,FALSE,NULL))
	{
	}
	virtual ~CHidIO()
	{
		CloseDevice();
		CloseHandle(m_hWriteEvent);
		CloseHandle(m_hReadEvent);
		CloseHandle(m_hAbordEvent);
	}

	void CloseDevice()
	{
		if(m_hReadHandle != INVALID_HANDLE_VALUE)
			CancelIo(m_hReadHandle);
		if(m_hWriteHandle != INVALID_HANDLE_VALUE)
			CancelIo(m_hWriteHandle);
		if(m_hReadHandle != INVALID_HANDLE_VALUE)
		{
			CloseHandle(m_hReadHandle);
			m_hReadHandle = INVALID_HANDLE_VALUE;
		}
		if(m_hWriteHandle != INVALID_HANDLE_VALUE)
		{
			CloseHandle(m_hWriteHandle);
			m_hWriteHandle = INVALID_HANDLE_VALUE;
		}
	}

	BOOL OpenDevice(USHORT usVID, USHORT usPID)
	{
		//CString MyDevPathName="";
		TCHAR MyDevPathName[MAX_PATH];

        //定义一个GUID的结构体HidGuid来保存HID设备的接口类GUID
        
		GUID HidGuid;
        
	    //定义一个DEVINFO的句柄hDevInfoSet来保存获取到的设备信息集合句柄
		HDEVINFO hDevInfoSet;
		//定义MemberIndex,表示当前搜索到的第几个设备,0表示第一个设备
		DWORD MemberIndex;
		//DevInterfaceData 用来保存设备的驱动接口信息
		SP_DEVICE_INTERFACE_DATA DevInterfaceData;
		//定义一个BOOL变量,保存函数调用是否返回成功
		BOOL Result;
		//定义一个RequiredSize的变量,用来接收需要保存详细信息的缓冲长度。
		DWORD RequiredSize;
		//定义一个指向设备详细信息的结构体指针。
		PSP_DEVICE_INTERFACE_DETAIL_DATA	pDevDetailData;
		//定义一个用来保存打开设备的句柄
		HANDLE hDevHandle;
		//定义一个HIDD_ATTRIBUTES的结构体变量,保存设备的属性。
		HIDD_ATTRIBUTES DevAttributes;
		
		//初始化设备未找到
		BOOL MyDevFound=FALSE;
		
		//初始化读,写句柄为无效的句柄
		m_hReadHandle=INVALID_HANDLE_VALUE;
		m_hWriteHandle=INVALID_HANDLE_VALUE;
		
		//对DevInterfaceData结构体的cbSize初始化为结构体大小
		DevInterfaceData.cbSize=sizeof(DevInterfaceData);
		
		//对DevAttributes结构体的Size初始化为结构体大小
		DevAttributes.Size=sizeof(DevAttributes);
		
		//调用HidD_GetHidGuid函数获取HID设备的GUID,并保存在HidGuid中
		HidD_GetHidGuid(&HidGuid);
		
		
		//根据HidGuid来获取设备信息集合。其中Flags参数设置为
		//DIGCF_DEVICEINTERFACE|DIGCF_PRESENT,前者表示使用的GUID为
		//接口类GUID,后者表示只列举正在使用的设备,因为我们这里只
		//查找已经连接上的设备。返回的句柄保存在hDevinfo中。注意设备
		//信息集合在使用完毕后,要使用函数SetupDiDestroyDeviceInfoList
		//销毁,不然会造成内存泄漏。
		
	
		hDevInfoSet=SetupDiGetClassDevs(&HidGuid,
			NULL,
			NULL,
			DIGCF_DEVICEINTERFACE|DIGCF_PRESENT);
			
		//AddToInfOut("开始查找设备");
		//然后对设备集合中每个设备进行列举,检查是否是我们要找的设备
		//当找到我们指定的设备,或者设备已经查找完毕时,就退出查找
		//首先指向第一个设备,即将MemberIndex设置为0
	
		MemberIndex = 0;

		while(1)
		{

			/*
				调用SetupDiEnumDeviceInterfaces在设备信息集合中获取编号为MemberIndex的设备信息
			*/
			Result=SetupDiEnumDeviceInterfaces(hDevInfoSet,
				NULL,
				&HidGuid,
				MemberIndex,
				&DevInterfaceData);
			
		    //如果获取信息失败,则说明设备已经查找完毕,退出循环。
			if(Result==FALSE) break;
			
			//将MemberIndex指向下一个设备
			MemberIndex++;
			
			//如果获取信息成功,则继续获取该设备的详细信息。在获取设备
			//详细信息时,需要先知道保存详细信息需要多大的缓冲区,这通过
			//第一次调用函数SetupDiGetDeviceInterfaceDetail来获取。这时
			//提供缓冲区和长度都为NULL的参数,并提供一个用来保存需要多大
			//缓冲区的变量RequiredSize。
			
			Result=SetupDiGetDeviceInterfaceDetail(hDevInfoSet,
				&DevInterfaceData,
				NULL,
				NULL,
				&RequiredSize,
				NULL);
			
			//然后,分配一个大小为RequiredSize缓冲区,用来保存设备详细信息。
			pDevDetailData=(PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(RequiredSize);
			if(pDevDetailData==NULL) //如果内存不足,则直接返回
			{
				//MessageBox("内存不足");
				SetupDiDestroyDeviceInfoList(hDevInfoSet);
				return FALSE;
			}
			
			//并设置pDevDetailData的cbSize为结构体的大小(注意只是结构体大小,
			//不包括后面缓冲区)。
			pDevDetailData->cbSize=sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
			
		
			//然后再次调用SetupDiGetDeviceInterfaceDetail函数来获取设备的
			//详细信息。这次调用设置使用的缓冲区已经缓冲区大小。
			Result=SetupDiGetDeviceInterfaceDetail(hDevInfoSet,
				&DevInterfaceData,
				pDevDetailData,
				RequiredSize,
				NULL,
				NULL);
			
			//将设备路径复制出来,然后销毁刚刚申请的内存。
			//MyDevPathName=pDevDetailData->DevicePath;
			//_tcscpy(MyDevPathName, pDevDetailData->DevicePath);
			wcscpy_s(MyDevPathName, pDevDetailData->DevicePath);
            free(pDevDetailData);
			
			//如果调用失败,则查找下一个设备。
			if(Result==FALSE) continue;
			

			//如果调用成功,则使用不带读写访问的CreateFile函数
			//来获取设备的属性,包括VID,PID,版本号等。
			//对于一些独占设备(例如USB键盘),使用读访问方式是无法打开的
			//而使用不带读写访问的格式才可以打开这些设备,从而获取设备的属性。
			hDevHandle=CreateFile(MyDevPathName, 
				NULL,
				FILE_SHARE_READ|FILE_SHARE_WRITE, 
				NULL,
				OPEN_EXISTING,
				FILE_ATTRIBUTE_NORMAL,
				NULL);
			
			//如果打开成功,则获取设备属性
			if(hDevHandle!=INVALID_HANDLE_VALUE)
			{
				//获取设备的属性并保存在DevAttributes结构体中
				Result=HidD_GetAttributes(hDevHandle,
					&DevAttributes);
				
				//关闭刚刚打开的设备
				CloseHandle(hDevHandle);
				
				//获取失败,查找下一个
				if(Result==FALSE) continue;
				
				//如果获取成功,则将属性中的VID,PID已经设备版本号与我们需要的
				//进行比较,如果都一致的话,则说明它就是我们要找的设备。
				if(DevAttributes.VendorID == usVID
					&& DevAttributes.ProductID == usPID){
						
							MyDevFound=TRUE;  // 设置设备已经找到
							
							//AddToInfOut("设备已经找到");
						
							//那么就是我们要找的设备,分别使用读写方式打开之,并保存其句柄
							//并且选择为异步访问方式
							
							//读方式打开设备
							m_hReadHandle=CreateFile(MyDevPathName, 
								GENERIC_READ,
								FILE_SHARE_READ|FILE_SHARE_WRITE, 
								NULL,
								OPEN_EXISTING,							
								FILE_ATTRIBUTE_NORMAL,
								NULL);
								//if(hReadHandle!=INVALID_HANDLE_VALUE)AddToInfOut("读访问打开设备成功");
								//else AddToInfOut("读访问打开设备失败");
							

							//写方式打开设备
							m_hWriteHandle=CreateFile(MyDevPathName, 
								GENERIC_WRITE,
								FILE_SHARE_READ|FILE_SHARE_WRITE, 
								NULL,
								OPEN_EXISTING,
								//FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,
								FILE_ATTRIBUTE_NORMAL,
								NULL);
								
								//if(hWriteHandle!=INVALID_HANDLE_VALUE)AddToInfOut("写访问打开设备成功");
								//else AddToInfOut("写访问打开设备失败");
						

							//手动触发事件,让读报告线程恢复运行,因为在这之前并没有调用
							//读数据的函数,也就不会引起事件的产生,所以需要先手动触发一
							//次事件,让读报告线程恢复运行
							//SetEvent(ReadOverlapped.hEvent);
							
							//显示设备的状态
							//SetDlgItemText(IDC_DS,"设备已打开");
							
							//找到设备,退出循环。本程序只检测一个目标设备,查找到后就退出
							//查找了。如果你需要将所有的目标设备都列出来的话,可以设置一个
							//数组,找到后就保存在数组中,直到所有设备都查找完毕才退出查找。
							
							break;
						}
			}
			// 如果打开失败,则查找下一个设备
			else continue;
		}
		
		//调用SetupDiDestroyDeviceInfoList函数销毁设备信息集合
		SetupDiDestroyDeviceInfoList(hDevInfoSet);
		
		//如果设备已经找到,那么应该使能各操作按钮,并同时禁止打开设备按钮
		return MyDevFound;
	}


	BOOL ReadFile(char *pcBuffer, DWORD szMaxLen, DWORD *pdwLength, DWORD dwMilliseconds)
	{
		HANDLE events[2] = {m_hAbordEvent, m_hReadEvent};

		OVERLAPPED overlapped;
		memset(&overlapped, 0, sizeof(overlapped));
		overlapped.hEvent = m_hReadEvent;

		if(pdwLength != NULL)
			*pdwLength = 0;
		
		if(!::ReadFile(m_hReadHandle, pcBuffer, szMaxLen, NULL, &overlapped))
			return FALSE;
		DWORD dwIndex = WaitForMultipleObjects(2, events, FALSE, dwMilliseconds);
		if(dwIndex == WAIT_OBJECT_0
			|| dwIndex == WAIT_OBJECT_0 + 1)
		{
			ResetEvent(events[dwIndex - WAIT_OBJECT_0]);

			if(dwIndex == WAIT_OBJECT_0)
				return FALSE;	//Abort event
			else
			{
				DWORD dwLength = 0;
				//Read OK
				GetOverlappedResult(m_hReadHandle, &overlapped, &dwLength, TRUE);
				if(pdwLength != NULL)
					*pdwLength = dwLength;
				return TRUE;
			}				
		}
		else
			return FALSE;
	}

	BOOL WriteFile(const char *pcBuffer, DWORD szLen, DWORD *pdwLength, DWORD dwMilliseconds)
	{
		HANDLE events[2] = {m_hAbordEvent, m_hWriteEvent};
        
		OVERLAPPED overlapped;
		memset(&overlapped, 0, sizeof(overlapped));
		overlapped.hEvent = m_hWriteEvent;

		if(pdwLength != NULL)
			*pdwLength = 0;

		DWORD dwStart2 = GetTickCount();

		if(!::WriteFile(m_hWriteHandle, pcBuffer, szLen, NULL, &overlapped))
			return FALSE;

		DWORD dwIndex = WaitForMultipleObjects(2, events, FALSE, dwMilliseconds);
		
		if(dwIndex == WAIT_OBJECT_0
			|| dwIndex == WAIT_OBJECT_0 + 1)
		{
			ResetEvent(events[dwIndex - WAIT_OBJECT_0]);

			if(dwIndex == WAIT_OBJECT_0)
				return FALSE;	//Abort event
			else
			{
				DWORD dwLength = 0;
				//Write OK
				GetOverlappedResult(m_hWriteHandle, &overlapped, &dwLength, TRUE);
				if(pdwLength != NULL)
					*pdwLength = dwLength;
				return TRUE;
			}				
		}
		else
			return FALSE;
	}
};



class CHidCmd
{
protected:
	CHAR	m_acBuffer[HID_MAX_PACKET_SIZE_EP + 1];
	CHidIO	m_hidIO;
public:
	CHidCmd()
		: m_hidIO()
	{
	}
	virtual ~CHidCmd()
	{
	}

	void CloseDevice()
	{
		m_hidIO.CloseDevice();
	}

	BOOL OpenDevice(USHORT usVID, USHORT usPID)
	{
		return m_hidIO.OpenDevice(usVID, usPID);
	}

	BOOL ReadFile(unsigned char *pcBuffer, size_t szMaxLen, DWORD *pdwLength, DWORD dwMilliseconds)
	{
        BOOL bRet;

        bRet = m_hidIO.ReadFile(m_acBuffer, sizeof(m_acBuffer), pdwLength, dwMilliseconds);
        (*pdwLength)--;
        memcpy(pcBuffer, m_acBuffer+1, *pdwLength);

		return bRet;
	}

	BOOL WriteFile(unsigned char *pcBuffer, DWORD dwLen, DWORD *pdwLength, DWORD dwMilliseconds)
	{
		/* Set new package index value */
		DWORD dwCmdLength = dwLen;
		if(dwCmdLength > sizeof(m_acBuffer) - 1)
			dwCmdLength = sizeof(m_acBuffer) - 1;
        
        memset(m_acBuffer, 0xCC, sizeof(m_acBuffer));
		m_acBuffer[0] = 0x00;	//Always 0x00
        memcpy(m_acBuffer+1  , pcBuffer, dwCmdLength);
		BOOL bRet = m_hidIO.WriteFile(m_acBuffer, 65, pdwLength, dwMilliseconds);
        if(bRet)
        {
                *pdwLength = *pdwLength - 1;
        }

        return bRet;
	}

};



#endif

9 USB 设备IN 中断

在这里插入图片描述

在这里插入图片描述

        if(u32IntSts & USBD_INTSTS_EP2)
        {
            /* Clear event flag */
            USBD_CLR_INT_FLAG(USBD_INTSTS_EP2);
            // Interrupt IN
            EP2_Handler();
        }

这个中断服务程序的目的是告诉你,之前准备好的数据已经被发送完毕了,请准备好下一个数据。
设置MAXPLD寄存器是告诉单片机,已经准备好USB设备发送给USB主机的数据了。

10 USB 设备OUT 中断

在这里插入图片描述

在这里插入图片描述

设置MAXPLD寄存器是告诉单片机,USB设备已经准备好接收USB主机发送过来的数据了。

(稍后补充)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值