⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usbsample.c

📁 FreeRTOSV4.1.0 安裝文件 FreeRTOS 是一个源码公开的免费的嵌入式实时操作系统
💻 C
📖 第 1 页 / 共 3 页
字号:
	 0xa1,  0x00,	/*   COLLECTION (Physical)			*/
	 0x09,  0x30,	/*     USAGE (X)					*/
	 0x09,  0x31,	/*     USAGE (Y)					*/
	 0x09,  0x32,	/*     USAGE (Z)					*/
	 0x15,  0x81,	/*     LOGICAL_MINIMUM (-127)		*/
	 0x25,  0x7f,	/*     LOGICAL_MAXIMUM (127)		*/
	 0x75,  0x08,	/*     REPORT_SIZE (8)				*/
	 0x95,  0x03,	/*     REPORT_COUNT (3)				*/
	 0x81,  0x02,	/*     INPUT (Data,Var,Abs)			*/
	 0xc0,			/*   END_COLLECTION					*/
	 0xc0			/* END_COLLECTION					*/
};

const char pxDeviceDescriptor[] = 
{
	/* Device descriptor */
	0x12,								/* bLength				*/
	0x01,								/* bDescriptorType		*/
	0x10, 0x01,							/* bcdUSBL				*/
	usbDEVICE_CLASS_VENDOR_SPECIFIC,	/* bDeviceClass:		*/
	0x00,								/* bDeviceSubclass:		*/
	0x00,								/* bDeviceProtocol:		*/
	0x08,								/* bMaxPacketSize0		*/
	0xFF, 0xFF,							/* idVendorL			*/
	0x01, 0x00,							/* idProductL			*/
	0x00, 0x01,							/* bcdDeviceL			*/
	usbMANUFACTURER_STRING,				/* iManufacturer		*/
	usbPRODUCT_STRING,					/* iProduct				*/
	0x00,								/* SerialNumber			*/
	0x01								/* bNumConfigs			*/
};

const char pxConfigDescriptor[] = {
	/* Configuration 1 descriptor */
	0x09,			/* CbLength									*/
	0x02,			/* CbDescriptorType							*/
	0x22, 0x00,		/* CwTotalLength 2 EP + Control				*/
	0x01,			/* CbNumInterfaces							*/
	0x01,			/* CbConfigurationValue						*/
	usbCONFIGURATION_STRING,/* CiConfiguration					*/
	usbBUS_POWERED,	/* CbmAttributes Bus powered + Remote Wakeup*/
	0x32,			/* CMaxPower: 100mA							*/

	/* Joystick Interface Descriptor Requirement */
	0x09,			/* bLength									*/
	0x04,			/* bDescriptorType							*/
	0x00,			/* bInterfaceNumber							*/
	0x00,			/* bAlternateSetting						*/
	0x01,			/* bNumEndpoints							*/
	0x03,			/* bInterfaceClass: HID code				*/
	0x00,			/* bInterfaceSubclass						*/
	0x00,			/* bInterfaceProtocol						*/
	usbINTERFACE_STRING,/* iInterface							*/

	/* HID Descriptor */
	0x09,			/* bLength									*/
	0x21,			/* bDescriptor type: HID Descriptor Type	*/
	0x00, 0x01,		/* bcdHID									*/
	0x00,			/* bCountryCode								*/
	0x01,			/* bNumDescriptors							*/
	usbHID_REPORT_DESCRIPTOR,	  /* bDescriptorType			*/
	sizeof( pxReportDescriptor ), 0x00, /* wItemLength			*/

	/* Endpoint 1 descriptor */
	0x07,			/* bLength									*/
	0x05,			/* bDescriptorType							*/
	0x81,			/* bEndpointAddress, Endpoint 01 - IN		*/
	0x03,			/* bmAttributes      INT					*/
	0x03, 0x00,		/* wMaxPacketSize: 3 bytes (x, y, z)		*/
	0x0A			/* bInterval								*/
};

/*-----------------------------------------------------------*/

/* File scope state variables. */
static unsigned portCHAR ucUSBConfig = ( unsigned portCHAR ) 0;
static unsigned portLONG ulReceivedAddress = ( unsigned portLONG ) 0;
static eDRIVER_STATE eDriverState = eNOTHING;

