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 USBHOST by
USBHost/USBHALHost_M451.cpp
- Committer:
- shivanandgowdakr
- Date:
- 2018-07-02
- Revision:
- 7:ccd0ac9ae1c9
- Parent:
- 1:ab240722d7ef
File content as of revision 7:ccd0ac9ae1c9:
/* mbed Microcontroller Library * Copyright (c) 2015-2016 Nuvoton * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #if defined(TARGET_M451) #include "mbed.h" #include "USBHALHost.h" #include "dbg.h" #include "pinmap.h" #define HCCA_SIZE sizeof(HCCA) #define ED_SIZE sizeof(HCED) #define TD_SIZE sizeof(HCTD) #define TOTAL_SIZE (HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE) + (MAX_TD*TD_SIZE)) #ifndef USBH_HcRhDescriptorA_POTPGT_Pos #define USBH_HcRhDescriptorA_POTPGT_Pos (24) #endif #ifndef USBH_HcRhDescriptorA_POTPGT_Msk #define USBH_HcRhDescriptorA_POTPGT_Msk (0xfful << USBH_HcRhDescriptorA_POTPGT_Pos) #endif static volatile MBED_ALIGN(256) uint8_t usb_buf[TOTAL_SIZE]; // 256 bytes aligned! USBHALHost * USBHALHost::instHost; USBHALHost::USBHALHost() { instHost = this; memInit(); memset((void*)usb_hcca, 0, HCCA_SIZE); for (int i = 0; i < MAX_ENDPOINT; i++) { edBufAlloc[i] = false; } for (int i = 0; i < MAX_TD; i++) { tdBufAlloc[i] = false; } } void USBHALHost::init() { // Unlock protected registers SYS_UnlockReg(); // Enable USBH clock CLK_EnableModuleClock(USBH_MODULE); // Set USBH clock source/divider CLK_SetModuleClock(USBH_MODULE, 0, CLK_CLKDIV0_USB(3)); // Configure OTG function as Host-Only SYS->USBPHY = SYS_USBPHY_LDO33EN_Msk | SYS_USBPHY_USBROLE_STD_USBH; /* Below settings is use power switch IC to enable/disable USB Host power. Set PA.2 is VBUS_EN function pin and PA.3 VBUS_ST function pin */ pin_function(PA_3, SYS_GPA_MFPL_PA3MFP_USB_VBUS_ST); pin_function(PA_2, SYS_GPA_MFPL_PA2MFP_USB_VBUS_EN); // Enable OTG clock CLK_EnableModuleClock(OTG_MODULE); // Lock protected registers SYS_LockReg(); // Overcurrent flag is low active USBH->HcMiscControl |= USBH_HcMiscControl_OCAL_Msk; // Disable HC interrupts USBH->HcInterruptDisable = OR_INTR_ENABLE_MIE; // Needed by some controllers USBH->HcControl = 0; // Software reset USBH->HcCommandStatus = OR_CMD_STATUS_HCR; while (USBH->HcCommandStatus & OR_CMD_STATUS_HCR); // Put HC in reset state USBH->HcControl = (USBH->HcControl & ~OR_CONTROL_HCFS) | OR_CONTROL_HC_RSET; // HCD must wait 10ms for HC reset complete wait_ms(100); USBH->HcControlHeadED = 0; // Initialize Control ED list head to 0 USBH->HcBulkHeadED = 0; // Initialize Bulk ED list head to 0 USBH->HcHCCA = (uint32_t) usb_hcca; USBH->HcFmInterval = DEFAULT_FMINTERVAL; // Frame interval = 12000 - 1 // MPS = 10,104 USBH->HcPeriodicStart = FI * 90 / 100; // 90% of frame interval USBH->HcLSThreshold = 0x628; // Low speed threshold // Put HC in operational state USBH->HcControl = (USBH->HcControl & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER; // FIXME USBH->HcRhDescriptorA = USBH->HcRhDescriptorA & ~(USBH_HcRhDescriptorA_NOCP_Msk | USBH_HcRhDescriptorA_OCPM_Msk | USBH_HcRhDescriptorA_PSM_Msk); // Issue SetGlobalPower command USBH->HcRhStatus = USBH_HcRhStatus_LPSC_Msk; // Power On To Power Good Time, in 2 ms units wait_ms(((USBH->HcRhDescriptorA & USBH_HcRhDescriptorA_POTPGT_Msk) >> USBH_HcRhDescriptorA_POTPGT_Pos) * 2); // Clear Interrrupt Status USBH->HcInterruptStatus |= USBH->HcInterruptStatus; // Enable interrupts we care about USBH->HcInterruptEnable = OR_INTR_ENABLE_MIE | OR_INTR_ENABLE_WDH | OR_INTR_ENABLE_RHSC; NVIC_SetVector(USBH_IRQn, (uint32_t)(_usbisr)); NVIC_EnableIRQ(USBH_IRQn); // Check for any connected devices if (USBH->HcRhPortStatus[0] & OR_RH_PORT_CCS) { // Device connected wait_ms(150); deviceConnected(0, 1, USBH->HcRhPortStatus[0] & OR_RH_PORT_LSDA); } } uint32_t USBHALHost::controlHeadED() { return USBH->HcControlHeadED; } uint32_t USBHALHost::bulkHeadED() { return USBH->HcBulkHeadED; } uint32_t USBHALHost::interruptHeadED() { // FIXME: Only support one INT ED? return usb_hcca->IntTable[0]; } void USBHALHost::updateBulkHeadED(uint32_t addr) { USBH->HcBulkHeadED = addr; } void USBHALHost::updateControlHeadED(uint32_t addr) { USBH->HcControlHeadED = addr; } void USBHALHost::updateInterruptHeadED(uint32_t addr) { // FIXME: Only support one INT ED? usb_hcca->IntTable[0] = addr; } void USBHALHost::enableList(ENDPOINT_TYPE type) { switch(type) { case CONTROL_ENDPOINT: USBH->HcCommandStatus = OR_CMD_STATUS_CLF; USBH->HcControl |= OR_CONTROL_CLE; break; case ISOCHRONOUS_ENDPOINT: // FIXME break; case BULK_ENDPOINT: USBH->HcCommandStatus = OR_CMD_STATUS_BLF; USBH->HcControl |= OR_CONTROL_BLE; break; case INTERRUPT_ENDPOINT: USBH->HcControl |= OR_CONTROL_PLE; break; } } bool USBHALHost::disableList(ENDPOINT_TYPE type) { switch(type) { case CONTROL_ENDPOINT: if(USBH->HcControl & OR_CONTROL_CLE) { USBH->HcControl &= ~OR_CONTROL_CLE; return true; } return false; case ISOCHRONOUS_ENDPOINT: // FIXME return false; case BULK_ENDPOINT: if(USBH->HcControl & OR_CONTROL_BLE){ USBH->HcControl &= ~OR_CONTROL_BLE; return true; } return false; case INTERRUPT_ENDPOINT: if(USBH->HcControl & OR_CONTROL_PLE) { USBH->HcControl &= ~OR_CONTROL_PLE; return true; } return false; } return false; } void USBHALHost::memInit() { usb_hcca = (volatile HCCA *)usb_buf; usb_edBuf = usb_buf + HCCA_SIZE; usb_tdBuf = usb_buf + HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE); } volatile uint8_t * USBHALHost::getED() { for (int i = 0; i < MAX_ENDPOINT; i++) { if ( !edBufAlloc[i] ) { edBufAlloc[i] = true; return (volatile uint8_t *)(usb_edBuf + i*ED_SIZE); } } perror("Could not allocate ED\r\n"); return NULL; //Could not alloc ED } volatile uint8_t * USBHALHost::getTD() { int i; for (i = 0; i < MAX_TD; i++) { if ( !tdBufAlloc[i] ) { tdBufAlloc[i] = true; return (volatile uint8_t *)(usb_tdBuf + i*TD_SIZE); } } perror("Could not allocate TD\r\n"); return NULL; //Could not alloc TD } void USBHALHost::freeED(volatile uint8_t * ed) { int i; i = (ed - usb_edBuf) / ED_SIZE; edBufAlloc[i] = false; } void USBHALHost::freeTD(volatile uint8_t * td) { int i; i = (td - usb_tdBuf) / TD_SIZE; tdBufAlloc[i] = false; } void USBHALHost::resetRootHub() { // Reset port1 USBH->HcRhPortStatus[0] = OR_RH_PORT_PRS; while (USBH->HcRhPortStatus[0] & OR_RH_PORT_PRS); USBH->HcRhPortStatus[0] = OR_RH_PORT_PRSC; } void USBHALHost::_usbisr(void) { if (instHost) { instHost->UsbIrqhandler(); } } void USBHALHost::UsbIrqhandler() { uint32_t ints = USBH->HcInterruptStatus; // Root hub status change interrupt if (ints & OR_INTR_STATUS_RHSC) { uint32_t ints_roothub = USBH->HcRhStatus; uint32_t ints_port1 = USBH->HcRhPortStatus[0]; uint32_t ints_port2 = USBH->HcRhPortStatus[1]; // Port1: ConnectStatusChange if (ints_port1 & OR_RH_PORT_CSC) { if (ints_roothub & OR_RH_STATUS_DRWE) { // When DRWE is on, Connect Status Change means a remote wakeup event. } else { if (ints_port1 & OR_RH_PORT_CCS) { // Root device connected // wait 150ms to avoid bounce wait_ms(150); //Hub 0 (root hub), Port 1 (count starts at 1), Low or High speed deviceConnected(0, 1, ints_port1 & OR_RH_PORT_LSDA); } else { // Root device disconnected if (!(ints & OR_INTR_STATUS_WDH)) { usb_hcca->DoneHead = 0; } // wait 200ms to avoid bounce wait_ms(200); deviceDisconnected(0, 1, NULL, usb_hcca->DoneHead & 0xFFFFFFFE); if (ints & OR_INTR_STATUS_WDH) { usb_hcca->DoneHead = 0; USBH->HcInterruptStatus = OR_INTR_STATUS_WDH; } } } USBH->HcRhPortStatus[0] = OR_RH_PORT_CSC; } // Port1: Reset completed if (ints_port1 & OR_RH_PORT_PRSC) { USBH->HcRhPortStatus[0] = OR_RH_PORT_PRSC; } // Port1: PortEnableStatusChange if (ints_port1 & OR_RH_PORT_PESC) { USBH->HcRhPortStatus[0] = OR_RH_PORT_PESC; } // Port2: PortOverCurrentIndicatorChange if (ints_port2 & OR_RH_PORT_OCIC) { USBH->HcRhPortStatus[1] = OR_RH_PORT_OCIC; } USBH->HcInterruptStatus = OR_INTR_STATUS_RHSC; } // Writeback Done Head interrupt if (ints & OR_INTR_STATUS_WDH) { transferCompleted(usb_hcca->DoneHead & 0xFFFFFFFE); USBH->HcInterruptStatus = OR_INTR_STATUS_WDH; } } #endif