Open FFBoard
Open source force feedback firmware
dcd_nrf5x.c
Go to the documentation of this file.
1/*
2 * The MIT License (MIT)
3 *
4 * Copyright (c) 2019 Ha Thach (tinyusb.org)
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 *
24 * This file is part of the TinyUSB stack.
25 */
26
27#include "tusb_option.h"
28
29#if CFG_TUD_ENABLED && CFG_TUSB_MCU == OPT_MCU_NRF5X
30
31#include <stdatomic.h>
32
33// Suppress warning caused by nrfx driver
34#ifdef __GNUC__
35#pragma GCC diagnostic push
36#pragma GCC diagnostic ignored "-Wcast-qual"
37#pragma GCC diagnostic ignored "-Wcast-align"
38#pragma GCC diagnostic ignored "-Wunused-parameter"
39#endif
40
41#include "nrf.h"
42#include "nrf_clock.h"
43#include "nrfx_usbd_errata.h"
44
45#ifdef __GNUC__
46#pragma GCC diagnostic pop
47#endif
48
49#include "device/dcd.h"
50
51// TODO remove later
52#include "device/usbd.h"
53#include "device/usbd_pvt.h" // to use defer function helper
54
55#if CFG_TUSB_OS == OPT_OS_MYNEWT
56#include "mcu/mcu.h"
57#endif
58
59/* Try to detect nrfx version if not configured with CFG_TUD_NRF_NRFX_VERSION
60 * nrfx v1 and v2 are concurrently developed. There is no NRFX_VERSION only MDK VERSION which is as follows:
61 * - v3.0.0: 8.53.1 (conflict with v2.11.0), v3.1.0: 8.55.0 ...
62 * - v2.11.0: 8.53.1, v2.6.0: 8.44.1, v2.5.0: 8.40.2, v2.4.0: 8.37.0, v2.3.0: 8.35.0, v2.2.0: 8.32.1, v2.1.0: 8.30.2, v2.0.0: 8.29.0
63 * - v1.9.0: 8.40.3, v1.8.6: 8.35.0 (conflict with v2.3.0), v1.8.5: 8.32.3, v1.8.4: 8.32.1 (conflict with v2.2.0),
64 * v1.8.2: 8.32.1 (conflict with v2.2.0), v1.8.1: 8.27.1
65 * Therefore the check for v1 would be:
66 * - MDK < 8.29.0 (v2.0), MDK == 8.32.3, 8.40.3
67 * - in case of conflict User of those version must upgrade to other 1.x version or set CFG_TUD_NRF_NRFX_VERSION
68*/
69#ifndef CFG_TUD_NRF_NRFX_VERSION
70 #define _MDK_VERSION (10000*MDK_MAJOR_VERSION + 100*MDK_MINOR_VERSION + MDK_MICRO_VERSION)
71
72 #if _MDK_VERSION < 82900 || _MDK_VERSION == 83203 || _MDK_VERSION == 84003
73 // nrfx <= 1.8.1, or 1.8.5 or 1.9.0
74 #define CFG_TUD_NRF_NRFX_VERSION 1
75 #else
76 #define CFG_TUD_NRF_NRFX_VERSION 2
77 #endif
78#endif
79
80/*------------------------------------------------------------------*/
81/* MACRO TYPEDEF CONSTANT ENUM
82 *------------------------------------------------------------------*/
83enum {
84 // Max allowed by USB specs
86
87 // Mask of all END event (IN & OUT) for all endpoints. ENDEPIN0-7, ENDEPOUT0-7, ENDISOIN, ENDISOOUT
88 EDPT_END_ALL_MASK = (0xff << USBD_INTEN_ENDEPIN0_Pos) | (0xff << USBD_INTEN_ENDEPOUT0_Pos) |
89 USBD_INTENCLR_ENDISOIN_Msk | USBD_INTEN_ENDISOOUT_Msk
90};
91
92enum {
93 EP_ISO_NUM = 8, // Endpoint number is fixed (8) for ISOOUT and ISOIN
94 EP_CBI_COUNT = 8 // Control Bulk Interrupt endpoints count
95};
96
97// Transfer Descriptor
98typedef struct {
99 uint8_t* buffer;
100 uint16_t total_len;
101 volatile uint16_t actual_len;
102 uint16_t mps; // max packet size
103
104 // nRF will auto accept OUT packet after DMA is done
105 // indicate packet is already ACK
106 volatile bool data_received;
107 volatile bool started;
108
109 // Set to true when data was transferred from RAM to ISO IN output buffer.
110 // New data can be put in ISO IN output buffer after SOF.
112
113} xfer_td_t;
114
115// Data for managing dcd
116static struct {
117 // All 8 endpoints including control IN & OUT (offset 1)
118 // +1 for ISO endpoints
120
121 // nRF can only carry one DMA at a time, this is used to guard the access to EasyDMA
122 atomic_flag dma_running;
123
124 // Track whether sof has been manually enabled
127
128/*------------------------------------------------------------------*/
129/* Control / Bulk / Interrupt (CBI) Transfer
130 *------------------------------------------------------------------*/
131
132// check if we are in ISR
133TU_ATTR_ALWAYS_INLINE static inline bool is_in_isr(void) {
134 return (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) ? true : false;
135}
136
137// helper to start DMA
138static void start_dma(volatile uint32_t* reg_startep) {
139 (*reg_startep) = 1;
140 __ISB();
141 __DSB();
142
143 // TASKS_EP0STATUS, TASKS_EP0RCVOUT seem to need EasyDMA to be available
144 // However these don't trigger any DMA transfer and got ENDED event subsequently
145 // Therefore dma_pending is corrected right away
146 if ((reg_startep == &NRF_USBD->TASKS_EP0STATUS) || (reg_startep == &NRF_USBD->TASKS_EP0RCVOUT)) {
147 atomic_flag_clear(&_dcd.dma_running);
148 }
149}
150
151static void edpt_dma_start(volatile uint32_t* reg_startep) {
152 if (atomic_flag_test_and_set(&_dcd.dma_running)) {
153 usbd_defer_func((osal_task_func_t)(uintptr_t ) edpt_dma_start, (void*) (uintptr_t) reg_startep, is_in_isr());
154 } else {
155 start_dma(reg_startep);
156 }
157}
158
159// DMA is complete
160static void edpt_dma_end(void) {
161 atomic_flag_clear(&_dcd.dma_running);
162}
163
164// helper getting td
165static inline xfer_td_t* get_td(uint8_t epnum, uint8_t dir) {
166 return &_dcd.xfer[epnum][dir];
167}
168
169static void xact_out_dma(uint8_t epnum);
170
171// Function wraps xact_out_dma which wants uint8_t while usbd_defer_func wants void (*)(void *)
172static void xact_out_dma_wrapper(void* epnum) {
173 xact_out_dma((uint8_t) ((uintptr_t) epnum));
174}
175
176// Start DMA to move data from Endpoint -> RAM
177static void xact_out_dma(uint8_t epnum) {
179 uint32_t xact_len;
180
181 // DMA can't be active during read of SIZE.EPOUT or SIZE.ISOOUT, so try to lock,
182 // If already running defer call regardless if it was called from ISR or task,
183 if (atomic_flag_test_and_set(&_dcd.dma_running)) {
184 usbd_defer_func((osal_task_func_t) xact_out_dma_wrapper, (void*) (uint32_t) epnum, is_in_isr());
185 return;
186 }
187 if (epnum == EP_ISO_NUM) {
188 xact_len = NRF_USBD->SIZE.ISOOUT;
189 // If ZERO bit is set, ignore ISOOUT length
190 if (xact_len & USBD_SIZE_ISOOUT_ZERO_Msk) {
191 xact_len = 0;
192 atomic_flag_clear(&_dcd.dma_running);
193 } else {
194 if (xfer->started) {
195 // Trigger DMA move data from Endpoint -> SRAM
196 NRF_USBD->ISOOUT.PTR = (uint32_t) xfer->buffer;
197 NRF_USBD->ISOOUT.MAXCNT = xact_len;
198
199 start_dma(&NRF_USBD->TASKS_STARTISOOUT);
200 } else {
201 atomic_flag_clear(&_dcd.dma_running);
202 }
203 }
204 } else {
205 // limit xact len to remaining length
206 xact_len = tu_min16((uint16_t) NRF_USBD->SIZE.EPOUT[epnum], xfer->total_len - xfer->actual_len);
207
208 // Trigger DMA move data from Endpoint -> SRAM
209 NRF_USBD->EPOUT[epnum].PTR = (uint32_t) xfer->buffer;
210 NRF_USBD->EPOUT[epnum].MAXCNT = xact_len;
211
212 start_dma(&NRF_USBD->TASKS_STARTEPOUT[epnum]);
213 }
214}
215
216// Prepare for a CBI transaction IN, call at the start
217// it start DMA to transfer data from RAM -> Endpoint
218static void xact_in_dma(uint8_t epnum) {
219 xfer_td_t* xfer = get_td(epnum, TUSB_DIR_IN);
220
221 // Each transaction is up to Max Packet Size
222 uint16_t const xact_len = tu_min16(xfer->total_len - xfer->actual_len, xfer->mps);
223
224 NRF_USBD->EPIN[epnum].PTR = (uint32_t) xfer->buffer;
225 NRF_USBD->EPIN[epnum].MAXCNT = xact_len;
226
227 edpt_dma_start(&NRF_USBD->TASKS_STARTEPIN[epnum]);
228}
229
230//--------------------------------------------------------------------+
231// Controller API
232//--------------------------------------------------------------------+
233bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
234 (void) rhport;
235 (void) rh_init;
236 TU_LOG2("dcd init\r\n");
237 return true;
238}
239
240void dcd_int_enable(uint8_t rhport) {
241 (void) rhport;
242 NVIC_EnableIRQ(USBD_IRQn);
243}
244
245void dcd_int_disable(uint8_t rhport) {
246 (void) rhport;
247 NVIC_DisableIRQ(USBD_IRQn);
248}
249
250void dcd_set_address(uint8_t rhport, uint8_t dev_addr) {
251 (void) rhport;
252 (void) dev_addr;
253 // Set Address is automatically update by hw controller, nothing to do
254
255 // Enable usbevent for suspend and resume detection
256 // Since the bus signal D+/D- are stable now.
257
258 // Clear current pending first
259 NRF_USBD->EVENTCAUSE |= NRF_USBD->EVENTCAUSE;
260 NRF_USBD->EVENTS_USBEVENT = 0;
261
262 NRF_USBD->INTENSET = USBD_INTEN_USBEVENT_Msk;
263}
264
265void dcd_remote_wakeup(uint8_t rhport) {
266 (void) rhport;
267
268 // Bring controller out of low power mode
269 // will start wakeup when USBWUALLOWED is set
270 NRF_USBD->LOWPOWER = 0;
271}
272
273// disconnect by disabling internal pull-up resistor on D+/D-
274void dcd_disconnect(uint8_t rhport) {
275 (void) rhport;
276 NRF_USBD->USBPULLUP = 0;
277
278 // Disable Pull-up does not trigger Power USB Removed, in fact it have no
279 // impact on the USB Power status at all -> need to submit unplugged event to the stack.
280 dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, false);
281}
282
283// connect by enabling internal pull-up resistor on D+/D-
284void dcd_connect(uint8_t rhport) {
285 (void) rhport;
286 NRF_USBD->USBPULLUP = 1;
287}
288
289void dcd_sof_enable(uint8_t rhport, bool en) {
290 (void) rhport;
291 if (en) {
292 _dcd.sof_enabled = true;
293 NRF_USBD->INTENSET = USBD_INTENSET_SOF_Msk;
294 } else {
295 _dcd.sof_enabled = false;
296 NRF_USBD->INTENCLR = USBD_INTENCLR_SOF_Msk;
297 }
298}
299
300//--------------------------------------------------------------------+
301// Endpoint API
302//--------------------------------------------------------------------+
303bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) {
304 (void) rhport;
305
306 uint8_t const ep_addr = desc_edpt->bEndpointAddress;
307 uint8_t const epnum = tu_edpt_number(ep_addr);
308 uint8_t const dir = tu_edpt_dir(ep_addr);
309
310 _dcd.xfer[epnum][dir].mps = tu_edpt_packet_size(desc_edpt);
311
312 if (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS) {
313 if (dir == TUSB_DIR_OUT) {
314 NRF_USBD->INTENSET = TU_BIT(USBD_INTEN_ENDEPOUT0_Pos + epnum);
315 NRF_USBD->EPOUTEN |= TU_BIT(epnum);
316
317 // Write any value to SIZE register will allow nRF to ACK/accept data
318 NRF_USBD->SIZE.EPOUT[epnum] = 0;
319 } else {
320 NRF_USBD->INTENSET = TU_BIT(USBD_INTEN_ENDEPIN0_Pos + epnum);
321 NRF_USBD->EPINEN |= TU_BIT(epnum);
322 }
323 // clear stall and reset DataToggle
324 NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_UnStall << USBD_EPSTALL_STALL_Pos) | ep_addr;
325 NRF_USBD->DTOGGLE = (USBD_DTOGGLE_VALUE_Data0 << USBD_DTOGGLE_VALUE_Pos) | ep_addr;
326 } else {
327 TU_ASSERT(epnum == EP_ISO_NUM);
328 if (dir == TUSB_DIR_OUT) {
329 // SPLIT ISO buffer when ISO IN endpoint is already opened.
330 if (_dcd.xfer[EP_ISO_NUM][TUSB_DIR_IN].mps) NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_HalfIN;
331
332 // Clear old events
333 NRF_USBD->EVENTS_ENDISOOUT = 0;
334
335 // Clear SOF event in case interrupt was not enabled yet.
336 if ((NRF_USBD->INTEN & USBD_INTEN_SOF_Msk) == 0) NRF_USBD->EVENTS_SOF = 0;
337
338 // Enable SOF and ISOOUT interrupts, and ISOOUT endpoint.
339 NRF_USBD->INTENSET = USBD_INTENSET_ENDISOOUT_Msk | USBD_INTENSET_SOF_Msk;
340 NRF_USBD->EPOUTEN |= USBD_EPOUTEN_ISOOUT_Msk;
341 } else {
342 NRF_USBD->EVENTS_ENDISOIN = 0;
343
344 // SPLIT ISO buffer when ISO OUT endpoint is already opened.
345 if (_dcd.xfer[EP_ISO_NUM][TUSB_DIR_OUT].mps) NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_HalfIN;
346
347 // Clear SOF event in case interrupt was not enabled yet.
348 if ((NRF_USBD->INTEN & USBD_INTEN_SOF_Msk) == 0) NRF_USBD->EVENTS_SOF = 0;
349
350 // Enable SOF and ISOIN interrupts, and ISOIN endpoint.
351 NRF_USBD->INTENSET = USBD_INTENSET_ENDISOIN_Msk | USBD_INTENSET_SOF_Msk;
352 NRF_USBD->EPINEN |= USBD_EPINEN_ISOIN_Msk;
353 }
354 }
355
356 __ISB();
357 __DSB();
358
359 return true;
360}
361
362void dcd_edpt_close_all(uint8_t rhport) {
363 // disable interrupt to prevent race condition
364 dcd_int_disable(rhport);
365
366 // disable all non-control (bulk + interrupt) endpoints
367 for (uint8_t ep = 1; ep < EP_CBI_COUNT; ep++) {
368 NRF_USBD->INTENCLR = TU_BIT(USBD_INTEN_ENDEPOUT0_Pos + ep) | TU_BIT(USBD_INTEN_ENDEPIN0_Pos + ep);
369
370 NRF_USBD->TASKS_STARTEPIN[ep] = 0;
371 NRF_USBD->TASKS_STARTEPOUT[ep] = 0;
372
373 tu_memclr(_dcd.xfer[ep], 2 * sizeof(xfer_td_t));
374 }
375
376 // disable both ISO
377 NRF_USBD->INTENCLR = USBD_INTENCLR_SOF_Msk | USBD_INTENCLR_ENDISOOUT_Msk | USBD_INTENCLR_ENDISOIN_Msk;
378 NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_OneDir;
379
380 NRF_USBD->TASKS_STARTISOIN = 0;
381 NRF_USBD->TASKS_STARTISOOUT = 0;
382
383 tu_memclr(_dcd.xfer[EP_ISO_NUM], 2 * sizeof(xfer_td_t));
384
385 // de-activate all non-control
386 NRF_USBD->EPOUTEN = 1UL;
387 NRF_USBD->EPINEN = 1UL;
388
389 dcd_int_enable(rhport);
390}
391
392void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
393 (void) rhport;
394
395 uint8_t const epnum = tu_edpt_number(ep_addr);
396 uint8_t const dir = tu_edpt_dir(ep_addr);
397
398 if (epnum != EP_ISO_NUM) {
399 // CBI
400 if (dir == TUSB_DIR_OUT) {
401 NRF_USBD->INTENCLR = TU_BIT(USBD_INTEN_ENDEPOUT0_Pos + epnum);
402 NRF_USBD->EPOUTEN &= ~TU_BIT(epnum);
403 } else {
404 NRF_USBD->INTENCLR = TU_BIT(USBD_INTEN_ENDEPIN0_Pos + epnum);
405 NRF_USBD->EPINEN &= ~TU_BIT(epnum);
406 }
407 } else {
408 _dcd.xfer[EP_ISO_NUM][dir].mps = 0;
409 // ISO
410 if (dir == TUSB_DIR_OUT) {
411 NRF_USBD->INTENCLR = USBD_INTENCLR_ENDISOOUT_Msk;
412 NRF_USBD->EPOUTEN &= ~USBD_EPOUTEN_ISOOUT_Msk;
413 NRF_USBD->EVENTS_ENDISOOUT = 0;
414 } else {
415 NRF_USBD->INTENCLR = USBD_INTENCLR_ENDISOIN_Msk;
416 NRF_USBD->EPINEN &= ~USBD_EPINEN_ISOIN_Msk;
417 }
418 // One of the ISO endpoints closed, no need to split buffers any more.
419 NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_OneDir;
420 // When both ISO endpoint are close there is no need for SOF any more.
421 if (_dcd.xfer[EP_ISO_NUM][TUSB_DIR_IN].mps + _dcd.xfer[EP_ISO_NUM][TUSB_DIR_OUT].mps == 0)
422 NRF_USBD->INTENCLR = USBD_INTENCLR_SOF_Msk;
423 }
424 _dcd.xfer[epnum][dir].started = false;
425 __ISB();
426 __DSB();
427}
428
429bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) {
430 (void) rhport;
431
432 uint8_t const epnum = tu_edpt_number(ep_addr);
433 uint8_t const dir = tu_edpt_dir(ep_addr);
434
435 xfer_td_t* xfer = get_td(epnum, dir);
436
437 TU_ASSERT(!xfer->started);
438 xfer->buffer = buffer;
440 xfer->actual_len = 0;
441
442 // Control endpoint with zero-length packet and opposite direction to 1st request byte --> status stage
443 bool const control_status = (epnum == 0 && total_bytes == 0 && dir != tu_edpt_dir(NRF_USBD->BMREQUESTTYPE));
444
445 if (control_status) {
446 // The nRF doesn't interrupt on status transmit so we queue up a success response.
448
449 // Status Phase also requires EasyDMA has to be available as well !!!!
450 edpt_dma_start(&NRF_USBD->TASKS_EP0STATUS);
451 } else if (dir == TUSB_DIR_OUT) {
452 xfer->started = true;
453 if (epnum == 0) {
454 // Accept next Control Out packet. TASKS_EP0RCVOUT also require EasyDMA
455 edpt_dma_start(&NRF_USBD->TASKS_EP0RCVOUT);
456 } else {
457 // started just set, it could start DMA transfer if interrupt was trigger after this line
458 // code only needs to start transfer (from Endpoint to RAM) when data_received was set
459 // before started was set. If started is NOT set but data_received is, it means that
460 // current transfer was already finished and next data is already present in endpoint and
461 // can be consumed by future transfer
462 __ISB();
463 __DSB();
464 if (xfer->data_received && xfer->started) {
465 // Data is already received previously
466 // start DMA to copy to SRAM
467 xfer->data_received = false;
468 xact_out_dma(epnum);
469 } else {
470 // nRF auto accept next Bulk/Interrupt OUT packet
471 // nothing to do
472 }
473 }
474 } else {
475 // Start DMA to copy data from RAM -> Endpoint
476 xact_in_dma(epnum);
477 }
478
479 return true;
480}
481
482void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
483 (void) rhport;
484
485 uint8_t const epnum = tu_edpt_number(ep_addr);
486 uint8_t const dir = tu_edpt_dir(ep_addr);
487
488 xfer_td_t* xfer = get_td(epnum, dir);
489
490 if (epnum == 0) {
491 NRF_USBD->TASKS_EP0STALL = 1;
492 } else if (epnum != EP_ISO_NUM) {
493 NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_Stall << USBD_EPSTALL_STALL_Pos) | ep_addr;
494
495 // Note: nRF can auto ACK packet OUT before get stalled.
496 // There maybe data in endpoint fifo already, we need to pull it out
497 if ((dir == TUSB_DIR_OUT) && xfer->data_received) {
498 xfer->data_received = false;
499 xact_out_dma(epnum);
500 }
501 }
502
503 __ISB();
504 __DSB();
505}
506
507void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
508 (void) rhport;
509 uint8_t const epnum = tu_edpt_number(ep_addr);
510 uint8_t const dir = tu_edpt_dir(ep_addr);
511
512 if (epnum != 0 && epnum != EP_ISO_NUM) {
513 // reset data toggle to DATA0
514 // First write this register with VALUE=Nop to select the endpoint, then either read it to get the status from
515 // VALUE, or write it again with VALUE=Data0 or Data1
516 NRF_USBD->DTOGGLE = ep_addr;
517 NRF_USBD->DTOGGLE = (USBD_DTOGGLE_VALUE_Data0 << USBD_DTOGGLE_VALUE_Pos) | ep_addr;
518
519 // clear stall
520 NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_UnStall << USBD_EPSTALL_STALL_Pos) | ep_addr;
521
522 // Write any value to SIZE register will allow nRF to ACK/accept data
523 if (dir == TUSB_DIR_OUT) NRF_USBD->SIZE.EPOUT[epnum] = 0;
524
525 __ISB();
526 __DSB();
527 }
528}
529
530/*------------------------------------------------------------------*/
531/* Interrupt Handler
532 *------------------------------------------------------------------*/
533void bus_reset(void) {
534 // 6.35.6 USB controller automatically disabled all endpoints (except control)
535 NRF_USBD->EPOUTEN = 1UL;
536 NRF_USBD->EPINEN = 1UL;
537
538 for (int i = 0; i < 8; i++) {
539 NRF_USBD->TASKS_STARTEPIN[i] = 0;
540 NRF_USBD->TASKS_STARTEPOUT[i] = 0;
541 }
542
543 NRF_USBD->TASKS_STARTISOIN = 0;
544 NRF_USBD->TASKS_STARTISOOUT = 0;
545
546 // Clear USB Event Interrupt
547 NRF_USBD->EVENTS_USBEVENT = 0;
548 NRF_USBD->EVENTCAUSE |= NRF_USBD->EVENTCAUSE;
549
550 // Reset interrupt
551 NRF_USBD->INTENCLR = NRF_USBD->INTEN;
552 NRF_USBD->INTENSET = USBD_INTEN_USBRESET_Msk | USBD_INTEN_USBEVENT_Msk | USBD_INTEN_EPDATA_Msk |
553 USBD_INTEN_EP0SETUP_Msk | USBD_INTEN_EP0DATADONE_Msk | USBD_INTEN_ENDEPIN0_Msk |
554 USBD_INTEN_ENDEPOUT0_Msk;
555
556 tu_varclr(&_dcd);
557 _dcd.xfer[0][TUSB_DIR_IN].mps = MAX_PACKET_SIZE;
558 _dcd.xfer[0][TUSB_DIR_OUT].mps = MAX_PACKET_SIZE;
559}
560
561void dcd_int_handler(uint8_t rhport) {
562 (void) rhport;
563
564 uint32_t const inten = NRF_USBD->INTEN;
565 uint32_t int_status = 0;
566
567 volatile uint32_t* regevt = &NRF_USBD->EVENTS_USBRESET;
568
569 for (uint8_t i = 0; i < USBD_INTEN_EPDATA_Pos + 1; i++) {
570 if (tu_bit_test(inten, i) && regevt[i]) {
571 int_status |= TU_BIT(i);
572
573 // event clear
574 regevt[i] = 0;
575 __ISB();
576 __DSB();
577 }
578 }
579
580 if (int_status & USBD_INTEN_USBRESET_Msk) {
581 bus_reset();
583 }
584
585 // ISOIN: Data was moved to endpoint buffer, client will be notified in SOF
586 if (int_status & USBD_INTEN_ENDISOIN_Msk) {
588
589 xfer->actual_len = NRF_USBD->ISOIN.AMOUNT;
590 // Data transferred from RAM to endpoint output buffer.
591 // Next transfer can be scheduled after SOF.
593 }
594
595 if (int_status & USBD_INTEN_SOF_Msk) {
596 bool iso_enabled = false;
597
598 // ISOOUT: Transfer data gathered in previous frame from buffer to RAM
599 if (NRF_USBD->EPOUTEN & USBD_EPOUTEN_ISOOUT_Msk) {
600 iso_enabled = true;
601 // Transfer from endpoint to RAM only if data is not corrupted
602 if ((int_status & USBD_INTEN_USBEVENT_Msk) == 0 ||
603 (NRF_USBD->EVENTCAUSE & USBD_EVENTCAUSE_ISOOUTCRC_Msk) == 0) {
605 }
606 }
607
608 // ISOIN: Notify client that data was transferred
609 if (NRF_USBD->EPINEN & USBD_EPINEN_ISOIN_Msk) {
610 iso_enabled = true;
611
616 }
617 }
618
619 if (!iso_enabled && !_dcd.sof_enabled) {
620 // SOF interrupt not manually enabled and ISO endpoint is not used,
621 // SOF is only enabled one-time for remote wakeup so we disable it now
622
623 NRF_USBD->INTENCLR = USBD_INTENCLR_SOF_Msk;
624 }
625
626 const uint32_t frame = NRF_USBD->FRAMECNTR;
627 dcd_event_sof(0, frame, true);
628 //dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
629 }
630
631 if (int_status & USBD_INTEN_USBEVENT_Msk) {
632 TU_LOG(3, "EVENTCAUSE = 0x%04" PRIX32 "\r\n", NRF_USBD->EVENTCAUSE);
633
634 enum {
635 EVT_CAUSE_MASK = USBD_EVENTCAUSE_SUSPEND_Msk | USBD_EVENTCAUSE_RESUME_Msk | USBD_EVENTCAUSE_USBWUALLOWED_Msk |
636 USBD_EVENTCAUSE_ISOOUTCRC_Msk
637 };
638 uint32_t const evt_cause = NRF_USBD->EVENTCAUSE & EVT_CAUSE_MASK;
639 NRF_USBD->EVENTCAUSE = evt_cause; // clear interrupt
640
641 if (evt_cause & USBD_EVENTCAUSE_SUSPEND_Msk) {
642 // Put controller into low power mode
643 // Leave HFXO disable to application, since it may be used by other peripherals
644 NRF_USBD->LOWPOWER = 1;
645
646 dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
647 }
648
649 if (evt_cause & USBD_EVENTCAUSE_USBWUALLOWED_Msk) {
650 // USB is out of low power mode, and wakeup is allowed
651 // Initiate RESUME signal
652 NRF_USBD->DPDMVALUE = USBD_DPDMVALUE_STATE_Resume;
653 NRF_USBD->TASKS_DPDMDRIVE = 1;
654
655 // There is no Resume interrupt for remote wakeup, enable SOF for to report bus ready state
656 // Clear SOF event in case interrupt was not enabled yet.
657 if ((NRF_USBD->INTEN & USBD_INTEN_SOF_Msk) == 0) NRF_USBD->EVENTS_SOF = 0;
658 NRF_USBD->INTENSET = USBD_INTENSET_SOF_Msk;
659 }
660
661 if (evt_cause & USBD_EVENTCAUSE_RESUME_Msk) {
662 dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
663 }
664 }
665
666 // Setup tokens are specific to the Control endpoint.
667 if (int_status & USBD_INTEN_EP0SETUP_Msk) {
668 uint8_t const setup[8] = {
669 NRF_USBD->BMREQUESTTYPE, NRF_USBD->BREQUEST, NRF_USBD->WVALUEL, NRF_USBD->WVALUEH,
670 NRF_USBD->WINDEXL, NRF_USBD->WINDEXH, NRF_USBD->WLENGTHL, NRF_USBD->WLENGTHH
671 };
672
673 // nrf5x hw auto handle set address, there is no need to inform usb stack
675
676 if (!(TUSB_REQ_RCPT_DEVICE == request->bmRequestType_bit.recipient &&
679 dcd_event_setup_received(0, setup, true);
680 }
681 }
682
683 if (int_status & EDPT_END_ALL_MASK) {
684 // DMA complete move data from SRAM <-> Endpoint
685 // Must before endpoint transfer handling
686 edpt_dma_end();
687 }
688
689 //--------------------------------------------------------------------+
690 /* Control/Bulk/Interrupt (CBI) Transfer
691 *
692 * Data flow is:
693 * (bus) (dma)
694 * Host <-------> Endpoint <-------> RAM
695 *
696 * For CBI OUT:
697 * - Host -> Endpoint
698 * EPDATA (or EP0DATADONE) interrupted, check EPDATASTATUS.EPOUT[i]
699 * to start DMA. For Bulk/Interrupt, this step can occur automatically (without sw),
700 * which means data may or may not be ready (out_received flag).
701 * - Endpoint -> RAM
702 * ENDEPOUT[i] interrupted, transaction complete, sw prepare next transaction
703 *
704 * For CBI IN:
705 * - RAM -> Endpoint
706 * ENDEPIN[i] interrupted indicate DMA is complete. HW will start
707 * to move data to host
708 * - Endpoint -> Host
709 * EPDATA (or EP0DATADONE) interrupted, check EPDATASTATUS.EPIN[i].
710 * Transaction is complete, sw prepare next transaction
711 *
712 * Note: in both Control In and Out of Data stage from Host <-> Endpoint
713 * EP0DATADONE will be set as interrupt source
714 */
715 //--------------------------------------------------------------------+
716
717 /* CBI OUT: Endpoint -> SRAM (aka transaction complete)
718 * Note: Since nRF controller auto ACK next packet without SW awareness
719 * We must handle this stage before Host -> Endpoint just in case 2 event happens at once
720 *
721 * ISO OUT: Transaction must fit in single packet, it can be shorter then total
722 * len if Host decides to sent fewer bytes, it this case transaction is also
723 * complete and next transfer is not initiated here like for CBI.
724 */
725 for (uint8_t epnum = 0; epnum < EP_CBI_COUNT + 1; epnum++) {
726 if (tu_bit_test(int_status, USBD_INTEN_ENDEPOUT0_Pos + epnum)) {
728 uint16_t const xact_len = NRF_USBD->EPOUT[epnum].AMOUNT;
729
730 xfer->buffer += xact_len;
731 xfer->actual_len += xact_len;
732
733 // Transfer complete if transaction len < Max Packet Size or total len is transferred
734 if ((epnum != EP_ISO_NUM) && (xact_len == xfer->mps) && (xfer->actual_len < xfer->total_len)) {
735 if (epnum == 0) {
736 // Accept next Control Out packet. TASKS_EP0RCVOUT also require EasyDMA
737 edpt_dma_start(&NRF_USBD->TASKS_EP0RCVOUT);
738 } else {
739 // nRF auto accept next Bulk/Interrupt OUT packet
740 // nothing to do
741 }
742 } else {
743 TU_ASSERT(xfer->started,);
745 xfer->started = false;
746
747 // CBI OUT complete
749 }
750 }
751
752 // Ended event for CBI IN : nothing to do
753 }
754
755 // Endpoint <-> Host ( In & OUT )
756 if (int_status & (USBD_INTEN_EPDATA_Msk | USBD_INTEN_EP0DATADONE_Msk)) {
757 uint32_t data_status = NRF_USBD->EPDATASTATUS;
758 NRF_USBD->EPDATASTATUS = data_status;
759 __ISB();
760 __DSB();
761
762 // EP0DATADONE is set with either Control Out on IN Data
763 // Since EPDATASTATUS cannot be used to determine whether it is control OUT or IN.
764 // We will use BMREQUESTTYPE in setup packet to determine the direction
765 bool const is_control_in = (int_status & USBD_INTEN_EP0DATADONE_Msk) && (NRF_USBD->BMREQUESTTYPE & TUSB_DIR_IN_MASK);
766 bool const is_control_out = (int_status & USBD_INTEN_EP0DATADONE_Msk) && !(NRF_USBD->BMREQUESTTYPE & TUSB_DIR_IN_MASK);
767
768 // CBI In: Endpoint -> Host (transaction complete)
769 for (uint8_t epnum = 0; epnum < EP_CBI_COUNT; epnum++) {
770 if (tu_bit_test(data_status, epnum) || (epnum == 0 && is_control_in)) {
771 xfer_td_t* xfer = get_td(epnum, TUSB_DIR_IN);
772 uint8_t const xact_len = NRF_USBD->EPIN[epnum].AMOUNT;
773
774 xfer->buffer += xact_len;
775 xfer->actual_len += xact_len;
776
777 if (xfer->actual_len < xfer->total_len) {
778 // Start DMA to copy next data packet
779 xact_in_dma(epnum);
780 } else {
781 // CBI IN complete
783 }
784 }
785 }
786
787 // CBI OUT: Host -> Endpoint
788 for (uint8_t epnum = 0; epnum < EP_CBI_COUNT; epnum++) {
789 if (tu_bit_test(data_status, 16 + epnum) || (epnum == 0 && is_control_out)) {
791
793 xact_out_dma(epnum);
794 } else {
795 // Data overflow !!! Nah, nRF will auto accept next Bulk/Interrupt OUT packet
796 // Mark this endpoint with data received
797 xfer->data_received = true;
798 }
799 }
800 }
801 }
802}
803
804//--------------------------------------------------------------------+
805// HFCLK helper
806//--------------------------------------------------------------------+
807#ifdef SOFTDEVICE_PRESENT
808
809// For enable/disable hfclk with SoftDevice
810#include "nrf_mbr.h"
811#include "nrf_sdm.h"
812#include "nrf_soc.h"
813
814#ifndef SD_MAGIC_NUMBER
815 #define SD_MAGIC_NUMBER 0x51B1E5DB
816#endif
817
818TU_ATTR_ALWAYS_INLINE static inline bool is_sd_existed(void) {
819 return *((uint32_t*)(SOFTDEVICE_INFO_STRUCT_ADDRESS+4)) == SD_MAGIC_NUMBER;
820}
821
822// check if SD is existed and enabled
823TU_ATTR_ALWAYS_INLINE static inline bool is_sd_enabled(void) {
824 if ( !is_sd_existed() ) return false;
825 uint8_t sd_en = false;
826 (void) sd_softdevice_is_enabled(&sd_en);
827 return sd_en;
828}
829#endif
830
831static bool hfclk_running(void) {
832#ifdef SOFTDEVICE_PRESENT
833 if ( is_sd_enabled() ) {
834 uint32_t is_running = 0;
835 (void) sd_clock_hfclk_is_running(&is_running);
836 return (is_running ? true : false);
837 }
838#endif
839
840#if CFG_TUD_NRF_NRFX_VERSION == 1
841 return nrf_clock_hf_is_running(NRF_CLOCK_HFCLK_HIGH_ACCURACY);
842#else
843 return nrf_clock_hf_is_running(NRF_CLOCK, NRF_CLOCK_HFCLK_HIGH_ACCURACY);
844#endif
845}
846
847static void hfclk_enable(void) {
848#if CFG_TUSB_OS == OPT_OS_MYNEWT
849 usb_clock_request();
850 return;
851#else
852
853 // already running, nothing to do
854 if (hfclk_running()) return;
855
856#ifdef SOFTDEVICE_PRESENT
857 if ( is_sd_enabled() ) {
858 (void)sd_clock_hfclk_request();
859 return;
860 }
861#endif
862
863#if CFG_TUD_NRF_NRFX_VERSION == 1
864 nrf_clock_event_clear(NRF_CLOCK_EVENT_HFCLKSTARTED);
865 nrf_clock_task_trigger(NRF_CLOCK_TASK_HFCLKSTART);
866#else
867 nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKSTARTED);
868 nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTART);
869#endif
870#endif
871}
872
873static void hfclk_disable(void) {
874#if CFG_TUSB_OS == OPT_OS_MYNEWT
875 usb_clock_release();
876 return;
877#else
878
879#ifdef SOFTDEVICE_PRESENT
880 if ( is_sd_enabled() ) {
881 (void)sd_clock_hfclk_release();
882 return;
883 }
884#endif
885
886#if CFG_TUD_NRF_NRFX_VERSION == 1
887 nrf_clock_task_trigger(NRF_CLOCK_TASK_HFCLKSTOP);
888#else
889 nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTOP);
890#endif
891#endif
892}
893
894// Power & Clock Peripheral on nRF5x to manage USB
895//
896// USB Bus power is managed by Power module, there are 3 VBUS power events:
897// Detected, Ready, Removed. Upon these power events, This function will
898// enable ( or disable ) usb & hfclk peripheral, set the usb pin pull up
899// accordingly to the controller Startup/Standby Sequence in USBD 51.4 specs.
900//
901// Therefore this function must be called to handle USB power event by
902// - nrfx_power_usbevt_init() : if Softdevice is not used or enabled
903// - SoftDevice SOC event : if SD is used and enabled
904void tusb_hal_nrf_power_event(uint32_t event) {
905 // Value is chosen to be as same as NRFX_POWER_USB_EVT_* in nrfx_power.h
906 enum {
907 USB_EVT_DETECTED = 0,
908 USB_EVT_REMOVED = 1,
909 USB_EVT_READY = 2
910 };
911
912#if CFG_TUSB_DEBUG >= 3
913 const char* const power_evt_str[] = {"Detected", "Removed", "Ready"};
914 TU_LOG(3, "Power USB event: %s\r\n", power_evt_str[event]);
915#endif
916
917 switch (event) {
918 case USB_EVT_DETECTED:
919 if (!NRF_USBD->ENABLE) {
920 // Prepare for receiving READY event: disable interrupt since we will blocking wait
921 NRF_USBD->INTENCLR = USBD_INTEN_USBEVENT_Msk;
922 NRF_USBD->EVENTCAUSE = USBD_EVENTCAUSE_READY_Msk;
923 __ISB();
924 __DSB(); // for sync
925
926#ifdef NRF52_SERIES // NRF53 does not need this errata
927 // ERRATA 171, 187, 166
928 if (nrfx_usbd_errata_187()) {
929 // CRITICAL_REGION_ENTER();
930 if (*((volatile uint32_t*) (0x4006EC00)) == 0x00000000) {
931 *((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
932 *((volatile uint32_t*) (0x4006ED14)) = 0x00000003;
933 *((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
934 } else {
935 *((volatile uint32_t*) (0x4006ED14)) = 0x00000003;
936 }
937 // CRITICAL_REGION_EXIT();
938 }
939
940 if (nrfx_usbd_errata_171()) {
941 // CRITICAL_REGION_ENTER();
942 if (*((volatile uint32_t*) (0x4006EC00)) == 0x00000000) {
943 *((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
944 *((volatile uint32_t*) (0x4006EC14)) = 0x000000C0;
945 *((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
946 } else {
947 *((volatile uint32_t*) (0x4006EC14)) = 0x000000C0;
948 }
949 // CRITICAL_REGION_EXIT();
950 }
951#endif
952
953 // Enable the peripheral (will cause Ready event)
954 NRF_USBD->ENABLE = 1;
955 __ISB();
956 __DSB(); // for sync
957
958 // Enable HFCLK
959 hfclk_enable();
960 }
961 break;
962
963 case USB_EVT_READY:
964 // Skip if pull-up is enabled and HCLK is already running.
965 // Application probably call this more than necessary.
966 if (NRF_USBD->USBPULLUP && hfclk_running()) break;
967
968 // Waiting for USBD peripheral enabled
969 while (!(USBD_EVENTCAUSE_READY_Msk & NRF_USBD->EVENTCAUSE)) {}
970
971 NRF_USBD->EVENTCAUSE = USBD_EVENTCAUSE_READY_Msk;
972 __ISB();
973 __DSB(); // for sync
974
975#ifdef NRF52_SERIES
976 if (nrfx_usbd_errata_171()) {
977 // CRITICAL_REGION_ENTER();
978 if (*((volatile uint32_t*) (0x4006EC00)) == 0x00000000) {
979 *((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
980 *((volatile uint32_t*) (0x4006EC14)) = 0x00000000;
981 *((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
982 } else {
983 *((volatile uint32_t*) (0x4006EC14)) = 0x00000000;
984 }
985
986 // CRITICAL_REGION_EXIT();
987 }
988
989 if (nrfx_usbd_errata_187()) {
990 // CRITICAL_REGION_ENTER();
991 if (*((volatile uint32_t*) (0x4006EC00)) == 0x00000000) {
992 *((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
993 *((volatile uint32_t*) (0x4006ED14)) = 0x00000000;
994 *((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
995 } else {
996 *((volatile uint32_t*) (0x4006ED14)) = 0x00000000;
997 }
998 // CRITICAL_REGION_EXIT();
999 }
1000
1001 if (nrfx_usbd_errata_166()) {
1002 *((volatile uint32_t*) (NRF_USBD_BASE + 0x800)) = 0x7E3;
1003 *((volatile uint32_t*) (NRF_USBD_BASE + 0x804)) = 0x40;
1004
1005 __ISB();
1006 __DSB();
1007 }
1008#endif
1009
1010 // ISO buffer Lower half for IN, upper half for OUT
1011 NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_HalfIN;
1012
1013 // Enable bus-reset interrupt
1014 NRF_USBD->INTENSET = USBD_INTEN_USBRESET_Msk;
1015
1016 // Enable interrupt, priorities should be set by application
1017 NVIC_ClearPendingIRQ(USBD_IRQn);
1018
1019 // Don't enable USBD interrupt yet, if dcd_init() did not finish yet
1020 // Interrupt will be enabled by tud_init(), when USB stack is ready
1021 // to handle interrupts.
1022 if (tud_inited()) {
1023 NVIC_EnableIRQ(USBD_IRQn);
1024 }
1025
1026 // Wait for HFCLK
1027 while (!hfclk_running()) {}
1028
1029 // Enable pull up
1030 NRF_USBD->USBPULLUP = 1;
1031 __ISB();
1032 __DSB(); // for sync
1033 break;
1034
1035 case USB_EVT_REMOVED:
1036 if (NRF_USBD->ENABLE) {
1037 // Abort all transfers
1038
1039 // Disable pull up
1040 NRF_USBD->USBPULLUP = 0;
1041 __ISB();
1042 __DSB(); // for sync
1043
1044 // Disable Interrupt
1045 NVIC_DisableIRQ(USBD_IRQn);
1046
1047 // disable all interrupt
1048 NRF_USBD->INTENCLR = NRF_USBD->INTEN;
1049
1050 NRF_USBD->ENABLE = 0;
1051 __ISB();
1052 __DSB(); // for sync
1053
1054 hfclk_disable();
1055
1056 dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, is_in_isr());
1057 }
1058 break;
1059
1060 default:
1061 break;
1062 }
1063}
1064
1065#endif
static TU_ATTR_ALWAYS_INLINE void dcd_event_bus_signal(uint8_t rhport, dcd_eventid_t eid, bool in_isr)
Definition: dcd.h:196
static TU_ATTR_ALWAYS_INLINE void dcd_event_xfer_complete(uint8_t rhport, uint8_t ep_addr, uint32_t xferred_bytes, uint8_t result, bool in_isr)
Definition: dcd.h:222
static TU_ATTR_ALWAYS_INLINE void dcd_event_sof(uint8_t rhport, uint32_t frame_count, bool in_isr)
Definition: dcd.h:232
static TU_ATTR_ALWAYS_INLINE void dcd_event_setup_received(uint8_t rhport, uint8_t const *setup, bool in_isr)
Definition: dcd.h:213
static TU_ATTR_ALWAYS_INLINE void dcd_event_bus_reset(uint8_t rhport, tusb_speed_t speed, bool in_isr)
Definition: dcd.h:204
atomic_flag dma_running
Definition: dcd_nrf5x.c:122
@ EDPT_END_ALL_MASK
Definition: dcd_nrf5x.c:88
@ MAX_PACKET_SIZE
Definition: dcd_nrf5x.c:85
static void hfclk_enable(void)
Definition: dcd_nrf5x.c:847
static bool hfclk_running(void)
Definition: dcd_nrf5x.c:831
static void hfclk_disable(void)
Definition: dcd_nrf5x.c:873
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
Definition: dcd_nrf5x.c:482
static void edpt_dma_start(volatile uint32_t *reg_startep)
Definition: dcd_nrf5x.c:151
static void edpt_dma_end(void)
Definition: dcd_nrf5x.c:160
void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
Definition: dcd_nrf5x.c:392
static struct @315 _dcd
void dcd_int_handler(uint8_t rhport)
Definition: dcd_nrf5x.c:561
void dcd_disconnect(uint8_t rhport)
Definition: dcd_nrf5x.c:274
xfer_td_t xfer[EP_CBI_COUNT+1][2]
Definition: dcd_nrf5x.c:119
void dcd_edpt_close_all(uint8_t rhport)
Definition: dcd_nrf5x.c:362
static TU_ATTR_ALWAYS_INLINE bool is_in_isr(void)
Definition: dcd_nrf5x.c:133
void dcd_int_disable(uint8_t rhport)
Definition: dcd_nrf5x.c:245
static TU_ATTR_ALWAYS_INLINE bool is_sd_existed(void)
Definition: dcd_nrf5x.c:818
void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
Definition: dcd_nrf5x.c:507
void tusb_hal_nrf_power_event(uint32_t event)
Definition: dcd_nrf5x.c:904
static void xact_in_dma(uint8_t epnum)
Definition: dcd_nrf5x.c:218
void dcd_connect(uint8_t rhport)
Definition: dcd_nrf5x.c:284
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_edpt)
Definition: dcd_nrf5x.c:303
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
Definition: dcd_nrf5x.c:429
static void start_dma(volatile uint32_t *reg_startep)
Definition: dcd_nrf5x.c:138
void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
Definition: dcd_nrf5x.c:250
static TU_ATTR_ALWAYS_INLINE bool is_sd_enabled(void)
Definition: dcd_nrf5x.c:823
bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init)
Definition: dcd_nrf5x.c:233
void bus_reset(void)
Definition: dcd_nrf5x.c:533
static void xact_out_dma_wrapper(void *epnum)
Definition: dcd_nrf5x.c:172
bool sof_enabled
Definition: dcd_nrf5x.c:125
@ EP_CBI_COUNT
Definition: dcd_nrf5x.c:94
@ EP_ISO_NUM
Definition: dcd_nrf5x.c:93
static void xact_out_dma(uint8_t epnum)
Definition: dcd_nrf5x.c:177
static xfer_td_t * get_td(uint8_t epnum, uint8_t dir)
Definition: dcd_nrf5x.c:165
void dcd_int_enable(uint8_t rhport)
Definition: dcd_nrf5x.c:240
void dcd_remote_wakeup(uint8_t rhport)
Definition: dcd_nrf5x.c:265
void dcd_sof_enable(uint8_t rhport, bool en)
Definition: dcd_nrf5x.c:289
uint16_t total_bytes
Definition: dcd_nuc505.c:113
uint8_t dev_addr
Definition: dcd_pic32mz.c:81
uint8_t const * buffer
Definition: midi_device.h:100
AUDIO Channel Cluster Descriptor (4.1)
Definition: audio.h:647
struct TU_ATTR_PACKED::@16::TU_ATTR_PACKED bmRequestType_bit
uint8_t bmAttributes
See: audio_clock_source_attribute_t.
Definition: audio.h:672
uint8_t bEndpointAddress
Definition: video.h:306
uint8_t bRequest
Request type audio_cs_req_t.
Definition: audio.h:831
volatile uint16_t actual_len
Definition: dcd_nrf5x.c:101
uint16_t total_len
Definition: dcd_nrf5x.c:100
uint16_t mps
Definition: dcd_nrf5x.c:102
bool iso_in_transfer_ready
Definition: dcd_nrf5x.c:111
uint8_t * buffer
Definition: dcd_nrf5x.c:99
volatile bool data_received
Definition: dcd_nrf5x.c:106
volatile bool started
Definition: dcd_nrf5x.c:107
static TU_ATTR_ALWAYS_INLINE uint16_t tu_min16(uint16_t x, uint16_t y)
Definition: tusb_common.h:155
static TU_ATTR_ALWAYS_INLINE bool tu_bit_test(uint32_t value, uint8_t pos)
Definition: tusb_common.h:151
@ TUSB_DIR_IN
Definition: tusb_types.h:67
@ TUSB_DIR_OUT
Definition: tusb_types.h:66
@ TUSB_DIR_IN_MASK
Definition: tusb_types.h:69
@ TUSB_REQ_SET_ADDRESS
Definition: tusb_types.h:127
@ TUSB_SPEED_FULL
Definition: tusb_types.h:50
static TU_ATTR_ALWAYS_INLINE uint8_t tu_edpt_number(uint8_t addr)
Definition: tusb_types.h:507
@ XFER_RESULT_SUCCESS
Definition: tusb_types.h:237
@ TUSB_REQ_RCPT_DEVICE
Definition: tusb_types.h:151
static TU_ATTR_ALWAYS_INLINE uint16_t tu_edpt_packet_size(tusb_desc_endpoint_t const *desc_ep)
Definition: tusb_types.h:515
@ TUSB_XFER_ISOCHRONOUS
Definition: tusb_types.h:60
TU_ATTR_PACKED_END TU_ATTR_BIT_FIELD_ORDER_END static TU_ATTR_ALWAYS_INLINE tusb_dir_t tu_edpt_dir(uint8_t addr)
Definition: tusb_types.h:502
@ TUSB_REQ_TYPE_STANDARD
Definition: tusb_types.h:144
void usbd_defer_func(osal_task_func_t func, void *param, bool in_isr)
Definition: usbd.c:1262
bool tud_inited(void)
Definition: usbd.c:447
CFG_TUH_MEM_ALIGN tusb_control_request_t request
Definition: usbh.c:259