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_M451.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_M451) 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 #ifndef USBH_HcRhDescriptorA_POTPGT_Pos 00031 #define USBH_HcRhDescriptorA_POTPGT_Pos (24) 00032 #endif 00033 #ifndef USBH_HcRhDescriptorA_POTPGT_Msk 00034 #define USBH_HcRhDescriptorA_POTPGT_Msk (0xfful << USBH_HcRhDescriptorA_POTPGT_Pos) 00035 #endif 00036 00037 static volatile MBED_ALIGN(256) uint8_t usb_buf[TOTAL_SIZE]; // 256 bytes aligned! 00038 00039 USBHALHost * USBHALHost::instHost; 00040 00041 USBHALHost::USBHALHost() 00042 { 00043 instHost = this; 00044 memInit(); 00045 memset((void*)usb_hcca, 0, HCCA_SIZE); 00046 for (int i = 0; i < MAX_ENDPOINT; i++) { 00047 edBufAlloc[i] = false; 00048 } 00049 for (int i = 0; i < MAX_TD; i++) { 00050 tdBufAlloc[i] = false; 00051 } 00052 } 00053 00054 void USBHALHost::init() 00055 { 00056 // Unlock protected registers 00057 SYS_UnlockReg(); 00058 00059 // Enable USBH clock 00060 CLK_EnableModuleClock(USBH_MODULE); 00061 // Set USBH clock source/divider 00062 CLK_SetModuleClock(USBH_MODULE, 0, CLK_CLKDIV0_USB(3)); 00063 00064 // Configure OTG function as Host-Only 00065 SYS->USBPHY = SYS_USBPHY_LDO33EN_Msk | SYS_USBPHY_USBROLE_STD_USBH; 00066 00067 /* Below settings is use power switch IC to enable/disable USB Host power. 00068 Set PA.2 is VBUS_EN function pin and PA.3 VBUS_ST function pin */ 00069 pin_function(PA_3, SYS_GPA_MFPL_PA3MFP_USB_VBUS_ST); 00070 pin_function(PA_2, SYS_GPA_MFPL_PA2MFP_USB_VBUS_EN); 00071 00072 // Enable OTG clock 00073 CLK_EnableModuleClock(OTG_MODULE); 00074 00075 // Lock protected registers 00076 SYS_LockReg(); 00077 00078 // Overcurrent flag is low active 00079 USBH->HcMiscControl |= USBH_HcMiscControl_OCAL_Msk; 00080 00081 // Disable HC interrupts 00082 USBH->HcInterruptDisable = OR_INTR_ENABLE_MIE; 00083 00084 // Needed by some controllers 00085 USBH->HcControl = 0; 00086 00087 // Software reset 00088 USBH->HcCommandStatus = OR_CMD_STATUS_HCR; 00089 while (USBH->HcCommandStatus & OR_CMD_STATUS_HCR); 00090 00091 // Put HC in reset state 00092 USBH->HcControl = (USBH->HcControl & ~OR_CONTROL_HCFS) | OR_CONTROL_HC_RSET; 00093 // HCD must wait 10ms for HC reset complete 00094 wait_ms(100); 00095 00096 USBH->HcControlHeadED = 0; // Initialize Control ED list head to 0 00097 USBH->HcBulkHeadED = 0; // Initialize Bulk ED list head to 0 00098 USBH->HcHCCA = (uint32_t) usb_hcca; 00099 00100 USBH->HcFmInterval = DEFAULT_FMINTERVAL; // Frame interval = 12000 - 1 00101 // MPS = 10,104 00102 USBH->HcPeriodicStart = FI * 90 / 100; // 90% of frame interval 00103 USBH->HcLSThreshold = 0x628; // Low speed threshold 00104 00105 // Put HC in operational state 00106 USBH->HcControl = (USBH->HcControl & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER; 00107 00108 // FIXME 00109 USBH->HcRhDescriptorA = USBH->HcRhDescriptorA & ~(USBH_HcRhDescriptorA_NOCP_Msk | USBH_HcRhDescriptorA_OCPM_Msk | USBH_HcRhDescriptorA_PSM_Msk); 00110 // Issue SetGlobalPower command 00111 USBH->HcRhStatus = USBH_HcRhStatus_LPSC_Msk; 00112 // Power On To Power Good Time, in 2 ms units 00113 wait_ms(((USBH->HcRhDescriptorA & USBH_HcRhDescriptorA_POTPGT_Msk) >> USBH_HcRhDescriptorA_POTPGT_Pos) * 2); 00114 00115 // Clear Interrrupt Status 00116 USBH->HcInterruptStatus |= USBH->HcInterruptStatus; 00117 // Enable interrupts we care about 00118 USBH->HcInterruptEnable = OR_INTR_ENABLE_MIE | OR_INTR_ENABLE_WDH | OR_INTR_ENABLE_RHSC; 00119 00120 NVIC_SetVector(USBH_IRQn, (uint32_t)(_usbisr)); 00121 NVIC_EnableIRQ(USBH_IRQn); 00122 00123 // Check for any connected devices 00124 if (USBH->HcRhPortStatus[0] & OR_RH_PORT_CCS) { 00125 // Device connected 00126 wait_ms(150); 00127 deviceConnected(0, 1, USBH->HcRhPortStatus[0] & OR_RH_PORT_LSDA); 00128 } 00129 } 00130 00131 uint32_t USBHALHost::controlHeadED() 00132 { 00133 return USBH->HcControlHeadED; 00134 } 00135 00136 uint32_t USBHALHost::bulkHeadED() 00137 { 00138 return USBH->HcBulkHeadED; 00139 } 00140 00141 uint32_t USBHALHost::interruptHeadED() 00142 { 00143 // FIXME: Only support one INT ED? 00144 return usb_hcca->IntTable[0]; 00145 } 00146 00147 void USBHALHost::updateBulkHeadED(uint32_t addr) 00148 { 00149 USBH->HcBulkHeadED = addr; 00150 } 00151 00152 00153 void USBHALHost::updateControlHeadED(uint32_t addr) 00154 { 00155 USBH->HcControlHeadED = addr; 00156 } 00157 00158 void USBHALHost::updateInterruptHeadED(uint32_t addr) 00159 { 00160 // FIXME: Only support one INT ED? 00161 usb_hcca->IntTable[0] = addr; 00162 } 00163 00164 00165 void USBHALHost::enableList(ENDPOINT_TYPE type) 00166 { 00167 switch(type) { 00168 case CONTROL_ENDPOINT: 00169 USBH->HcCommandStatus = OR_CMD_STATUS_CLF; 00170 USBH->HcControl |= OR_CONTROL_CLE; 00171 break; 00172 case ISOCHRONOUS_ENDPOINT: 00173 // FIXME 00174 break; 00175 case BULK_ENDPOINT: 00176 USBH->HcCommandStatus = OR_CMD_STATUS_BLF; 00177 USBH->HcControl |= OR_CONTROL_BLE; 00178 break; 00179 case INTERRUPT_ENDPOINT: 00180 USBH->HcControl |= OR_CONTROL_PLE; 00181 break; 00182 } 00183 } 00184 00185 00186 bool USBHALHost::disableList(ENDPOINT_TYPE type) 00187 { 00188 switch(type) { 00189 case CONTROL_ENDPOINT: 00190 if(USBH->HcControl & OR_CONTROL_CLE) { 00191 USBH->HcControl &= ~OR_CONTROL_CLE; 00192 return true; 00193 } 00194 return false; 00195 case ISOCHRONOUS_ENDPOINT: 00196 // FIXME 00197 return false; 00198 case BULK_ENDPOINT: 00199 if(USBH->HcControl & OR_CONTROL_BLE){ 00200 USBH->HcControl &= ~OR_CONTROL_BLE; 00201 return true; 00202 } 00203 return false; 00204 case INTERRUPT_ENDPOINT: 00205 if(USBH->HcControl & OR_CONTROL_PLE) { 00206 USBH->HcControl &= ~OR_CONTROL_PLE; 00207 return true; 00208 } 00209 return false; 00210 } 00211 return false; 00212 } 00213 00214 00215 void USBHALHost::memInit() 00216 { 00217 usb_hcca = (volatile HCCA *)usb_buf; 00218 usb_edBuf = usb_buf + HCCA_SIZE; 00219 usb_tdBuf = usb_buf + HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE); 00220 } 00221 00222 volatile uint8_t * USBHALHost::getED() 00223 { 00224 for (int i = 0; i < MAX_ENDPOINT; i++) { 00225 if ( !edBufAlloc[i] ) { 00226 edBufAlloc[i] = true; 00227 return (volatile uint8_t *)(usb_edBuf + i*ED_SIZE); 00228 } 00229 } 00230 perror("Could not allocate ED\r\n"); 00231 return NULL; //Could not alloc ED 00232 } 00233 00234 volatile uint8_t * USBHALHost::getTD() 00235 { 00236 int i; 00237 for (i = 0; i < MAX_TD; i++) { 00238 if ( !tdBufAlloc[i] ) { 00239 tdBufAlloc[i] = true; 00240 return (volatile uint8_t *)(usb_tdBuf + i*TD_SIZE); 00241 } 00242 } 00243 perror("Could not allocate TD\r\n"); 00244 return NULL; //Could not alloc TD 00245 } 00246 00247 00248 void USBHALHost::freeED(volatile uint8_t * ed) 00249 { 00250 int i; 00251 i = (ed - usb_edBuf) / ED_SIZE; 00252 edBufAlloc[i] = false; 00253 } 00254 00255 void USBHALHost::freeTD(volatile uint8_t * td) 00256 { 00257 int i; 00258 i = (td - usb_tdBuf) / TD_SIZE; 00259 tdBufAlloc[i] = false; 00260 } 00261 00262 00263 void USBHALHost::resetRootHub() 00264 { 00265 // Reset port1 00266 USBH->HcRhPortStatus[0] = OR_RH_PORT_PRS; 00267 while (USBH->HcRhPortStatus[0] & OR_RH_PORT_PRS); 00268 USBH->HcRhPortStatus[0] = OR_RH_PORT_PRSC; 00269 } 00270 00271 00272 void USBHALHost::_usbisr(void) 00273 { 00274 if (instHost) { 00275 instHost->UsbIrqhandler(); 00276 } 00277 } 00278 00279 void USBHALHost::UsbIrqhandler() 00280 { 00281 uint32_t ints = USBH->HcInterruptStatus; 00282 00283 // Root hub status change interrupt 00284 if (ints & OR_INTR_STATUS_RHSC) { 00285 uint32_t ints_roothub = USBH->HcRhStatus; 00286 uint32_t ints_port1 = USBH->HcRhPortStatus[0]; 00287 uint32_t ints_port2 = USBH->HcRhPortStatus[1]; 00288 00289 // Port1: ConnectStatusChange 00290 if (ints_port1 & OR_RH_PORT_CSC) { 00291 if (ints_roothub & OR_RH_STATUS_DRWE) { 00292 // When DRWE is on, Connect Status Change means a remote wakeup event. 00293 } else { 00294 if (ints_port1 & OR_RH_PORT_CCS) { 00295 // Root device connected 00296 00297 // wait 150ms to avoid bounce 00298 wait_ms(150); 00299 00300 //Hub 0 (root hub), Port 1 (count starts at 1), Low or High speed 00301 deviceConnected(0, 1, ints_port1 & OR_RH_PORT_LSDA); 00302 } else { 00303 // Root device disconnected 00304 00305 if (!(ints & OR_INTR_STATUS_WDH)) { 00306 usb_hcca->DoneHead = 0; 00307 } 00308 00309 // wait 200ms to avoid bounce 00310 wait_ms(200); 00311 00312 deviceDisconnected(0, 1, NULL, usb_hcca->DoneHead & 0xFFFFFFFE); 00313 00314 if (ints & OR_INTR_STATUS_WDH) { 00315 usb_hcca->DoneHead = 0; 00316 USBH->HcInterruptStatus = OR_INTR_STATUS_WDH; 00317 } 00318 } 00319 } 00320 USBH->HcRhPortStatus[0] = OR_RH_PORT_CSC; 00321 } 00322 // Port1: Reset completed 00323 if (ints_port1 & OR_RH_PORT_PRSC) { 00324 USBH->HcRhPortStatus[0] = OR_RH_PORT_PRSC; 00325 } 00326 // Port1: PortEnableStatusChange 00327 if (ints_port1 & OR_RH_PORT_PESC) { 00328 USBH->HcRhPortStatus[0] = OR_RH_PORT_PESC; 00329 } 00330 00331 // Port2: PortOverCurrentIndicatorChange 00332 if (ints_port2 & OR_RH_PORT_OCIC) { 00333 USBH->HcRhPortStatus[1] = OR_RH_PORT_OCIC; 00334 } 00335 00336 USBH->HcInterruptStatus = OR_INTR_STATUS_RHSC; 00337 } 00338 00339 // Writeback Done Head interrupt 00340 if (ints & OR_INTR_STATUS_WDH) { 00341 transferCompleted(usb_hcca->DoneHead & 0xFFFFFFFE); 00342 USBH->HcInterruptStatus = OR_INTR_STATUS_WDH; 00343 } 00344 00345 00346 } 00347 #endif
Generated on Tue Jul 12 2022 13:16:18 by
