mirror of
https://github.com/hathach/tinyusb.git
synced 2025-01-31 05:52:55 +08:00
enhance and fix bug with dcd for nrf5x
fix issue with large enough bulk out.
This commit is contained in:
parent
b9f8575e2d
commit
84ef486418
@ -47,6 +47,7 @@
|
|||||||
#include "nrf_drv_usbd_errata.h"
|
#include "nrf_drv_usbd_errata.h"
|
||||||
|
|
||||||
#include "device/dcd.h"
|
#include "device/dcd.h"
|
||||||
|
#include "device/usbd_pvt.h" // to use defer function helper
|
||||||
|
|
||||||
/*------------------------------------------------------------------*/
|
/*------------------------------------------------------------------*/
|
||||||
/* MACRO TYPEDEF CONSTANT ENUM
|
/* MACRO TYPEDEF CONSTANT ENUM
|
||||||
@ -70,8 +71,8 @@ typedef struct
|
|||||||
uint16_t actual_len;
|
uint16_t actual_len;
|
||||||
uint8_t mps; // max packet size
|
uint8_t mps; // max packet size
|
||||||
|
|
||||||
// FIXME nrf52840 auto ACK OUT packet after DMA is done
|
// nrf52840 will auto ACK OUT packet after DMA is done
|
||||||
bool data_received;
|
volatile bool data_received; // indicate packet is already ACK
|
||||||
|
|
||||||
} nom_xfer_t;
|
} nom_xfer_t;
|
||||||
|
|
||||||
@ -140,29 +141,34 @@ void dcd_set_config (uint8_t rhport, uint8_t config_num)
|
|||||||
/*------------------------------------------------------------------*/
|
/*------------------------------------------------------------------*/
|
||||||
/* Control
|
/* 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
|
// Only one dma can be active
|
||||||
while ( _dcd.dma_running )
|
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;
|
_dcd.dma_running = true;
|
||||||
|
|
||||||
if ( dir == TUSB_DIR_OUT )
|
(*reg_startep) = 1;
|
||||||
{
|
|
||||||
NRF_USBD->TASKS_STARTEPOUT[epnum] = 1;
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
NRF_USBD->TASKS_STARTEPIN[epnum] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
__ISB(); __DSB();
|
__ISB(); __DSB();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void edpt_dma_end(void)
|
static void edpt_dma_end(void)
|
||||||
{
|
{
|
||||||
|
TU_ASSERT(_dcd.dma_running, );
|
||||||
|
|
||||||
_dcd.dma_running = false;
|
_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].PTR = (uint32_t) _dcd.control.buffer;
|
||||||
NRF_USBD->EPIN[0].MAXCNT = xact_len;
|
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;
|
_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)
|
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;
|
NRF_USBD->SIZE.EPOUT[epnum] = 0;
|
||||||
__ISB(); __DSB();
|
__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].PTR = (uint32_t) xfer->buffer;
|
||||||
NRF_USBD->EPOUT[epnum].MAXCNT = xact_len;
|
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->buffer += xact_len;
|
||||||
xfer->actual_len += xact_len;
|
xfer->actual_len += xact_len;
|
||||||
@ -271,7 +278,7 @@ static void xact_in_prepare(uint8_t epnum)
|
|||||||
|
|
||||||
xfer->buffer += xact_len;
|
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)
|
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 )
|
if ( xfer->data_received )
|
||||||
{
|
{
|
||||||
xfer->data_received = false;
|
// nrf52840 auto ACK OUT packet after DMA is done
|
||||||
|
// Data already received previously --> trigger DMA to copy to SRAM
|
||||||
// FIXME nrf52840 auto ACK OUT packet after DMA is done
|
|
||||||
// Data already received preivously
|
|
||||||
xact_out_dma(epnum);
|
xact_out_dma(epnum);
|
||||||
}else
|
}else
|
||||||
{
|
{
|
||||||
@ -421,12 +426,12 @@ void USBD_IRQHandler(void)
|
|||||||
{
|
{
|
||||||
if ( _dcd.control.dir == TUSB_DIR_OUT )
|
if ( _dcd.control.dir == TUSB_DIR_OUT )
|
||||||
{
|
{
|
||||||
// OUT data from Host -> Endpoint
|
// Control OUT: data from Host -> Endpoint
|
||||||
// Trigger DMA to move Endpoint -> SRAM
|
// Trigger DMA to move Endpoint -> SRAM
|
||||||
edpt_dma_start(0, TUSB_DIR_OUT);
|
edpt_dma_start(&NRF_USBD->TASKS_STARTEPOUT[0]);
|
||||||
}else
|
}else
|
||||||
{
|
{
|
||||||
// IN: data transferred from Endpoint -> Host
|
// Control IN: data transferred from Endpoint -> Host
|
||||||
if ( _dcd.control.actual_len < _dcd.control.total_len )
|
if ( _dcd.control.actual_len < _dcd.control.total_len )
|
||||||
{
|
{
|
||||||
xact_control_start();
|
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 ( int_status & USBD_INTEN_ENDEPOUT0_Msk)
|
||||||
{
|
{
|
||||||
if ( _dcd.control.actual_len < _dcd.control.total_len )
|
if ( _dcd.control.actual_len < _dcd.control.total_len )
|
||||||
@ -452,55 +457,12 @@ void USBD_IRQHandler(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*------------- Bulk/Interrupt Transfer -------------*/
|
/*------------- Bulk/Interrupt Transfer -------------*/
|
||||||
if ( int_status & USBD_INTEN_EPDATA_Msk)
|
|
||||||
{
|
|
||||||
uint32_t data_status = NRF_USBD->EPDATASTATUS;
|
|
||||||
|
|
||||||
nrf_usbd_epdatastatus_clear(data_status);
|
/* Bulk/Int OUT: data from DMA -> SRAM
|
||||||
|
* Note: Since nrf controller auto ACK next packet without SW awareness
|
||||||
// In: data from Endpoint -> Host
|
* We must handle this stage before Host -> Endpoint just in case
|
||||||
for(uint8_t epnum=1; epnum<8; epnum++)
|
* 2 event happens at once
|
||||||
{
|
*/
|
||||||
if ( BIT_TEST_(data_status, epnum ) )
|
|
||||||
{
|
|
||||||
nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_IN);
|
|
||||||
|
|
||||||
xfer->actual_len += NRF_USBD->EPIN[epnum].MAXCNT;
|
|
||||||
|
|
||||||
if ( xfer->actual_len < xfer->total_len )
|
|
||||||
{
|
|
||||||
// more to xfer
|
|
||||||
xact_in_prepare(epnum);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
// BULK/INT IN complete
|
|
||||||
dcd_xfer_complete(0, epnum | TUSB_DIR_IN_MASK, xfer->actual_len, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// OUT: data from Host -> Endpoint
|
|
||||||
for(uint8_t epnum=1; epnum<8; epnum++)
|
|
||||||
{
|
|
||||||
if ( BIT_TEST_(data_status, 16+epnum ) )
|
|
||||||
{
|
|
||||||
nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_OUT);
|
|
||||||
|
|
||||||
if (xfer->actual_len < xfer->total_len)
|
|
||||||
{
|
|
||||||
xact_out_dma(epnum);
|
|
||||||
}else
|
|
||||||
{
|
|
||||||
// FIXME nrf52840 auto ACK OUT packet after DMA is done
|
|
||||||
|
|
||||||
// Mark this endpoint with data received
|
|
||||||
xfer->data_received = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// OUT: data from DMA -> SRAM
|
|
||||||
for(uint8_t epnum=1; epnum<8; epnum++)
|
for(uint8_t epnum=1; epnum<8; epnum++)
|
||||||
{
|
{
|
||||||
if ( BIT_TEST_(int_status, USBD_INTEN_ENDEPOUT0_Pos+epnum) )
|
if ( BIT_TEST_(int_status, USBD_INTEN_ENDEPOUT0_Pos+epnum) )
|
||||||
@ -509,10 +471,12 @@ void USBD_IRQHandler(void)
|
|||||||
|
|
||||||
uint8_t const xact_len = NRF_USBD->EPOUT[epnum].AMOUNT;
|
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
|
// Transfer complete if transaction len < Max Packet Size or total len is transferred
|
||||||
if ( (xact_len == xfer->mps) && (xfer->actual_len < xfer->total_len) )
|
if ( (xact_len == xfer->mps) && (xfer->actual_len < xfer->total_len) )
|
||||||
{
|
{
|
||||||
// Prepare for more data from Host -> Endpoint
|
// Prepare for next transaction
|
||||||
xact_out_prepare(epnum);
|
xact_out_prepare(epnum);
|
||||||
}else
|
}else
|
||||||
{
|
{
|
||||||
@ -524,6 +488,52 @@ void USBD_IRQHandler(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( int_status & USBD_INTEN_EPDATA_Msk)
|
||||||
|
{
|
||||||
|
uint32_t data_status = NRF_USBD->EPDATASTATUS;
|
||||||
|
|
||||||
|
nrf_usbd_epdatastatus_clear(data_status);
|
||||||
|
|
||||||
|
// Bulk/Int In: data from Endpoint -> Host
|
||||||
|
for(uint8_t epnum=1; epnum<8; epnum++)
|
||||||
|
{
|
||||||
|
if ( BIT_TEST_(data_status, epnum ) )
|
||||||
|
{
|
||||||
|
nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_IN);
|
||||||
|
|
||||||
|
xfer->actual_len += NRF_USBD->EPIN[epnum].MAXCNT;
|
||||||
|
|
||||||
|
if ( xfer->actual_len < xfer->total_len )
|
||||||
|
{
|
||||||
|
// prepare next transaction
|
||||||
|
xact_in_prepare(epnum);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
// Bulk/Int IN complete
|
||||||
|
dcd_xfer_complete(0, epnum | TUSB_DIR_IN_MASK, xfer->actual_len, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bulk/Int OUT: data from Host -> Endpoint
|
||||||
|
for(uint8_t epnum=1; epnum<8; epnum++)
|
||||||
|
{
|
||||||
|
if ( BIT_TEST_(data_status, 16+epnum ) )
|
||||||
|
{
|
||||||
|
nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_OUT);
|
||||||
|
|
||||||
|
if (xfer->actual_len < xfer->total_len)
|
||||||
|
{
|
||||||
|
xact_out_dma(epnum);
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
// Data overflow !!! Nah, nrf52840 will auto ACK OUT packet after DMA is done
|
||||||
|
// Mark this endpoint with data received
|
||||||
|
xfer->data_received = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SOF interrupt
|
// SOF interrupt
|
||||||
if ( int_status & USBD_INTEN_SOF_Msk )
|
if ( int_status & USBD_INTEN_SOF_Msk )
|
||||||
|
Loading…
x
Reference in New Issue
Block a user