/* Array in which the USB interrupt status is passed between the ISR and task. */
static xISRStatus xISRMessages[ usbQUEUE_LENGTH + 1 ];

/* Structure used to control the characters being sent to the host. */
static xTX_MESSAGE pxCharsForTx;

/* Queue used to pass messages between the ISR and the task. */
static xQueueHandle xUSBInterruptQueue; 

/* ISR entry has to be written in the asm file as we want a context switch
to occur from within the ISR.  See the port documentation on the FreeRTOS.org
WEB site for more information. */
extern void vUSBISREntry( void );

/*-----------------------------------------------------------*/

/* Macros to manipulate the control and status registers.  These registers 
cannot be accessed using a direct read modify write operation outside of the 
ISR as some bits are left unchanged by writing with a 0, and some are left 
unchanged by writing with a 1. */

#define usbINT_CLEAR_MASK	(AT91C_UDP_TXCOMP | AT91C_UDP_STALLSENT | AT91C_UDP_RXSETUP | AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1 )

#define usbCSR_SET_BIT( pulValueNow, ulBit )											\
{																						\
	/* Set TXCOMP, RX_DATA_BK0, RXSETUP, */												\
	/* STALLSENT and RX_DATA_BK1 to 1 so the */											\
	/* write has no effect. */															\
	( * ( ( unsigned portLONG * ) pulValueNow ) ) |= ( unsigned portLONG ) 0x4f;		\
																						\
	/* Clear the FORCE_STALL and TXPKTRDY bits */										\
	/* so the write has no effect. */													\
	( * ( ( unsigned portLONG * ) pulValueNow ) ) &= ( unsigned portLONG ) 0xffffffcf;	\
																						\
	/* Set whichever bit we want set. */												\
	( * ( ( unsigned portLONG * ) pulValueNow ) ) |= ( ulBit );							\
}

#define usbCSR_CLEAR_BIT( pulValueNow, ulBit )											\
{																						\
	/* Set TXCOMP, RX_DATA_BK0, RXSETUP, */												\
	/* STALLSENT and RX_DATA_BK1 to 1 so the */											\
	/* write has no effect. */															\
	( * ( ( unsigned portLONG * ) pulValueNow ) ) |= ( unsigned portLONG ) 0x4f;		\
																						\
	/* Clear the FORCE_STALL and TXPKTRDY bits */										\
	/* so the write has no effect. */													\
	( * ( ( unsigned portLONG * ) pulValueNow ) ) &= ( unsigned portLONG ) 0xffffffcf;	\
																						\
	/* Clear whichever bit we want clear. */											\
	( * ( ( unsigned portLONG * ) pulValueNow ) ) &= ( ~ulBit );						\
}

/*-----------------------------------------------------------*/

