Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of USBHost by
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 __align(256) uint8_t usb_buf[TOTAL_SIZE] __attribute((section("AHBSRAM1"),aligned)); //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 Fri Jul 15 2022 03:47:32 by
