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