summaryrefslogtreecommitdiff
path: root/src/portable
diff options
context:
space:
mode:
authorhathach <[email protected]>2018-11-20 11:06:16 +0700
committerGitHub <[email protected]>2018-11-20 11:06:16 +0700
commitaa71b8fd874901347dedf4046a74d686907cf147 (patch)
treebcc958c04628507c72879ead57766d0bc732d588 /src/portable
parent5757918df4a3cc4561775db61d9f720df8b23c31 (diff)
parent5e65886fdd2bc5bac4ee9335fff1726f9382c109 (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.c7
-rw-r--r--src/portable/nordic/nrf5x/dcd_nrf5x.c267
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)
{