diff options
| author | hathach <[email protected]> | 2018-11-20 11:06:16 +0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2018-11-20 11:06:16 +0700 |
| commit | aa71b8fd874901347dedf4046a74d686907cf147 (patch) | |
| tree | bcc958c04628507c72879ead57766d0bc732d588 /src/portable | |
| parent | 5757918df4a3cc4561775db61d9f720df8b23c31 (diff) | |
| parent | 5e65886fdd2bc5bac4ee9335fff1726f9382c109 (diff) | |
Merge pull request #10 from hathach/devlocal
merge for local develop
Diffstat (limited to 'src/portable')
| -rw-r--r-- | src/portable/microchip/samd51/hal_samd51.c | 7 | ||||
| -rw-r--r-- | src/portable/nordic/nrf5x/dcd_nrf5x.c | 267 |
2 files changed, 154 insertions, 120 deletions
diff --git a/src/portable/microchip/samd51/hal_samd51.c b/src/portable/microchip/samd51/hal_samd51.c index d8c71a7fe..775c29001 100644 --- a/src/portable/microchip/samd51/hal_samd51.c +++ b/src/portable/microchip/samd51/hal_samd51.c @@ -45,13 +45,6 @@ #include "tusb_hal.h" /*------------------------------------------------------------------*/ -/* MACRO TYPEDEF CONSTANT ENUM - *------------------------------------------------------------------*/ -#define USB_NVIC_PRIO 7 - -void tusb_hal_nrf_power_event(uint32_t event); - -/*------------------------------------------------------------------*/ /* TUSB HAL *------------------------------------------------------------------*/ bool tusb_hal_init(void) diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c index 74b7bb7b8..816ff62ae 100644 --- a/src/portable/nordic/nrf5x/dcd_nrf5x.c +++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c @@ -64,9 +64,7 @@ enum USBD_INTENCLR_ENDISOIN_Msk | USBD_INTEN_ENDISOOUT_Msk }; -/*------------------------------------------------------------------*/ -/* VARIABLE DECLARATION - *------------------------------------------------------------------*/ +// Transfer descriptor typedef struct { uint8_t* buffer; @@ -78,66 +76,23 @@ typedef struct // indicate packet is already ACK volatile bool data_received; -} nom_xfer_t; +} xfer_td_t; -/*static*/ struct +// Data for managing dcd +static struct { // All 8 endpoints including control IN & OUT (offset 1) - nom_xfer_t xfer[8][2]; + xfer_td_t xfer[8][2]; + // Only one DMA can run at a time volatile bool dma_running; }_dcd; -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; -} - /*------------------------------------------------------------------*/ -/* Controller API +/* Control / Bulk / Interrupt (CBI) Transfer *------------------------------------------------------------------*/ -bool dcd_init (uint8_t rhport) -{ - (void) rhport; - return true; -} - -void dcd_connect (uint8_t rhport) -{ - -} -void dcd_disconnect (uint8_t rhport) -{ -} - -void dcd_set_address (uint8_t rhport, uint8_t dev_addr) -{ - (void) rhport; - // Set Address is automatically update by hw controller -} - -void dcd_set_config (uint8_t rhport, uint8_t config_num) -{ - (void) rhport; - (void) config_num; - // Nothing to do -} - -/*------------------------------------------------------------------*/ -/* Control - *------------------------------------------------------------------*/ +// helper to start DMA static void edpt_dma_start(volatile uint32_t* reg_startep) { // Only one dma can be active @@ -162,39 +117,43 @@ static void edpt_dma_start(volatile uint32_t* reg_startep) __ISB(); __DSB(); } +// DMA is complete static void edpt_dma_end(void) { TU_ASSERT(_dcd.dma_running, ); - _dcd.dma_running = false; } -/*------------------------------------------------------------------*/ -/* - *------------------------------------------------------------------*/ - -static inline nom_xfer_t* get_td(uint8_t epnum, uint8_t dir) +// helper getting td +static inline xfer_td_t* get_td(uint8_t epnum, uint8_t dir) { return &_dcd.xfer[epnum][dir]; } -/*------------- Bulk/Int OUT transfer -------------*/ +/*------------- CBI OUT Transfer -------------*/ -/** - * Prepare Bulk/Int out transaction, Endpoint start to accept/ACK Data - * @param epnum - */ +// Prepare for a CBI transaction OUT, call at the start +// Allow ACK incoming data static void xact_out_prepare(uint8_t epnum) { - // Write zero value to SIZE register will allow hw to ACK (accept data) - // If it is not already done by DMA - NRF_USBD->SIZE.EPOUT[epnum] = 0; + 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 + NRF_USBD->SIZE.EPOUT[epnum] = 0; + } + __ISB(); __DSB(); } +// Start DMA to move data from Endpoint -> RAM static void xact_out_dma(uint8_t epnum) { - nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_OUT); + xfer_td_t* xfer = get_td(epnum, TUSB_DIR_OUT); uint8_t const xact_len = NRF_USBD->SIZE.EPOUT[epnum]; @@ -208,16 +167,13 @@ static void xact_out_dma(uint8_t epnum) xfer->actual_len += xact_len; } +/*------------- CBI IN Transfer -------------*/ -/*------------- Bulk/Int IN transfer -------------*/ - -/** - * Prepare Bulk/Int in transaction, use DMA to transfer data from Memory -> Endpoint - * @param epnum - */ +// Prepare for a CBI transaction IN, call at the start +// it start DMA to transfer data from RAM -> Endpoint static void xact_in_prepare(uint8_t epnum) { - nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_IN); + xfer_td_t* xfer = get_td(epnum, TUSB_DIR_IN); // Each transaction is up to Max Packet Size uint8_t const xact_len = tu_min16(xfer->total_len - xfer->actual_len, xfer->mps); @@ -230,6 +186,37 @@ static void xact_in_prepare(uint8_t epnum) edpt_dma_start(&NRF_USBD->TASKS_STARTEPIN[epnum]); } +//--------------------------------------------------------------------+ +// Tinyusb DCD API +//--------------------------------------------------------------------+ +bool dcd_init (uint8_t rhport) +{ + (void) rhport; + return true; +} + +void dcd_connect (uint8_t rhport) +{ + +} +void dcd_disconnect (uint8_t rhport) +{ + +} + +void dcd_set_address (uint8_t rhport, uint8_t dev_addr) +{ + (void) rhport; + // Set Address is automatically update by hw controller +} + +void dcd_set_config (uint8_t rhport, uint8_t config_num) +{ + (void) rhport; + (void) config_num; + // Nothing to do +} + bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) { (void) rhport; @@ -253,16 +240,6 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) return true; } -void control_status_token(uint8_t addr) { - NRF_USBD->EPIN[0].PTR = 0; - NRF_USBD->EPIN[0].MAXCNT = 0; - // Status Phase also require Easy DMA has to be free as well !!!! - NRF_USBD->TASKS_EP0STATUS = 1; - - // The nRF doesn't interrupt on status transmit so we queue up a success response. - dcd_event_xfer_complete(0, addr, 0, DCD_XFER_SUCCESS, false); -} - bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) { (void) rhport; @@ -270,27 +247,36 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t uint8_t const epnum = edpt_number(ep_addr); uint8_t const dir = edpt_dir(ep_addr); - nom_xfer_t* xfer = get_td(epnum, dir); + xfer_td_t* xfer = get_td(epnum, dir); xfer->buffer = buffer; xfer->total_len = total_bytes; xfer->actual_len = 0; - // How does the control endpoint handle a ZLP in the data phase? - if (epnum == 0 && total_bytes == 0) { - control_status_token(ep_addr); - } else if ( dir == TUSB_DIR_OUT ) + // Control endpoint with zero-length packet --> status stage + if ( epnum == 0 && total_bytes == 0 ) + { + // Status Phase also require Easy DMA has to be free as well !!!! + edpt_dma_start(&NRF_USBD->TASKS_EP0STATUS); + edpt_dma_end(); + + // The nRF doesn't interrupt on status transmit so we queue up a success response. + dcd_event_xfer_complete(0, ep_addr, 0, DCD_XFER_SUCCESS, false); + } + else if ( dir == TUSB_DIR_OUT ) { if ( xfer->data_received ) { // nrf52840 auto ACK OUT packet after DMA is done // Data already received previously --> trigger DMA to copy to SRAM xact_out_dma(epnum); - }else + } + else { xact_out_prepare(epnum); } - }else + } + else { xact_in_prepare(epnum); } @@ -313,7 +299,7 @@ void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr) { (void) rhport; - if ( ep_addr == 0) + if ( edpt_number(ep_addr) == 0 ) { NRF_USBD->TASKS_EP0STALL = 1; }else @@ -328,7 +314,7 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) { (void) rhport; - if ( ep_addr ) + if ( edpt_number(ep_addr) ) { NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_UnStall << USBD_EPSTALL_STALL_Pos) | ep_addr; __ISB(); __DSB(); @@ -340,19 +326,35 @@ bool dcd_edpt_busy (uint8_t rhport, uint8_t ep_addr) (void) rhport; // USBD shouldn't check control endpoint state - if ( 0 == ep_addr ) return false; + if ( 0 == edpt_number(ep_addr) ) return false; uint8_t const epnum = edpt_number(ep_addr); uint8_t const dir = edpt_dir(ep_addr); - nom_xfer_t* xfer = get_td(epnum, dir); + xfer_td_t* xfer = get_td(epnum, dir); return xfer->actual_len < xfer->total_len; } /*------------------------------------------------------------------*/ -/* +/* Interrupt Handler *------------------------------------------------------------------*/ +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; +} + void USBD_IRQHandler(void) { uint32_t const inten = NRF_USBD->INTEN; @@ -388,19 +390,52 @@ void USBD_IRQHandler(void) // Setup tokens are specific to the Control endpoint. if ( int_status & USBD_INTEN_EP0SETUP_Msk ) { - uint8_t setup[8] = { + uint8_t const setup[8] = { NRF_USBD->BMREQUESTTYPE , NRF_USBD->BREQUEST, NRF_USBD->WVALUEL , NRF_USBD->WVALUEH, NRF_USBD->WINDEXL , NRF_USBD->WINDEXH , NRF_USBD->WLENGTHL, NRF_USBD->WLENGTHH }; - if (setup[1] != TUSB_REQ_SET_ADDRESS) { + + // 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) ) + { dcd_event_setup_received(0, setup, true); } } - /*------------- Bulk/Interrupt Transfer -------------*/ + //--------------------------------------------------------------------+ + /* 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 + */ + //--------------------------------------------------------------------+ - /* Bulk/Int OUT: data from DMA -> SRAM - * Note: Since nrf controller auto ACK next packet without SW awareness + /* CBI OUT: Endpoint -> SRAM (aka transaction complete) + * Note: Since nRF controller auto ACK next packet without SW awareness * We must handle this stage before Host -> Endpoint just in case * 2 event happens at once */ @@ -408,10 +443,10 @@ void USBD_IRQHandler(void) { if ( BIT_TEST_(int_status, USBD_INTEN_ENDEPOUT0_Pos+epnum)) { - nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_OUT); - + xfer_td_t* xfer = get_td(epnum, TUSB_DIR_OUT); uint8_t const xact_len = NRF_USBD->EPOUT[epnum].AMOUNT; + // Data in endpoint has been consumed xfer->data_received = false; // Transfer complete if transaction len < Max Packet Size or total len is transferred @@ -428,21 +463,27 @@ void USBD_IRQHandler(void) } } - // Ended event for Bulk/Int : nothing to do + // Ended event for CBI IN : nothing to do } - if ( int_status & USBD_INTEN_EPDATA_Msk || int_status & USBD_INTEN_EP0DATADONE_Msk) + // Endpoint <-> Host + if ( int_status & (USBD_INTEN_EPDATA_Msk | USBD_INTEN_EP0DATADONE_Msk) ) { uint32_t data_status = NRF_USBD->EPDATASTATUS; - nrf_usbd_epdatastatus_clear(data_status); - // Bulk/Int In: data from Endpoint -> Host + // 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) for(uint8_t epnum=0; epnum<8; epnum++) { - if ( BIT_TEST_(data_status, epnum ) || (epnum == 0 && BIT_TEST_(int_status, USBD_INTEN_EP0DATADONE_Pos))) + if ( BIT_TEST_(data_status, epnum ) || ( epnum == 0 && is_control_in) ) { - nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_IN); + xfer_td_t* xfer = get_td(epnum, TUSB_DIR_IN); xfer->actual_len += NRF_USBD->EPIN[epnum].MAXCNT; @@ -458,12 +499,12 @@ void USBD_IRQHandler(void) } } - // Bulk/Int OUT: data from Host -> Endpoint + // CBI OUT: Host -> Endpoint for(uint8_t epnum=0; epnum<8; epnum++) { - if ( BIT_TEST_(data_status, 16+epnum ) ) + if ( BIT_TEST_(data_status, 16+epnum ) || ( epnum == 0 && is_control_out) ) { - nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_OUT); + xfer_td_t* xfer = get_td(epnum, TUSB_DIR_OUT); if (xfer->actual_len < xfer->total_len) { |
