Adaptation of the official mbed USBHost repository to work with the LPC4088 Display Module
Dependents: DMSupport DMSupport DMSupport DMSupport
Fork of DM_USBHost by
Diff: USBHost/USBHALHost.cpp
- Revision:
- 27:aa2fd412f1d3
- Parent:
- 24:868cbfe611a7
- Child:
- 31:9a462d032742
diff -r 607951c26872 -r aa2fd412f1d3 USBHost/USBHALHost.cpp --- a/USBHost/USBHALHost.cpp Mon Aug 18 13:45:26 2014 +0100 +++ b/USBHost/USBHALHost.cpp Tue Dec 02 15:16:39 2014 +0000 @@ -39,7 +39,28 @@ #define TOTAL_SIZE (HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE) + (MAX_TD*TD_SIZE)) -static volatile uint8_t usb_buf[TOTAL_SIZE] __attribute((section("AHBSRAM1"),aligned(256))); //256 bytes aligned! +// Put the USB structures in the only memory accessible by the USB stack - the AHBSRAM0 +static volatile uint8_t usb_buf[TOTAL_SIZE] __attribute__((section("AHBSRAM0"),aligned(256)));// __attribute__((section("AHBSRAM0"),aligned(256))); //256 bytes aligned! + +// A very basic implementation of malloc to allocate in the AHBSRAM0 +#define SAFE_MEM_TO_USE (10*1024) +#define SAFE_MEM_BLOCK_SIZE (512) +#define SAFE_MEM_NUM_BLOCKS (SAFE_MEM_TO_USE/SAFE_MEM_BLOCK_SIZE) +typedef struct { + volatile uint8_t* ptr; + bool used; +} safe_mem_info_t; +static safe_mem_info_t safe_mem_list[SAFE_MEM_NUM_BLOCKS]; +static uint8_t safe_mem_data[SAFE_MEM_TO_USE] __attribute__((section("AHBSRAM0"),aligned(256)));//__attribute__((section("AHBSRAM0"),aligned)); //256 bytes aligned! + +// To detect when memory outside of the AHBSRAM0 is passed to the USB stack +void assert_mem_region(uint32_t ptr) +{ + if (( ptr != 0) && ((ptr & 0xff000000) != 0x20000000)) { + USB_ERR("0x%08x not in USB MEM", ptr); + mbed_die(); + } +} USBHALHost * USBHALHost::instHost; @@ -53,23 +74,64 @@ for (int i = 0; i < MAX_TD; i++) { tdBufAlloc[i] = false; } + for (int i = 0; i < SAFE_MEM_NUM_BLOCKS; i++) { + safe_mem_list[i].used = false; + safe_mem_list[i].ptr = safe_mem_data + SAFE_MEM_BLOCK_SIZE*i; + } } +uint8_t* USBHALHost::getSafeMem(uint32_t size) { + uint8_t* result = NULL; + if (size > 512) { + USB_ERR("getSafeMem(%u) not supported", size); + } else { + safemem_mutex.lock(); + for (int i = 0; i < SAFE_MEM_NUM_BLOCKS; i++) { + if (!safe_mem_list[i].used) { + safe_mem_list[i].used = true; + result = (uint8_t*)safe_mem_list[i].ptr; + break; + } + } + safemem_mutex.unlock(); + } + if (result == NULL) { + USB_ERR("getSafeMem(%u) failed to allocate", size); + } + return result; +} + +void USBHALHost::returnSafeMem(uint8_t* mem) { + safemem_mutex.lock(); + int i; + for (i = 0; i < SAFE_MEM_NUM_BLOCKS; i++) { + if (safe_mem_list[i].ptr == mem) { + safe_mem_list[i].used = false; + break; + } + } + safemem_mutex.unlock(); + if (i == SAFE_MEM_NUM_BLOCKS) { + USB_ERR("returnSafeMem(%p) not allocated", mem); + } +} + + void USBHALHost::init() { NVIC_DisableIRQ(USB_IRQn); //Cut power LPC_SC->PCONP &= ~(1UL<<31); - wait_ms(100); + wait_ms(1000); // turn on power for USB LPC_SC->PCONP |= (1UL<<31); // Enable USB host clock, port selection and AHB clock - LPC_USB->USBClkCtrl |= CLOCK_MASK; + LPC_USB->USBClkCtrl = 0x19; // Wait for clocks to become available - while ((LPC_USB->USBClkSt & CLOCK_MASK) != CLOCK_MASK); + while ((LPC_USB->USBClkSt & 0x19) != 0x19); // it seems the bits[0:1] mean the following // 0: U1=device, U2=host @@ -77,25 +139,39 @@ // 2: reserved // 3: U1=host, U2=device // NB: this register is only available if OTG clock (aka "port select") is enabled!! - // since we don't care about port 2, set just bit 0 to 1 (U1=host) - LPC_USB->OTGStCtrl |= 1; - - // now that we've configured the ports, we can turn off the portsel clock - LPC_USB->USBClkCtrl &= ~PORTSEL_CLK_EN; + LPC_USB->OTGStCtrl = 1; // configure USB D+/D- pins - // P0[29] = USB_D+, 01 - // P0[30] = USB_D-, 01 - LPC_PINCON->PINSEL1 &= ~((3<<26) | (3<<28)); - LPC_PINCON->PINSEL1 |= ((1<<26) | (1<<28)); + + LPC_IOCON->P0_29 &= ~0x9F; // USB_D+1 + LPC_IOCON->P0_29 |= 0x01; // USB_D+1 + LPC_IOCON->P0_30 &= ~0x9F; // USB_D-1 + LPC_IOCON->P0_30 |= 0x01; // USB_D-1 + + LPC_IOCON->P0_31 &= ~0x9F; // USB_D+2 + LPC_IOCON->P0_31 |= 0x01; // USB_D+2 + + LPC_IOCON->P1_30 &= ~0x1F; // USB_PWRD2 + LPC_IOCON->P1_30 |= 0x01; // USB_PWRD2 + LPC_IOCON->P1_31 &= ~0x1F; // USB_OVRCR2 + LPC_IOCON->P1_31 |= 0x01; // USB_OVRCR2 + + LPC_IOCON->P0_14 &= ~0x1F; // USB ID Pin as GPIO, output, high + LPC_GPIO0->DIR |= (1<<14); + LPC_GPIO0->SET = (1<<14); + LPC_IOCON->P4_31 &= ~0x1F; // USB CONN Pin as GPIO, output, low + LPC_GPIO4->DIR |= (1UL<<31); + LPC_GPIO4->CLR = (1UL<<31); + + USB_DBG("initialize OHCI\n"); + + // Wait 100 ms before apply reset + wait_ms(100); LPC_USB->HcControl = 0; // HARDWARE RESET LPC_USB->HcControlHeadED = 0; // Initialize Control list head to Zero LPC_USB->HcBulkHeadED = 0; // Initialize Bulk list head to Zero - // Wait 100 ms before apply reset - wait_ms(100); - // software reset LPC_USB->HcCommandStatus = OR_CMD_STATUS_HCR; @@ -105,6 +181,7 @@ // Put HC in operational state LPC_USB->HcControl = (LPC_USB->HcControl & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER; + // Set Global Power LPC_USB->HcRhStatus = OR_RH_STATUS_LPSC; @@ -119,15 +196,19 @@ NVIC_SetVector(USB_IRQn, (uint32_t)(_usbisr)); LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC; LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; + LPC_USB->HcRhPortStatus2 = OR_RH_PORT_CSC; + LPC_USB->HcRhPortStatus2 = OR_RH_PORT_PRSC; + + resetRootHub(); + NVIC_SetPriority(USB_IRQn, 0); NVIC_EnableIRQ(USB_IRQn); - // Check for any connected devices - if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS) { + if (LPC_USB->HcRhPortStatus2 & OR_RH_PORT_CCS) { //Device connected wait_ms(150); - USB_DBG("Device connected (%08x)\n\r", LPC_USB->HcRhPortStatus1); - deviceConnected(0, 1, LPC_USB->HcRhPortStatus1 & OR_RH_PORT_LSDA); + USB_DBG("Device connected (%08x)\n\r", LPC_USB->HcRhPortStatus2); + deviceConnected(0, 2, LPC_USB->HcRhPortStatus2 & OR_RH_PORT_LSDA); } } @@ -216,8 +297,8 @@ return (volatile uint8_t *)(usb_edBuf + i*ED_SIZE); } } - perror("Could not allocate ED\r\n"); - return NULL; //Could not alloc ED + USB_ERR("Could not allocate ED\r\n"); + return NULL; } volatile uint8_t * USBHALHost::getTD() { @@ -228,8 +309,8 @@ return (volatile uint8_t *)(usb_tdBuf + i*TD_SIZE); } } - perror("Could not allocate TD\r\n"); - return NULL; //Could not alloc TD + USB_ERR("Could not allocate TD\r\n"); + return NULL; } @@ -247,6 +328,11 @@ void USBHALHost::resetRootHub() { + + DigitalOut usb2_vbus_en(P0_12); + usb2_vbus_en = 1; + wait_ms(100); /* USB 2.0 spec says at least 50ms delay before port reset */ + // Initiate port reset LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRS; @@ -254,6 +340,19 @@ // ...and clear port reset signal LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; + + usb2_vbus_en = 0; + + // Initiate port reset + LPC_USB->HcRhPortStatus2 = OR_RH_PORT_PRS; + + while (LPC_USB->HcRhPortStatus2 & OR_RH_PORT_PRS); + + // ...and clear port reset signal + LPC_USB->HcRhPortStatus2 = OR_RH_PORT_PRSC; + + usb2_vbus_en = 1; + wait_ms(200); /* Wait for 100 MS after port reset */ } @@ -266,25 +365,24 @@ void USBHALHost::UsbIrqhandler() { if( LPC_USB->HcInterruptStatus & LPC_USB->HcInterruptEnable ) //Is there something to actually process? { - uint32_t int_status = LPC_USB->HcInterruptStatus & LPC_USB->HcInterruptEnable; - + // Root hub status change interrupt if (int_status & OR_INTR_STATUS_RHSC) { - if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CSC) { + if (LPC_USB->HcRhPortStatus2 & OR_RH_PORT_CSC) { if (LPC_USB->HcRhStatus & OR_RH_STATUS_DRWE) { // When DRWE is on, Connect Status Change // means a remote wakeup event. } else { //Root device connected - if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS) { + if (LPC_USB->HcRhPortStatus2 & OR_RH_PORT_CCS) { // 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, LPC_USB->HcRhPortStatus1 & OR_RH_PORT_LSDA); + //Hub 0 (root hub), Port 2 (count starts at 1), Low or High speed + deviceConnected(0, 2, LPC_USB->HcRhPortStatus2 & OR_RH_PORT_LSDA); } //Root device disconnected @@ -297,7 +395,7 @@ // wait 200ms to avoid bounce wait_ms(200); - deviceDisconnected(0, 1, NULL, usb_hcca->DoneHead & 0xFFFFFFFE); + deviceDisconnected(0, 2, NULL, usb_hcca->DoneHead & 0xFFFFFFFE); if (int_status & OR_INTR_STATUS_WDH) { usb_hcca->DoneHead = 0; @@ -305,10 +403,10 @@ } } } - LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC; + LPC_USB->HcRhPortStatus2 = OR_RH_PORT_CSC; } - if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRSC) { - LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; + if (LPC_USB->HcRhPortStatus2 & OR_RH_PORT_PRSC) { + LPC_USB->HcRhPortStatus2 = OR_RH_PORT_PRSC; } LPC_USB->HcInterruptStatus = OR_INTR_STATUS_RHSC; }