__arm void vUSB_ISR( void )
{
portBASE_TYPE xTaskWokenByPost = pdFALSE; 
static volatile unsigned portLONG ulNextMessage = 0;
xISRStatus *pxMessage;
unsigned portLONG ulTemp, ulRxBytes;

	/* Take the next message from the queue.  Note that usbQUEUE_LENGTH *must*
	be all 1's, as in 0x01, 0x03, 0x07, etc. */
	pxMessage = &( xISRMessages[ ( ulNextMessage & usbQUEUE_LENGTH ) ] );
	ulNextMessage++;

	/* Take a snapshot of the current USB state for processing at the task
	level. */
	pxMessage->ulISR = AT91C_BASE_UDP->UDP_ISR;
	pxMessage->ulCSR0 = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];

	/* Clear the interrupts from the ICR register.  The bus end interrupt is
	cleared separately as it does not appear in the mask register. */
	AT91C_BASE_UDP->UDP_ICR = AT91C_BASE_UDP->UDP_IMR | AT91C_UDP_ENDBUSRES;
	
	/* If there are bytes in the FIFO then we have to retrieve them here.  
	Ideally this would be done at the task level.  However we need to clear the
	RXSETUP interrupt before leaving the ISR, and this may cause the data in
	the FIFO to be overwritten.  Also the DIR bit has to be changed before the
	RXSETUP bit is cleared (as per the SAM7 manual). */
	ulTemp = pxMessage->ulCSR0;
	
	/* Are there any bytes in the FIFO? */
	ulRxBytes = ulTemp >> 16;
	ulRxBytes &= usbRX_COUNT_MASK;
	
	/* With this minimal implementation we are only interested in receiving 
	setup bytes on the control end point. */
	if( ( ulRxBytes > 0 ) && ( ulTemp & AT91C_UDP_RXSETUP ) )
	{
		/* Take off 1 for a zero based index. */
		while( ulRxBytes > 0 )
		{
			ulRxBytes--;
			pxMessage->ucFifoData[ ulRxBytes ] = AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_0 ];			
		}
		
		/* The direction must be changed first. */
		usbCSR_SET_BIT( &ulTemp, ( AT91C_UDP_DIR ) );
		AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulTemp;
	}
	
	/* Must write zero's to TXCOMP, STALLSENT, RXSETUP, and the RX DATA
	registers to clear the interrupts in the CSR register. */
	usbCSR_CLEAR_BIT( &ulTemp, usbINT_CLEAR_MASK );
	AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulTemp;

	/* Also clear the interrupts in the CSR1 register. */
	ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
	usbCSR_CLEAR_BIT( &ulTemp, usbINT_CLEAR_MASK );	
	AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulTemp;

	/* The message now contains the entire state and optional data from
	the USB interrupt.  This can now be posted on the Rx queue ready for
	processing at the task level. */
	xTaskWokenByPost = xQueueSendFromISR( xUSBInterruptQueue, &pxMessage, xTaskWokenByPost );

	/* We may want to switch to the USB task, if this message has made
	it the highest priority task that is ready to execute. */
	portEND_SWITCHING_ISR( xTaskWokenByPost );

	/* Clear the AIC ready for the next interrupt. */		
	AT91C_BASE_AIC->AIC_EOICR = 0;
}
/*-----------------------------------------------------------*/

void vUSBDemoTask( void *pvParameters )
{
xISRStatus *pxMessage;

	/* The parameters are not used in this task. */
	( void ) pvParameters;

    /* Init USB device */
    portENTER_CRITICAL();
	    vInitUSBInterface();
    portEXIT_CRITICAL();

	/* Process interrupts as they arrive.   The ISR takes a snapshot of the 
	interrupt status then posts the information on this queue for processing
	at the task level.  This simple demo implementation only processes
	a few interrupt sources. */
	for( ;; )
	{
		if( xQueueReceive( xUSBInterruptQueue, &pxMessage, usbSHORT_DELAY ) )
		{
			if( pxMessage->ulISR & AT91C_UDP_EPINT0 )
			{
				/* Process end point 0 interrupt. */
				prvProcessEndPoint0Interrupt( pxMessage );
			}

			if( pxMessage->ulISR & AT91C_UDP_ENDBUSRES )
			{
				/* Process an end of bus reset interrupt. */
				prvResetEndPoints();		
			}
		}
		else
		{
			/* The ISR did not post any data for us to process on the queue, so
			just generate and send some sample data. */
			if( eDriverState == eREADY_TO_SEND )
			{
				prvTransmitSampleValues();
			}
		}
	}
}
/*-----------------------------------------------------------*/

static void prvTransmitSampleValues( void )
{
unsigned portLONG ulStatus;
static portLONG lState = usbXUP;

/* Variables to hold dummy x, y and z joystick axis data. */
static signed portCHAR x = 0, y = 0, z = 0;

	/* Generate some sample data in the x and y axis - draw a square. */
	switch( lState )
	{
		case usbXUP	:	x += usbDATA_INC;
						if( x >= usbMAX_COORD )
						{
							lState = usbYUP;
						}
						break;
						
		case usbXDOWN :	x -= usbDATA_INC;
						if( x <= -usbMAX_COORD )
						{
							lState = usbYDOWN;
						}
						break;
						
		case usbYUP :	y += usbDATA_INC;
						if( y >= usbMAX_COORD )
						{
							lState = usbXDOWN;
						}
						break;
						
		case usbYDOWN :	y -= usbDATA_INC;
						if( y <= -usbMAX_COORD )
						{
							lState = usbXUP;
						}
						break;
	}

	/* Just make the z axis go up and down. */
	z += usbDATA_INC;

	/* Can we place data in the fifo? */
	if( !( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] & AT91C_UDP_TXPKTRDY ) )
	{
		/* Write our sample data to the fifo. */
		AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_1 ] = x;
		AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_1 ] = y;
		AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_1 ] = z;
		
		/* Send the data. */
		portENTER_CRITICAL();
		{
			ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
			usbCSR_SET_BIT( &ulStatus, ( AT91C_UDP_TXPKTRDY ) );
			AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulStatus;
		}
		portEXIT_CRITICAL();
	}
}
/*-----------------------------------------------------------*/

