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 mbed-os by
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 Tue Jul 12 2022 13:16:18 by
