USB host library, support isochronous,bulk,interrupt and control.

Dependents:   BaseUsbHost_example BaseJpegDecode_example SimpleJpegDecode_example

Import programBaseUsbHost_example

BaseUsbHost example program

Committer:
va009039
Date:
Mon Feb 11 12:00:47 2013 +0000
Revision:
5:8a2d056e9b38
Parent:
4:d931d24c2f81
add GetStringDescriptor()

Who changed what in which revision?

UserRevisionLine numberNew contents of line
va009039 4:d931d24c2f81 1 // BaseUsbHost.cpp 2013/1/25
va009039 0:b7d6879637a8 2 #include "mbed.h"
va009039 0:b7d6879637a8 3 #include "rtos.h"
va009039 0:b7d6879637a8 4 #include "BaseUsbHost.h"
va009039 4:d931d24c2f81 5 //#define DEBUG
va009039 0:b7d6879637a8 6 #include "BaseUsbHostDebug.h"
va009039 0:b7d6879637a8 7 #define TEST
va009039 0:b7d6879637a8 8 #include "BaseUsbHostTest.h"
va009039 0:b7d6879637a8 9
va009039 0:b7d6879637a8 10 // bits of the USB/OTG clock control register
va009039 0:b7d6879637a8 11 #define HOST_CLK_EN (1<<0)
va009039 0:b7d6879637a8 12 #define DEV_CLK_EN (1<<1)
va009039 0:b7d6879637a8 13 #define PORTSEL_CLK_EN (1<<3)
va009039 0:b7d6879637a8 14 #define AHB_CLK_EN (1<<4)
va009039 0:b7d6879637a8 15
va009039 0:b7d6879637a8 16 // bits of the USB/OTG clock status register
va009039 0:b7d6879637a8 17 #define HOST_CLK_ON (1<<0)
va009039 0:b7d6879637a8 18 #define DEV_CLK_ON (1<<1)
va009039 0:b7d6879637a8 19 #define PORTSEL_CLK_ON (1<<3)
va009039 0:b7d6879637a8 20 #define AHB_CLK_ON (1<<4)
va009039 0:b7d6879637a8 21
va009039 0:b7d6879637a8 22 // we need host clock, OTG/portsel clock and AHB clock
va009039 0:b7d6879637a8 23 #define CLOCK_MASK (HOST_CLK_EN | PORTSEL_CLK_EN | AHB_CLK_EN)
va009039 0:b7d6879637a8 24
va009039 0:b7d6879637a8 25 #define FI 0x2EDF /* 12000 bits per frame (-1) */
va009039 0:b7d6879637a8 26 #define DEFAULT_FMINTERVAL ((((6 * (FI - 210)) / 7) << 16) | FI)
va009039 0:b7d6879637a8 27
va009039 0:b7d6879637a8 28 static BaseUsbHost* pHost = NULL;
va009039 0:b7d6879637a8 29
va009039 0:b7d6879637a8 30 extern "C" void USB_IRQHandler(void) __irq;
va009039 0:b7d6879637a8 31 void USB_IRQHandler(void) __irq
va009039 0:b7d6879637a8 32 {
va009039 0:b7d6879637a8 33 if (pHost) {
va009039 0:b7d6879637a8 34 pHost->irqHandler();
va009039 0:b7d6879637a8 35 }
va009039 0:b7d6879637a8 36 }
va009039 0:b7d6879637a8 37
va009039 0:b7d6879637a8 38 BaseUsbHost::BaseUsbHost()
va009039 0:b7d6879637a8 39 {
va009039 0:b7d6879637a8 40 if (pHost) {
va009039 0:b7d6879637a8 41 TEST_ASSERT(pHost == NULL);
va009039 0:b7d6879637a8 42 return;
va009039 0:b7d6879637a8 43 }
va009039 0:b7d6879637a8 44 pHost = this;
va009039 0:b7d6879637a8 45 NVIC_DisableIRQ(USB_IRQn);
va009039 4:d931d24c2f81 46 m_pHcca = new HCCA();
va009039 0:b7d6879637a8 47 TEST_ASSERT(m_pHcca);
va009039 0:b7d6879637a8 48 init_hw_ohci(m_pHcca);
va009039 0:b7d6879637a8 49 ResetRootHub();
va009039 0:b7d6879637a8 50 NVIC_SetPriority(USB_IRQn, 0);
va009039 0:b7d6879637a8 51 NVIC_EnableIRQ(USB_IRQn);
va009039 0:b7d6879637a8 52 }
va009039 0:b7d6879637a8 53
va009039 0:b7d6879637a8 54 void BaseUsbHost::init_hw_ohci(HCCA* pHcca)
va009039 0:b7d6879637a8 55 {
va009039 0:b7d6879637a8 56 LPC_SC->PCONP &= ~(1UL<<31); //Cut power
va009039 0:b7d6879637a8 57 wait(1);
va009039 0:b7d6879637a8 58 LPC_SC->PCONP |= (1UL<<31); // turn on power for USB
va009039 0:b7d6879637a8 59 LPC_USB->USBClkCtrl |= CLOCK_MASK; // Enable USB host clock, port selection and AHB clock
va009039 0:b7d6879637a8 60 // Wait for clocks to become available
va009039 0:b7d6879637a8 61 while ((LPC_USB->USBClkSt & CLOCK_MASK) != CLOCK_MASK)
va009039 0:b7d6879637a8 62 ;
va009039 0:b7d6879637a8 63 LPC_USB->OTGStCtrl |= 1;
va009039 0:b7d6879637a8 64 LPC_USB->USBClkCtrl &= ~PORTSEL_CLK_EN;
va009039 0:b7d6879637a8 65
va009039 0:b7d6879637a8 66 LPC_PINCON->PINSEL1 &= ~((3<<26) | (3<<28));
va009039 0:b7d6879637a8 67 LPC_PINCON->PINSEL1 |= ((1<<26)|(1<<28)); // 0x14000000
va009039 0:b7d6879637a8 68
va009039 0:b7d6879637a8 69 DBG("initialize OHCI\n");
va009039 0:b7d6879637a8 70 wait_ms(100); /* Wait 50 ms before apply reset */
va009039 0:b7d6879637a8 71 TEST_ASSERT((LPC_USB->HcRevision&0xff) == 0x10); // check revision
va009039 0:b7d6879637a8 72 LPC_USB->HcControl = 0; /* HARDWARE RESET */
va009039 0:b7d6879637a8 73 LPC_USB->HcControlHeadED = 0; /* Initialize Control list head to Zero */
va009039 0:b7d6879637a8 74 LPC_USB->HcBulkHeadED = 0; /* Initialize Bulk list head to Zero */
va009039 0:b7d6879637a8 75 /* SOFTWARE RESET */
va009039 0:b7d6879637a8 76 LPC_USB->HcCommandStatus = OR_CMD_STATUS_HCR;
va009039 0:b7d6879637a8 77 LPC_USB->HcFmInterval = DEFAULT_FMINTERVAL; /* Write Fm Interval and Largest Data Packet Counter */
va009039 0:b7d6879637a8 78 LPC_USB->HcPeriodicStart = FI*90/100;
va009039 0:b7d6879637a8 79 /* Put HC in operational state */
va009039 0:b7d6879637a8 80 LPC_USB->HcControl = (LPC_USB->HcControl & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER;
va009039 0:b7d6879637a8 81 LPC_USB->HcRhStatus = OR_RH_STATUS_LPSC; /* Set Global Power */
va009039 0:b7d6879637a8 82 TEST_ASSERT(pHcca);
va009039 0:b7d6879637a8 83 for (int i = 0; i < 32; i++) {
va009039 0:b7d6879637a8 84 pHcca->InterruptTable[i] = NULL;
va009039 0:b7d6879637a8 85 }
va009039 4:d931d24c2f81 86 LPC_USB->HcHCCA = reinterpret_cast<uint32_t>(pHcca);
va009039 0:b7d6879637a8 87 LPC_USB->HcInterruptStatus |= LPC_USB->HcInterruptStatus; /* Clear Interrrupt Status */
va009039 0:b7d6879637a8 88 LPC_USB->HcInterruptEnable = OR_INTR_ENABLE_MIE|OR_INTR_ENABLE_WDH|OR_INTR_ENABLE_FNO;
va009039 0:b7d6879637a8 89
va009039 0:b7d6879637a8 90 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC;
va009039 0:b7d6879637a8 91 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC;
va009039 0:b7d6879637a8 92 }
va009039 0:b7d6879637a8 93
va009039 0:b7d6879637a8 94 void BaseUsbHost::ResetRootHub()
va009039 0:b7d6879637a8 95 {
va009039 0:b7d6879637a8 96 wait_ms(100); /* USB 2.0 spec says at least 50ms delay before port reset */
va009039 0:b7d6879637a8 97 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRS; // Initiate port reset
va009039 0:b7d6879637a8 98 DBG("Before loop\n");
va009039 0:b7d6879637a8 99 while (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRS)
va009039 0:b7d6879637a8 100 ;
va009039 0:b7d6879637a8 101 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; // ...and clear port reset signal
va009039 0:b7d6879637a8 102 DBG("After loop\n");
va009039 0:b7d6879637a8 103 wait_ms(200); /* Wait for 100 MS after port reset */
va009039 0:b7d6879637a8 104 }
va009039 0:b7d6879637a8 105
va009039 0:b7d6879637a8 106 HCTD* td_reverse(HCTD* td)
va009039 0:b7d6879637a8 107 {
va009039 0:b7d6879637a8 108 HCTD* result = NULL;
va009039 0:b7d6879637a8 109 HCTD* next;
va009039 0:b7d6879637a8 110 while(td) {
va009039 4:d931d24c2f81 111 next = const_cast<HCTD*>(td->Next);
va009039 4:d931d24c2f81 112 td->Next = result;
va009039 0:b7d6879637a8 113 result = td;
va009039 0:b7d6879637a8 114 td = next;
va009039 0:b7d6879637a8 115 }
va009039 0:b7d6879637a8 116 return result;
va009039 0:b7d6879637a8 117 }
va009039 0:b7d6879637a8 118
va009039 0:b7d6879637a8 119 void BaseUsbHost::irqHandler()
va009039 0:b7d6879637a8 120 {
va009039 0:b7d6879637a8 121 if (!(LPC_USB->HcInterruptStatus & LPC_USB->HcInterruptEnable)) {
va009039 0:b7d6879637a8 122 return;
va009039 0:b7d6879637a8 123 }
va009039 0:b7d6879637a8 124 m_report_irq++;
va009039 0:b7d6879637a8 125 uint32_t status = LPC_USB->HcInterruptStatus;
va009039 0:b7d6879637a8 126 if (status & OR_INTR_STATUS_FNO) {
va009039 0:b7d6879637a8 127 m_report_FNO++;
va009039 0:b7d6879637a8 128 }
va009039 0:b7d6879637a8 129 if (status & OR_INTR_STATUS_WDH) {
va009039 4:d931d24c2f81 130 union {
va009039 4:d931d24c2f81 131 HCTD* done_td;
va009039 4:d931d24c2f81 132 uint32_t lsb;
va009039 4:d931d24c2f81 133 };
va009039 4:d931d24c2f81 134 done_td = const_cast<HCTD*>(m_pHcca->DoneHead);
va009039 0:b7d6879637a8 135 TEST_ASSERT(done_td);
va009039 0:b7d6879637a8 136 m_pHcca->DoneHead = NULL; // reset
va009039 4:d931d24c2f81 137 if (lsb & 1) { // error ?
va009039 4:d931d24c2f81 138 lsb &= ~1;
va009039 0:b7d6879637a8 139 }
va009039 4:d931d24c2f81 140 HCTD* td = td_reverse(done_td);
va009039 0:b7d6879637a8 141 while(td) {
va009039 4:d931d24c2f81 142 BaseEp* ep = td->ep;
va009039 0:b7d6879637a8 143 TEST_ASSERT(ep);
va009039 4:d931d24c2f81 144 if (ep) {
va009039 4:d931d24c2f81 145 ep->irqWdhHandler(td);
va009039 4:d931d24c2f81 146 }
va009039 4:d931d24c2f81 147 td = td->Next;
va009039 0:b7d6879637a8 148 }
va009039 0:b7d6879637a8 149 m_report_WDH++;
va009039 0:b7d6879637a8 150 }
va009039 0:b7d6879637a8 151 LPC_USB->HcInterruptStatus = status; // Clear Interrrupt Status
va009039 0:b7d6879637a8 152 }
va009039 0:b7d6879637a8 153
va009039 0:b7d6879637a8 154 BaseEp::BaseEp(int addr, uint8_t ep, uint16_t size, int lowSpeed):m_td_queue_count(0)
va009039 0:b7d6879637a8 155 {
va009039 0:b7d6879637a8 156 DBG("%p FA=%d EN=%02x MPS=%d S=%d\n", this, addr, ep, size, lowSpeed);
va009039 0:b7d6879637a8 157 TEST_ASSERT(size >= 8 && size <= 1023);
va009039 0:b7d6879637a8 158 TEST_ASSERT(lowSpeed == 0 || lowSpeed == 1);
va009039 4:d931d24c2f81 159 m_pED = new HCED(addr, ep, size, lowSpeed);
va009039 4:d931d24c2f81 160 TEST_ASSERT(m_pED);
va009039 0:b7d6879637a8 161 }
va009039 0:b7d6879637a8 162
va009039 0:b7d6879637a8 163 int BaseEp::GetAddr()
va009039 0:b7d6879637a8 164 {
va009039 4:d931d24c2f81 165 TEST_ASSERT(m_pED);
va009039 4:d931d24c2f81 166 if (m_pED) {
va009039 4:d931d24c2f81 167 return m_pED->FunctionAddress();
va009039 0:b7d6879637a8 168 }
va009039 0:b7d6879637a8 169 return 0;
va009039 0:b7d6879637a8 170 }
va009039 0:b7d6879637a8 171
va009039 0:b7d6879637a8 172 int BaseEp::GetLowSpeed()
va009039 0:b7d6879637a8 173 {
va009039 4:d931d24c2f81 174 TEST_ASSERT(m_pED);
va009039 4:d931d24c2f81 175 if (m_pED) {
va009039 4:d931d24c2f81 176 return m_pED->Speed();
va009039 0:b7d6879637a8 177 }
va009039 0:b7d6879637a8 178 return 0;
va009039 0:b7d6879637a8 179 }
va009039 0:b7d6879637a8 180
va009039 0:b7d6879637a8 181 void BaseEp::update_FunctionAddress(int addr)
va009039 0:b7d6879637a8 182 {
va009039 0:b7d6879637a8 183 TEST_ASSERT(addr >= 0 && addr <= 127);
va009039 4:d931d24c2f81 184 TEST_ASSERT(m_pED);
va009039 4:d931d24c2f81 185 if (m_pED) {
va009039 4:d931d24c2f81 186 m_pED->setFunctionAddress(addr);
va009039 4:d931d24c2f81 187 }
va009039 0:b7d6879637a8 188 }
va009039 0:b7d6879637a8 189
va009039 0:b7d6879637a8 190 void BaseEp::update_MaxPacketSize(uint16_t size)
va009039 0:b7d6879637a8 191 {
va009039 0:b7d6879637a8 192 TEST_ASSERT(size >= 8 && size <= 1023);
va009039 4:d931d24c2f81 193 TEST_ASSERT(m_pED);
va009039 4:d931d24c2f81 194 if (m_pED) {
va009039 4:d931d24c2f81 195 m_pED->setMaxPacketSize(size);
va009039 4:d931d24c2f81 196 }
va009039 0:b7d6879637a8 197 }
va009039 0:b7d6879637a8 198
va009039 3:ae77d63a1eda 199 int BaseEp::transfer(uint8_t* buf, int len)
va009039 3:ae77d63a1eda 200 {
va009039 3:ae77d63a1eda 201 HCTD* data_td = m_pED->TailTd;
va009039 3:ae77d63a1eda 202 TEST_ASSERT(data_td);
va009039 3:ae77d63a1eda 203 if (data_td == NULL) {
va009039 3:ae77d63a1eda 204 return USB_ERROR;
va009039 3:ae77d63a1eda 205 }
va009039 4:d931d24c2f81 206 data_td->transfer(buf, len);
va009039 4:d931d24c2f81 207 HCTD* blank_td = new HCTD(this);
va009039 3:ae77d63a1eda 208 TEST_ASSERT(blank_td);
va009039 3:ae77d63a1eda 209 if (blank_td == NULL) {
va009039 3:ae77d63a1eda 210 return USB_ERROR_MEMORY;
va009039 3:ae77d63a1eda 211 }
va009039 4:d931d24c2f81 212 data_td->Next = blank_td;
va009039 3:ae77d63a1eda 213 m_pED->TailTd = blank_td;
va009039 3:ae77d63a1eda 214 enable();
va009039 3:ae77d63a1eda 215 return USB_PROCESSING;
va009039 3:ae77d63a1eda 216 }
va009039 3:ae77d63a1eda 217
va009039 3:ae77d63a1eda 218 int BaseEp::status(uint32_t millisec)
va009039 3:ae77d63a1eda 219 {
va009039 3:ae77d63a1eda 220 HCTD* td = get_queue_HCTD(millisec);
va009039 3:ae77d63a1eda 221 if (td == NULL) {
va009039 3:ae77d63a1eda 222 return USB_PROCESSING;
va009039 3:ae77d63a1eda 223 }
va009039 4:d931d24c2f81 224 uint8_t cc = td->ConditionCode();
va009039 3:ae77d63a1eda 225 int ret;
va009039 3:ae77d63a1eda 226 switch(cc) {
va009039 3:ae77d63a1eda 227 case 0:
va009039 3:ae77d63a1eda 228 case 8:
va009039 3:ae77d63a1eda 229 case 9:
va009039 4:d931d24c2f81 230 ret = td->status();
va009039 3:ae77d63a1eda 231 break;
va009039 3:ae77d63a1eda 232 case 4:
va009039 3:ae77d63a1eda 233 ret = USB_ERROR_STALL;
va009039 3:ae77d63a1eda 234 break;
va009039 3:ae77d63a1eda 235 case 5:
va009039 3:ae77d63a1eda 236 ret = USB_ERROR_DEVICE_NOT_RESPONDING;
va009039 3:ae77d63a1eda 237 break;
va009039 3:ae77d63a1eda 238 default:
va009039 3:ae77d63a1eda 239 DBG("ConditionCode=%d\n", cc);
va009039 3:ae77d63a1eda 240 ret = USB_ERROR;
va009039 3:ae77d63a1eda 241 break;
va009039 3:ae77d63a1eda 242 }
va009039 4:d931d24c2f81 243 delete td;
va009039 3:ae77d63a1eda 244 return ret;
va009039 3:ae77d63a1eda 245 }
va009039 3:ae77d63a1eda 246
va009039 3:ae77d63a1eda 247 int BaseEp::send_receive(uint8_t* buf, int len, int millisec)
va009039 3:ae77d63a1eda 248 {
va009039 3:ae77d63a1eda 249 if (m_td_queue_count == 0) {
va009039 3:ae77d63a1eda 250 int rc = transfer(buf, len);
va009039 3:ae77d63a1eda 251 if (rc != USB_PROCESSING) {
va009039 3:ae77d63a1eda 252 return rc;
va009039 3:ae77d63a1eda 253 }
va009039 3:ae77d63a1eda 254 m_td_queue_count++;
va009039 3:ae77d63a1eda 255 }
va009039 3:ae77d63a1eda 256
va009039 3:ae77d63a1eda 257 int ret = status(millisec);
va009039 3:ae77d63a1eda 258 if (ret != USB_PROCESSING) {
va009039 3:ae77d63a1eda 259 m_td_queue_count--;
va009039 3:ae77d63a1eda 260 }
va009039 3:ae77d63a1eda 261 return ret;
va009039 3:ae77d63a1eda 262 }
va009039 3:ae77d63a1eda 263
va009039 0:b7d6879637a8 264 HCTD* BaseEp::get_queue_HCTD(uint32_t millisec)
va009039 0:b7d6879637a8 265 {
va009039 0:b7d6879637a8 266 for(int i = 0; i < 16; i++) {
va009039 0:b7d6879637a8 267 osEvent evt = m_queue.get(millisec);
va009039 0:b7d6879637a8 268 if (evt.status == osEventMessage) {
va009039 0:b7d6879637a8 269 HCTD* td = reinterpret_cast<HCTD*>(evt.value.p);
va009039 0:b7d6879637a8 270 TEST_ASSERT(td);
va009039 4:d931d24c2f81 271 uint8_t cc = td->ConditionCode();
va009039 4:d931d24c2f81 272 if (cc != 0) {
va009039 4:d931d24c2f81 273 m_ConditionCode = cc;
va009039 0:b7d6879637a8 274 DBG_TD(td);
va009039 0:b7d6879637a8 275 }
va009039 0:b7d6879637a8 276 return td;
va009039 0:b7d6879637a8 277 } else if (evt.status == osOK) {
va009039 0:b7d6879637a8 278 continue;
va009039 0:b7d6879637a8 279 } else if (evt.status == osEventTimeout) {
va009039 0:b7d6879637a8 280 return NULL;
va009039 0:b7d6879637a8 281 } else {
va009039 0:b7d6879637a8 282 DBG("evt.status: %02x\n", evt.status);
va009039 0:b7d6879637a8 283 TEST_ASSERT(evt.status == osEventMessage);
va009039 0:b7d6879637a8 284 }
va009039 0:b7d6879637a8 285 }
va009039 0:b7d6879637a8 286 return NULL;
va009039 0:b7d6879637a8 287 }
va009039 0:b7d6879637a8 288
va009039 0:b7d6879637a8 289 int BaseEp::wait_queue_HCTD(HCTD* wait_td, uint32_t millisec)
va009039 0:b7d6879637a8 290 {
va009039 0:b7d6879637a8 291 for(int i = 0; i < 16; i++) {
va009039 0:b7d6879637a8 292 HCTD* td = get_queue_HCTD(millisec);
va009039 0:b7d6879637a8 293 if (td) {
va009039 4:d931d24c2f81 294 uint8_t cc = td->ConditionCode();
va009039 4:d931d24c2f81 295 if (cc != 0) {
va009039 0:b7d6879637a8 296 DBG_TD(td);
va009039 4:d931d24c2f81 297 delete td;
va009039 3:ae77d63a1eda 298 switch(cc) {
va009039 3:ae77d63a1eda 299 case 4:
va009039 3:ae77d63a1eda 300 return USB_ERROR_STALL;
va009039 3:ae77d63a1eda 301 default:
va009039 3:ae77d63a1eda 302 return USB_ERROR;
va009039 3:ae77d63a1eda 303 }
va009039 0:b7d6879637a8 304 }
va009039 4:d931d24c2f81 305 delete td;
va009039 0:b7d6879637a8 306 if (td == wait_td) {
va009039 0:b7d6879637a8 307 return USB_OK;
va009039 0:b7d6879637a8 308 }
va009039 0:b7d6879637a8 309 }
va009039 0:b7d6879637a8 310 }
va009039 0:b7d6879637a8 311 return USB_ERROR;
va009039 0:b7d6879637a8 312 }