USBHOST lib for STM

Dependents:   door-access-controller-dev

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers USBHALHost_M451.cpp Source File

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