3388 views|4 replies

1w

Posts

16

Resources
The OP
 

[RISC-V MCU CH32V103 Evaluation] 3. USB HID routine operation [Copy link]

 

I have been studying USB for a while. After much research, I think HID is the most suitable one for me.

Because HID does not require any driver, any computer with a USB port should be able to recognize it.

Good USB information found on the Internet:

USB Device Descriptors - Overview

When a USB device is inserted, the host will request various descriptors from the device to identify the device. So what are device descriptors?

Descriptor is a complete data structure that can be implemented through programming in C language and stored in USB devices. It is used to describe all the properties of a USB device. The USB host requires the device to send this information through a series of commands.

The role of the descriptor is to pass information to the host through command operations, so that the host knows what functions the device has, what type of device it belongs to, how much bandwidth it will occupy, what type of transmission method it uses, and the amount of data. Only after the host determines this information can the device actually start working.

What are the standard descriptors for USB?

USB has 5 standard descriptors: device descriptor, configuration descriptor, character descriptor, interface descriptor, and endpoint descriptor.

There is a certain relationship between descriptors. A device has only one device descriptor, while a device descriptor can contain multiple configuration descriptors, and a configuration descriptor can contain multiple interface descriptors. If an interface uses several endpoints, there will be several endpoint descriptors. From this we can see that the relationship between USB descriptors is layered. The top layer is the device descriptor, the configuration descriptor is below, the interface descriptor is below, and the endpoint descriptor is below. When obtaining descriptors, first obtain the device descriptor, and then obtain the configuration descriptor. According to the configuration set length in the configuration descriptor, read back the configuration descriptor, interface descriptor, and endpoint descriptor at a time. It may also be necessary to obtain the device serial number, manufacturer string, product string, etc.

Then, all data exchanges between the host and the microcontroller are completed through interrupts.

The README in the example program explains the functions of the example program:

I just used a tool I found on the Internet to verify it:

The tool is as follows:

Debug.rar (46.84 KB, downloads: 20)

I sent 1,1,2,2,3,3,4,4,5,5,6,6,7,7

The returned numbers are all taken and returned: as shown in the above picture.

It can be seen that the program is completely correct.

Briefly explain the operating principle:

First initialize the USB:

void USB_DeviceInit( void )                                    
{	
	R8_USB_CTRL = 0x00;				
 
	R8_UEP4_1_MOD = RB_UEP4_RX_EN|RB_UEP4_TX_EN|RB_UEP1_RX_EN|RB_UEP1_TX_EN;   
	R8_UEP2_3_MOD = RB_UEP2_RX_EN|RB_UEP2_TX_EN|RB_UEP3_RX_EN|RB_UEP3_TX_EN; 
    R8_UEP5_6_MOD = RB_UEP5_RX_EN|RB_UEP5_TX_EN|RB_UEP6_RX_EN|RB_UEP6_TX_EN;	
    R8_UEP7_MOD = RB_UEP7_RX_EN|RB_UEP7_TX_EN;
	
	R16_UEP0_DMA = (UINT16)(UINT32)pEP0_RAM_Addr;
	R16_UEP1_DMA = (UINT16)(UINT32)pEP1_RAM_Addr;
	R16_UEP2_DMA = (UINT16)(UINT32)pEP2_RAM_Addr;
	R16_UEP3_DMA = (UINT16)(UINT32)pEP3_RAM_Addr;
    R16_UEP4_DMA = (UINT16)(UINT32)pEP4_RAM_Addr;
	R16_UEP5_DMA = (UINT16)(UINT32)pEP5_RAM_Addr;
	R16_UEP6_DMA = (UINT16)(UINT32)pEP6_RAM_Addr;
	R16_UEP7_DMA = (UINT16)(UINT32)pEP7_RAM_Addr;

	R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
	R8_UEP1_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
	R8_UEP2_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
	R8_UEP3_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
	R8_UEP4_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
	R8_UEP5_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
	R8_UEP6_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
	R8_UEP7_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
															
	R8_USB_INT_FG = 0xFF;                                             
	R8_USB_INT_EN = RB_UIE_SUSPEND | RB_UIE_BUS_RST | RB_UIE_TRANSFER; 

	R8_USB_DEV_AD = 0x00;
	R8_USB_CTRL = RB_UC_DEV_PU_EN | RB_UC_INT_BUSY | RB_UC_DMA_EN;  
	R8_UDEV_CTRL = RB_UD_PD_DIS|RB_UD_PORT_EN; 					
} 

