USBHOST lib for STM
Dependents: door-access-controller-dev
USBHALHost_NUC472.cpp
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2015-2016 Nuvoton 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_NUC472) 00018 00019 #include "mbed.h" 00020 #include "USBHALHost.h" 00021 #include "dbg.h" 00022 #include "pinmap.h" 00023 00024 #define HCCA_SIZE sizeof(HCCA) 00025 #define ED_SIZE sizeof(HCED) 00026 #define TD_SIZE sizeof(HCTD) 00027 00028 #define TOTAL_SIZE (HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE) + (MAX_TD*TD_SIZE)) 00029 00030 static volatile MBED_ALIGN(256) uint8_t usb_buf[TOTAL_SIZE]; // 256 bytes aligned! 00031 00032 USBHALHost * USBHALHost::instHost; 00033 00034 USBHALHost::USBHALHost() 00035 { 00036 instHost = this; 00037 memInit(); 00038 memset((void*)usb_hcca, 0, HCCA_SIZE); 00039 for (int i = 0; i < MAX_ENDPOINT; i++) { 00040 edBufAlloc[i] = false; 00041 } 00042 for (int i = 0; i < MAX_TD; i++) { 00043 tdBufAlloc[i] = false; 00044 } 00045 } 00046 00047 void USBHALHost::init() 00048 { 00049 // Unlock protected registers 00050 SYS_UnlockReg(); 00051 00052 // NOTE: Configure as OTG device first; otherwise, program will trap in wait loop CLK_STATUS_PLL2STB_Msk below. 00053 SYS->USBPHY = SYS_USBPHY_LDO33EN_Msk | SYS_USBPHY_USBROLE_ON_THE_GO; 00054 00055 // NOTE: Enable OTG here; otherwise, program will trap in wait loop CLK_STATUS_PLL2STB_Msk below. 00056 CLK_EnableModuleClock(OTG_MODULE); 00057 OTG->PHYCTL = (OTG->PHYCTL | OTG_PHYCTL_OTGPHYEN_Msk) & ~OTG_PHYCTL_IDDETEN_Msk; 00058 //OTG->CTL |= OTG_CTL_OTGEN_Msk | OTG_CTL_BUSREQ_Msk; 00059 00060 // PB.0: USB0 external VBUS regulator status 00061 // USB_OC 00062 // PB.1: USB0 external VBUS regulator enable 00063 // NCT3520U low active (USB_PWR_EN) 00064 pin_function(PB_0, SYS_GPB_MFPL_PB0MFP_USB0_OTG5V_ST); 00065 pin_function(PB_1, SYS_GPB_MFPL_PB1MFP_USB0_OTG5V_EN); 00066 00067 // PB.2: USB1 differential signal D- 00068 // PB.3: USB1 differential signal D+ 00069 //pin_function(PB_2, SYS_GPB_MFPL_PB2MFP_USB1_D_N); 00070 //pin_function(PB_3, SYS_GPB_MFPL_PB3MFP_USB1_D_P); 00071 00072 // Set PB.4 output high to enable USB power 00073 //gpio_t gpio; 00074 //gpio_init_out_ex(&gpio, PB_4, 1); 00075 00076 // NOTE: 00077 // 1. Set USBH clock source to PLL2; otherwise, program will trap in wait loop CLK_STATUS_PLL2STB_Msk below. 00078 // 2. Don't set CLK_PLL2CTL_PLL2CKEN_Msk. USBH will work abnormally with it enabled. 00079 CLK->CLKSEL0 &= ~CLK_CLKSEL0_USBHSEL_Msk; 00080 // Enable PLL2, 480 MHz / 2 / (1+4) => 48 MHz output 00081 CLK->PLL2CTL = /*CLK_PLL2CTL_PLL2CKEN_Msk | */ (4 << CLK_PLL2CTL_PLL2DIV_Pos); 00082 // Wait PLL2 stable ... 00083 while (!(CLK->STATUS & CLK_STATUS_PLL2STB_Msk)); 00084 00085 // Select USB Host clock source from PLL2, clock divied by 1 00086 CLK_SetModuleClock(USBH_MODULE, CLK_CLKSEL0_USBHSEL_PLL2, CLK_CLKDIV0_USB(1)); 00087 00088 // Enable USB Host clock 00089 CLK_EnableModuleClock(USBH_MODULE); 00090 00091 // Lock protected registers 00092 SYS_LockReg(); 00093 00094 // Overcurrent flag is high active 00095 USBH->HcMiscControl &= ~USBH_HcMiscControl_OCAL_Msk; 00096 00097 // Disable HC interrupts 00098 USBH->HcInterruptDisable = OR_INTR_ENABLE_MIE; 00099 00100 // Needed by some controllers 00101 USBH->HcControl = 0; 00102 00103 // Software reset 00104 USBH->HcCommandStatus = OR_CMD_STATUS_HCR; 00105 while (USBH->HcCommandStatus & OR_CMD_STATUS_HCR); 00106 00107 // Put HC in reset state 00108 USBH->HcControl = (USBH->HcControl & ~OR_CONTROL_HCFS) | OR_CONTROL_HC_RSET; 00109 // HCD must wait 10ms for HC reset complete 00110 wait_ms(100); 00111 00112 USBH->HcControlHeadED = 0; // Initialize Control ED list head to 0 00113 USBH->HcBulkHeadED = 0; // Initialize Bulk ED list head to 0 00114 USBH->HcHCCA = (uint32_t) usb_hcca; 00115 00116 USBH->HcFmInterval = DEFAULT_FMINTERVAL; // Frame interval = 12000 - 1 00117 // MPS = 10,104 00118 USBH->HcPeriodicStart = FI * 90 / 100; // 90% of frame interval 00119 USBH->HcLSThreshold = 0x628; // Low speed threshold 00120 00121 // Put HC in operational state 00122 USBH->HcControl = (USBH->HcControl & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER; 00123 00124 // FIXME: Ports are power switched. All ports are powered at the same time. Doesn't match BSP sample. 00125 USBH->HcRhDescriptorA = USBH->HcRhDescriptorA & ~USBH_HcRhDescriptorA_NPS_Msk & ~USBH_HcRhDescriptorA_PSM_Msk; 00126 // Issue SetGlobalPower command 00127 USBH->HcRhStatus = USBH_HcRhStatus_LPSC_Msk; 00128 // Power On To Power Good Time, in 2 ms units 00129 wait_ms(((USBH->HcRhDescriptorA & USBH_HcRhDescriptorA_POTPGT_Msk) >> USBH_HcRhDescriptorA_POTPGT_Pos) * 2); 00130 00131 // Clear Interrrupt Status 00132 USBH->HcInterruptStatus |= USBH->HcInterruptStatus; 00133 // Enable interrupts we care about 00134 USBH->HcInterruptEnable = OR_INTR_ENABLE_MIE | OR_INTR_ENABLE_WDH | OR_INTR_ENABLE_RHSC; 00135 00136 00137 // Unlock protected registers 00138 SYS_UnlockReg(); 00139 00140 // NOTE: Configure as USB host after USBH init above; otherwise system will crash. 00141 SYS->USBPHY = (SYS->USBPHY & ~SYS_USBPHY_USBROLE_Msk) | SYS_USBPHY_USBROLE_STD_USBH; 00142 00143 // Lock protected registers 00144 SYS_LockReg(); 00145 00146 NVIC_SetVector(USBH_IRQn, (uint32_t)(_usbisr)); 00147 NVIC_EnableIRQ(USBH_IRQn); 00148 00149 // Check for any connected devices 00150 if (USBH->HcRhPortStatus[0] & OR_RH_PORT_CCS) { 00151 // Device connected 00152 wait_ms(150); 00153 deviceConnected(0, 1, USBH->HcRhPortStatus[0] & OR_RH_PORT_LSDA); 00154 } 00155 } 00156 00157 uint32_t USBHALHost::controlHeadED() 00158 { 00159 return USBH->HcControlHeadED; 00160 } 00161 00162 uint32_t USBHALHost::bulkHeadED() 00163 { 00164 return USBH->HcBulkHeadED; 00165 } 00166 00167 uint32_t USBHALHost::interruptHeadED() 00168 { 00169 // FIXME: Only support one INT ED? 00170 return usb_hcca->IntTable[0]; 00171 } 00172 00173 void USBHALHost::updateBulkHeadED(uint32_t addr) 00174 { 00175 USBH->HcBulkHeadED = addr; 00176 } 00177 00178 00179 void USBHALHost::updateControlHeadED(uint32_t addr) 00180 { 00181 USBH->HcControlHeadED = addr; 00182 } 00183 00184 void USBHALHost::updateInterruptHeadED(uint32_t addr) 00185 { 00186 // FIXME: Only support one INT ED? 00187 usb_hcca->IntTable[0] = addr; 00188 } 00189 00190 00191 void USBHALHost::enableList(ENDPOINT_TYPE type) 00192 { 00193 switch(type) { 00194 case CONTROL_ENDPOINT: 00195 USBH->HcCommandStatus = OR_CMD_STATUS_CLF; 00196 USBH->HcControl |= OR_CONTROL_CLE; 00197 break; 00198 case ISOCHRONOUS_ENDPOINT: 00199 // FIXME 00200 break; 00201 case BULK_ENDPOINT: 00202 USBH->HcCommandStatus = OR_CMD_STATUS_BLF; 00203 USBH->HcControl |= OR_CONTROL_BLE; 00204 break; 00205 case INTERRUPT_ENDPOINT: 00206 USBH->HcControl |= OR_CONTROL_PLE; 00207 break; 00208 } 00209 } 00210 00211 00212 bool USBHALHost::disableList(ENDPOINT_TYPE type) 00213 { 00214 switch(type) { 00215 case CONTROL_ENDPOINT: 00216 if(USBH->HcControl & OR_CONTROL_CLE) { 00217 USBH->HcControl &= ~OR_CONTROL_CLE; 00218 return true; 00219 } 00220 return false; 00221 case ISOCHRONOUS_ENDPOINT: 00222 // FIXME 00223 return false; 00224 case BULK_ENDPOINT: 00225 if(USBH->HcControl & OR_CONTROL_BLE){ 00226 USBH->HcControl &= ~OR_CONTROL_BLE; 00227 return true; 00228 } 00229 return false; 00230 case INTERRUPT_ENDPOINT: 00231 if(USBH->HcControl & OR_CONTROL_PLE) { 00232 USBH->HcControl &= ~OR_CONTROL_PLE; 00233 return true; 00234 } 00235 return false; 00236 } 00237 return false; 00238 } 00239 00240 00241 void USBHALHost::memInit() 00242 { 00243 usb_hcca = (volatile HCCA *)usb_buf; 00244 usb_edBuf = usb_buf + HCCA_SIZE; 00245 usb_tdBuf = usb_buf + HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE); 00246 } 00247 00248 volatile uint8_t * USBHALHost::getED() 00249 { 00250 for (int i = 0; i < MAX_ENDPOINT; i++) { 00251 if ( !edBufAlloc[i] ) { 00252 edBufAlloc[i] = true; 00253 return (volatile uint8_t *)(usb_edBuf + i*ED_SIZE); 00254 } 00255 } 00256 perror("Could not allocate ED\r\n"); 00257 return NULL; //Could not alloc ED 00258 } 00259 00260 volatile uint8_t * USBHALHost::getTD() 00261 { 00262 int i; 00263 for (i = 0; i < MAX_TD; i++) { 00264 if ( !tdBufAlloc[i] ) { 00265 tdBufAlloc[i] = true; 00266 return (volatile uint8_t *)(usb_tdBuf + i*TD_SIZE); 00267 } 00268 } 00269 perror("Could not allocate TD\r\n"); 00270 return NULL; //Could not alloc TD 00271 } 00272 00273 00274 void USBHALHost::freeED(volatile uint8_t * ed) 00275 { 00276 int i; 00277 i = (ed - usb_edBuf) / ED_SIZE; 00278 edBufAlloc[i] = false; 00279 } 00280 00281 void USBHALHost::freeTD(volatile uint8_t * td) 00282 { 00283 int i; 00284 i = (td - usb_tdBuf) / TD_SIZE; 00285 tdBufAlloc[i] = false; 00286 } 00287 00288 00289 void USBHALHost::resetRootHub() 00290 { 00291 // Reset port1 00292 USBH->HcRhPortStatus[0] = OR_RH_PORT_PRS; 00293 while (USBH->HcRhPortStatus[0] & OR_RH_PORT_PRS); 00294 USBH->HcRhPortStatus[0] = OR_RH_PORT_PRSC; 00295 } 00296 00297 00298 void USBHALHost::_usbisr(void) 00299 { 00300 if (instHost) { 00301 instHost->UsbIrqhandler(); 00302 } 00303 } 00304 00305 void USBHALHost::UsbIrqhandler() 00306 { 00307 uint32_t ints = USBH->HcInterruptStatus; 00308 00309 // Root hub status change interrupt 00310 if (ints & OR_INTR_STATUS_RHSC) { 00311 uint32_t ints_roothub = USBH->HcRhStatus; 00312 uint32_t ints_port1 = USBH->HcRhPortStatus[0]; 00313 00314 // Port1: ConnectStatusChange 00315 if (ints_port1 & OR_RH_PORT_CSC) { 00316 if (ints_roothub & OR_RH_STATUS_DRWE) { 00317 // When DRWE is on, Connect Status Change means a remote wakeup event. 00318 } else { 00319 if (ints_port1 & OR_RH_PORT_CCS) { 00320 // Root device connected 00321 00322 // wait 150ms to avoid bounce 00323 wait_ms(150); 00324 00325 //Hub 0 (root hub), Port 1 (count starts at 1), Low or High speed 00326 deviceConnected(0, 1, ints_port1 & OR_RH_PORT_LSDA); 00327 } else { 00328 // Root device disconnected 00329 00330 if (!(ints & OR_INTR_STATUS_WDH)) { 00331 usb_hcca->DoneHead = 0; 00332 } 00333 00334 // wait 200ms to avoid bounce 00335 wait_ms(200); 00336 00337 deviceDisconnected(0, 1, NULL, usb_hcca->DoneHead & 0xFFFFFFFE); 00338 00339 if (ints & OR_INTR_STATUS_WDH) { 00340 usb_hcca->DoneHead = 0; 00341 USBH->HcInterruptStatus = OR_INTR_STATUS_WDH; 00342 } 00343 } 00344 } 00345 USBH->HcRhPortStatus[0] = OR_RH_PORT_CSC; 00346 } 00347 // Port1: Reset completed 00348 if (ints_port1 & OR_RH_PORT_PRSC) { 00349 USBH->HcRhPortStatus[0] = OR_RH_PORT_PRSC; 00350 } 00351 // Port1: PortEnableStatusChange 00352 if (ints_port1 & OR_RH_PORT_PESC) { 00353 USBH->HcRhPortStatus[0] = OR_RH_PORT_PESC; 00354 } 00355 00356 USBH->HcInterruptStatus = OR_INTR_STATUS_RHSC; 00357 } 00358 00359 // Writeback Done Head interrupt 00360 if (ints & OR_INTR_STATUS_WDH) { 00361 transferCompleted(usb_hcca->DoneHead & 0xFFFFFFFE); 00362 USBH->HcInterruptStatus = OR_INTR_STATUS_WDH; 00363 } 00364 } 00365 #endif
Generated on Fri Jul 15 2022 21:16:05 by 1.7.2