| 
									
										
										
										
											2019-03-20 16:11:42 +07:00
										 |  |  | /* 
 | 
					
						
							|  |  |  |  * The MIT License (MIT) | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2019-05-14 11:48:05 +07:00
										 |  |  |  * Copyright (c) 2019 Ha Thach (tinyusb.org) | 
					
						
							| 
									
										
										
										
											2019-03-20 16:11:42 +07:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | 
					
						
							|  |  |  |  * of this software and associated documentation files (the "Software"), to deal | 
					
						
							|  |  |  |  * in the Software without restriction, including without limitation the rights | 
					
						
							|  |  |  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | 
					
						
							|  |  |  |  * copies of the Software, and to permit persons to whom the Software is | 
					
						
							|  |  |  |  * furnished to do so, subject to the following conditions: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The above copyright notice and this permission notice shall be included in | 
					
						
							|  |  |  |  * all copies or substantial portions of the Software. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
					
						
							|  |  |  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
					
						
							|  |  |  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | 
					
						
							|  |  |  |  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 
					
						
							|  |  |  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | 
					
						
							|  |  |  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | 
					
						
							|  |  |  |  * THE SOFTWARE. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This file is part of the TinyUSB stack. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-03-02 13:41:35 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-12 13:14:59 +07:00
										 |  |  | #include "tusb_option.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-23 15:25:45 +07:00
										 |  |  | #if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_NRF5X
 | 
					
						
							| 
									
										
										
										
											2018-03-26 22:54:34 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-13 16:30:53 +07:00
										 |  |  | #include "nrf.h"
 | 
					
						
							| 
									
										
										
										
											2019-08-05 21:54:20 +07:00
										 |  |  | #include "nrf_clock.h"
 | 
					
						
							| 
									
										
										
										
											2018-03-13 16:30:53 +07:00
										 |  |  | #include "nrf_power.h"
 | 
					
						
							| 
									
										
										
										
											2019-08-05 21:54:20 +07:00
										 |  |  | #include "nrfx_usbd_errata.h"
 | 
					
						
							| 
									
										
										
										
											2018-03-28 13:44:39 +07:00
										 |  |  | #include "device/dcd.h"
 | 
					
						
							| 
									
										
										
										
											2018-08-01 00:50:04 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  | // TODO remove later
 | 
					
						
							|  |  |  | #include "device/usbd.h"
 | 
					
						
							| 
									
										
										
										
											2018-06-23 13:20:07 +07:00
										 |  |  | #include "device/usbd_pvt.h" // to use defer function helper
 | 
					
						
							| 
									
										
										
										
											2018-03-02 13:41:35 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-13 16:30:53 +07:00
										 |  |  | /*------------------------------------------------------------------*/ | 
					
						
							|  |  |  | /* MACRO TYPEDEF CONSTANT ENUM
 | 
					
						
							|  |  |  |  *------------------------------------------------------------------*/ | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  | enum | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   // Max allowed by USB specs
 | 
					
						
							|  |  |  |   MAX_PACKET_SIZE   = 64, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Mask of all END event (IN & OUT) for all endpoints. ENDEPIN0-7, ENDEPOUT0-7, ENDISOIN, ENDISOOUT
 | 
					
						
							| 
									
										
										
										
											2018-08-28 12:18:10 +07:00
										 |  |  |   EDPT_END_ALL_MASK = (0xff << USBD_INTEN_ENDEPIN0_Pos) | (0xff << USBD_INTEN_ENDEPOUT0_Pos) | | 
					
						
							|  |  |  |                       USBD_INTENCLR_ENDISOIN_Msk | USBD_INTEN_ENDISOOUT_Msk | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-03-02 13:41:35 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-21 21:22:12 +07:00
										 |  |  | enum | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-09-21 15:53:15 +02:00
										 |  |  |   // Endpoint number is fixed (8) for ISOOUT and ISOIN.
 | 
					
						
							|  |  |  |   EP_ISO_NUM = 8, | 
					
						
							|  |  |  |   // CBI endpoints count
 | 
					
						
							| 
									
										
										
										
											2020-05-21 21:22:12 +07:00
										 |  |  |   EP_COUNT = 8 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-16 22:17:11 +07:00
										 |  |  | // Transfer descriptor
 | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  | typedef struct | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   uint8_t* buffer; | 
					
						
							|  |  |  |   uint16_t total_len; | 
					
						
							| 
									
										
										
										
											2018-08-13 18:09:29 +07:00
										 |  |  |   volatile uint16_t actual_len; | 
					
						
							| 
									
										
										
										
											2020-09-21 15:49:41 +02:00
										 |  |  |   uint16_t  mps; // max packet size
 | 
					
						
							| 
									
										
										
										
											2018-04-07 15:03:56 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-23 13:20:07 +07:00
										 |  |  |   // nrf52840 will auto ACK OUT packet after DMA is done
 | 
					
						
							| 
									
										
										
										
											2018-08-13 18:09:29 +07:00
										 |  |  |   // indicate packet is already ACK
 | 
					
						
							|  |  |  |   volatile bool data_received; | 
					
						
							| 
									
										
										
										
											2020-09-21 15:53:15 +02:00
										 |  |  |   // Set to true when data was transferred from RAM to ISO IN output buffer.
 | 
					
						
							|  |  |  |   // New data can be put in ISO IN output buffer after SOF.
 | 
					
						
							|  |  |  |   bool iso_in_transfer_ready; | 
					
						
							| 
									
										
										
										
											2018-06-13 17:13:12 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-16 22:17:11 +07:00
										 |  |  | } xfer_td_t; | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-16 22:17:11 +07:00
										 |  |  | // Data for managing dcd
 | 
					
						
							|  |  |  | static struct | 
					
						
							| 
									
										
										
										
											2018-03-14 22:01:29 +07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-11-08 13:45:30 -08:00
										 |  |  |   // All 8 endpoints including control IN & OUT (offset 1)
 | 
					
						
							| 
									
										
										
										
											2020-09-21 15:53:15 +02:00
										 |  |  |   // +1 for ISO endpoints
 | 
					
						
							|  |  |  |   xfer_td_t xfer[EP_COUNT + 1][2]; | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-21 21:22:12 +07:00
										 |  |  |   // Number of pending DMA that is started but not handled yet by dcd_int_handler().
 | 
					
						
							|  |  |  |   // Since nRF can only carry one DMA can run at a time, this value is normally be either 0 or 1.
 | 
					
						
							|  |  |  |   // However, in critical section with interrupt disabled, the DMA can be finished and added up
 | 
					
						
							|  |  |  |   // until handled by dcd_init_handler() when exiting critical section.
 | 
					
						
							|  |  |  |   volatile uint8_t dma_pending; | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  | }_dcd; | 
					
						
							| 
									
										
										
										
											2018-03-02 13:41:35 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-15 17:09:55 +07:00
										 |  |  | /*------------------------------------------------------------------*/ | 
					
						
							| 
									
										
										
										
											2018-11-16 22:17:11 +07:00
										 |  |  | /* Control / Bulk / Interrupt (CBI) Transfer
 | 
					
						
							| 
									
										
										
										
											2018-03-15 17:09:55 +07:00
										 |  |  |  *------------------------------------------------------------------*/ | 
					
						
							| 
									
										
										
										
											2018-03-14 15:21:47 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-21 21:22:12 +07:00
										 |  |  | // NVIC_GetEnableIRQ is only available in CMSIS v5
 | 
					
						
							|  |  |  | #ifndef NVIC_GetEnableIRQ
 | 
					
						
							|  |  |  | static inline uint32_t NVIC_GetEnableIRQ(IRQn_Type IRQn) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if ((int32_t)(IRQn) >= 0) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return((uint32_t)(((NVIC->ISER[(((uint32_t)(int32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return(0U); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-16 22:17:11 +07:00
										 |  |  | // helper to start DMA
 | 
					
						
							| 
									
										
										
										
											2018-06-23 13:20:07 +07:00
										 |  |  | static void edpt_dma_start(volatile uint32_t* reg_startep) | 
					
						
							| 
									
										
										
										
											2018-03-15 17:09:55 +07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-06-23 13:20:07 +07:00
										 |  |  |   // Only one dma can be active
 | 
					
						
							| 
									
										
										
										
											2020-05-21 21:22:12 +07:00
										 |  |  |   if ( _dcd.dma_pending ) | 
					
						
							| 
									
										
										
										
											2018-04-14 03:39:01 +07:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2018-06-23 13:20:07 +07:00
										 |  |  |     if (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-05-21 21:22:12 +07:00
										 |  |  |       // Called within ISR, use usbd task to defer later
 | 
					
						
							| 
									
										
										
										
											2018-06-23 13:20:07 +07:00
										 |  |  |       usbd_defer_func( (osal_task_func_t) edpt_dma_start, (void*) reg_startep, true ); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-05-21 21:22:12 +07:00
										 |  |  |       if ( __get_PRIMASK() || !NVIC_GetEnableIRQ(USBD_IRQn) ) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         // Called in critical section with interrupt disabled. We have to manually check
 | 
					
						
							|  |  |  |         // for the DMA complete by comparing current pending DMA with number of ENDED Events
 | 
					
						
							|  |  |  |         uint32_t ended = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-15 16:08:23 +02:00
										 |  |  |         while ( _dcd.dma_pending > ((uint8_t) ended) ) | 
					
						
							| 
									
										
										
										
											2020-05-21 21:22:12 +07:00
										 |  |  |         { | 
					
						
							|  |  |  |           ended = NRF_USBD->EVENTS_ENDISOIN + NRF_USBD->EVENTS_ENDISOOUT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           for (uint8_t i=0; i<EP_COUNT; i++) | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             ended += NRF_USBD->EVENTS_ENDEPIN[i] + NRF_USBD->EVENTS_ENDEPOUT[i]; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }else | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         // Called in non-critical thread-mode, should be 99% of the time.
 | 
					
						
							|  |  |  |         // Should be safe to blocking wait until previous DMA transfer complete
 | 
					
						
							|  |  |  |         while ( _dcd.dma_pending ) { } | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-06-23 13:20:07 +07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-04-14 03:39:01 +07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-03-15 17:09:55 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-21 21:22:12 +07:00
										 |  |  |   _dcd.dma_pending++; | 
					
						
							| 
									
										
										
										
											2018-03-15 17:09:55 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-23 13:20:07 +07:00
										 |  |  |   (*reg_startep) = 1; | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  |   __ISB(); __DSB(); | 
					
						
							| 
									
										
										
										
											2018-03-15 17:09:55 +07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-16 22:17:11 +07:00
										 |  |  | // DMA is complete
 | 
					
						
							| 
									
										
										
										
											2018-03-15 17:09:55 +07:00
										 |  |  | static void edpt_dma_end(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-05-21 21:22:12 +07:00
										 |  |  |   TU_ASSERT(_dcd.dma_pending, ); | 
					
						
							|  |  |  |   _dcd.dma_pending = 0; | 
					
						
							| 
									
										
										
										
											2018-03-15 17:09:55 +07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-03-14 22:01:29 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-16 22:17:11 +07:00
										 |  |  | // helper getting td
 | 
					
						
							|  |  |  | static inline xfer_td_t* get_td(uint8_t epnum, uint8_t dir) | 
					
						
							| 
									
										
										
										
											2018-04-12 00:33:31 +07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-11-08 13:45:30 -08:00
										 |  |  |   return &_dcd.xfer[epnum][dir]; | 
					
						
							| 
									
										
										
										
											2018-04-12 00:33:31 +07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-16 22:17:11 +07:00
										 |  |  | /*------------- CBI OUT Transfer -------------*/ | 
					
						
							| 
									
										
										
										
											2018-06-13 17:13:12 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-16 22:17:11 +07:00
										 |  |  | // Prepare for a CBI transaction OUT, call at the start
 | 
					
						
							|  |  |  | // Allow ACK incoming data
 | 
					
						
							| 
									
										
										
										
											2018-06-13 17:13:12 +07:00
										 |  |  | static void xact_out_prepare(uint8_t epnum) | 
					
						
							| 
									
										
										
										
											2018-04-12 00:33:31 +07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-11-16 21:52:10 +07:00
										 |  |  |   if ( epnum == 0 ) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     NRF_USBD->TASKS_EP0RCVOUT = 1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // Write zero value to SIZE register will allow hw to ACK (accept data)
 | 
					
						
							|  |  |  |     // If it is not already done by DMA
 | 
					
						
							| 
									
										
										
										
											2020-09-21 15:53:15 +02:00
										 |  |  |     // SIZE.ISOOUT can also be accessed this way
 | 
					
						
							| 
									
										
										
										
											2018-11-16 21:52:10 +07:00
										 |  |  |     NRF_USBD->SIZE.EPOUT[epnum] = 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-13 17:13:12 +07:00
										 |  |  |   __ISB(); __DSB(); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-04-12 00:33:31 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-16 22:17:11 +07:00
										 |  |  | // Start DMA to move data from Endpoint -> RAM
 | 
					
						
							| 
									
										
										
										
											2018-06-13 17:13:12 +07:00
										 |  |  | static void xact_out_dma(uint8_t epnum) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-11-16 22:17:11 +07:00
										 |  |  |   xfer_td_t* xfer = get_td(epnum, TUSB_DIR_OUT); | 
					
						
							| 
									
										
										
										
											2020-09-21 15:53:15 +02:00
										 |  |  |   uint32_t xact_len; | 
					
						
							| 
									
										
										
										
											2018-04-12 00:33:31 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-21 15:53:15 +02:00
										 |  |  |   if (epnum == EP_ISO_NUM) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     xact_len = NRF_USBD->SIZE.ISOOUT; | 
					
						
							|  |  |  |     // If ZERO bit is set, ignore ISOOUT length
 | 
					
						
							|  |  |  |     if (xact_len & USBD_SIZE_ISOOUT_ZERO_Msk) xact_len = 0; | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       // Trigger DMA move data from Endpoint -> SRAM
 | 
					
						
							|  |  |  |       NRF_USBD->ISOOUT.PTR = (uint32_t) xfer->buffer; | 
					
						
							|  |  |  |       NRF_USBD->ISOOUT.MAXCNT = xact_len; | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-21 15:53:15 +02:00
										 |  |  |       edpt_dma_start(&NRF_USBD->TASKS_STARTISOOUT); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     xact_len = (uint8_t)NRF_USBD->SIZE.EPOUT[epnum]; | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-21 15:53:15 +02:00
										 |  |  |     // Trigger DMA move data from Endpoint -> SRAM
 | 
					
						
							|  |  |  |     NRF_USBD->EPOUT[epnum].PTR = (uint32_t) xfer->buffer; | 
					
						
							|  |  |  |     NRF_USBD->EPOUT[epnum].MAXCNT = xact_len; | 
					
						
							| 
									
										
										
										
											2018-06-13 17:13:12 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-21 15:53:15 +02:00
										 |  |  |     edpt_dma_start(&NRF_USBD->TASKS_STARTEPOUT[epnum]); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-06-13 17:13:12 +07:00
										 |  |  |   xfer->buffer     += xact_len; | 
					
						
							|  |  |  |   xfer->actual_len += xact_len; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-16 22:17:11 +07:00
										 |  |  | /*------------- CBI IN Transfer -------------*/ | 
					
						
							| 
									
										
										
										
											2018-06-13 17:13:12 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-16 22:17:11 +07:00
										 |  |  | // Prepare for a CBI transaction IN, call at the start
 | 
					
						
							|  |  |  | // it start DMA to transfer data from RAM -> Endpoint
 | 
					
						
							| 
									
										
										
										
											2018-06-13 17:13:12 +07:00
										 |  |  | static void xact_in_prepare(uint8_t epnum) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-11-16 22:17:11 +07:00
										 |  |  |   xfer_td_t* xfer = get_td(epnum, TUSB_DIR_IN); | 
					
						
							| 
									
										
										
										
											2018-06-13 17:13:12 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Each transaction is up to Max Packet Size
 | 
					
						
							| 
									
										
										
										
											2020-09-21 15:49:41 +02:00
										 |  |  |   uint16_t const xact_len = tu_min16(xfer->total_len - xfer->actual_len, xfer->mps); | 
					
						
							| 
									
										
										
										
											2018-06-13 17:13:12 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   NRF_USBD->EPIN[epnum].PTR    = (uint32_t) xfer->buffer; | 
					
						
							|  |  |  |   NRF_USBD->EPIN[epnum].MAXCNT = xact_len; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   xfer->buffer += xact_len; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-23 13:20:07 +07:00
										 |  |  |   edpt_dma_start(&NRF_USBD->TASKS_STARTEPIN[epnum]); | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-16 22:17:11 +07:00
										 |  |  | //--------------------------------------------------------------------+
 | 
					
						
							| 
									
										
										
										
											2018-12-17 12:14:11 +07:00
										 |  |  | // Controller API
 | 
					
						
							| 
									
										
										
										
											2018-11-16 22:17:11 +07:00
										 |  |  | //--------------------------------------------------------------------+
 | 
					
						
							| 
									
										
										
										
											2019-03-29 16:23:00 +07:00
										 |  |  | void dcd_init (uint8_t rhport) | 
					
						
							| 
									
										
										
										
											2018-11-16 22:17:11 +07:00
										 |  |  | { | 
					
						
							|  |  |  |   (void) rhport; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-05 13:20:25 +07:00
										 |  |  | void dcd_int_enable(uint8_t rhport) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   (void) rhport; | 
					
						
							|  |  |  |   NVIC_EnableIRQ(USBD_IRQn); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void dcd_int_disable(uint8_t rhport) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   (void) rhport; | 
					
						
							|  |  |  |   NVIC_DisableIRQ(USBD_IRQn); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-16 22:17:11 +07:00
										 |  |  | void dcd_set_address (uint8_t rhport, uint8_t dev_addr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   (void) rhport; | 
					
						
							| 
									
										
										
										
											2018-11-26 12:25:28 +07:00
										 |  |  |   (void) dev_addr; | 
					
						
							| 
									
										
										
										
											2019-03-13 23:14:48 +07:00
										 |  |  |   // Set Address is automatically update by hw controller, nothing to do
 | 
					
						
							| 
									
										
										
										
											2019-03-29 01:34:53 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-30 02:26:15 +07:00
										 |  |  |   // Enable usbevent for suspend and resume detection
 | 
					
						
							| 
									
										
										
										
											2019-04-02 01:20:34 +07:00
										 |  |  |   // Since the bus signal D+/D- are stable now.
 | 
					
						
							| 
									
										
										
										
											2019-03-30 02:26:15 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Clear current pending first
 | 
					
						
							| 
									
										
										
										
											2019-03-29 01:34:53 +07:00
										 |  |  |   NRF_USBD->EVENTCAUSE |= NRF_USBD->EVENTCAUSE; | 
					
						
							|  |  |  |   NRF_USBD->EVENTS_USBEVENT = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   NRF_USBD->INTENSET = USBD_INTEN_USBEVENT_Msk; | 
					
						
							| 
									
										
										
										
											2018-11-16 22:17:11 +07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-30 14:47:11 +07:00
										 |  |  | void dcd_remote_wakeup(uint8_t rhport) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   (void) rhport; | 
					
						
							| 
									
										
										
										
											2019-03-30 23:01:23 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-31 23:57:38 +07:00
										 |  |  |   // Bring controller out of low power mode
 | 
					
						
							|  |  |  |   NRF_USBD->LOWPOWER = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Initiate RESUME signal
 | 
					
						
							| 
									
										
										
										
											2019-03-30 23:01:23 +07:00
										 |  |  |   NRF_USBD->DPDMVALUE = USBD_DPDMVALUE_STATE_Resume; | 
					
						
							|  |  |  |   NRF_USBD->TASKS_DPDMDRIVE = 1; | 
					
						
							| 
									
										
										
										
											2019-03-31 23:57:38 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // TODO There is no USBEVENT Resume interrupt
 | 
					
						
							|  |  |  |   // We may manually raise DCD_EVENT_RESUME event here
 | 
					
						
							| 
									
										
										
										
											2019-03-30 14:47:11 +07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-09 11:47:02 +07:00
										 |  |  | // disconnect by disabling internal pull-up resistor on D+/D-
 | 
					
						
							|  |  |  | void dcd_disconnect(uint8_t rhport) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   (void) rhport; | 
					
						
							|  |  |  |   NRF_USBD->USBPULLUP = 0; | 
					
						
							| 
									
										
										
										
											2020-08-04 14:18:12 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Disable Pull-up does not trigger Power USB Removed, in fact it have no
 | 
					
						
							|  |  |  |   // impact on the USB Power status at all -> need to submit unplugged event to the stack.
 | 
					
						
							|  |  |  |   dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, false); | 
					
						
							| 
									
										
										
										
											2020-04-09 11:47:02 +07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // connect by enabling internal pull-up resistor on D+/D-
 | 
					
						
							|  |  |  | void dcd_connect(uint8_t rhport) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   (void) rhport; | 
					
						
							|  |  |  |   NRF_USBD->USBPULLUP = 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-17 12:14:11 +07:00
										 |  |  | //--------------------------------------------------------------------+
 | 
					
						
							|  |  |  | // Endpoint API
 | 
					
						
							|  |  |  | //--------------------------------------------------------------------+
 | 
					
						
							| 
									
										
										
										
											2018-03-28 13:47:58 +07:00
										 |  |  | bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) | 
					
						
							| 
									
										
										
										
											2018-03-14 15:21:47 +07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  |   (void) rhport; | 
					
						
							| 
									
										
										
										
											2018-03-15 13:22:28 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-12 11:51:31 +07:00
										 |  |  |   uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress); | 
					
						
							|  |  |  |   uint8_t const dir   = tu_edpt_dir(desc_edpt->bEndpointAddress); | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 13:45:30 -08:00
										 |  |  |   _dcd.xfer[epnum][dir].mps = desc_edpt->wMaxPacketSize.size; | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-21 15:53:15 +02:00
										 |  |  |   if (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS) | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-09-21 15:53:15 +02:00
										 |  |  |     if (dir == TUSB_DIR_OUT) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       NRF_USBD->INTENSET = TU_BIT(USBD_INTEN_ENDEPOUT0_Pos + epnum); | 
					
						
							|  |  |  |       NRF_USBD->EPOUTEN |= TU_BIT(epnum); | 
					
						
							|  |  |  |     }else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       NRF_USBD->INTENSET = TU_BIT(USBD_INTEN_ENDEPIN0_Pos + epnum); | 
					
						
							|  |  |  |       NRF_USBD->EPINEN  |= TU_BIT(epnum); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-09-21 15:53:15 +02:00
										 |  |  |     TU_ASSERT(epnum == EP_ISO_NUM); | 
					
						
							|  |  |  |     if (dir == TUSB_DIR_OUT) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       // SPLIT ISO buffer when ISO IN endpoint is already opened.
 | 
					
						
							|  |  |  |       if (_dcd.xfer[EP_ISO_NUM][TUSB_DIR_IN].mps) NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_HalfIN; | 
					
						
							|  |  |  |       // Clear old events
 | 
					
						
							|  |  |  |       NRF_USBD->EVENTS_ENDISOOUT = 0; | 
					
						
							|  |  |  |       // Clear SOF event in case interrupt was not enabled yet.
 | 
					
						
							|  |  |  |       if ((NRF_USBD->INTEN & USBD_INTEN_SOF_Msk) == 0) NRF_USBD->EVENTS_SOF = 0; | 
					
						
							|  |  |  |       // Enable SOF and ISOOUT interrupts, and ISOOUT endpoint.
 | 
					
						
							|  |  |  |       NRF_USBD->INTENSET = USBD_INTENSET_ENDISOOUT_Msk | USBD_INTENSET_SOF_Msk; | 
					
						
							|  |  |  |       NRF_USBD->EPOUTEN |= USBD_EPOUTEN_ISOOUT_Msk; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       NRF_USBD->EVENTS_ENDISOIN = 0; | 
					
						
							|  |  |  |       // SPLIT ISO buffer when ISO OUT endpoint is already opened.
 | 
					
						
							|  |  |  |       if (_dcd.xfer[EP_ISO_NUM][TUSB_DIR_OUT].mps) NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_HalfIN; | 
					
						
							|  |  |  |       // Clear SOF event in case interrupt was not enabled yet.
 | 
					
						
							|  |  |  |       if ((NRF_USBD->INTEN & USBD_INTEN_SOF_Msk) == 0) NRF_USBD->EVENTS_SOF = 0; | 
					
						
							|  |  |  |       // Enable SOF and ISOIN interrupts, and ISOIN endpoint.
 | 
					
						
							|  |  |  |       NRF_USBD->INTENSET = USBD_INTENSET_ENDISOIN_Msk | USBD_INTENSET_SOF_Msk; | 
					
						
							|  |  |  |       NRF_USBD->EPINEN  |= USBD_EPINEN_ISOIN_Msk; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  |   } | 
					
						
							|  |  |  |   __ISB(); __DSB(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-14 15:21:47 +07:00
										 |  |  |   return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-21 15:45:17 +02:00
										 |  |  | void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   (void) rhport; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   uint8_t const epnum = tu_edpt_number(ep_addr); | 
					
						
							|  |  |  |   uint8_t const dir   = tu_edpt_dir(ep_addr); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-21 15:53:15 +02:00
										 |  |  |   if (epnum != EP_ISO_NUM) | 
					
						
							| 
									
										
										
										
											2020-09-21 15:45:17 +02:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-09-21 15:53:15 +02:00
										 |  |  |     // CBI
 | 
					
						
							|  |  |  |     if (dir == TUSB_DIR_OUT) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       NRF_USBD->INTENCLR = TU_BIT(USBD_INTEN_ENDEPOUT0_Pos + epnum); | 
					
						
							|  |  |  |       NRF_USBD->EPOUTEN &= ~TU_BIT(epnum); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       NRF_USBD->INTENCLR = TU_BIT(USBD_INTEN_ENDEPIN0_Pos + epnum); | 
					
						
							|  |  |  |       NRF_USBD->EPINEN &= ~TU_BIT(epnum); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-09-21 15:45:17 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-09-21 15:53:15 +02:00
										 |  |  |     _dcd.xfer[EP_ISO_NUM][dir].mps = 0; | 
					
						
							|  |  |  |     // ISO
 | 
					
						
							|  |  |  |     if (dir == TUSB_DIR_OUT) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       NRF_USBD->INTENCLR = USBD_INTENCLR_ENDISOOUT_Msk; | 
					
						
							|  |  |  |       NRF_USBD->EPOUTEN &= ~USBD_EPOUTEN_ISOOUT_Msk; | 
					
						
							|  |  |  |       NRF_USBD->EVENTS_ENDISOOUT = 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       NRF_USBD->INTENCLR = USBD_INTENCLR_ENDISOIN_Msk; | 
					
						
							|  |  |  |       NRF_USBD->EPINEN &= ~USBD_EPINEN_ISOIN_Msk; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // One of the ISO endpoints closed, no need to split buffers any more.
 | 
					
						
							|  |  |  |     NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_OneDir; | 
					
						
							|  |  |  |     // When both ISO endpoint are close there is no need for SOF any more.
 | 
					
						
							|  |  |  |     if (_dcd.xfer[EP_ISO_NUM][TUSB_DIR_IN].mps + _dcd.xfer[EP_ISO_NUM][TUSB_DIR_OUT].mps == 0) NRF_USBD->INTENCLR = USBD_INTENCLR_SOF_Msk; | 
					
						
							| 
									
										
										
										
											2020-09-21 15:45:17 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   __ISB(); __DSB(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-28 13:47:58 +07:00
										 |  |  | bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) | 
					
						
							| 
									
										
										
										
											2018-03-14 15:21:47 +07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  |   (void) rhport; | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-12 11:51:31 +07:00
										 |  |  |   uint8_t const epnum = tu_edpt_number(ep_addr); | 
					
						
							|  |  |  |   uint8_t const dir   = tu_edpt_dir(ep_addr); | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-16 22:17:11 +07:00
										 |  |  |   xfer_td_t* xfer = get_td(epnum, dir); | 
					
						
							| 
									
										
										
										
											2018-04-07 15:03:56 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   xfer->buffer     = buffer; | 
					
						
							|  |  |  |   xfer->total_len  = total_bytes; | 
					
						
							|  |  |  |   xfer->actual_len = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-08 14:20:28 +07:00
										 |  |  |   // Control endpoint with zero-length packet and opposite direction to 1st request byte --> status stage
 | 
					
						
							|  |  |  |   bool const control_status = (epnum == 0 && total_bytes == 0 && dir != tu_edpt_dir(NRF_USBD->BMREQUESTTYPE)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if ( control_status ) | 
					
						
							| 
									
										
										
										
											2018-11-16 21:52:10 +07:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-05-21 21:22:12 +07:00
										 |  |  |     // Status Phase also requires Easy DMA has to be available as well !!!!
 | 
					
						
							|  |  |  |     // However TASKS_EP0STATUS doesn't trigger any DMA transfer and got ENDED event subsequently
 | 
					
						
							|  |  |  |     // Therefore dma_running state will be corrected right away
 | 
					
						
							| 
									
										
										
										
											2018-11-16 21:52:10 +07:00
										 |  |  |     edpt_dma_start(&NRF_USBD->TASKS_EP0STATUS); | 
					
						
							| 
									
										
										
										
											2020-05-21 21:22:12 +07:00
										 |  |  |     if (_dcd.dma_pending) _dcd.dma_pending--; // correct the dma_running++ in dma start
 | 
					
						
							| 
									
										
										
										
											2018-11-16 21:52:10 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // The nRF doesn't interrupt on status transmit so we queue up a success response.
 | 
					
						
							| 
									
										
										
										
											2018-11-23 15:22:46 +07:00
										 |  |  |     dcd_event_xfer_complete(0, ep_addr, 0, XFER_RESULT_SUCCESS, false); | 
					
						
							| 
									
										
										
										
											2018-11-16 21:52:10 +07:00
										 |  |  |   } | 
					
						
							|  |  |  |   else if ( dir == TUSB_DIR_OUT ) | 
					
						
							| 
									
										
										
										
											2018-06-13 17:13:12 +07:00
										 |  |  |   { | 
					
						
							|  |  |  |     if ( xfer->data_received ) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2018-06-23 13:20:07 +07:00
										 |  |  |       // nrf52840 auto ACK OUT packet after DMA is done
 | 
					
						
							|  |  |  |       // Data already received previously --> trigger DMA to copy to SRAM
 | 
					
						
							| 
									
										
										
										
											2018-06-13 17:13:12 +07:00
										 |  |  |       xact_out_dma(epnum); | 
					
						
							| 
									
										
										
										
											2018-11-16 21:52:10 +07:00
										 |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							| 
									
										
										
										
											2018-06-13 17:13:12 +07:00
										 |  |  |     { | 
					
						
							|  |  |  |       xact_out_prepare(epnum); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-11-16 21:52:10 +07:00
										 |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							| 
									
										
										
										
											2018-06-13 17:13:12 +07:00
										 |  |  |   { | 
					
						
							|  |  |  |     xact_in_prepare(epnum); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-14 15:21:47 +07:00
										 |  |  |   return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-28 13:47:58 +07:00
										 |  |  | void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr) | 
					
						
							| 
									
										
										
										
											2018-03-14 15:21:47 +07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  |   (void) rhport; | 
					
						
							| 
									
										
										
										
											2020-09-21 15:53:15 +02:00
										 |  |  |   uint8_t const epnum = tu_edpt_number(ep_addr); | 
					
						
							| 
									
										
										
										
											2018-03-21 16:08:42 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-21 15:53:15 +02:00
										 |  |  |   if ( epnum == 0 ) | 
					
						
							| 
									
										
										
										
											2018-03-21 16:08:42 +07:00
										 |  |  |   { | 
					
						
							|  |  |  |     NRF_USBD->TASKS_EP0STALL = 1; | 
					
						
							| 
									
										
										
										
											2020-09-21 15:53:15 +02:00
										 |  |  |   }else if (epnum != EP_ISO_NUM) | 
					
						
							| 
									
										
										
										
											2018-03-21 16:08:42 +07:00
										 |  |  |   { | 
					
						
							|  |  |  |     NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_Stall << USBD_EPSTALL_STALL_Pos) | ep_addr; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-03-14 15:21:47 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 16:08:42 +07:00
										 |  |  |   __ISB(); __DSB(); | 
					
						
							| 
									
										
										
										
											2018-03-14 15:21:47 +07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-28 13:47:58 +07:00
										 |  |  | void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) | 
					
						
							| 
									
										
										
										
											2018-03-14 15:21:47 +07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  |   (void) rhport; | 
					
						
							| 
									
										
										
										
											2020-09-21 15:53:15 +02:00
										 |  |  |   uint8_t const epnum = tu_edpt_number(ep_addr); | 
					
						
							| 
									
										
										
										
											2018-07-25 21:21:33 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-21 15:53:15 +02:00
										 |  |  |   if ( epnum != 0 && epnum != EP_ISO_NUM ) | 
					
						
							| 
									
										
										
										
											2018-03-21 16:08:42 +07:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2019-05-09 23:31:18 +07:00
										 |  |  |     // clear stall
 | 
					
						
							| 
									
										
										
										
											2018-03-21 16:08:42 +07:00
										 |  |  |     NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_UnStall << USBD_EPSTALL_STALL_Pos) | ep_addr; | 
					
						
							| 
									
										
										
										
											2019-05-09 23:31:18 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // reset data toggle to DATA0
 | 
					
						
							|  |  |  |     NRF_USBD->DTOGGLE = (USBD_DTOGGLE_VALUE_Data0 << USBD_DTOGGLE_VALUE_Pos) | ep_addr; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-25 21:21:33 +07:00
										 |  |  |     __ISB(); __DSB(); | 
					
						
							| 
									
										
										
										
											2018-03-21 16:08:42 +07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-03-14 15:21:47 +07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*------------------------------------------------------------------*/ | 
					
						
							| 
									
										
										
										
											2018-11-16 22:17:11 +07:00
										 |  |  | /* Interrupt Handler
 | 
					
						
							| 
									
										
										
										
											2018-03-14 15:21:47 +07:00
										 |  |  |  *------------------------------------------------------------------*/ | 
					
						
							| 
									
										
										
										
											2018-11-16 22:17:11 +07:00
										 |  |  | void bus_reset(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   for(int i=0; i<8; i++) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     NRF_USBD->TASKS_STARTEPIN[i] = 0; | 
					
						
							|  |  |  |     NRF_USBD->TASKS_STARTEPOUT[i] = 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   NRF_USBD->TASKS_STARTISOIN  = 0; | 
					
						
							|  |  |  |   NRF_USBD->TASKS_STARTISOOUT = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   tu_varclr(&_dcd); | 
					
						
							|  |  |  |   _dcd.xfer[0][TUSB_DIR_IN].mps = MAX_PACKET_SIZE; | 
					
						
							|  |  |  |   _dcd.xfer[0][TUSB_DIR_OUT].mps = MAX_PACKET_SIZE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-17 12:27:53 +07:00
										 |  |  | void dcd_int_handler(uint8_t rhport) | 
					
						
							| 
									
										
										
										
											2018-03-13 16:59:51 +07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-04-06 17:35:11 +07:00
										 |  |  |   (void) rhport; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-13 16:59:51 +07:00
										 |  |  |   uint32_t const inten  = NRF_USBD->INTEN; | 
					
						
							|  |  |  |   uint32_t int_status = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-14 03:39:01 +07:00
										 |  |  |   volatile uint32_t* regevt = &NRF_USBD->EVENTS_USBRESET; | 
					
						
							| 
									
										
										
										
											2018-03-13 16:59:51 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-26 12:25:28 +07:00
										 |  |  |   for(uint8_t i=0; i<USBD_INTEN_EPDATA_Pos+1; i++) | 
					
						
							| 
									
										
										
										
											2018-03-13 16:59:51 +07:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2019-05-14 12:54:29 +07:00
										 |  |  |     if ( tu_bit_test(inten, i) && regevt[i]  ) | 
					
						
							| 
									
										
										
										
											2018-03-13 16:59:51 +07:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2018-12-14 15:28:38 +07:00
										 |  |  |       int_status |= TU_BIT(i); | 
					
						
							| 
									
										
										
										
											2018-03-13 16:59:51 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-14 03:39:01 +07:00
										 |  |  |       // event clear
 | 
					
						
							|  |  |  |       regevt[i] = 0; | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  |       __ISB(); __DSB(); | 
					
						
							| 
									
										
										
										
											2018-03-13 16:59:51 +07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-03-14 22:01:29 +07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-03-13 16:59:51 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-14 22:01:29 +07:00
										 |  |  |   if ( int_status & USBD_INTEN_USBRESET_Msk ) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     bus_reset(); | 
					
						
							| 
									
										
										
										
											2021-01-08 22:34:36 +07:00
										 |  |  |     dcd_event_bus_reset(0, TUSB_SPEED_FULL, true); | 
					
						
							| 
									
										
										
										
											2018-03-14 22:01:29 +07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-03-14 15:21:47 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-21 15:53:15 +02:00
										 |  |  |   // ISOIN: Data was moved to endpoint buffer, client will be notified in SOF
 | 
					
						
							|  |  |  |   if ( int_status & USBD_INTEN_ENDISOIN_Msk ) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     xfer_td_t* xfer = get_td(EP_ISO_NUM, TUSB_DIR_IN); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     xfer->actual_len = NRF_USBD->ISOIN.AMOUNT; | 
					
						
							|  |  |  |     // Data transferred from RAM to endpoint output buffer.
 | 
					
						
							|  |  |  |     // Next transfer can be scheduled after SOF.
 | 
					
						
							|  |  |  |     xfer->iso_in_transfer_ready = true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-29 01:34:53 +07:00
										 |  |  |   if ( int_status & USBD_INTEN_SOF_Msk ) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-09-21 15:53:15 +02:00
										 |  |  |     // ISOOUT: Transfer data gathered in previous frame from buffer to RAM
 | 
					
						
							|  |  |  |     if (NRF_USBD->EPOUTEN & USBD_EPOUTEN_ISOOUT_Msk) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       xact_out_dma(EP_ISO_NUM); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // ISOIN: Notify client that data was transferred
 | 
					
						
							|  |  |  |     xfer_td_t* xfer = get_td(EP_ISO_NUM, TUSB_DIR_IN); | 
					
						
							|  |  |  |     if ( xfer->iso_in_transfer_ready ) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       xfer->iso_in_transfer_ready = false; | 
					
						
							|  |  |  |       dcd_event_xfer_complete(0, EP_ISO_NUM | TUSB_DIR_IN_MASK, xfer->actual_len, XFER_RESULT_SUCCESS, true); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-03-29 01:34:53 +07:00
										 |  |  |     dcd_event_bus_signal(0, DCD_EVENT_SOF, true); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if ( int_status & USBD_INTEN_USBEVENT_Msk ) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2019-03-30 02:26:15 +07:00
										 |  |  |     uint32_t const evt_cause = NRF_USBD->EVENTCAUSE & (USBD_EVENTCAUSE_SUSPEND_Msk | USBD_EVENTCAUSE_RESUME_Msk); | 
					
						
							|  |  |  |     NRF_USBD->EVENTCAUSE = evt_cause; // clear interrupt
 | 
					
						
							| 
									
										
										
										
											2019-03-29 01:34:53 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-30 02:26:15 +07:00
										 |  |  |     if ( evt_cause & USBD_EVENTCAUSE_SUSPEND_Msk ) | 
					
						
							| 
									
										
										
										
											2019-03-29 01:34:53 +07:00
										 |  |  |     { | 
					
						
							|  |  |  |       dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true); | 
					
						
							| 
									
										
										
										
											2019-03-30 23:01:23 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-31 23:57:38 +07:00
										 |  |  |       // Put controller into low power mode
 | 
					
						
							|  |  |  |       NRF_USBD->LOWPOWER = 1; | 
					
						
							| 
									
										
										
										
											2019-03-30 23:01:23 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-31 23:57:38 +07:00
										 |  |  |       // Leave HFXO disable to application, since it may be used by other
 | 
					
						
							| 
									
										
										
										
											2019-03-29 01:34:53 +07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-03-30 02:26:15 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if ( evt_cause & USBD_EVENTCAUSE_RESUME_Msk  ) | 
					
						
							| 
									
										
										
										
											2019-03-29 01:34:53 +07:00
										 |  |  |     { | 
					
						
							|  |  |  |       dcd_event_bus_signal(0, DCD_EVENT_RESUME , true); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  |   if ( int_status & EDPT_END_ALL_MASK ) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // DMA complete move data from SRAM -> Endpoint
 | 
					
						
							|  |  |  |     edpt_dma_end(); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-03-30 02:26:15 +07:00
										 |  |  |   | 
					
						
							| 
									
										
										
										
											2018-11-08 13:45:30 -08:00
										 |  |  |   // Setup tokens are specific to the Control endpoint.
 | 
					
						
							| 
									
										
										
										
											2018-03-14 22:01:29 +07:00
										 |  |  |   if ( int_status & USBD_INTEN_EP0SETUP_Msk ) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2018-11-16 21:52:10 +07:00
										 |  |  |     uint8_t const setup[8] = { | 
					
						
							| 
									
										
										
										
											2018-06-24 00:16:22 +07:00
										 |  |  |         NRF_USBD->BMREQUESTTYPE , NRF_USBD->BREQUEST, NRF_USBD->WVALUEL , NRF_USBD->WVALUEH, | 
					
						
							|  |  |  |         NRF_USBD->WINDEXL       , NRF_USBD->WINDEXH , NRF_USBD->WLENGTHL, NRF_USBD->WLENGTHH | 
					
						
							| 
									
										
										
										
											2018-03-14 22:01:29 +07:00
										 |  |  |     }; | 
					
						
							| 
									
										
										
										
											2018-11-16 21:52:10 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // nrf5x hw auto handle set address, there is no need to inform usb stack
 | 
					
						
							|  |  |  |     tusb_control_request_t const * request = (tusb_control_request_t const *) setup; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if ( !(TUSB_REQ_RCPT_DEVICE == request->bmRequestType_bit.recipient && | 
					
						
							|  |  |  |            TUSB_REQ_TYPE_STANDARD == request->bmRequestType_bit.type && | 
					
						
							|  |  |  |            TUSB_REQ_SET_ADDRESS == request->bRequest) ) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2018-11-08 13:45:30 -08:00
										 |  |  |       dcd_event_setup_received(0, setup, true); | 
					
						
							| 
									
										
										
										
											2018-03-15 13:22:28 +07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-03-14 22:01:29 +07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-16 21:52:10 +07:00
										 |  |  |   //--------------------------------------------------------------------+
 | 
					
						
							|  |  |  |   /* Control/Bulk/Interrupt (CBI) Transfer
 | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * Data flow is: | 
					
						
							|  |  |  |    *           (bus)              (dma) | 
					
						
							|  |  |  |    *    Host <-------> Endpoint <-------> RAM | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * For CBI OUT: | 
					
						
							|  |  |  |    *  - Host -> Endpoint | 
					
						
							|  |  |  |    *      EPDATA (or EP0DATADONE) interrupted, check EPDATASTATUS.EPOUT[i] | 
					
						
							|  |  |  |    *      to start DMA. This step can occur automatically (without sw), | 
					
						
							|  |  |  |    *      which means data may or may not ready (data_received flag). | 
					
						
							|  |  |  |    *  - Endpoint -> RAM | 
					
						
							|  |  |  |    *      ENDEPOUT[i] interrupted, transaction complete, sw prepare next transaction | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * For CBI IN: | 
					
						
							|  |  |  |    *  - RAM -> Endpoint | 
					
						
							|  |  |  |    *      ENDEPIN[i] interrupted indicate DMA is complete. HW will start | 
					
						
							|  |  |  |    *      to move daat to host | 
					
						
							|  |  |  |    *  - Endpoint -> Host | 
					
						
							|  |  |  |    *      EPDATA (or EP0DATADONE) interrupted, check EPDATASTATUS.EPIN[i]. | 
					
						
							|  |  |  |    *      Transaction is complete, sw prepare next transaction | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * Note: in both Control In and Out of Data stage from Host <-> Endpoint | 
					
						
							|  |  |  |    * EP0DATADONE will be set as interrupt source | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   //--------------------------------------------------------------------+
 | 
					
						
							| 
									
										
										
										
											2018-06-23 13:20:07 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-16 21:52:10 +07:00
										 |  |  |   /* CBI OUT: Endpoint -> SRAM (aka transaction complete)
 | 
					
						
							|  |  |  |    * Note: Since nRF controller auto ACK next packet without SW awareness | 
					
						
							| 
									
										
										
										
											2018-06-23 13:20:07 +07:00
										 |  |  |    * We must handle this stage before Host -> Endpoint just in case | 
					
						
							|  |  |  |    * 2 event happens at once | 
					
						
							| 
									
										
										
										
											2020-09-21 15:53:15 +02:00
										 |  |  |    * ISO OUT: Transaction must fit in single packed, it can be shorter then total | 
					
						
							|  |  |  |    * len if Host decides to sent fewer bytes, it this case transaction is also | 
					
						
							|  |  |  |    * complete and next transfer is not initiated here like for CBI. | 
					
						
							| 
									
										
										
										
											2018-06-23 13:20:07 +07:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2020-09-21 15:53:15 +02:00
										 |  |  |   for(uint8_t epnum=0; epnum<EP_COUNT+1; epnum++) | 
					
						
							| 
									
										
										
										
											2018-06-23 13:20:07 +07:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2019-05-14 12:54:29 +07:00
										 |  |  |     if ( tu_bit_test(int_status, USBD_INTEN_ENDEPOUT0_Pos+epnum)) | 
					
						
							| 
									
										
										
										
											2018-06-23 13:20:07 +07:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2018-11-16 22:17:11 +07:00
										 |  |  |       xfer_td_t* xfer = get_td(epnum, TUSB_DIR_OUT); | 
					
						
							| 
									
										
										
										
											2018-06-23 13:20:07 +07:00
										 |  |  |       uint8_t const xact_len = NRF_USBD->EPOUT[epnum].AMOUNT; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-16 21:52:10 +07:00
										 |  |  |       // Data in endpoint has been consumed
 | 
					
						
							| 
									
										
										
										
											2018-06-23 13:20:07 +07:00
										 |  |  |       xfer->data_received = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Transfer complete if transaction len < Max Packet Size or total len is transferred
 | 
					
						
							| 
									
										
										
										
											2020-09-21 15:53:15 +02:00
										 |  |  |       if ( (epnum != EP_ISO_NUM) && (xact_len == xfer->mps) && (xfer->actual_len < xfer->total_len) ) | 
					
						
							| 
									
										
										
										
											2018-06-23 13:20:07 +07:00
										 |  |  |       { | 
					
						
							|  |  |  |         // Prepare for next transaction
 | 
					
						
							|  |  |  |         xact_out_prepare(epnum); | 
					
						
							|  |  |  |       }else | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         xfer->total_len = xfer->actual_len; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-01 20:41:26 +07:00
										 |  |  |         // CBI OUT complete
 | 
					
						
							| 
									
										
										
										
											2018-11-23 15:22:46 +07:00
										 |  |  |         dcd_event_xfer_complete(0, epnum, xfer->actual_len, XFER_RESULT_SUCCESS, true); | 
					
						
							| 
									
										
										
										
											2018-06-23 13:20:07 +07:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-06-24 00:16:22 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-16 21:52:10 +07:00
										 |  |  |     // Ended event for CBI IN : nothing to do
 | 
					
						
							| 
									
										
										
										
											2018-06-23 13:20:07 +07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-16 21:52:10 +07:00
										 |  |  |   // Endpoint <-> Host
 | 
					
						
							|  |  |  |   if ( int_status & (USBD_INTEN_EPDATA_Msk | USBD_INTEN_EP0DATADONE_Msk) ) | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  |   { | 
					
						
							|  |  |  |     uint32_t data_status = NRF_USBD->EPDATASTATUS; | 
					
						
							| 
									
										
										
										
											2019-11-11 00:01:12 +07:00
										 |  |  |     NRF_USBD->EPDATASTATUS = data_status; | 
					
						
							|  |  |  |     __ISB(); __DSB(); | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-16 21:52:10 +07:00
										 |  |  |     // EP0DATADONE is set with either Control Out on IN Data
 | 
					
						
							|  |  |  |     // Since EPDATASTATUS cannot be used to determine whether it is control OUT or IN.
 | 
					
						
							|  |  |  |     // We will use BMREQUESTTYPE in setup packet to determine the direction
 | 
					
						
							|  |  |  |     bool const is_control_in = (int_status & USBD_INTEN_EP0DATADONE_Msk) && (NRF_USBD->BMREQUESTTYPE & TUSB_DIR_IN_MASK); | 
					
						
							|  |  |  |     bool const is_control_out = (int_status & USBD_INTEN_EP0DATADONE_Msk) && !(NRF_USBD->BMREQUESTTYPE & TUSB_DIR_IN_MASK); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // CBI In: Endpoint -> Host (transaction complete)
 | 
					
						
							| 
									
										
										
										
											2018-11-08 13:45:30 -08:00
										 |  |  |     for(uint8_t epnum=0; epnum<8; epnum++) | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-05-14 12:54:29 +07:00
										 |  |  |       if ( tu_bit_test(data_status, epnum ) || ( epnum == 0 && is_control_in) ) | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  |       { | 
					
						
							| 
									
										
										
										
											2018-11-16 22:17:11 +07:00
										 |  |  |         xfer_td_t* xfer = get_td(epnum, TUSB_DIR_IN); | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         xfer->actual_len += NRF_USBD->EPIN[epnum].MAXCNT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if ( xfer->actual_len < xfer->total_len ) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2018-06-23 13:20:07 +07:00
										 |  |  |           // prepare next transaction
 | 
					
						
							| 
									
										
										
										
											2018-06-13 17:13:12 +07:00
										 |  |  |           xact_in_prepare(epnum); | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  |         } else | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2019-05-01 20:41:26 +07:00
										 |  |  |           // CBI IN complete
 | 
					
						
							| 
									
										
										
										
											2018-11-23 15:22:46 +07:00
										 |  |  |           dcd_event_xfer_complete(0, epnum | TUSB_DIR_IN_MASK, xfer->actual_len, XFER_RESULT_SUCCESS, true); | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-16 21:52:10 +07:00
										 |  |  |     // CBI OUT: Host -> Endpoint
 | 
					
						
							| 
									
										
										
										
											2018-11-08 13:45:30 -08:00
										 |  |  |     for(uint8_t epnum=0; epnum<8; epnum++) | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-05-14 12:54:29 +07:00
										 |  |  |       if ( tu_bit_test(data_status, 16+epnum ) || ( epnum == 0 && is_control_out) ) | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  |       { | 
					
						
							| 
									
										
										
										
											2018-11-16 22:17:11 +07:00
										 |  |  |         xfer_td_t* xfer = get_td(epnum, TUSB_DIR_OUT); | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-13 17:13:12 +07:00
										 |  |  |         if (xfer->actual_len < xfer->total_len) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           xact_out_dma(epnum); | 
					
						
							|  |  |  |         }else | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2018-06-23 13:20:07 +07:00
										 |  |  |           // Data overflow !!! Nah, nrf52840 will auto ACK OUT packet after DMA is done
 | 
					
						
							| 
									
										
										
										
											2018-06-13 17:13:12 +07:00
										 |  |  |           // Mark this endpoint with data received
 | 
					
						
							|  |  |  |           xfer->data_received = true; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-03-13 16:59:51 +07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-03-26 22:54:34 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-05 21:54:20 +07:00
										 |  |  | //--------------------------------------------------------------------+
 | 
					
						
							|  |  |  | // HFCLK helper
 | 
					
						
							|  |  |  | //--------------------------------------------------------------------+
 | 
					
						
							|  |  |  | #ifdef SOFTDEVICE_PRESENT
 | 
					
						
							| 
									
										
										
										
											2020-05-05 23:07:56 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  | // For enable/disable hfclk with SoftDevice
 | 
					
						
							|  |  |  | #include "nrf_mbr.h"
 | 
					
						
							|  |  |  | #include "nrf_sdm.h"
 | 
					
						
							|  |  |  | #include "nrf_soc.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifndef SD_MAGIC_NUMBER
 | 
					
						
							|  |  |  |   #define SD_MAGIC_NUMBER   0x51B1E5DB
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline bool is_sd_existed(void) | 
					
						
							| 
									
										
										
										
											2019-08-05 21:54:20 +07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-05-05 23:07:56 +07:00
										 |  |  |   return *((uint32_t*)(SOFTDEVICE_INFO_STRUCT_ADDRESS+4)) == SD_MAGIC_NUMBER; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // check if SD is existed and enabled
 | 
					
						
							|  |  |  | static inline bool is_sd_enabled(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if ( !is_sd_existed() ) return false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-05 21:54:20 +07:00
										 |  |  |   uint8_t sd_en = false; | 
					
						
							|  |  |  |   (void) sd_softdevice_is_enabled(&sd_en); | 
					
						
							|  |  |  |   return sd_en; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool hfclk_running(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #ifdef SOFTDEVICE_PRESENT
 | 
					
						
							|  |  |  |   if ( is_sd_enabled() ) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     uint32_t is_running; | 
					
						
							|  |  |  |     (void) sd_clock_hfclk_is_running(&is_running); | 
					
						
							|  |  |  |     return (is_running ? true : false); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-11 00:01:12 +07:00
										 |  |  |   return nrf_clock_hf_is_running(NRF_CLOCK, NRF_CLOCK_HFCLK_HIGH_ACCURACY); | 
					
						
							| 
									
										
										
										
											2019-08-05 21:54:20 +07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void hfclk_enable(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   // already running, nothing to do
 | 
					
						
							|  |  |  |   if ( hfclk_running() ) return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef SOFTDEVICE_PRESENT
 | 
					
						
							|  |  |  |   if ( is_sd_enabled() ) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     (void)sd_clock_hfclk_request(); | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-11 00:01:12 +07:00
										 |  |  |   nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKSTARTED); | 
					
						
							|  |  |  |   nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTART); | 
					
						
							| 
									
										
										
										
											2019-08-05 21:54:20 +07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void hfclk_disable(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #ifdef SOFTDEVICE_PRESENT
 | 
					
						
							|  |  |  |   if ( is_sd_enabled() ) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     (void)sd_clock_hfclk_release(); | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-11 00:01:12 +07:00
										 |  |  |   nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTOP); | 
					
						
							| 
									
										
										
										
											2019-08-05 21:54:20 +07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Power & Clock Peripheral on nRF5x to manage USB
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // USB Bus power is managed by Power module, there are 3 VBUS power events:
 | 
					
						
							|  |  |  | // Detected, Ready, Removed. Upon these power events, This function will
 | 
					
						
							|  |  |  | // enable ( or disable ) usb & hfclk peripheral, set the usb pin pull up
 | 
					
						
							|  |  |  | // accordingly to the controller Startup/Standby Sequence in USBD 51.4 specs.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Therefore this function must be called to handle USB power event by
 | 
					
						
							|  |  |  | // - nrfx_power_usbevt_init() : if Softdevice is not used or enabled
 | 
					
						
							|  |  |  | // - SoftDevice SOC event : if SD is used and enabled
 | 
					
						
							|  |  |  | void tusb_hal_nrf_power_event (uint32_t event) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-08-05 22:09:37 +07:00
										 |  |  |   // Value is chosen to be as same as NRFX_POWER_USB_EVT_* in nrfx_power.h
 | 
					
						
							|  |  |  |   enum { | 
					
						
							| 
									
										
										
										
											2019-08-05 22:31:41 +07:00
										 |  |  |     USB_EVT_DETECTED = 0, | 
					
						
							|  |  |  |     USB_EVT_REMOVED = 1, | 
					
						
							|  |  |  |     USB_EVT_READY = 2 | 
					
						
							| 
									
										
										
										
											2019-08-05 22:09:37 +07:00
										 |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-05 21:54:20 +07:00
										 |  |  |   switch ( event ) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2019-08-05 22:31:41 +07:00
										 |  |  |     case USB_EVT_DETECTED: | 
					
						
							| 
									
										
										
										
											2020-08-04 14:18:12 +07:00
										 |  |  |       TU_LOG2("Power USB Detect\r\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-05 21:54:20 +07:00
										 |  |  |       if ( !NRF_USBD->ENABLE ) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         /* Prepare for READY event receiving */ | 
					
						
							| 
									
										
										
										
											2019-11-11 00:01:12 +07:00
										 |  |  |         NRF_USBD->EVENTCAUSE = USBD_EVENTCAUSE_READY_Msk; | 
					
						
							|  |  |  |         __ISB(); __DSB(); // for sync
 | 
					
						
							| 
									
										
										
										
											2019-08-05 21:54:20 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         /* Enable the peripheral */ | 
					
						
							|  |  |  |         // ERRATA 171, 187, 166
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if ( nrfx_usbd_errata_187() ) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           // CRITICAL_REGION_ENTER();
 | 
					
						
							|  |  |  |           if ( *((volatile uint32_t *) (0x4006EC00)) == 0x00000000 ) | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             *((volatile uint32_t *) (0x4006EC00)) = 0x00009375; | 
					
						
							|  |  |  |             *((volatile uint32_t *) (0x4006ED14)) = 0x00000003; | 
					
						
							|  |  |  |             *((volatile uint32_t *) (0x4006EC00)) = 0x00009375; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           else | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             *((volatile uint32_t *) (0x4006ED14)) = 0x00000003; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           // CRITICAL_REGION_EXIT();
 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if ( nrfx_usbd_errata_171() ) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           // CRITICAL_REGION_ENTER();
 | 
					
						
							|  |  |  |           if ( *((volatile uint32_t *) (0x4006EC00)) == 0x00000000 ) | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             *((volatile uint32_t *) (0x4006EC00)) = 0x00009375; | 
					
						
							|  |  |  |             *((volatile uint32_t *) (0x4006EC14)) = 0x000000C0; | 
					
						
							|  |  |  |             *((volatile uint32_t *) (0x4006EC00)) = 0x00009375; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           else | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             *((volatile uint32_t *) (0x4006EC14)) = 0x000000C0; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           // CRITICAL_REGION_EXIT();
 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-11 00:01:12 +07:00
										 |  |  |         NRF_USBD->ENABLE = 1; | 
					
						
							|  |  |  |         __ISB(); __DSB(); // for sync
 | 
					
						
							| 
									
										
										
										
											2019-08-05 21:54:20 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // Enable HFCLK
 | 
					
						
							|  |  |  |         hfclk_enable(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-05 22:31:41 +07:00
										 |  |  |     case USB_EVT_READY: | 
					
						
							| 
									
										
										
										
											2020-08-04 14:18:12 +07:00
										 |  |  |       TU_LOG2("Power USB Ready\r\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Skip if pull-up is enabled and HCLK is already running.
 | 
					
						
							|  |  |  |       // Application probably call this more than necessary.
 | 
					
						
							|  |  |  |       if ( NRF_USBD->USBPULLUP && hfclk_running() ) break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-05 21:54:20 +07:00
										 |  |  |       /* Waiting for USBD peripheral enabled */ | 
					
						
							|  |  |  |       while ( !(USBD_EVENTCAUSE_READY_Msk & NRF_USBD->EVENTCAUSE) ) { } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-11 00:01:12 +07:00
										 |  |  |       NRF_USBD->EVENTCAUSE = USBD_EVENTCAUSE_READY_Msk; | 
					
						
							|  |  |  |       __ISB(); __DSB(); // for sync
 | 
					
						
							| 
									
										
										
										
											2019-08-05 21:54:20 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       if ( nrfx_usbd_errata_171() ) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         // CRITICAL_REGION_ENTER();
 | 
					
						
							|  |  |  |         if ( *((volatile uint32_t *) (0x4006EC00)) == 0x00000000 ) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           *((volatile uint32_t *) (0x4006EC00)) = 0x00009375; | 
					
						
							|  |  |  |           *((volatile uint32_t *) (0x4006EC14)) = 0x00000000; | 
					
						
							|  |  |  |           *((volatile uint32_t *) (0x4006EC00)) = 0x00009375; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           *((volatile uint32_t *) (0x4006EC14)) = 0x00000000; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // CRITICAL_REGION_EXIT();
 | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if ( nrfx_usbd_errata_187() ) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         // CRITICAL_REGION_ENTER();
 | 
					
						
							|  |  |  |         if ( *((volatile uint32_t *) (0x4006EC00)) == 0x00000000 ) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           *((volatile uint32_t *) (0x4006EC00)) = 0x00009375; | 
					
						
							|  |  |  |           *((volatile uint32_t *) (0x4006ED14)) = 0x00000000; | 
					
						
							|  |  |  |           *((volatile uint32_t *) (0x4006EC00)) = 0x00009375; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           *((volatile uint32_t *) (0x4006ED14)) = 0x00000000; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         // CRITICAL_REGION_EXIT();
 | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if ( nrfx_usbd_errata_166() ) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         *((volatile uint32_t *) (NRF_USBD_BASE + 0x800)) = 0x7E3; | 
					
						
							|  |  |  |         *((volatile uint32_t *) (NRF_USBD_BASE + 0x804)) = 0x40; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-11 00:01:12 +07:00
										 |  |  |         __ISB(); __DSB(); | 
					
						
							| 
									
										
										
										
											2019-08-05 21:54:20 +07:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-11 00:01:12 +07:00
										 |  |  |       // ISO buffer Lower half for IN, upper half for OUT
 | 
					
						
							|  |  |  |       NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_HalfIN; | 
					
						
							| 
									
										
										
										
											2019-08-05 21:54:20 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       // Enable interrupt
 | 
					
						
							|  |  |  |       NRF_USBD->INTENSET = USBD_INTEN_USBRESET_Msk | USBD_INTEN_EPDATA_Msk | | 
					
						
							|  |  |  |           USBD_INTEN_EP0SETUP_Msk | USBD_INTEN_EP0DATADONE_Msk | USBD_INTEN_ENDEPIN0_Msk | USBD_INTEN_ENDEPOUT0_Msk; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Enable interrupt, priorities should be set by application
 | 
					
						
							|  |  |  |       NVIC_ClearPendingIRQ(USBD_IRQn); | 
					
						
							|  |  |  |       NVIC_EnableIRQ(USBD_IRQn); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Wait for HFCLK
 | 
					
						
							|  |  |  |       while ( !hfclk_running() ) { } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Enable pull up
 | 
					
						
							| 
									
										
										
										
											2019-11-11 00:01:12 +07:00
										 |  |  |       NRF_USBD->USBPULLUP = 1; | 
					
						
							|  |  |  |       __ISB(); __DSB(); // for sync
 | 
					
						
							| 
									
										
										
										
											2019-08-05 21:54:20 +07:00
										 |  |  |     break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-05 22:31:41 +07:00
										 |  |  |     case USB_EVT_REMOVED: | 
					
						
							| 
									
										
										
										
											2020-08-04 14:18:12 +07:00
										 |  |  |       TU_LOG2("Power USB Removed\r\n"); | 
					
						
							| 
									
										
										
										
											2019-08-05 21:54:20 +07:00
										 |  |  |       if ( NRF_USBD->ENABLE ) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         // Abort all transfers
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Disable pull up
 | 
					
						
							| 
									
										
										
										
											2019-11-11 00:01:12 +07:00
										 |  |  |         NRF_USBD->USBPULLUP = 0; | 
					
						
							|  |  |  |         __ISB(); __DSB(); // for sync
 | 
					
						
							| 
									
										
										
										
											2019-08-05 21:54:20 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // Disable Interrupt
 | 
					
						
							|  |  |  |         NVIC_DisableIRQ(USBD_IRQn); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // disable all interrupt
 | 
					
						
							|  |  |  |         NRF_USBD->INTENCLR = NRF_USBD->INTEN; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-11 00:01:12 +07:00
										 |  |  |         NRF_USBD->ENABLE = 0; | 
					
						
							|  |  |  |         __ISB(); __DSB(); // for sync
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-05 21:54:20 +07:00
										 |  |  |         hfclk_disable(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-01 12:02:59 +07:00
										 |  |  |         dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) ? true : false); | 
					
						
							| 
									
										
										
										
											2019-08-05 21:54:20 +07:00
										 |  |  |       } | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     default: break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-26 22:54:34 +07:00
										 |  |  | #endif
 |