summaryrefslogtreecommitdiff
path: root/tinyusb
diff options
context:
space:
mode:
authorhathach <[email protected]>2018-04-14 03:39:01 +0700
committerhathach <[email protected]>2018-04-14 03:39:01 +0700
commit8af60fded39cf0d6a8736c8b01a8b49ca77f13cb (patch)
tree40ff0d19061dc0d0949e1b56e88ae0a2f80d5e26 /tinyusb
parente7d7cb222a32f768b47e6e39d92d12ed187a7055 (diff)
add Errata 104 for out transfer, seems to work with cdc bootloader
Diffstat (limited to 'tinyusb')
-rw-r--r--tinyusb/portable/nordic/nrf5x/dcd_nrf5x.c104
1 files changed, 64 insertions, 40 deletions
diff --git a/tinyusb/portable/nordic/nrf5x/dcd_nrf5x.c b/tinyusb/portable/nordic/nrf5x/dcd_nrf5x.c
index 2f7d97172..735e04d71 100644
--- a/tinyusb/portable/nordic/nrf5x/dcd_nrf5x.c
+++ b/tinyusb/portable/nordic/nrf5x/dcd_nrf5x.c
@@ -74,6 +74,7 @@ typedef struct
// FIXME Errata 104 walkaround
uint16_t frame_num;
+ uint8_t prev_size;
} nom_xfer_t;
/*static*/ struct
@@ -142,7 +143,10 @@ void dcd_set_config (uint8_t rhport, uint8_t config_num)
static void edpt_dma_start(uint8_t epnum, uint8_t dir)
{
// Only one dma could be active, TODO resolve when this is called in ISR and dma is running
- while ( _dcd.dma_running ) { }
+ while ( _dcd.dma_running )
+ {
+ TU_ASSERT ( 0 == (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk), );
+ }
_dcd.dma_running = true;
@@ -187,25 +191,6 @@ static void control_xact_start(void)
_dcd.control.len -= xact_len;
}
-//static void control_xact_done(void)
-//{
-// if ( _dcd_data.control.xfer_len > 0 )
-// {
-// if ( _dcd_data.control.dir == TUSB_DIR_OUT )
-// {
-// // out control need to wait for END EPOUT event before updating Pointer
-// edpt_dma_start(0, TUSB_DIR_OUT);
-// }else
-// {
-// control_xact_start();
-// }
-// }else
-// {
-// dcd_xfer_complete(0, 0, 0, true);
-// }
-//}
-
-
bool dcd_control_xfer (uint8_t rhport, tusb_dir_t dir, uint8_t * buffer, uint16_t length)
{
(void) rhport;
@@ -310,7 +295,8 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
// FIXME Errata 104 walkaround
if ( nrf_drv_usbd_errata_104() )
{
- xfer->frame_num = (uint16_t) NRF_USBD->FRAMECNTR;
+ xfer->frame_num = (uint16_t) NRF_USBD->FRAMECNTR;
+ xfer->prev_size = NRF_USBD->SIZE.EPOUT[epnum];
}
normal_xact_start(epnum, dir);
@@ -360,22 +346,35 @@ bool dcd_edpt_busy (uint8_t rhport, uint8_t ep_addr)
/*------------------------------------------------------------------*/
/*
*------------------------------------------------------------------*/
+
+static uint16_t frame_sofar(uint16_t fr)
+{
+ uint16_t diff = (uint16_t) NRF_USBD->FRAMECNTR;
+
+ if ( diff > fr )
+ {
+ diff -= fr;
+ }else
+ {
+ diff = (diff + 1024) - fr; // Frame counter cap at 1024
+ }
+}
+
void USBD_IRQHandler(void)
{
uint32_t const inten = NRF_USBD->INTEN;
uint32_t int_status = 0;
- volatile uint32_t* regclr = &NRF_USBD->EVENTS_USBRESET;
+ volatile uint32_t* regevt = &NRF_USBD->EVENTS_USBRESET;
for(int i=0; i<32; i++)
{
- if ( BIT_TEST_(inten, i) && regclr[i] )
+ if ( BIT_TEST_(inten, i) && regevt[i] )
{
int_status |= BIT_(i);
- // nrf_usbd_event_clear()
- regclr[i] = 0;
-
+ // event clear
+ regevt[i] = 0;
__ISB(); __DSB();
}
}
@@ -426,9 +425,9 @@ void USBD_IRQHandler(void)
}
}
+ // OUT data moved from Endpoint -> SRAM
if ( int_status & USBD_INTEN_ENDEPOUT0_Msk)
{
- // OUT data moved from Endpoint -> SRAM
if ( _dcd.control.len > 0 )
{
control_xact_start();
@@ -476,6 +475,14 @@ void USBD_IRQHandler(void)
uint8_t const xact_len = NRF_USBD->SIZE.EPOUT[epnum];
+ TU_ASSERT(xfer->actual_len < xfer->total_len, );
+ // FIXME Errata 104 walkaround
+ if ( nrf_drv_usbd_errata_104() )
+ {
+ xfer->prev_size = xact_len;
+ xfer->frame_num = (uint16_t) NRF_USBD->FRAMECNTR;
+ }
+
// Trigger DMA move data from Endpoint -> SRAM
NRF_USBD->EPOUT[epnum].PTR = (uint32_t) xfer->buffer;
NRF_USBD->EPOUT[epnum].MAXCNT = xact_len;
@@ -516,12 +523,39 @@ void USBD_IRQHandler(void)
// SOF interrupt
if ( int_status & USBD_INTEN_SOF_Msk )
{
-#if 0
+ dcd_bus_event(0, USBD_BUS_EVENT_SOF);
+
+#if 1
// FIXME Errata 104 The EPDATA event might not be generated, and the related update of EPDATASTATUS does not occur.
// There is no way for software to tell if a xfer is complete or not.
// Walkaround: we will asssume an non-control IN transfer is always complete after 10 frames
if ( nrf_drv_usbd_errata_104() )
{
+ // Check all OUT transfer, if the SIZE changes --> consider it is complete
+ for (int ep=1; ep<= 8; ep++)
+ {
+ nom_xfer_t* xfer = get_td(ep, TUSB_DIR_OUT);
+ if ((xfer->actual_len < xfer->total_len) && (xfer->prev_size != NRF_USBD->SIZE.EPOUT[ep]) )
+ {
+ if ( frame_sofar(xfer->frame_num) > 2)
+ {
+ uint8_t const xact_len = NRF_USBD->SIZE.EPOUT[ep];
+ xfer->prev_size = xact_len;
+ xfer->frame_num = (uint16_t) NRF_USBD->FRAMECNTR;
+
+ // Trigger DMA move data from Endpoint -> SRAM
+ NRF_USBD->EPOUT[ep].PTR = (uint32_t) xfer->buffer;
+ NRF_USBD->EPOUT[ep].MAXCNT = xact_len;
+
+ edpt_dma_start(ep, TUSB_DIR_OUT);
+
+ xfer->buffer += xact_len;
+ xfer->actual_len += xact_len;
+ }
+ }
+ }
+
+#if 0
// Check all the queued IN transfer, retire all transfer if 10 frames has passed
for (int ep=1; ep<= 8; ep++)
{
@@ -529,28 +563,18 @@ void USBD_IRQHandler(void)
if (xfer->actual_len < xfer->total_len)
{
- uint16_t diff = (uint16_t) NRF_USBD->FRAMECNTR;
-
- if ( diff > xfer->frame_num )
- {
- diff -= xfer->frame_num;
- }else
- {
- diff = (diff + 1024) - xfer->frame_num; // Frame counter cap at 1024
- }
-
// Walkaround, mark this transfer as complete
- if (diff > 10)
+ if (frame_sofar(xfer->frame_num) > 10)
{
xfer->actual_len = xfer->total_len;
dcd_xfer_complete(0, ep | TUSB_DIR_IN_MASK, xfer->actual_len, true);
}
}
}
+#endif
}
#endif
- dcd_bus_event(0, USBD_BUS_EVENT_SOF);
}