summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhathach <[email protected]>2018-06-23 13:20:07 +0700
committerhathach <[email protected]>2018-06-23 13:20:07 +0700
commit84ef486418fe1d1e83217c8bdc55aaad2456a5fd (patch)
tree636992bf4f879a3b66ae06615d0289f16d3e0b8e /src
parentb9f8575e2d0632b2b4a2358cf181c276c49eca2f (diff)
enhance and fix bug with dcd for nrf5x
fix issue with large enough bulk out.
Diffstat (limited to 'src')
-rw-r--r--src/portable/nordic/nrf5x/dcd_nrf5x.c124
1 files changed, 67 insertions, 57 deletions
diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c
index ca6c152cd..3d3fbdc80 100644
--- a/src/portable/nordic/nrf5x/dcd_nrf5x.c
+++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c
@@ -47,6 +47,7 @@
#include "nrf_drv_usbd_errata.h"
#include "device/dcd.h"
+#include "device/usbd_pvt.h" // to use defer function helper
/*------------------------------------------------------------------*/
/* MACRO TYPEDEF CONSTANT ENUM
@@ -70,8 +71,8 @@ typedef struct
uint16_t actual_len;
uint8_t mps; // max packet size
- // FIXME nrf52840 auto ACK OUT packet after DMA is done
- bool data_received;
+ // nrf52840 will auto ACK OUT packet after DMA is done
+ volatile bool data_received; // indicate packet is already ACK
} nom_xfer_t;
@@ -140,29 +141,34 @@ void dcd_set_config (uint8_t rhport, uint8_t config_num)
/*------------------------------------------------------------------*/
/* Control
*------------------------------------------------------------------*/
-static void edpt_dma_start(uint8_t epnum, uint8_t dir)
+static void edpt_dma_start(volatile uint32_t* reg_startep)
{
- // Only one dma could be active, TODO resolve when this is called in ISR and dma is running
- while ( _dcd.dma_running )
+ // Only one dma can be active
+ if ( _dcd.dma_running )
{
- TU_ASSERT ( 0 == (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk), );
+ if (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk)
+ {
+ // If called within ISR, use usbd task to defer later
+ usbd_defer_func( (osal_task_func_t) edpt_dma_start, (void*) reg_startep, true );
+ return;
+ }
+ else
+ {
+ // Otherwise simply block wait
+ while ( _dcd.dma_running ) { }
+ }
}
_dcd.dma_running = true;
- if ( dir == TUSB_DIR_OUT )
- {
- NRF_USBD->TASKS_STARTEPOUT[epnum] = 1;
- } else
- {
- NRF_USBD->TASKS_STARTEPIN[epnum] = 1;
- }
-
+ (*reg_startep) = 1;
__ISB(); __DSB();
}
static void edpt_dma_end(void)
{
+ TU_ASSERT(_dcd.dma_running, );
+
_dcd.dma_running = false;
}
@@ -184,7 +190,7 @@ static void xact_control_start(void)
NRF_USBD->EPIN[0].PTR = (uint32_t) _dcd.control.buffer;
NRF_USBD->EPIN[0].MAXCNT = xact_len;
- edpt_dma_start(0, TUSB_DIR_IN);
+ edpt_dma_start(&NRF_USBD->TASKS_STARTEPIN[0]);
}
_dcd.control.buffer += xact_len;
@@ -231,7 +237,8 @@ static inline nom_xfer_t* get_td(uint8_t epnum, uint8_t dir)
*/
static void xact_out_prepare(uint8_t epnum)
{
- // Write any value to size will allow hw to ACK (accept data)
+ // 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();
}
@@ -246,7 +253,7 @@ static void xact_out_dma(uint8_t epnum)
NRF_USBD->EPOUT[epnum].PTR = (uint32_t) xfer->buffer;
NRF_USBD->EPOUT[epnum].MAXCNT = xact_len;
- edpt_dma_start(epnum, TUSB_DIR_OUT);
+ edpt_dma_start(&NRF_USBD->TASKS_STARTEPOUT[epnum]);
xfer->buffer += xact_len;
xfer->actual_len += xact_len;
@@ -271,7 +278,7 @@ static void xact_in_prepare(uint8_t epnum)
xfer->buffer += xact_len;
- edpt_dma_start(epnum, TUSB_DIR_IN);
+ edpt_dma_start(&NRF_USBD->TASKS_STARTEPIN[epnum]);
}
bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
@@ -314,10 +321,8 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
{
if ( xfer->data_received )
{
- xfer->data_received = false;
-
- // FIXME nrf52840 auto ACK OUT packet after DMA is done
- // Data already received preivously
+ // nrf52840 auto ACK OUT packet after DMA is done
+ // Data already received previously --> trigger DMA to copy to SRAM
xact_out_dma(epnum);
}else
{
@@ -421,12 +426,12 @@ void USBD_IRQHandler(void)
{
if ( _dcd.control.dir == TUSB_DIR_OUT )
{
- // OUT data from Host -> Endpoint
+ // Control OUT: data from Host -> Endpoint
// Trigger DMA to move Endpoint -> SRAM
- edpt_dma_start(0, TUSB_DIR_OUT);
+ edpt_dma_start(&NRF_USBD->TASKS_STARTEPOUT[0]);
}else
{
- // IN: data transferred from Endpoint -> Host
+ // Control IN: data transferred from Endpoint -> Host
if ( _dcd.control.actual_len < _dcd.control.total_len )
{
xact_control_start();
@@ -438,7 +443,7 @@ void USBD_IRQHandler(void)
}
}
- // OUT data moved from Endpoint -> SRAM
+ // Control OUT: data from Endpoint -> SRAM
if ( int_status & USBD_INTEN_ENDEPOUT0_Msk)
{
if ( _dcd.control.actual_len < _dcd.control.total_len )
@@ -452,13 +457,44 @@ void USBD_IRQHandler(void)
}
/*------------- Bulk/Interrupt Transfer -------------*/
+
+ /* Bulk/Int OUT: data from DMA -> SRAM
+ * 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
+ */
+ for(uint8_t epnum=1; epnum<8; epnum++)
+ {
+ if ( BIT_TEST_(int_status, USBD_INTEN_ENDEPOUT0_Pos+epnum) )
+ {
+ nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_OUT);
+
+ uint8_t const xact_len = NRF_USBD->EPOUT[epnum].AMOUNT;
+
+ xfer->data_received = false;
+
+ // Transfer complete if transaction len < Max Packet Size or total len is transferred
+ if ( (xact_len == xfer->mps) && (xfer->actual_len < xfer->total_len) )
+ {
+ // Prepare for next transaction
+ xact_out_prepare(epnum);
+ }else
+ {
+ xfer->total_len = xfer->actual_len;
+
+ // BULK/INT OUT complete
+ dcd_xfer_complete(0, epnum, xfer->actual_len, true);
+ }
+ }
+ }
+
if ( int_status & USBD_INTEN_EPDATA_Msk)
{
uint32_t data_status = NRF_USBD->EPDATASTATUS;
nrf_usbd_epdatastatus_clear(data_status);
- // In: data from Endpoint -> Host
+ // Bulk/Int In: data from Endpoint -> Host
for(uint8_t epnum=1; epnum<8; epnum++)
{
if ( BIT_TEST_(data_status, epnum ) )
@@ -469,17 +505,17 @@ void USBD_IRQHandler(void)
if ( xfer->actual_len < xfer->total_len )
{
- // more to xfer
+ // prepare next transaction
xact_in_prepare(epnum);
} else
{
- // BULK/INT IN complete
+ // Bulk/Int IN complete
dcd_xfer_complete(0, epnum | TUSB_DIR_IN_MASK, xfer->actual_len, true);
}
}
}
- // OUT: data from Host -> Endpoint
+ // Bulk/Int OUT: data from Host -> Endpoint
for(uint8_t epnum=1; epnum<8; epnum++)
{
if ( BIT_TEST_(data_status, 16+epnum ) )
@@ -491,8 +527,7 @@ void USBD_IRQHandler(void)
xact_out_dma(epnum);
}else
{
- // FIXME nrf52840 auto ACK OUT packet after DMA is done
-
+ // Data overflow !!! Nah, nrf52840 will auto ACK OUT packet after DMA is done
// Mark this endpoint with data received
xfer->data_received = true;
}
@@ -500,31 +535,6 @@ void USBD_IRQHandler(void)
}
}
- // OUT: data from DMA -> SRAM
- for(uint8_t epnum=1; epnum<8; epnum++)
- {
- if ( BIT_TEST_(int_status, USBD_INTEN_ENDEPOUT0_Pos+epnum) )
- {
- nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_OUT);
-
- uint8_t const xact_len = NRF_USBD->EPOUT[epnum].AMOUNT;
-
- // Transfer complete if transaction len < Max Packet Size or total len is transferred
- if ( (xact_len == xfer->mps) && (xfer->actual_len < xfer->total_len) )
- {
- // Prepare for more data from Host -> Endpoint
- xact_out_prepare(epnum);
- }else
- {
- xfer->total_len = xfer->actual_len;
-
- // BULK/INT OUT complete
- dcd_xfer_complete(0, epnum, xfer->actual_len, true);
- }
- }
- }
-
-
// SOF interrupt
if ( int_status & USBD_INTEN_SOF_Msk )
{