Adaptation of the official mbed USBHost repository to work with the LPC4088 Display Module
Dependents: DMSupport DMSupport DMSupport DMSupport
Fork of DM_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 // Put the USB structures in the only memory accessible by the USB stack - the AHBSRAM1 00043 static volatile uint8_t usb_buf[TOTAL_SIZE] __attribute__((section("AHBSRAM1"),aligned(256)));// __attribute__((section("AHBSRAM0"),aligned(256))); //256 bytes aligned! 00044 00045 // A very basic implementation of malloc to allocate in the AHBSRAM1 00046 #define SAFE_MEM_TO_USE (10*1024) 00047 #define SAFE_MEM_BLOCK_SIZE (512) 00048 #define SAFE_MEM_NUM_BLOCKS (SAFE_MEM_TO_USE/SAFE_MEM_BLOCK_SIZE) 00049 typedef struct { 00050 volatile uint8_t* ptr; 00051 bool used; 00052 } safe_mem_info_t; 00053 static safe_mem_info_t safe_mem_list[SAFE_MEM_NUM_BLOCKS]; 00054 static uint8_t safe_mem_data[SAFE_MEM_TO_USE] __attribute__((section("AHBSRAM1"),aligned(256)));//__attribute__((section("AHBSRAM0"),aligned)); //256 bytes aligned! 00055 00056 // To detect when memory outside of the AHBSRAM0 is passed to the USB stack 00057 void assert_mem_region(uint32_t ptr) 00058 { 00059 if (( ptr != 0) && ((ptr & 0xff000000) != 0x20000000)) { 00060 USB_ERR("0x%08x not in USB MEM", ptr); 00061 mbed_die(); 00062 } 00063 } 00064 00065 USBHALHost * USBHALHost::instHost; 00066 00067 USBHALHost::USBHALHost() { 00068 instHost = this; 00069 memInit(); 00070 memset((void*)usb_hcca, 0, HCCA_SIZE); 00071 for (int i = 0; i < MAX_ENDPOINT; i++) { 00072 edBufAlloc[i] = false; 00073 } 00074 for (int i = 0; i < MAX_TD; i++) { 00075 tdBufAlloc[i] = false; 00076 } 00077 for (int i = 0; i < SAFE_MEM_NUM_BLOCKS; i++) { 00078 safe_mem_list[i].used = false; 00079 safe_mem_list[i].ptr = safe_mem_data + SAFE_MEM_BLOCK_SIZE*i; 00080 } 00081 00082 } 00083 00084 uint8_t* USBHALHost::getSafeMem(uint32_t size) { 00085 uint8_t* result = NULL; 00086 if (size > 512) { 00087 USB_ERR("getSafeMem(%u) not supported", size); 00088 } else { 00089 safemem_mutex.lock(); 00090 for (int i = 0; i < SAFE_MEM_NUM_BLOCKS; i++) { 00091 if (!safe_mem_list[i].used) { 00092 safe_mem_list[i].used = true; 00093 result = (uint8_t*)safe_mem_list[i].ptr; 00094 break; 00095 } 00096 } 00097 safemem_mutex.unlock(); 00098 } 00099 if (result == NULL) { 00100 USB_ERR("getSafeMem(%u) failed to allocate", size); 00101 } 00102 return result; 00103 } 00104 00105 void USBHALHost::returnSafeMem(uint8_t* mem) { 00106 safemem_mutex.lock(); 00107 int i; 00108 for (i = 0; i < SAFE_MEM_NUM_BLOCKS; i++) { 00109 if (safe_mem_list[i].ptr == mem) { 00110 safe_mem_list[i].used = false; 00111 break; 00112 } 00113 } 00114 safemem_mutex.unlock(); 00115 if (i == SAFE_MEM_NUM_BLOCKS) { 00116 USB_ERR("returnSafeMem(%p) not allocated", mem); 00117 } 00118 } 00119 00120 00121 void USBHALHost::init() { 00122 NVIC_DisableIRQ(USB_IRQn); 00123 00124 //Cut power 00125 LPC_SC->PCONP &= ~(1UL<<31); 00126 ThisThread::sleep_for(1000); 00127 00128 // turn on power for USB 00129 LPC_SC->PCONP |= (1UL<<31); 00130 00131 // Enable USB host clock, port selection and AHB clock 00132 LPC_USB->USBClkCtrl = 0x19; 00133 00134 // Wait for clocks to become available 00135 while ((LPC_USB->USBClkSt & 0x19) != 0x19); 00136 00137 // it seems the bits[0:1] mean the following 00138 // 0: U1=device, U2=host 00139 // 1: U1=host, U2=host 00140 // 2: reserved 00141 // 3: U1=host, U2=device 00142 // NB: this register is only available if OTG clock (aka "port select") is enabled!! 00143 LPC_USB->OTGStCtrl = 1; 00144 00145 // configure USB D+/D- pins 00146 00147 LPC_IOCON->P0_29 &= ~0x9F; // USB_D+1 00148 LPC_IOCON->P0_29 |= 0x01; // USB_D+1 00149 LPC_IOCON->P0_30 &= ~0x9F; // USB_D-1 00150 LPC_IOCON->P0_30 |= 0x01; // USB_D-1 00151 00152 LPC_IOCON->P0_31 &= ~0x9F; // USB_D+2 00153 LPC_IOCON->P0_31 |= 0x01; // USB_D+2 00154 00155 LPC_IOCON->P1_30 &= ~0x1F; // USB_PWRD2 00156 LPC_IOCON->P1_30 |= 0x01; // USB_PWRD2 00157 LPC_IOCON->P1_31 &= ~0x1F; // USB_OVRCR2 00158 LPC_IOCON->P1_31 |= 0x01; // USB_OVRCR2 00159 00160 LPC_IOCON->P0_14 &= ~0x1F; // USB ID Pin as GPIO, output, high 00161 LPC_GPIO0->DIR |= (1<<14); 00162 LPC_GPIO0->SET = (1<<14); 00163 LPC_IOCON->P4_31 &= ~0x1F; // USB CONN Pin as GPIO, output, low 00164 LPC_GPIO4->DIR |= (1UL<<31); 00165 LPC_GPIO4->CLR = (1UL<<31); 00166 00167 USB_DBG("initialize OHCI\n"); 00168 00169 // Wait 100 ms before apply reset 00170 ThisThread::sleep_for(100); 00171 00172 LPC_USB->HcControl = 0; // HARDWARE RESET 00173 LPC_USB->HcControlHeadED = 0; // Initialize Control list head to Zero 00174 LPC_USB->HcBulkHeadED = 0; // Initialize Bulk list head to Zero 00175 00176 // software reset 00177 LPC_USB->HcCommandStatus = OR_CMD_STATUS_HCR; 00178 00179 // Write Fm Interval and Largest Data Packet Counter 00180 LPC_USB->HcFmInterval = DEFAULT_FMINTERVAL; 00181 LPC_USB->HcPeriodicStart = FI * 90 / 100; 00182 00183 // Put HC in operational state 00184 LPC_USB->HcControl = (LPC_USB->HcControl & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER; 00185 00186 // Set Global Power 00187 LPC_USB->HcRhStatus = OR_RH_STATUS_LPSC; 00188 00189 LPC_USB->HcHCCA = (uint32_t)(usb_hcca); 00190 00191 // Clear Interrrupt Status 00192 LPC_USB->HcInterruptStatus |= LPC_USB->HcInterruptStatus; 00193 00194 LPC_USB->HcInterruptEnable = OR_INTR_ENABLE_MIE | OR_INTR_ENABLE_WDH | OR_INTR_ENABLE_RHSC; 00195 00196 // Enable the USB Interrupt 00197 NVIC_SetVector(USB_IRQn, (uint32_t)(_usbisr)); 00198 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC; 00199 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; 00200 LPC_USB->HcRhPortStatus2 = OR_RH_PORT_CSC; 00201 LPC_USB->HcRhPortStatus2 = OR_RH_PORT_PRSC; 00202 resetRootHub(); 00203 NVIC_SetPriority(USB_IRQn, 0); 00204 NVIC_EnableIRQ(USB_IRQn); 00205 00206 if (LPC_USB->HcRhPortStatus2 & OR_RH_PORT_CCS) { 00207 //Device connected 00208 ThisThread::sleep_for(150); 00209 USB_DBG("Device connected (%08x)\n\r", LPC_USB->HcRhPortStatus2); 00210 deviceConnected(0, 2, LPC_USB->HcRhPortStatus2 & OR_RH_PORT_LSDA); 00211 } 00212 } 00213 00214 uint32_t USBHALHost::controlHeadED() { 00215 return LPC_USB->HcControlHeadED; 00216 } 00217 00218 uint32_t USBHALHost::bulkHeadED() { 00219 return LPC_USB->HcBulkHeadED; 00220 } 00221 00222 uint32_t USBHALHost::interruptHeadED() { 00223 return usb_hcca->IntTable[0]; 00224 } 00225 00226 void USBHALHost::updateBulkHeadED(uint32_t addr) { 00227 LPC_USB->HcBulkHeadED = addr; 00228 } 00229 00230 00231 void USBHALHost::updateControlHeadED(uint32_t addr) { 00232 LPC_USB->HcControlHeadED = addr; 00233 } 00234 00235 void USBHALHost::updateInterruptHeadED(uint32_t addr) { 00236 usb_hcca->IntTable[0] = addr; 00237 } 00238 00239 00240 void USBHALHost::enableList(ENDPOINT_TYPE type) { 00241 switch(type) { 00242 case CONTROL_ENDPOINT: 00243 LPC_USB->HcCommandStatus = OR_CMD_STATUS_CLF; 00244 LPC_USB->HcControl |= OR_CONTROL_CLE; 00245 break; 00246 case ISOCHRONOUS_ENDPOINT: 00247 break; 00248 case BULK_ENDPOINT: 00249 LPC_USB->HcCommandStatus = OR_CMD_STATUS_BLF; 00250 LPC_USB->HcControl |= OR_CONTROL_BLE; 00251 break; 00252 case INTERRUPT_ENDPOINT: 00253 LPC_USB->HcControl |= OR_CONTROL_PLE; 00254 break; 00255 } 00256 } 00257 00258 00259 bool USBHALHost::disableList(ENDPOINT_TYPE type) { 00260 switch(type) { 00261 case CONTROL_ENDPOINT: 00262 if(LPC_USB->HcControl & OR_CONTROL_CLE) { 00263 LPC_USB->HcControl &= ~OR_CONTROL_CLE; 00264 return true; 00265 } 00266 return false; 00267 case ISOCHRONOUS_ENDPOINT: 00268 return false; 00269 case BULK_ENDPOINT: 00270 if(LPC_USB->HcControl & OR_CONTROL_BLE){ 00271 LPC_USB->HcControl &= ~OR_CONTROL_BLE; 00272 return true; 00273 } 00274 return false; 00275 case INTERRUPT_ENDPOINT: 00276 if(LPC_USB->HcControl & OR_CONTROL_PLE) { 00277 LPC_USB->HcControl &= ~OR_CONTROL_PLE; 00278 return true; 00279 } 00280 return false; 00281 } 00282 return false; 00283 } 00284 00285 00286 void USBHALHost::memInit() { 00287 usb_hcca = (volatile HCCA *)usb_buf; 00288 usb_edBuf = usb_buf + HCCA_SIZE; 00289 usb_tdBuf = usb_buf + HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE); 00290 } 00291 00292 volatile uint8_t * USBHALHost::getED() { 00293 for (int i = 0; i < MAX_ENDPOINT; i++) { 00294 if ( !edBufAlloc[i] ) { 00295 edBufAlloc[i] = true; 00296 return (volatile uint8_t *)(usb_edBuf + i*ED_SIZE); 00297 } 00298 } 00299 USB_ERR("Could not allocate ED\r\n"); 00300 return NULL; 00301 } 00302 00303 volatile uint8_t * USBHALHost::getTD() { 00304 int i; 00305 for (i = 0; i < MAX_TD; i++) { 00306 if ( !tdBufAlloc[i] ) { 00307 tdBufAlloc[i] = true; 00308 return (volatile uint8_t *)(usb_tdBuf + i*TD_SIZE); 00309 } 00310 } 00311 USB_ERR("Could not allocate TD\r\n"); 00312 return NULL; 00313 } 00314 00315 00316 void USBHALHost::freeED(volatile uint8_t * ed) { 00317 int i; 00318 i = (ed - usb_edBuf) / ED_SIZE; 00319 edBufAlloc[i] = false; 00320 } 00321 00322 void USBHALHost::freeTD(volatile uint8_t * td) { 00323 int i; 00324 i = (td - usb_tdBuf) / TD_SIZE; 00325 tdBufAlloc[i] = false; 00326 } 00327 00328 00329 void USBHALHost::resetRootHub() { 00330 00331 DigitalOut usb2_vbus_en(P0_12); 00332 usb2_vbus_en = 1; 00333 ThisThread::sleep_for(100); /* USB 2.0 spec says at least 50ms delay before port reset */ 00334 00335 // Initiate port reset 00336 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRS; 00337 00338 while (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRS); 00339 00340 // ...and clear port reset signal 00341 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; 00342 00343 usb2_vbus_en = 0; 00344 00345 // Initiate port reset 00346 LPC_USB->HcRhPortStatus2 = OR_RH_PORT_PRS; 00347 00348 while (LPC_USB->HcRhPortStatus2 & OR_RH_PORT_PRS); 00349 00350 // ...and clear port reset signal 00351 LPC_USB->HcRhPortStatus2 = OR_RH_PORT_PRSC; 00352 00353 usb2_vbus_en = 1; 00354 ThisThread::sleep_for(200); /* Wait for at least 100 MS after port reset */ 00355 } 00356 00357 00358 void USBHALHost::_usbisr(void) { 00359 if (instHost) { 00360 instHost->UsbIrqhandler(); 00361 } 00362 } 00363 00364 void USBHALHost::UsbIrqhandler() { 00365 00366 if( LPC_USB->HcInterruptStatus & LPC_USB->HcInterruptEnable ) //Is there something to actually process? 00367 { 00368 uint32_t int_status = LPC_USB->HcInterruptStatus & LPC_USB->HcInterruptEnable; 00369 00370 // Root hub status change interrupt 00371 if (int_status & OR_INTR_STATUS_RHSC) { 00372 if (LPC_USB->HcRhPortStatus2 & OR_RH_PORT_CSC) { 00373 if (LPC_USB->HcRhStatus & OR_RH_STATUS_DRWE) { 00374 // When DRWE is on, Connect Status Change 00375 // means a remote wakeup event. 00376 } else { 00377 00378 //Root device connected 00379 if (LPC_USB->HcRhPortStatus2 & OR_RH_PORT_CCS) { 00380 00381 // wait 150ms to avoid bounce (removed since wait is not allowed in isr) 00382 //ThisThread::sleep_for(150); 00383 00384 //Hub 0 (root hub), Port 2 (count starts at 1), Low or High speed 00385 deviceConnected(0, 2, LPC_USB->HcRhPortStatus2 & OR_RH_PORT_LSDA); 00386 } 00387 00388 //Root device disconnected 00389 else { 00390 00391 if (!(int_status & OR_INTR_STATUS_WDH)) { 00392 usb_hcca->DoneHead = 0; 00393 } 00394 00395 // wait 200ms to avoid bounce (removed since wait is not allowed in isr) 00396 //wait_ms(200); 00397 00398 deviceDisconnected(0, 2, NULL, usb_hcca->DoneHead & 0xFFFFFFFE); 00399 00400 if (int_status & OR_INTR_STATUS_WDH) { 00401 usb_hcca->DoneHead = 0; 00402 LPC_USB->HcInterruptStatus = OR_INTR_STATUS_WDH; 00403 } 00404 } 00405 } 00406 LPC_USB->HcRhPortStatus2 = OR_RH_PORT_CSC; 00407 } 00408 if (LPC_USB->HcRhPortStatus2 & OR_RH_PORT_PRSC) { 00409 LPC_USB->HcRhPortStatus2 = OR_RH_PORT_PRSC; 00410 } 00411 LPC_USB->HcInterruptStatus = OR_INTR_STATUS_RHSC; 00412 } 00413 00414 // Writeback Done Head interrupt 00415 if (int_status & OR_INTR_STATUS_WDH) { 00416 transferCompleted(usb_hcca->DoneHead & 0xFFFFFFFE); 00417 LPC_USB->HcInterruptStatus = OR_INTR_STATUS_WDH; 00418 } 00419 } 00420 }
Generated on Tue Jul 12 2022 21:45:29 by
