/* ---------------------------------------------------------------------------- * SAM Software Package License * ---------------------------------------------------------------------------- * Copyright (c) 2011-2012, Atmel Corporation * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following condition is met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * * Atmel's name may not be used to endorse or promote products derived from * this software without specific prior written permission. * * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ---------------------------------------------------------------------------- */ #include "chip.h" #if 0 //SAM3U_SERIES #include "USB_device.h" #include "udphs.h" /// Max size of the FMA FIFO #define EPT_VIRTUAL_SIZE (16384u) #define SHIFT_INTERUPT (8u) int _cmark; int _cend; // Global variable for endpoint number unsigned int NumEndpoint=0; void USBD_WaitIN(void) { // while (!(UEINTX & (1<UDPHS_EPT[0].UDPHS_EPTSTA & UDPHS_EPTSTA_TX_PK_RDY)); } void USBD_WaitOUT(void) { // while (!(UEINTX & (1<UDPHS_EPT[NumEndpoint].UDPHS_EPTSTA & UDPHS_EPTSTA_RX_BK_RDY)); } void USBD_ClearIN(void) { // UEINTX = ~(1<UDPHS_EPT[NumEndpoint].UDPHS_EPTCLRSTA = UDPHS_EPTCLRSTA_TX_COMPLT; } void USBD_ClearOUT(void) { // UEINTX = ~(1<UDPHS_EPT[NumEndpoint].UDPHS_EPTCLRSTA = UDPHS_EPTCLRSTA_RX_BK_RDY; } uint8_t USBD_WaitForINOrOUT(void) { // while (!(UEINTX & ((1<UDPHS_EPT[NumEndpoint].UDPHS_EPTSTA & (UDPHS_EPTSTA_RX_BK_RDY | UDPHS_EPTSTA_TX_PK_RDY))); return (UDPHS->UDPHS_EPT[NumEndpoint].UDPHS_EPTSTA & UDPHS_EPTSTA_RX_BK_RDY) == 0; } void USBD_ClearRxFlag(unsigned char bEndpoint) { UDPHS->UDPHS_EPT[NumEndpoint].UDPHS_EPTCLRSTA = UDPHS_EPTCLRSTA_RX_BK_RDY; } void USBD_Stall(void) { // UECONX = (1<UDPHS_EPT[NumEndpoint].UDPHS_EPTSETSTA = UDPHS_EPTSETSTA_FRCESTALL; } uint8_t USBD_Stalled(void) { // return UEINTX & (1<UDPHS_EPT[NumEndpoint].UDPHS_EPTSTA & UDPHS_EPTSTA_FRCESTALL)); } uint8_t USBD_ReceivedSetupInt(void) { // return UEINTX & (1<UDPHS_EPT[NumEndpoint].UDPHS_EPTSTA & UDPHS_EPTSTA_RX_SETUP) ); } void USBD_ClearSetupInt(void) { // UEINTX = ~((1<UDPHS_EPT[NumEndpoint].UDPHS_EPTCLRSTA = UDPHS_EPTSTA_RX_SETUP | UDPHS_EPTCLRSTA_RX_BK_RDY | UDPHS_EPTCLRSTA_TX_COMPLT; } uint8_t USBD_ReadWriteAllowed(void) { //return UEINTX & (1<UOTGHS_DEVEPTISR[ep] & UOTGHS_DEVEPTISR_BYCT_Msk) >> UOTGHS_DEVEPTISR_BYCT_Pos); // SAM3U //AT91C_UDPHS_BYTE_COUNT (0x7FF << 20) return ((UDPHS->UDPHS_EPT[NumEndpoint].UDPHS_EPTSTA & UDPHS_EPTSTA_BYTE_COUNT_Msk) >> UDPHS_EPTSTA_BYTE_COUNT_Pos); } uint8_t USBD_FifoFree(void) { // return UEINTX & (1<UDPHS_EPT[NumEndpoint].UDPHS_EPTSTA & UDPHS_EPTSTA_TX_PK_RDY )); } void USBD_ReleaseRX(void) { UEINTX = 0x6B; // FIFOCON=0 NAKINI=1 RWAL=1 NAKOUTI=0 RXSTPI=1 RXOUTI=0 STALLEDI=1 TXINI=1 } void USBD_ReleaseTX() { UEINTX = 0x3A; // FIFOCON=0 NAKINI=0 RWAL=1 NAKOUTI=1 RXSTPI=1 RXOUTI=0 STALLEDI=1 TXINI=0 } uint8_t USBD_FrameNumber(void) { return UDFNUML; } uint8_t USBD_GetConfiguration(void) { return _usbConfiguration; } void USBD_Recv(volatile uint8_t* data, uint8_t count) { uint8_t *pFifo; pFifo = (uint8_t*)((uint32_t *)UDPHS_RAM_ADDR + (EPT_VIRTUAL_SIZE * NumEndpoint)); while (count--) { *data++ = pFifo[0]; } // RXLED1; // light the RX LED // RxLEDPulse = TX_RX_LED_PULSE_MS; } uint8_t USBD_Recv8(void) { uint8_t *pFifo; // RXLED1; // light the RX LED // RxLEDPulse = TX_RX_LED_PULSE_MS; pFifo = (uint8_t*)((uint32_t *)UDPHS_RAM_ADDR + (EPT_VIRTUAL_SIZE * NumEndpoint)); // return UEDATX; return (pFifo[0]); } void USBD_Send8(uint8_t d) { uint8_t *pFifo; pFifo = (uint8_t*)((uint32_t *)UDPHS_RAM_ADDR + (EPT_VIRTUAL_SIZE * NumEndpoint)); // UEDATX = d; pFifo[0] =d; } // Blocking Send of data to an endpoint int USBD_Send(uint8_t ep, const void* d, int len) { if (!_usbConfiguration) return -1; int r = len; const uint8_t* data = (const uint8_t*)d; uint8_t zero = ep & TRANSFER_ZERO; uint8_t timeout = 250; // 250ms timeout on send? TODO while (len) { uint8_t n = USB_SendSpace(ep); if (n == 0) { if (!(--timeout)) return -1; delay(1); continue; } if (n > len) n = len; len -= n; { SetEP(ep); if (ep & TRANSFER_ZERO) { while (n--) Send8(0); } else if (ep & TRANSFER_PGM) { while (n--) Send8(*data++); } else { while (n--) Send8(*data++); } // if (!ReadWriteAllowed() || ((len == 0) && (ep & TRANSFER_RELEASE))) // Release full buffer // ReleaseTX(); } } TXLED1; // light the TX LED TxLEDPulse = TX_RX_LED_PULSE_MS; return r; } // Space in send EP uint8_t USBD_SendSpace(uint8_t ep) { SetEP(ep); if (!ReadWriteAllowed()) { return 0; } return 64 - FifoByteCount(); } // Number of bytes, assumes a rx endpoint uint8_t USBD_Available(uint8_t ep) { SetEP(ep); return FifoByteCount(); } void USBD_InitEP(uint8_t index, uint8_t type, uint8_t size) { UENUM = index; UECONX = 1; UECFG0X = type; UECFG1X = size; } void USBD_InitEndpoints(void) { for (uint8_t i = 1; i < sizeof(_initEndpoints); i++) { // Reset Endpoint Fifos UDPHS->UDPHS_EPT[i].UDPHS_EPTCLRSTA = UDPHS_EPTCLRSTA_TOGGLESQ | UDPHS_EPTCLRSTA_FRCESTALL; UDPHS->UDPHS_EPTRST = 1<UDPHS_EPT[i].UDPHS_EPTCFG = _initEndpoints[i]; while( (signed int)UDPHS_EPTCFG_EPT_MAPD != (signed int)((UDPHS->UDPHS_EPT[i].UDPHS_EPTCFG) & (unsigned int)UDPHS_EPTCFG_EPT_MAPD) ) ; UDPHS->UDPHS_EPT[i].UDPHS_EPTCTLENB = UDPHS_EPTCTLENB_EPT_ENABL; // UECFG1X = EP_DOUBLE_64; } ///\// UERST = 0x7E; // And reset them ///\// UERST = 0; } void USBD_InitControl(int end) { SetEP(0); UDPHS->UDPHS_EPT[0].UDPHS_EPTCFG = _initEndpoints[0]; while( (signed int)UDPHS_EPTCFG_EPT_MAPD != (signed int)((UDPHS->UDPHS_EPT[0].UDPHS_EPTCFG) & (unsigned int)UDPHS_EPTCFG_EPT_MAPD) ) ; UDPHS->UDPHS_EPT[0].UDPHS_EPTCTLENB = UDPHS_EPTCTLENB_RX_BK_RDY | UDPHS_EPTCTLENB_RX_SETUP | UDPHS_EPTCTLENB_EPT_ENABL; _cmark = 0; _cend = end; } void UDPHS_Handler( void ) { unsigned int status; unsigned char numIT; // Get interrupts status status = UDPHS->UDPHS_INTSTA & UDPHS->UDPHS_IEN; // Handle all UDPHS interrupts while (status != 0) { // Start of Frame - happens every millisecond so we use it for TX and RX LED one-shot timing, too if ((status & UDPHS_IEN_INT_SOF) != 0) { #ifdef CDC_ENABLED USB_Flush(CDC_TX); // Send a tx frame if found #endif // check whether the one-shot period has elapsed. if so, turn off the LED if (TxLEDPulse && !(--TxLEDPulse)) TXLED0; if (RxLEDPulse && !(--RxLEDPulse)) RXLED0; // Acknowledge interrupt UDPHS->UDPHS_CLRINT = UDPHS_CLRINT_INT_SOF; status &= ~UDPHS_IEN_INT_SOF; } // Suspend // This interrupt is always treated last (hence the '==') else if (status == UDPHS_IEN_DET_SUSPD) { //UDPHS_DisableBIAS(); // Enable wakeup UDPHS->UDPHS_IEN |= UDPHS_IEN_WAKE_UP | UDPHS_IEN_ENDOFRSM; UDPHS->UDPHS_IEN &= ~UDPHS_IEN_DET_SUSPD; // Acknowledge interrupt UDPHS->UDPHS_CLRINT = UDPHS_CLRINT_DET_SUSPD | UDPHS_CLRINT_WAKE_UP; //UDPHS_DisableUsbClock(); } // Resume else if( ((status & UDPHS_IEN_WAKE_UP) != 0) // line activity || ((status & UDPHS_IEN_ENDOFRSM) != 0)) { // pc wakeup { //UDPHS_EnableUsbClock(); //UDPHS_EnableBIAS(); UDPHS->UDPHS_CLRINT = UDPHS_CLRINT_WAKE_UP | UDPHS_CLRINT_ENDOFRSM | UDPHS_CLRINT_DET_SUSPD; UDPHS->UDPHS_IEN |= UDPHS_IEN_ENDOFRSM | UDPHS_IEN_DET_SUSPD; UDPHS->UDPHS_CLRINT = UDPHS_CLRINT_WAKE_UP | UDPHS_CLRINT_ENDOFRSM; UDPHS->UDPHS_IEN &= ~UDPHS_IEN_WAKE_UP; } } // End of Reset else if ((status & UDPHS_IEN_ENDRESET) == UDPHS_IEN_ENDRESET) { InitControl(0); // init ep0 _usbConfiguration = 0; // not configured yet //UEIENX = 1 << RXSTPE; // Enable interrupts for ep0 //UDPHS_ResetEndpoints(); //UDPHS_DisableEndpoints(); //USBD_ConfigureEndpoint(0); UDPHS->UDPHS_IEN |= (1<UDPHS_CLRINT = UDPHS_CLRINT_WAKE_UP | UDPHS_CLRINT_DET_SUSPD; //// Enable the Start Of Frame (SOF) interrupt if needed UDPHS->UDPHS_IEN |= UDPHS_IEN_INT_SOF; // Acknowledge end of bus reset interrupt UDPHS->UDPHS_CLRINT = UDPHS_CLRINT_ENDRESET; UDPHS->UDPHS_IEN |= UDPHS_IEN_DET_SUSPD; } // Handle upstream resume interrupt else if (status & UDPHS_IEN_UPSTR_RES) { // - Acknowledge the IT UDPHS->UDPHS_CLRINT = UDPHS_CLRINT_UPSTR_RES; } // Endpoint interrupts else { // Handle endpoint interrupts for (numIT = 0; numIT < NUM_IT_MAX; numIT++) { if ((status & (1 << SHIFT_INTERUPT << numIT)) != 0) { USB_ISR(); //EndpointHandler(numIT); // TODO: interrupt for bulk } } } // Retrieve new interrupt status status = UDPHS->UDPHS_INTSTA & UDPHS->UDPHS_IEN; } } void USBD_Attach( void ) {/* _usbConfiguration = 0; //UHWCON = 0x01; // power internal reg //USBCON = (1<PMC_PCER = (1 << ID_UDPHS); // Enable 480MHZ //AT91C_BASE_CKGR->CKGR_UCKR |= (AT91C_CKGR_PLLCOUNT & (3 << 20)) | AT91C_CKGR_UPLLEN; CKGR->CKGR_UCKR |= ((0xf << 20) & (3 << 20)) | AT91C_CKGR_UPLLEN; // Wait until UTMI PLL is locked while ((PMC->PMC_SR & PMC_LOCKU) == 0); // Reset and enable IP UDPHS UDPHS->UDPHS_CTRL &= ~UDPHS_CTRL_EN_UDPHS; UDPHS->UDPHS_CTRL |= UDPHS_CTRL_EN_UDPHS; //USBCON = ((1<UDPHS_IEN = 0; UDPHS->UDPHS_CLRINT = UDPHS_CLRINT_UPSTR_RES | UDPHS_CLRINT_ENDOFRSM | UDPHS_CLRINT_WAKE_UP | UDPHS_CLRINT_ENDRESET | UDPHS_CLRINT_INT_SOF | UDPHS_CLRINT_MICRO_SOF | UDPHS_CLRINT_DET_SUSPD; // Enable interrupts for EOR (End of Reset), wake up and SOF (start of frame) //UDIEN = (1<UDPHS_IEN = UDPHS_IEN_ENDOFRSM | UDPHS_IEN_WAKE_UP | UDPHS_IEN_DET_SUSPD; // enable attach resistor //UDCON = 0; UDPHS->UDPHS_CTRL &= ~UDPHS_CTRL_DETACH; // Pull Up on DP UDPHS->UDPHS_CTRL |= UDPHS_CTRL_PULLD_DIS; // Disable Pull Down TX_RX_LED_INIT; */} void USBD_Detach( void ) { UDPHS->UDPHS_CTRL |= UDPHS_CTRL_DETACH; // detach UDPHS->UDPHS_CTRL &= ~UDPHS_CTRL_PULLD_DIS; // Enable Pull Down } #endif /* SAM3U_SERIES */