📄 usb_hw.c
字号:
/*
**********************************************************************
* Micrium, Inc.
* 949 Crestview Circle
* Weston, FL 33327-1848
*
* uC/USB-Bulk
*
* (c) Copyright 2003 - 2004, Micrium, Inc.
* All rights reserved.
*
***********************************************************************
----------------------------------------------------------------------
File : USB_HW.h
Purpose : Hardware sample for Renesas M30245
-------- END-OF-HEADER ---------------------------------------------
*/
#include "IOM30245.h"
#include "USB_Private.h"
#include "RTOS.h"
/*********************************************************************
*
* Static data
*
**********************************************************************
*/
#define EP0CS_OUT_BUF_READY (1 << 0)
#define EP0CS_SETUP (1 << 2)
#define EP0CS_SETUP_READY (EP0CS_OUT_BUF_READY | EP0CS_SETUP)
//
// Computation of buffer locations. Should not require changes
//
#define BUFFER_OFF_IN 0
#define BUFFER_OFF_OUT BUFFER_OFF_IN + (MAXT_IN * 2)
extern void USB_HW_Send64(OS_U16 * pData16); // Assembly !
extern void USB_HW_Read64(OS_U16 * pData); // Assembly !
/*********************************************************************
*
* USB_HW_Init
*
* DESCRIPTION:
* Sets default values for EP0 and enables the various interrupts
* needed for USB operations.
*/
void USB_HW_Init(void){
EP0MP = 0x0008; // EP0 MAXP packet size = 64, continuous mode
EP0IC = 0x03; // Enable the EP0 interrupt
USBFIC = 0x03; // Enable the USB function interrupt
}
/*********************************************************************
*
* USB_HW_FreeBuffer
*
* Function description
* Let the USB controller know that received packet has been read
* and the buffer can now be re-used
*
* Context:
* Task or ISR
*/
void USB_HW_FreeBuffer(void) {
EP1OCS |= (1<<5); // Clear "out buffer ready": We are ready to receive a new packet
}
/*********************************************************************
*
* USB_HW_memcpy
*
* Function description
*
*
* Context:
* Task or ISR
*/
/* --> Coded in ASM
void USB_HW_memcpy(void * pDest, void * pSrc, unsigned Len) {
do {
*(char near*)pDest = *(char near*)pSrc;
} while (--Len);
}
*/
/*********************************************************************
*
* USB_HW_BufferAvailable
*
* Function description
* Returns if a buffer is available
*
* Context:
* Task or ISR. Interrupts must be disbled !
*/
int USB_HW_BufferAvailable(void) {
return ((EP1ICS & (3 << 0)) == 3) ? 0 : 1;
}
/*********************************************************************
*
* USB_HW_SendData
*
* Function description
* Sends out data (bulk mode) on EP1
*
* Context:
* Task
*/
void USB_HW_SendData(const void* pData, unsigned NumBytes) {
if (NumBytes) {
//
// Data is near area (RAM). This is so most of the time, so we can optimize here.
//
USB_U16 near * pData16;
pData16 = (USB_U16 near *)pData;
#ifdef __ICCM16C__
while (NumBytes >= 64) {
USB_HW_Send64(pData16);
pData16 += 32;
NumBytes -= 64;
}
#endif
while (NumBytes >= 16) {
EP1I = *pData16;
EP1I = *(pData16+1);
EP1I = *(pData16+2);
EP1I = *(pData16+3);
EP1I = *(pData16+4);
EP1I = *(pData16+5);
EP1I = *(pData16+6);
EP1I = *(pData16+7);
pData16 += 8;
NumBytes -= 16;
}
while (NumBytes >= 4) {
EP1I = *pData16;
EP1I = *(pData16 + 1);
pData16 += 2;
NumBytes -= 4;
}
if (NumBytes) {
char * pData8 = (char*)pData16;
do {
EP1IL = *pData8++;
} while (--NumBytes);
}
}
EP1ICS |= (1<<3); // Send this packet out
}
/*********************************************************************
*
* USB_HW_Read
*
* Function description
* Read the received data from the USB controller
* Note: This function is heavily speed optimized.
* It uses near pointers, which means the target RAM has
* to be in the 64 kb Area 0000 - ffff.
* This is typically so, since normally the chip is used
* with internal RAM only
*
* Context:
* Task or ISR
*/
void USB_HW_Read(void * pDest, int NumBytes, unsigned PacketOff) {
static char _ReadByte;
if (NumBytes) { // Safety only ... SHould not be required
register int near * pData;
pData = (int near *)pDest;
//
// If packet offset is even, we first need to fetch one byte
//
if (PacketOff & 1) {
char *p8 = (char*)pData;
*p8++ = _ReadByte;
pData = (int near *)p8;
NumBytes--;
}
//
// Optimization: Handle 64 bytes at a time in a fast subroutine
//
while (NumBytes >= 64) {
USB_HW_Read64((OS_U16*)pData);
pData += 32;
NumBytes -= 64;
}
//
// Read the bulk of the data
//
while (NumBytes >= 16) {
*pData = EP1O;
*(pData+1) = EP1O;
*(pData+2) = EP1O;
*(pData+3) = EP1O;
*(pData+4) = EP1O;
*(pData+5) = EP1O;
*(pData+6) = EP1O;
*(pData+7) = EP1O;
pData += 8;
NumBytes -=16;
}
while (NumBytes >= 2) {
*pData = EP1O;
pData ++;
NumBytes -= 2;
}
if (NumBytes) {
USB_U16 Data = EP1O;
*(char near *)pData = Data & 255;
_ReadByte = Data >> 8;
}
}
}
/*********************************************************************
*
* USB_HW_Attach
*/
void USB_HW_Attach(void) {
USBAD |= (1<<1); // and pullup D+ for host attachemnt
}
/*********************************************************************
*
* USB_HW_UnloadEP0
*
* Function description
* Called after a setup packet has been successfully evaluated.
* Tells the USB controller that the associated data buffer is
* no longer needed and can be freed.
*/
void USB_HW_UnloadEP0(void) {
EP0CS = 0x2240; // Set DATA_END, OPR, SETUP flag
}
/*********************************************************************
*
* USB_HW_StallEP0
*/
void USB_HW_StallEP0(void) {
EP0CS = 0x1140;
}
/*********************************************************************
*
* USB_HW_SetAddress
*/
void USB_HW_SetAddress(unsigned char Adr) {
USBA = Adr;
}
/*********************************************************************
*
* USB_HW_EnableEP1
*/
void USB_HW_EnableEP1(void) {
USBIE = 0x100; // Disable all EP interrupts
USBEPEN = 0; // Disable all EP's
/* Assign the buffer memory to the endpoints */
EP1IMP = 64; // MAXP (maximum packet size)
EP1OMP = 64; // MAXP (maximum packet size)
EP1IFC = (BUFFER_OFF_IN / 64) // bits[0..5]: Buffer start location / 64
|((MAXT_IN/64 - 1) << 6) // bits[6..9]: Buffer size / 64 - 1
| (1 << 10) // bit[10]: Double buffer mode enable
| (1 << 11); // bit[11]: Continuous mode enable
EP1OFC = (BUFFER_OFF_OUT / 64) // bits[0..5]: Buffer start location / 64
|((MAXT_OUT/64 - 1) << 6) // bits[6..9]: Buffer size / 64 - 1
| (1 << 10) // bit[10]: 1: Double buffer mode enable
| (1 << 11); // bit[11]: 1: Continuous mode enable
EP1OCS |= (1 << 5) // Unload from out buffer
| (1 << 6) // Clear over run
| (1 << 7)
| (1 << 8)
| (1 << 10);
EP1OCS |= (1 << 5) // Unload from out buffer
| (1 << 6) // Clear over run
| (1 << 7)
| (1 << 8)
| (1 << 10);
/* Enable USB endpoints & interrupts */
USBEPEN = 3; // Enable EP1 IN & OUT
USBIC = (0x1ff); // Clear pending interrupts
USBIE = 3; // Enable EP1 IN & OUT interrupts
}
/*********************************************************************
*
* USB_HW_EP0_Send
*
* Description
* Sends a packet on EP0.
*
* Notes
* (1) If last packet is = to MAXP, we have to send a NULL packet if specified.
*
*/
void USB_HW_EP0_Send(const unsigned char * pData, unsigned char SendLength, char SendNULLPacket) {
unsigned char Bytes2Send;
OS_DI();
//
// Send the data in chunks of no more than 8 bytes
//
while (SendLength) {
if ( SendLength < 8 ) { // If last packet is < MAXP, a NULL packet is not required
SendNULLPacket = 0;
}
if ( SendLength > 8 ) { // If more than 8 bytes then break it up
Bytes2Send = 8;
SendLength -= 8;
} else {
Bytes2Send = SendLength;
SendLength = 0;
}
//
// Load the fifo
//
for( ; Bytes2Send; Bytes2Send--) {
EP0IL = *pData++;
}
if (SendLength | (SendNULLPacket)) {
EP0CS |= (1<<7); // Set IN_PKY_RDY
} else {
EP0CS = 0x2280; // Set DATA_END, IPR, and DATA_END mask (NULL packet)
}
while ( (EP0CS & (1<<1)) ){} // and wait for this packet to be taken
}
//
// Send a NULL packet if required
//
if (SendNULLPacket) { // Is NULL packet needed?
EP0CS = 0x2280; // Set DATA_END, IPR, and DATA_END mask (NULL packet)
while (EP0CS & (1<<1)); // Wait for this packet to be taken
}
OS_RestoreI();
}
/*********************************************************************
*
* USB_HW_ClearOutPacketReady
*
* Description
* TBD
*/
void USB_HW_ClearOutPacketReady(void) {
EP0CS = (1<<6);
}
/*********************************************************************
*
* USB_HW_ClrSetupEnd
*
* Description
* TBD
*/
void USB_HW_ClrSetupEnd(void) {
EP0CS |= (1<<8);
}
/*********************************************************************
*
* USB_ISR_Function
*
* Function Description
* USB functional interrupt occurs when data is sent
* or received. Various flags are set or cleared here
* depending on program flow for the starter kit
*
*/
#pragma vector = 29
__regbank_interrupt void USB_ISR_Function(void){
OS_EnterInterrupt();
if ( (EP0CS & (1<<5)) ){ // Did the control transfer end early?
EP0CS |= (1 << 11); // Clear setup end
USBIC = (1<<8); // Clear error status flag
}
if ( (USBIS & (1<<8)) ){ // Error ?
USBIC = (1<<8); // Clear error status flag
}
if ( (USBIS & (1<<0)) ){ // EP1 IN Interrupt
USBIC = (1<<0); // Clear EP1 IN interrupt status flag
USB__OnTx();
}
if ( (USBIS & (1<<1)) ){ // EP1 OUT Interrupt ?
USBIC = (1<<1); // Clear EP1 OUT interrupt status flag
if ( (EP1OCS & (1<<1)) ) { // Data available ?
int PacketSize = EP1WC;
USB__OnRx(PacketSize);
}
}
OS_LeaveInterrupt();
}
/*********************************************************************
*
* USB_ISR_EP0
*
* Function Description
* USB Endpoint 0 interrupt occurs when a SETUP packet is received
* to setup the USB controller.
*/
#pragma vector = 6
__interrupt void USB_ISR_EP0(void) {
USB_SETUP_PACKET SetupPacket;
OS_EnterInterrupt();
if ((EP0CS & EP0CS_SETUP_READY) == EP0CS_SETUP_READY) { // Check is this is a SETUP packet
SetupPacket.bmRequestType = EP0OL; // If so, read the data out of the
SetupPacket.bRequest = EP0OL; // FIFO and place in this
SetupPacket.wValueLow = EP0OL; // structure
SetupPacket.wValueHigh = EP0OL;
SetupPacket.wIndexLow = EP0OL;
SetupPacket.wIndexHigh = EP0OL;
SetupPacket.wLengthLow = EP0OL;
SetupPacket.wLengthHigh = EP0OL;
if (EP0CS & (1<<12)){ // If SEND_STALL is set, then clear it
EP0CS |= (0<<12); // Since this is a new SETUP packet
}
USB__HandleSetup(&SetupPacket);
}
OS_LeaveInterrupt();
}
/*********************************************************************
*
* USB_ISR_Reset
*
* Function Description
* When a USB RESET occurs this function restores the
* necessary variables and EP's to default values
*
*/
#pragma vector = 26
__interrupt void USB_ISR_Reset(void) {}
/*********************************************************************
*
* VBUSDetectInterrupt
*
* Function Description
* Detects if the USB cable has been plugged in.
* Does not make sense for USB powered devices.
*/
#pragma vector = 28
__interrupt void VBUS_ISR_DetectInterrupt(void){}
/*********************************************************************
*
* USB_ISR_SOF
* Function Description
* Interrupt on every Start-Of-Frame
* Does not make sense.
*/
#pragma vector = 27
__interrupt void USB_ISR_SOF(void){}
/*********************************************************************
*
* USB_ISR_Suspend
*
* Function Description
* USB SUSPEND interrupt routine. When the D+/D- is idle for more than
* 3mS, the USB core will enter the SUSPEND state. This can also be caused
* if the USB cable is unplugged. Here all interrupts are disabled with
* the exception of the USB RESUME interrupt and the device enters STOP
* mode for low power.
*/
#pragma vector = 22
__interrupt void USB_ISR_Suspend(void){}
/*********************************************************************
*
* USB_ISR_Resume
*
* Function Description
* After entering the SUSPEND state, when the USB core detects signalling
* on D+/D-, an interrupt is generated, waking the device from the STOP
* state. This interrupt routine starts up the USB core and re-enables
* the appropriate interrupts for other functions.
*/
#pragma vector = 24
__interrupt void USB_ISR_Resume(void){}
/*************************** End of file ****************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -