Support Isochronous transfer additionally
Dependents: USBHostC270_example_GR-PEACH USBHostDac_example USBHostDac_Audio_in_out
Fork of USBHost_custom by
USBisochronous/USBIsochronous.cpp@41:5c3ebf7372ee, 2017-04-21 (annotated)
- Committer:
- HinoNaka
- Date:
- Fri Apr 21 07:23:33 2017 +0000
- Revision:
- 41:5c3ebf7372ee
Support Isochronous transfer
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
HinoNaka | 41:5c3ebf7372ee | 1 | // USBIsochronous.cpp |
HinoNaka | 41:5c3ebf7372ee | 2 | #include "USBHostConf.h" |
HinoNaka | 41:5c3ebf7372ee | 3 | #include "USBHost.h" |
HinoNaka | 41:5c3ebf7372ee | 4 | #include "USBIsochronous.h" |
HinoNaka | 41:5c3ebf7372ee | 5 | #if defined(TARGET_RZ_A1H) |
HinoNaka | 41:5c3ebf7372ee | 6 | #include "ohci_wrapp_RZ_A1.h" |
HinoNaka | 41:5c3ebf7372ee | 7 | #endif |
HinoNaka | 41:5c3ebf7372ee | 8 | |
HinoNaka | 41:5c3ebf7372ee | 9 | #define OR_CONTROL_PLE 0x00000004 |
HinoNaka | 41:5c3ebf7372ee | 10 | #define OR_CONTROL_IE 0x00000008 |
HinoNaka | 41:5c3ebf7372ee | 11 | |
HinoNaka | 41:5c3ebf7372ee | 12 | //#define ISO_DEBUG 1 |
HinoNaka | 41:5c3ebf7372ee | 13 | #ifdef ISO_DEBUG |
HinoNaka | 41:5c3ebf7372ee | 14 | #define ISO_DBG(x, ...) std::printf("[%s:%d]"x"\r\n", __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); |
HinoNaka | 41:5c3ebf7372ee | 15 | #else |
HinoNaka | 41:5c3ebf7372ee | 16 | #define ISO_DBG(...) while(0); |
HinoNaka | 41:5c3ebf7372ee | 17 | #endif |
HinoNaka | 41:5c3ebf7372ee | 18 | |
HinoNaka | 41:5c3ebf7372ee | 19 | #define TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);}; |
HinoNaka | 41:5c3ebf7372ee | 20 | |
HinoNaka | 41:5c3ebf7372ee | 21 | HCITD::HCITD(IsochronousEp* obj, uint16_t FrameNumber, int FrameCount, uint16_t PacketSize) { |
HinoNaka | 41:5c3ebf7372ee | 22 | Control = 0xe0000000 | // CC ConditionCode NOT ACCESSED |
HinoNaka | 41:5c3ebf7372ee | 23 | ((FrameCount-1) << 24)| // FC FrameCount |
HinoNaka | 41:5c3ebf7372ee | 24 | TD_DELAY_INT(0) | // DI DelayInterrupt |
HinoNaka | 41:5c3ebf7372ee | 25 | FrameNumber; // SF StartingFrame |
HinoNaka | 41:5c3ebf7372ee | 26 | BufferPage0 = const_cast<uint8_t*>(buf); |
HinoNaka | 41:5c3ebf7372ee | 27 | BufferEnd = const_cast<uint8_t*>(buf) + PacketSize * FrameCount - 1; |
HinoNaka | 41:5c3ebf7372ee | 28 | Next = NULL; |
HinoNaka | 41:5c3ebf7372ee | 29 | ep = obj; |
HinoNaka | 41:5c3ebf7372ee | 30 | uint32_t addr = reinterpret_cast<uint32_t>(buf); |
HinoNaka | 41:5c3ebf7372ee | 31 | for(int i = 0; i < FrameCount; i++) { |
HinoNaka | 41:5c3ebf7372ee | 32 | uint16_t offset = addr & 0x0fff; |
HinoNaka | 41:5c3ebf7372ee | 33 | if ((addr&0xfffff000) == (reinterpret_cast<uint32_t>(BufferEnd)&0xfffff000)) { |
HinoNaka | 41:5c3ebf7372ee | 34 | offset |= 0x1000; |
HinoNaka | 41:5c3ebf7372ee | 35 | } |
HinoNaka | 41:5c3ebf7372ee | 36 | OffsetPSW[i] = 0xe000|offset; |
HinoNaka | 41:5c3ebf7372ee | 37 | addr += PacketSize; |
HinoNaka | 41:5c3ebf7372ee | 38 | } |
HinoNaka | 41:5c3ebf7372ee | 39 | } |
HinoNaka | 41:5c3ebf7372ee | 40 | |
HinoNaka | 41:5c3ebf7372ee | 41 | void IsochronousEp::init(int addr, uint8_t ep, uint16_t size, uint8_t frameCount, uint8_t queueLimit) { |
HinoNaka | 41:5c3ebf7372ee | 42 | //ISO_DBG("%p FA:%d EP:%02X MPS:%d\n", this, addr, ep, size); |
HinoNaka | 41:5c3ebf7372ee | 43 | TEST_ASSERT(addr >= 1); |
HinoNaka | 41:5c3ebf7372ee | 44 | TEST_ASSERT(size >= 8 && size <= 1023); |
HinoNaka | 41:5c3ebf7372ee | 45 | m_pED = new _HCED(addr, ep, size); |
HinoNaka | 41:5c3ebf7372ee | 46 | TEST_ASSERT(m_pED); |
HinoNaka | 41:5c3ebf7372ee | 47 | |
HinoNaka | 41:5c3ebf7372ee | 48 | m_pED->setFormat(); // F Format ITD |
HinoNaka | 41:5c3ebf7372ee | 49 | |
HinoNaka | 41:5c3ebf7372ee | 50 | m_PacketSize = size; |
HinoNaka | 41:5c3ebf7372ee | 51 | TEST_ASSERT(frameCount >= 1 && frameCount <= 8); |
HinoNaka | 41:5c3ebf7372ee | 52 | m_FrameCount = frameCount; |
HinoNaka | 41:5c3ebf7372ee | 53 | TEST_ASSERT(queueLimit >= 1 && queueLimit <= HCITD_QUEUE_SIZE); |
HinoNaka | 41:5c3ebf7372ee | 54 | m_itd_queue_limit = queueLimit; |
HinoNaka | 41:5c3ebf7372ee | 55 | |
HinoNaka | 41:5c3ebf7372ee | 56 | m_itd_queue_count = 0; |
HinoNaka | 41:5c3ebf7372ee | 57 | reset(); |
HinoNaka | 41:5c3ebf7372ee | 58 | HCITD* itd = new_HCITD(this); |
HinoNaka | 41:5c3ebf7372ee | 59 | m_pED->init_queue<HCITD>(itd); |
HinoNaka | 41:5c3ebf7372ee | 60 | TEST_ASSERT(itd); |
HinoNaka | 41:5c3ebf7372ee | 61 | if (itd == NULL) { |
HinoNaka | 41:5c3ebf7372ee | 62 | return; |
HinoNaka | 41:5c3ebf7372ee | 63 | } |
HinoNaka | 41:5c3ebf7372ee | 64 | #if defined(TARGET_LPC1768) |
HinoNaka | 41:5c3ebf7372ee | 65 | _HCCA* hcca = reinterpret_cast<_HCCA*>(LPC_USB->HcHCCA); |
HinoNaka | 41:5c3ebf7372ee | 66 | #elif defined(TARGET_RZ_A1H) |
HinoNaka | 41:5c3ebf7372ee | 67 | _HCCA* hcca = reinterpret_cast<_HCCA*>(ohciwrapp_reg_r(OHCI_REG_HCCA)); |
HinoNaka | 41:5c3ebf7372ee | 68 | #endif |
HinoNaka | 41:5c3ebf7372ee | 69 | TEST_ASSERT(hcca); |
HinoNaka | 41:5c3ebf7372ee | 70 | if (hcca == NULL) { |
HinoNaka | 41:5c3ebf7372ee | 71 | return; |
HinoNaka | 41:5c3ebf7372ee | 72 | } |
HinoNaka | 41:5c3ebf7372ee | 73 | hcca->enqueue(m_pED); |
HinoNaka | 41:5c3ebf7372ee | 74 | } |
HinoNaka | 41:5c3ebf7372ee | 75 | |
HinoNaka | 41:5c3ebf7372ee | 76 | void IsochronousEp::reset(int delay_ms) |
HinoNaka | 41:5c3ebf7372ee | 77 | { |
HinoNaka | 41:5c3ebf7372ee | 78 | #if defined(TARGET_LPC1768) |
HinoNaka | 41:5c3ebf7372ee | 79 | m_FrameNumber = LPC_USB->HcFmNumber + delay_ms; |
HinoNaka | 41:5c3ebf7372ee | 80 | #elif defined(TARGET_RZ_A1H) |
HinoNaka | 41:5c3ebf7372ee | 81 | m_FrameNumber = ohciwrapp_reg_r(OHCI_REG_FMNUMBER) + delay_ms; |
HinoNaka | 41:5c3ebf7372ee | 82 | #endif |
HinoNaka | 41:5c3ebf7372ee | 83 | } |
HinoNaka | 41:5c3ebf7372ee | 84 | |
HinoNaka | 41:5c3ebf7372ee | 85 | HCITD* IsochronousEp::new_HCITD(IsochronousEp* obj) { |
HinoNaka | 41:5c3ebf7372ee | 86 | HCITD* itd = new(m_PacketSize*m_FrameCount)HCITD(obj, 0, m_FrameCount, m_PacketSize); |
HinoNaka | 41:5c3ebf7372ee | 87 | if (itd == NULL) { |
HinoNaka | 41:5c3ebf7372ee | 88 | return NULL; |
HinoNaka | 41:5c3ebf7372ee | 89 | } |
HinoNaka | 41:5c3ebf7372ee | 90 | return itd; |
HinoNaka | 41:5c3ebf7372ee | 91 | } |
HinoNaka | 41:5c3ebf7372ee | 92 | |
HinoNaka | 41:5c3ebf7372ee | 93 | HCITD* IsochronousEp::isochronousReceive(int timeout_ms) { |
HinoNaka | 41:5c3ebf7372ee | 94 | TEST_ASSERT(m_itd_queue_count >= 0); |
HinoNaka | 41:5c3ebf7372ee | 95 | while(m_itd_queue_count < m_itd_queue_limit) { |
HinoNaka | 41:5c3ebf7372ee | 96 | if (m_pED == NULL) { |
HinoNaka | 41:5c3ebf7372ee | 97 | ISO_DBG("m_pED is NULL"); |
HinoNaka | 41:5c3ebf7372ee | 98 | break; |
HinoNaka | 41:5c3ebf7372ee | 99 | } |
HinoNaka | 41:5c3ebf7372ee | 100 | if (m_pED->Skip()) { |
HinoNaka | 41:5c3ebf7372ee | 101 | break; |
HinoNaka | 41:5c3ebf7372ee | 102 | } |
HinoNaka | 41:5c3ebf7372ee | 103 | HCITD* blank_itd = new_HCITD(this); |
HinoNaka | 41:5c3ebf7372ee | 104 | ((HCITD *)m_pED->TailTd)->SetStartingFrame(m_FrameNumber); |
HinoNaka | 41:5c3ebf7372ee | 105 | m_FrameNumber += m_FrameCount; |
HinoNaka | 41:5c3ebf7372ee | 106 | TEST_ASSERT(blank_itd); |
HinoNaka | 41:5c3ebf7372ee | 107 | if (m_pED->enqueue<HCITD>(blank_itd)) { |
HinoNaka | 41:5c3ebf7372ee | 108 | m_itd_queue_count++; |
HinoNaka | 41:5c3ebf7372ee | 109 | } |
HinoNaka | 41:5c3ebf7372ee | 110 | enable(); // Enable Periodic |
HinoNaka | 41:5c3ebf7372ee | 111 | } |
HinoNaka | 41:5c3ebf7372ee | 112 | |
HinoNaka | 41:5c3ebf7372ee | 113 | HCITD* itd = get_queue_HCITD(timeout_ms); |
HinoNaka | 41:5c3ebf7372ee | 114 | if (itd) { |
HinoNaka | 41:5c3ebf7372ee | 115 | m_itd_queue_count--; |
HinoNaka | 41:5c3ebf7372ee | 116 | } |
HinoNaka | 41:5c3ebf7372ee | 117 | return itd; |
HinoNaka | 41:5c3ebf7372ee | 118 | } |
HinoNaka | 41:5c3ebf7372ee | 119 | |
HinoNaka | 41:5c3ebf7372ee | 120 | int IsochronousEp::isochronousSend(uint8_t* buf, int len, int timeout_ms) { |
HinoNaka | 41:5c3ebf7372ee | 121 | //ISO_DBG("buf: %p, len: %d", buf, len); |
HinoNaka | 41:5c3ebf7372ee | 122 | HCITD* itd; |
HinoNaka | 41:5c3ebf7372ee | 123 | |
HinoNaka | 41:5c3ebf7372ee | 124 | if (m_itd_queue_count >= m_itd_queue_limit) { |
HinoNaka | 41:5c3ebf7372ee | 125 | itd = get_queue_HCITD(timeout_ms); |
HinoNaka | 41:5c3ebf7372ee | 126 | } else { |
HinoNaka | 41:5c3ebf7372ee | 127 | itd = get_queue_HCITD(0); |
HinoNaka | 41:5c3ebf7372ee | 128 | } |
HinoNaka | 41:5c3ebf7372ee | 129 | if (itd) { |
HinoNaka | 41:5c3ebf7372ee | 130 | delete itd; |
HinoNaka | 41:5c3ebf7372ee | 131 | m_itd_queue_count--; |
HinoNaka | 41:5c3ebf7372ee | 132 | TEST_ASSERT(m_itd_queue_count >= 0); |
HinoNaka | 41:5c3ebf7372ee | 133 | } |
HinoNaka | 41:5c3ebf7372ee | 134 | TEST_ASSERT(m_itd_queue_count >= 0); |
HinoNaka | 41:5c3ebf7372ee | 135 | if(m_itd_queue_count < m_itd_queue_limit) { |
HinoNaka | 41:5c3ebf7372ee | 136 | if (m_pED == NULL) { |
HinoNaka | 41:5c3ebf7372ee | 137 | ISO_DBG("m_pED is NULL"); |
HinoNaka | 41:5c3ebf7372ee | 138 | return 0; |
HinoNaka | 41:5c3ebf7372ee | 139 | } |
HinoNaka | 41:5c3ebf7372ee | 140 | if (m_pED->Skip()) { |
HinoNaka | 41:5c3ebf7372ee | 141 | return 0; |
HinoNaka | 41:5c3ebf7372ee | 142 | } |
HinoNaka | 41:5c3ebf7372ee | 143 | itd = new_HCITD(this); |
HinoNaka | 41:5c3ebf7372ee | 144 | TEST_ASSERT(itd); |
HinoNaka | 41:5c3ebf7372ee | 145 | //ISO_DBG("m_pED: %p itd: %p", m_pED, itd); |
HinoNaka | 41:5c3ebf7372ee | 146 | ((HCITD *)m_pED->TailTd)->SetStartingFrame(m_FrameNumber); |
HinoNaka | 41:5c3ebf7372ee | 147 | m_FrameNumber += m_FrameCount; |
HinoNaka | 41:5c3ebf7372ee | 148 | memcpy(const_cast<uint8_t*>(((HCITD *)m_pED->TailTd)->buf), buf, len); |
HinoNaka | 41:5c3ebf7372ee | 149 | if (m_pED->enqueue<HCITD>(itd)) { |
HinoNaka | 41:5c3ebf7372ee | 150 | m_itd_queue_count++; |
HinoNaka | 41:5c3ebf7372ee | 151 | } |
HinoNaka | 41:5c3ebf7372ee | 152 | enable(); // Enable Periodic |
HinoNaka | 41:5c3ebf7372ee | 153 | //ISO_DBG("m_itd_queue_count: %d", m_itd_queue_count); |
HinoNaka | 41:5c3ebf7372ee | 154 | return len; |
HinoNaka | 41:5c3ebf7372ee | 155 | } |
HinoNaka | 41:5c3ebf7372ee | 156 | return 0; |
HinoNaka | 41:5c3ebf7372ee | 157 | } |
HinoNaka | 41:5c3ebf7372ee | 158 | |
HinoNaka | 41:5c3ebf7372ee | 159 | HCITD* IsochronousEp::get_queue_HCITD(int timeout_ms) { |
HinoNaka | 41:5c3ebf7372ee | 160 | osEvent evt = m_queue.get(timeout_ms); |
HinoNaka | 41:5c3ebf7372ee | 161 | if (evt.status == osEventMessage) { |
HinoNaka | 41:5c3ebf7372ee | 162 | HCITD* itd = reinterpret_cast<HCITD*>(evt.value.p); |
HinoNaka | 41:5c3ebf7372ee | 163 | TEST_ASSERT(itd); |
HinoNaka | 41:5c3ebf7372ee | 164 | return itd; |
HinoNaka | 41:5c3ebf7372ee | 165 | } |
HinoNaka | 41:5c3ebf7372ee | 166 | return NULL; |
HinoNaka | 41:5c3ebf7372ee | 167 | } |
HinoNaka | 41:5c3ebf7372ee | 168 | |
HinoNaka | 41:5c3ebf7372ee | 169 | void IsochronousEp::enable() { |
HinoNaka | 41:5c3ebf7372ee | 170 | #if defined(TARGET_LPC1768) |
HinoNaka | 41:5c3ebf7372ee | 171 | LPC_USB->HcControl |= (OR_CONTROL_PLE | OR_CONTROL_IE); |
HinoNaka | 41:5c3ebf7372ee | 172 | #elif defined(TARGET_RZ_A1H) |
HinoNaka | 41:5c3ebf7372ee | 173 | uint32_t data; |
HinoNaka | 41:5c3ebf7372ee | 174 | |
HinoNaka | 41:5c3ebf7372ee | 175 | data = ohciwrapp_reg_r(OHCI_REG_CONTROL) | OR_CONTROL_PLE | OR_CONTROL_IE; |
HinoNaka | 41:5c3ebf7372ee | 176 | ohciwrapp_reg_w(OHCI_REG_CONTROL, data); |
HinoNaka | 41:5c3ebf7372ee | 177 | #endif |
HinoNaka | 41:5c3ebf7372ee | 178 | } |
HinoNaka | 41:5c3ebf7372ee | 179 | |
HinoNaka | 41:5c3ebf7372ee | 180 | void IsochronousEp::disconnect() { |
HinoNaka | 41:5c3ebf7372ee | 181 | m_pED->setSkip(); // skip bit on |
HinoNaka | 41:5c3ebf7372ee | 182 | ISO_DBG("rtos-queue: %d", m_itd_queue_count); |
HinoNaka | 41:5c3ebf7372ee | 183 | int queue_count = m_itd_queue_count; |
HinoNaka | 41:5c3ebf7372ee | 184 | Timer t; |
HinoNaka | 41:5c3ebf7372ee | 185 | t.reset(); |
HinoNaka | 41:5c3ebf7372ee | 186 | t.start(); |
HinoNaka | 41:5c3ebf7372ee | 187 | do { |
HinoNaka | 41:5c3ebf7372ee | 188 | HCITD* itd = get_queue_HCITD(10); |
HinoNaka | 41:5c3ebf7372ee | 189 | if (itd) { |
HinoNaka | 41:5c3ebf7372ee | 190 | ISO_DBG("delete ITD:%p from rtos-queue %d ms", itd, t.read_ms()); |
HinoNaka | 41:5c3ebf7372ee | 191 | delete itd; |
HinoNaka | 41:5c3ebf7372ee | 192 | queue_count--; |
HinoNaka | 41:5c3ebf7372ee | 193 | t.reset(); |
HinoNaka | 41:5c3ebf7372ee | 194 | } |
HinoNaka | 41:5c3ebf7372ee | 195 | } while(t.read_ms() < 50); |
HinoNaka | 41:5c3ebf7372ee | 196 | ISO_DBG("rtos-queue: %d, %d ms", queue_count, t.read_ms()); |
HinoNaka | 41:5c3ebf7372ee | 197 | TEST_ASSERT(queue_count >= 0); |
HinoNaka | 41:5c3ebf7372ee | 198 | while(1) { |
HinoNaka | 41:5c3ebf7372ee | 199 | HCITD* itd = m_pED->dequeue<HCITD>(); |
HinoNaka | 41:5c3ebf7372ee | 200 | if (itd == NULL) { |
HinoNaka | 41:5c3ebf7372ee | 201 | break; |
HinoNaka | 41:5c3ebf7372ee | 202 | } |
HinoNaka | 41:5c3ebf7372ee | 203 | ISO_DBG("delete ITD:%p from ED(%p)-queue", itd, m_pED); |
HinoNaka | 41:5c3ebf7372ee | 204 | delete itd; |
HinoNaka | 41:5c3ebf7372ee | 205 | TEST_ASSERT(queue_count > 0); |
HinoNaka | 41:5c3ebf7372ee | 206 | queue_count--; |
HinoNaka | 41:5c3ebf7372ee | 207 | } |
HinoNaka | 41:5c3ebf7372ee | 208 | TEST_ASSERT(queue_count == 0); |
HinoNaka | 41:5c3ebf7372ee | 209 | HCITD* tail = reinterpret_cast<HCITD*>(m_pED->TailTd); |
HinoNaka | 41:5c3ebf7372ee | 210 | ISO_DBG("delete ITD:%p from ED(%p)-tail", tail, m_pED); |
HinoNaka | 41:5c3ebf7372ee | 211 | TEST_ASSERT(tail); |
HinoNaka | 41:5c3ebf7372ee | 212 | delete tail; |
HinoNaka | 41:5c3ebf7372ee | 213 | m_pED->init_queue<HCITD>(NULL); |
HinoNaka | 41:5c3ebf7372ee | 214 | |
HinoNaka | 41:5c3ebf7372ee | 215 | #if defined(TARGET_LPC1768) |
HinoNaka | 41:5c3ebf7372ee | 216 | _HCCA* hcca = reinterpret_cast<_HCCA*>(LPC_USB->HcHCCA); |
HinoNaka | 41:5c3ebf7372ee | 217 | #elif defined(TARGET_RZ_A1H) |
HinoNaka | 41:5c3ebf7372ee | 218 | _HCCA* hcca = reinterpret_cast<_HCCA*>(ohciwrapp_reg_r(OHCI_REG_HCCA)); |
HinoNaka | 41:5c3ebf7372ee | 219 | #endif |
HinoNaka | 41:5c3ebf7372ee | 220 | TEST_ASSERT(hcca); |
HinoNaka | 41:5c3ebf7372ee | 221 | hcca->dequeue(m_pED); |
HinoNaka | 41:5c3ebf7372ee | 222 | ISO_DBG("delete ED:%p", m_pED); |
HinoNaka | 41:5c3ebf7372ee | 223 | delete m_pED; |
HinoNaka | 41:5c3ebf7372ee | 224 | m_pED = NULL; |
HinoNaka | 41:5c3ebf7372ee | 225 | } |
HinoNaka | 41:5c3ebf7372ee | 226 |