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.
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;
}
