USBHost library

Dependencies:   FATFileSystem mbed-rtos

Dependents:   AbitUSBModem_HTTPTest AbitUSBModem_MQTTTest AbitUSBModem_WebsocketTest AbitUSBModem_SMSTest

Fork of USBHost by mbed official

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers USBHALHost_LPC17.cpp Source File

USBHALHost_LPC17.cpp

00001 /* mbed USBHost Library
00002  * Copyright (c) 2006-2013 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #if defined(TARGET_LPC1768)
00018 
00019 #include "mbed.h"
00020 #include "USBHALHost.h"
00021 #include "dbg.h"
00022 
00023 // bits of the USB/OTG clock control register
00024 #define HOST_CLK_EN     (1<<0)
00025 #define DEV_CLK_EN      (1<<1)
00026 #define PORTSEL_CLK_EN  (1<<3)
00027 #define AHB_CLK_EN      (1<<4)
00028 
00029 // bits of the USB/OTG clock status register
00030 #define HOST_CLK_ON     (1<<0)
00031 #define DEV_CLK_ON      (1<<1)
00032 #define PORTSEL_CLK_ON  (1<<3)
00033 #define AHB_CLK_ON      (1<<4)
00034 
00035 // we need host clock, OTG/portsel clock and AHB clock
00036 #define CLOCK_MASK (HOST_CLK_EN | PORTSEL_CLK_EN | AHB_CLK_EN)
00037 
00038 #define HCCA_SIZE sizeof(HCCA)
00039 #define ED_SIZE sizeof(HCED)
00040 #define TD_SIZE sizeof(HCTD)
00041 
00042 #define TOTAL_SIZE (HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE) + (MAX_TD*TD_SIZE))
00043 
00044 static volatile uint8_t usb_buf[TOTAL_SIZE] __attribute((section("AHBSRAM1"),aligned(256)));  //256 bytes aligned!
00045 
00046 USBHALHost * USBHALHost::instHost;
00047 
00048 USBHALHost::USBHALHost() {
00049     instHost = this;
00050     memInit();
00051     memset((void*)usb_hcca, 0, HCCA_SIZE);
00052     for (int i = 0; i < MAX_ENDPOINT; i++) {
00053         edBufAlloc[i] = false;
00054     }
00055     for (int i = 0; i < MAX_TD; i++) {
00056         tdBufAlloc[i] = false;
00057     }
00058 }
00059 
00060 void USBHALHost::init() {
00061     NVIC_DisableIRQ(USB_IRQn);
00062 
00063     //Cut power
00064     LPC_SC->PCONP &= ~(1UL<<31);
00065     wait_ms(100);
00066 
00067     // turn on power for USB
00068     LPC_SC->PCONP       |= (1UL<<31);
00069 
00070     // Enable USB host clock, port selection and AHB clock
00071     LPC_USB->USBClkCtrl |= CLOCK_MASK;
00072 
00073     // Wait for clocks to become available
00074     while ((LPC_USB->USBClkSt & CLOCK_MASK) != CLOCK_MASK);
00075 
00076     // it seems the bits[0:1] mean the following
00077     // 0: U1=device, U2=host
00078     // 1: U1=host, U2=host
00079     // 2: reserved
00080     // 3: U1=host, U2=device
00081     // NB: this register is only available if OTG clock (aka "port select") is enabled!!
00082     // since we don't care about port 2, set just bit 0 to 1 (U1=host)
00083     LPC_USB->OTGStCtrl |= 1;
00084 
00085     // now that we've configured the ports, we can turn off the portsel clock
00086     LPC_USB->USBClkCtrl &= ~PORTSEL_CLK_EN;
00087 
00088     // configure USB D+/D- pins
00089     // P0[29] = USB_D+, 01
00090     // P0[30] = USB_D-, 01
00091     LPC_PINCON->PINSEL1 &= ~((3<<26) | (3<<28));
00092     LPC_PINCON->PINSEL1 |=  ((1<<26) | (1<<28));
00093 
00094     LPC_USB->HcControl       = 0; // HARDWARE RESET
00095     LPC_USB->HcControlHeadED = 0; // Initialize Control list head to Zero
00096     LPC_USB->HcBulkHeadED    = 0; // Initialize Bulk list head to Zero
00097 
00098     // Wait 100 ms before apply reset
00099     wait_ms(100);
00100 
00101     // software reset
00102     LPC_USB->HcCommandStatus = OR_CMD_STATUS_HCR;
00103 
00104     // Write Fm Interval and Largest Data Packet Counter
00105     LPC_USB->HcFmInterval    = DEFAULT_FMINTERVAL;
00106     LPC_USB->HcPeriodicStart = FI * 90 / 100;
00107 
00108     // Put HC in operational state
00109     LPC_USB->HcControl  = (LPC_USB->HcControl & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER;
00110     // Set Global Power
00111     LPC_USB->HcRhStatus = OR_RH_STATUS_LPSC;
00112 
00113     LPC_USB->HcHCCA = (uint32_t)(usb_hcca);
00114 
00115     // Clear Interrrupt Status
00116     LPC_USB->HcInterruptStatus |= LPC_USB->HcInterruptStatus;
00117 
00118     LPC_USB->HcInterruptEnable  = OR_INTR_ENABLE_MIE | OR_INTR_ENABLE_WDH | OR_INTR_ENABLE_RHSC;
00119 
00120     // Enable the USB Interrupt
00121     NVIC_SetVector(USB_IRQn, (uint32_t)(_usbisr));
00122     LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC;
00123     LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC;
00124 
00125     NVIC_EnableIRQ(USB_IRQn);
00126 
00127     // Check for any connected devices
00128     if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS) {
00129         //Device connected
00130         wait_ms(150);
00131         USB_DBG("Device connected (%08x)\n\r", LPC_USB->HcRhPortStatus1);
00132         deviceConnected(0, 1, LPC_USB->HcRhPortStatus1 & OR_RH_PORT_LSDA);
00133     }
00134 }
00135 
00136 uint32_t USBHALHost::controlHeadED() {
00137     return LPC_USB->HcControlHeadED;
00138 }
00139 
00140 uint32_t USBHALHost::bulkHeadED() {
00141     return LPC_USB->HcBulkHeadED;
00142 }
00143 
00144 uint32_t USBHALHost::interruptHeadED() {
00145     return usb_hcca->IntTable[0];
00146 }
00147 
00148 void USBHALHost::updateBulkHeadED(uint32_t addr) {
00149     LPC_USB->HcBulkHeadED = addr;
00150 }
00151 
00152 
00153 void USBHALHost::updateControlHeadED(uint32_t addr) {
00154     LPC_USB->HcControlHeadED = addr;
00155 }
00156 
00157 void USBHALHost::updateInterruptHeadED(uint32_t addr) {
00158     usb_hcca->IntTable[0] = addr;
00159 }
00160 
00161 
00162 void USBHALHost::enableList(ENDPOINT_TYPE type) {
00163     switch(type) {
00164         case CONTROL_ENDPOINT:
00165             LPC_USB->HcCommandStatus = OR_CMD_STATUS_CLF;
00166             LPC_USB->HcControl |= OR_CONTROL_CLE;
00167             break;
00168         case ISOCHRONOUS_ENDPOINT:
00169             break;
00170         case BULK_ENDPOINT:
00171             LPC_USB->HcCommandStatus = OR_CMD_STATUS_BLF;
00172             LPC_USB->HcControl |= OR_CONTROL_BLE;
00173             break;
00174         case INTERRUPT_ENDPOINT:
00175             LPC_USB->HcControl |= OR_CONTROL_PLE;
00176             break;
00177     }
00178 }
00179 
00180 
00181 bool USBHALHost::disableList(ENDPOINT_TYPE type) {
00182     switch(type) {
00183         case CONTROL_ENDPOINT:
00184             if(LPC_USB->HcControl & OR_CONTROL_CLE) {
00185                 LPC_USB->HcControl &= ~OR_CONTROL_CLE;
00186                 return true;
00187             }
00188             return false;
00189         case ISOCHRONOUS_ENDPOINT:
00190             return false;
00191         case BULK_ENDPOINT:
00192             if(LPC_USB->HcControl & OR_CONTROL_BLE){
00193                 LPC_USB->HcControl &= ~OR_CONTROL_BLE;
00194                 return true;
00195             }
00196             return false;
00197         case INTERRUPT_ENDPOINT:
00198             if(LPC_USB->HcControl & OR_CONTROL_PLE) {
00199                 LPC_USB->HcControl &= ~OR_CONTROL_PLE;
00200                 return true;
00201             }
00202             return false;
00203     }
00204     return false;
00205 }
00206 
00207 
00208 void USBHALHost::memInit() {
00209     usb_hcca = (volatile HCCA *)usb_buf;
00210     usb_edBuf = usb_buf + HCCA_SIZE;
00211     usb_tdBuf = usb_buf + HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE);
00212 }
00213 
00214 volatile uint8_t * USBHALHost::getED() {
00215     for (int i = 0; i < MAX_ENDPOINT; i++) {
00216         if ( !edBufAlloc[i] ) {
00217             edBufAlloc[i] = true;
00218             return (volatile uint8_t *)(usb_edBuf + i*ED_SIZE);
00219         }
00220     }
00221     perror("Could not allocate ED\r\n");
00222     return NULL; //Could not alloc ED
00223 }
00224 
00225 volatile uint8_t * USBHALHost::getTD() {
00226     int i;
00227     for (i = 0; i < MAX_TD; i++) {
00228         if ( !tdBufAlloc[i] ) {
00229             tdBufAlloc[i] = true;
00230             return (volatile uint8_t *)(usb_tdBuf + i*TD_SIZE);
00231         }
00232     }
00233     perror("Could not allocate TD\r\n");
00234     return NULL; //Could not alloc TD
00235 }
00236 
00237 
00238 void USBHALHost::freeED(volatile uint8_t * ed) {
00239     int i;
00240     i = (ed - usb_edBuf) / ED_SIZE;
00241     edBufAlloc[i] = false;
00242 }
00243 
00244 void USBHALHost::freeTD(volatile uint8_t * td) {
00245     int i;
00246     i = (td - usb_tdBuf) / TD_SIZE;
00247     tdBufAlloc[i] = false;
00248 }
00249 
00250 
00251 void USBHALHost::resetRootHub() {
00252     // Initiate port reset
00253     LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRS;
00254 
00255     while (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRS);
00256 
00257     // ...and clear port reset signal
00258     LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC;
00259 }
00260 
00261 
00262 void USBHALHost::_usbisr(void) {
00263     if (instHost) {
00264         instHost->UsbIrqhandler();
00265     }
00266 }
00267 
00268 void USBHALHost::UsbIrqhandler() {
00269     if( LPC_USB->HcInterruptStatus & LPC_USB->HcInterruptEnable ) //Is there something to actually process?
00270     {
00271 
00272         uint32_t int_status = LPC_USB->HcInterruptStatus & LPC_USB->HcInterruptEnable;
00273 
00274         // Root hub status change interrupt
00275         if (int_status & OR_INTR_STATUS_RHSC) {
00276             if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CSC) {
00277                 if (LPC_USB->HcRhStatus & OR_RH_STATUS_DRWE) {
00278                     // When DRWE is on, Connect Status Change
00279                     // means a remote wakeup event.
00280                 } else {
00281 
00282                     //Root device connected
00283                     if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS) {
00284 
00285                         // wait 150ms to avoid bounce
00286                         wait_ms(150);
00287 
00288                         //Hub 0 (root hub), Port 1 (count starts at 1), Low or High speed
00289                         deviceConnected(0, 1, LPC_USB->HcRhPortStatus1 & OR_RH_PORT_LSDA);
00290                     }
00291 
00292                     //Root device disconnected
00293                     else {
00294 
00295                         if (!(int_status & OR_INTR_STATUS_WDH)) {
00296                             usb_hcca->DoneHead = 0;
00297                         }
00298 
00299                         // wait 200ms to avoid bounce
00300                         wait_ms(200);
00301 
00302                         deviceDisconnected(0, 1, NULL, usb_hcca->DoneHead & 0xFFFFFFFE);
00303 
00304                         if (int_status & OR_INTR_STATUS_WDH) {
00305                             usb_hcca->DoneHead = 0;
00306                             LPC_USB->HcInterruptStatus = OR_INTR_STATUS_WDH;
00307                         }
00308                     }
00309                 }
00310                 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC;
00311             }
00312             if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRSC) {
00313                 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC;
00314             }
00315             LPC_USB->HcInterruptStatus = OR_INTR_STATUS_RHSC;
00316         }
00317 
00318         // Writeback Done Head interrupt
00319         if (int_status & OR_INTR_STATUS_WDH) {
00320             transferCompleted(usb_hcca->DoneHead & 0xFFFFFFFE);
00321             LPC_USB->HcInterruptStatus = OR_INTR_STATUS_WDH;
00322         }
00323     }
00324 }
00325 #endif