Then in the interrupt, process the host's commands: there are three types, initialization, output, and input

void USB_DevTransProcess( void )
{
	UINT8  len, chtype;
	UINT8  intflag, errflag = 0;

	intflag = R8_USB_INT_FG;

	if( intflag & RB_UIF_TRANSFER )
	{
		switch ( R8_USB_INT_ST & MASK_UIS_TOKEN)
		{
			case UIS_TOKEN_SETUP:
				R8_UEP0_CTRL = RB_UEP_R_TOG | RB_UEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_NAK;
				len = R8_USB_RX_LEN;

				if ( len == sizeof( USB_SETUP_REQ ) )
				{
					SetupReqLen = pSetupReqPak->wLength;
					SetupReqCode = pSetupReqPak->bRequest;
					chtype = pSetupReqPak->bRequestType;

					len = 0;
					errflag = 0;
					if ( ( pSetupReqPak->bRequestType & USB_REQ_TYP_MASK ) != USB_REQ_TYP_STANDARD )
					{
						errflag = 0xFF;
					}
					else
					{
						switch( SetupReqCode )
						{
							case USB_GET_DESCRIPTOR:
							{
								switch( ((pSetupReqPak->wValue)>>8) )
								{
									case USB_DESCR_TYP_DEVICE:
										pDescr = MyDevDescr;
										len = MyDevDescr[0];
										break;

									case USB_DESCR_TYP_CONFIG:
										pDescr = MyCfgDescr;
										len = MyCfgDescr[2];
										break;

									case USB_DESCR_TYP_STRING:
										switch( (pSetupReqPak->wValue)&0xff )
										{
											case 1:
												pDescr = MyManuInfo;
												len = MyManuInfo[0];
												break;

											case 2:
												pDescr = MyProdInfo;
												len = MyProdInfo[0];
												break;

											case 0:
												pDescr = MyLangDescr;
												len = MyLangDescr[0];
												break;

											default:
												errflag = 0xFF;
												break;
										}
										break;

									default :
										errflag = 0xff;
										break;
								}

								if( SetupReqLen>len )	SetupReqLen = len;
								len = (SetupReqLen >= DevEP0SIZE) ? DevEP0SIZE : SetupReqLen;
								memcpy( pEP0_DataBuf, pDescr, len );
								pDescr += len;
							}
								break;

							case USB_SET_ADDRESS:
								SetupReqLen = (pSetupReqPak->wValue)&0xff;
								break;

							case USB_GET_CONFIGURATION:
								pEP0_DataBuf[0] = DevConfig;
								if ( SetupReqLen > 1 ) SetupReqLen = 1;
								break;

							case USB_SET_CONFIGURATION:
								DevConfig = (pSetupReqPak->wValue)&0xff;
								break;

							case USB_CLEAR_FEATURE:
								if ( ( pSetupReqPak->bRequestType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP )
								{
									switch( (pSetupReqPak->wIndex)&0xff )
									{
									case 0x82:
										R8_UEP2_CTRL = (R8_UEP2_CTRL & ~( RB_UEP_T_TOG|MASK_UEP_T_RES )) | UEP_T_RES_NAK;
										break;

									case 0x02:
										R8_UEP2_CTRL = (R8_UEP2_CTRL & ~( RB_UEP_R_TOG|MASK_UEP_R_RES )) | UEP_R_RES_ACK;
										break;

									case 0x81:
										R8_UEP1_CTRL = (R8_UEP1_CTRL & ~( RB_UEP_T_TOG|MASK_UEP_T_RES )) | UEP_T_RES_NAK;
										break;

									case 0x01:
										R8_UEP1_CTRL = (R8_UEP1_CTRL & ~( RB_UEP_R_TOG|MASK_UEP_R_RES )) | UEP_R_RES_ACK;
										break;

									default:
										errflag = 0xFF;
										break;

									}
								}
								else	errflag = 0xFF;
								break;

							case USB_GET_INTERFACE:
								pEP0_DataBuf[0] = 0x00;
								if ( SetupReqLen > 1 ) SetupReqLen = 1;
								break;

							case USB_GET_STATUS:
								pEP0_DataBuf[0] = 0x00;
								pEP0_DataBuf[1] = 0x00;
								if ( SetupReqLen > 2 ) SetupReqLen = 2;
								break;

							default:
								errflag = 0xff;
								break;
						}
					}
				}
				else	errflag = 0xff;

				if( errflag == 0xff)
				{
					R8_UEP0_CTRL = RB_UEP_R_TOG | RB_UEP_T_TOG | UEP_R_RES_STALL | UEP_T_RES_STALL;
				}
				else
				{
					if( chtype & 0x80 )
					{
						len = (SetupReqLen>DevEP0SIZE) ? DevEP0SIZE : SetupReqLen;
						SetupReqLen -= len;
					}
					else  len = 0;

					R8_UEP0_T_LEN = len;
					R8_UEP0_CTRL = RB_UEP_R_TOG | RB_UEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK;
				}
				break;

			case UIS_TOKEN_IN:
				switch ( R8_USB_INT_ST & ( MASK_UIS_TOKEN | MASK_UIS_ENDP ) )
				{
					case UIS_TOKEN_IN:
						switch( SetupReqCode )
						{
							case USB_GET_DESCRIPTOR:
									len = SetupReqLen >= DevEP0SIZE ? DevEP0SIZE : SetupReqLen;
									memcpy( pEP0_DataBuf, pDescr, len );
									SetupReqLen -= len;
									pDescr += len;
									R8_UEP0_T_LEN = len;
									R8_UEP0_CTRL ^= RB_UEP_T_TOG;
									break;

							case USB_SET_ADDRESS:
									R8_USB_DEV_AD = (R8_USB_DEV_AD&RB_UDA_GP_BIT) | SetupReqLen;
									R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
									break;

							default:
									R8_UEP0_T_LEN = 0;
									R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
									break;

						}
						break;

				case UIS_TOKEN_IN | 1:
					R8_UEP1_CTRL ^=  RB_UEP_T_TOG;
					R8_UEP1_CTRL = (R8_UEP1_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK;
					break;

				case UIS_TOKEN_IN | 2:
					R8_UEP2_CTRL ^=  RB_UEP_T_TOG;
					R8_UEP2_CTRL = (R8_UEP2_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK;
					break;

				case UIS_TOKEN_IN | 3:
					R8_UEP3_CTRL ^=  RB_UEP_T_TOG;
					R8_UEP3_CTRL = (R8_UEP3_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK;
					break;

				case UIS_TOKEN_IN | 4:
					R8_UEP4_CTRL ^=  RB_UEP_T_TOG;
					R8_UEP4_CTRL = (R8_UEP4_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK;
					break;

				case UIS_TOKEN_IN | 5:
					R8_UEP5_CTRL ^=  RB_UEP_T_TOG;
					R8_UEP5_CTRL = (R8_UEP5_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK;
					break;

				case UIS_TOKEN_IN | 6:
					R8_UEP6_CTRL ^=  RB_UEP_T_TOG;
					R8_UEP6_CTRL = (R8_UEP6_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK;
					break;

				case UIS_TOKEN_IN | 7:
					R8_UEP7_CTRL ^=  RB_UEP_T_TOG;
					R8_UEP7_CTRL = (R8_UEP7_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK;
					break;

				default :
					break;

				}
				break;

			case UIS_TOKEN_OUT:
				switch ( R8_USB_INT_ST & ( MASK_UIS_TOKEN | MASK_UIS_ENDP ) )
				{
					case UIS_TOKEN_OUT:
							len = R8_USB_RX_LEN;
							break;

					case UIS_TOKEN_OUT | 1:
						if ( R8_USB_INT_ST & RB_UIS_TOG_OK )
						{
							R8_UEP1_CTRL ^= RB_UEP_R_TOG;
							len = R8_USB_RX_LEN;
							DevEP1_OUT_Deal( len );
						}
						break;

					case UIS_TOKEN_OUT | 2:
						if ( R8_USB_INT_ST & RB_UIS_TOG_OK )
						{
							R8_UEP2_CTRL ^= RB_UEP_R_TOG;
							len = R8_USB_RX_LEN;
							DevEP2_OUT_Deal( len );
						}
						break;

					case UIS_TOKEN_OUT | 3:
						if ( R8_USB_INT_ST & RB_UIS_TOG_OK )
						{
							R8_UEP3_CTRL ^= RB_UEP_R_TOG;
							len = R8_USB_RX_LEN;
							DevEP3_OUT_Deal( len );
						}
						break;

					case UIS_TOKEN_OUT | 4:
						if ( R8_USB_INT_ST & RB_UIS_TOG_OK )
						{
							R8_UEP4_CTRL ^= RB_UEP_R_TOG;
							len = R8_USB_RX_LEN;
							DevEP4_OUT_Deal( len );
						}
						break;

					case UIS_TOKEN_OUT | 5:
						if ( R8_USB_INT_ST & RB_UIS_TOG_OK )
						{
							R8_UEP5_CTRL ^= RB_UEP_R_TOG;
							len = R8_USB_RX_LEN;
							DevEP5_OUT_Deal( len );
						}
						break;

					case UIS_TOKEN_OUT | 6:
						if ( R8_USB_INT_ST & RB_UIS_TOG_OK )
						{
							R8_UEP6_CTRL ^= RB_UEP_R_TOG;
							len = R8_USB_RX_LEN;
							DevEP6_OUT_Deal( len );
						}
						break;

					case UIS_TOKEN_OUT | 7:
						if ( R8_USB_INT_ST & RB_UIS_TOG_OK )
						{
							R8_UEP7_CTRL ^= RB_UEP_R_TOG;
							len = R8_USB_RX_LEN;
							DevEP7_OUT_Deal( len );
						}
						break;
				}

				break;

			case UIS_TOKEN_SOF:

				break;

			default :
				break;

		}


		R8_USB_INT_FG = RB_UIF_TRANSFER;
	}
	else if( intflag & RB_UIF_BUS_RST )
	{
		R8_USB_DEV_AD = 0;
		R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
		R8_UEP1_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
		R8_UEP2_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
		R8_UEP3_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
		R8_UEP4_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
		R8_UEP5_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
		R8_UEP6_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
		R8_UEP7_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;		
		
		R8_USB_INT_FG |= RB_UIF_BUS_RST;
	}
	else if( intflag & RB_UIF_SUSPEND )
	{
		if ( R8_USB_MIS_ST & RB_UMS_SUSPEND ) {;}
		else{;}
		R8_USB_INT_FG = RB_UIF_SUSPEND;
	}
	else
	{
		R8_USB_INT_FG = intflag;
	}
}

This post is from Domestic Chip Exchange

Latest reply

My friend, this example simulates CH372, not HID..   Details Published on 2021-11-20 21:31
Personal signaturehttp://shop34182318.taobao.com/
https://shop436095304.taobao.com/?spm=a230r.7195193.1997079397.37.69fe60dfT705yr
 
 

7462

Posts

2

Resources
2
 

The work of a big boss must be of high quality

This post is from Domestic Chip Exchange
Personal signature

默认摸鱼,再摸鱼。2022、9、28

 
 
 

134

Posts

0

Resources
3
 

Why is there no such example in ch579? Besides, it is probably difficult to deal with PC

This post is from Domestic Chip Exchange

Comments

There are tools on the PC side, not just the one I use  Details Published on 2021-1-29 11:06
Personal signature

 

 
 

1w

Posts

16

Resources
4
 
shzps posted on 2021-1-28 18:38 Why is there no such example in ch579? Besides, PC is probably difficult to deal with

There are tools on the PC side, not just the one I use

This post is from Domestic Chip Exchange
Personal signaturehttp://shop34182318.taobao.com/
https://shop436095304.taobao.com/?spm=a230r.7195193.1997079397.37.69fe60dfT705yr
 
 
 

124

Posts

1

Resources
5
 

My friend, this example simulates CH372, not HID..

This post is from Domestic Chip Exchange
 
 
 

Guess Your Favourite
Just looking around
Find a datasheet?

EEWorld Datasheet Technical Support

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号
快速回复 返回顶部 Return list