static void prvUSBTransmitNull( void )
{
unsigned portLONG ulStatus;

	/* Wait until the FIFO is free - even though we are not going to use it.
	THERE IS NO TIMEOUT HERE! */
	while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )
	{
		vTaskDelay( usbSHORTEST_DELAY );
	}

	portENTER_CRITICAL();
	{
		/* Set the length of data to send to equal the index of the next byte
		to send.  This will prevent the ACK to this NULL packet causing any
		further data transmissions. */
		pxCharsForTx.ulTotalDataLength = pxCharsForTx.ulNextCharIndex;

		/* Set the TXPKTRDY bit to cause a transmission with no data. */
		ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
		usbCSR_SET_BIT( &ulStatus, ( AT91C_UDP_TXPKTRDY ) );
		AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
	}
	portEXIT_CRITICAL();
}
/*-----------------------------------------------------------*/

static void prvSendStall( void )
{
unsigned portLONG ulStatus;

	portENTER_CRITICAL();
	{
		/* Force a stall by simply setting the FORCESTALL bit in the CSR. */
		ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
		usbCSR_SET_BIT( &ulStatus, AT91C_UDP_FORCESTALL );
		AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
	}
	portEXIT_CRITICAL();
}
/*-----------------------------------------------------------*/

static void prvResetEndPoints( void )
{
unsigned portLONG ulTemp;

	eDriverState = eJUST_RESET;

	/* Reset all the end points. */
	AT91C_BASE_UDP->UDP_RSTEP  = usbEND_POINT_RESET_MASK;
	AT91C_BASE_UDP->UDP_RSTEP  = ( unsigned portLONG ) 0x00;

	/* Enable data to be sent and received. */
	AT91C_BASE_UDP->UDP_FADDR = AT91C_UDP_FEN;

	/* Repair the configuration end point. */
	portENTER_CRITICAL();
	{
		ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
		usbCSR_SET_BIT( &ulTemp, ( ( unsigned portLONG ) ( AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL ) ) );
		AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulTemp;
		AT91F_UDP_EnableIt( AT91C_BASE_UDP, AT91C_UDP_EPINT0 );
	}
	portEXIT_CRITICAL();
}
/*-----------------------------------------------------------*/

static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage )
{
	if( pxMessage->ulCSR0 & AT91C_UDP_RX_DATA_BK0 )
	{		
		/* We only expect to receive zero length data here as ACK's. 
		Set the data pointer to the end of the current Tx packet to
		ensure we don't send out any more data. */	
		pxCharsForTx.ulNextCharIndex = pxCharsForTx.ulTotalDataLength;
	}

	if( pxMessage->ulCSR0 & AT91C_UDP_TXCOMP )
	{
		/* We received a TX complete interrupt.  What we do depends on
		what we sent to get this interrupt. */

		if( eDriverState == eJUST_GOT_CONFIG )
		{
			/* We sent an acknowledgement of a SET_CONFIG request.  We
			are now at the end of the enumeration. */
			AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_CONFG;

			/* Read the end point for data transfer. */
			portENTER_CRITICAL();
			{
				unsigned portLONG ulTemp;

				ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];					
				usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN );
				AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulTemp;		
				AT91F_UDP_EnableIt( AT91C_BASE_UDP, AT91C_UDP_EPINT1 );
			}
			portEXIT_CRITICAL();

			eDriverState = eREADY_TO_SEND;
		}		
		else if( eDriverState == eJUST_GOT_ADDRESS )
		{
			/* We sent an acknowledgement of a SET_ADDRESS request.  Move
			to the addressed state. */
			if( ulReceivedAddress != ( unsigned portLONG ) 0 )
			{			
				AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_FADDEN;
			}
			else

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -