2019-03-20 16:11:42 +07:00
|
|
|
/*
|
|
|
|
* The MIT License (MIT)
|
|
|
|
*
|
|
|
|
* Copyright (c) 2018, hathach (tinyusb.org)
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
* THE SOFTWARE.
|
|
|
|
*
|
|
|
|
* This file is part of the TinyUSB stack.
|
|
|
|
*/
|
2018-03-02 13:41:35 +07:00
|
|
|
|
2018-04-12 13:14:59 +07:00
|
|
|
#include "tusb_option.h"
|
|
|
|
|
2018-07-23 15:25:45 +07:00
|
|
|
#if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_NRF5X
|
2018-03-26 22:54:34 +07:00
|
|
|
|
2018-03-13 16:30:53 +07:00
|
|
|
#include "nrf.h"
|
|
|
|
#include "nrf_power.h"
|
2018-03-13 16:59:51 +07:00
|
|
|
#include "nrf_usbd.h"
|
2018-03-20 19:52:21 +07:00
|
|
|
#include "nrf_clock.h"
|
2018-03-14 15:21:47 +07:00
|
|
|
|
2018-03-28 13:44:39 +07:00
|
|
|
#include "device/dcd.h"
|
2018-08-01 00:50:04 +07:00
|
|
|
|
|
|
|
// TODO remove later
|
|
|
|
#include "device/usbd.h"
|
2018-06-23 13:20:07 +07:00
|
|
|
#include "device/usbd_pvt.h" // to use defer function helper
|
2018-03-02 13:41:35 +07:00
|
|
|
|
2018-03-13 16:30:53 +07:00
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
/* MACRO TYPEDEF CONSTANT ENUM
|
|
|
|
*------------------------------------------------------------------*/
|
2018-03-17 02:17:40 +07:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
// Max allowed by USB specs
|
|
|
|
MAX_PACKET_SIZE = 64,
|
|
|
|
|
|
|
|
// Mask of all END event (IN & OUT) for all endpoints. ENDEPIN0-7, ENDEPOUT0-7, ENDISOIN, ENDISOOUT
|
2018-08-28 12:18:10 +07:00
|
|
|
EDPT_END_ALL_MASK = (0xff << USBD_INTEN_ENDEPIN0_Pos) | (0xff << USBD_INTEN_ENDEPOUT0_Pos) |
|
|
|
|
USBD_INTENCLR_ENDISOIN_Msk | USBD_INTEN_ENDISOOUT_Msk
|
2018-03-17 02:17:40 +07:00
|
|
|
};
|
2018-03-02 13:41:35 +07:00
|
|
|
|
2018-11-16 22:17:11 +07:00
|
|
|
// Transfer descriptor
|
2018-03-17 02:17:40 +07:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
uint8_t* buffer;
|
|
|
|
uint16_t total_len;
|
2018-08-13 18:09:29 +07:00
|
|
|
volatile uint16_t actual_len;
|
2018-03-17 02:17:40 +07:00
|
|
|
uint8_t mps; // max packet size
|
2018-04-07 15:03:56 +07:00
|
|
|
|
2018-06-23 13:20:07 +07:00
|
|
|
// nrf52840 will auto ACK OUT packet after DMA is done
|
2018-08-13 18:09:29 +07:00
|
|
|
// indicate packet is already ACK
|
|
|
|
volatile bool data_received;
|
2018-06-13 17:13:12 +07:00
|
|
|
|
2018-11-16 22:17:11 +07:00
|
|
|
} xfer_td_t;
|
2018-03-17 02:17:40 +07:00
|
|
|
|
2018-11-16 22:17:11 +07:00
|
|
|
// Data for managing dcd
|
|
|
|
static struct
|
2018-03-14 22:01:29 +07:00
|
|
|
{
|
2018-11-08 13:45:30 -08:00
|
|
|
// All 8 endpoints including control IN & OUT (offset 1)
|
2018-11-16 22:17:11 +07:00
|
|
|
xfer_td_t xfer[8][2];
|
2018-03-17 02:17:40 +07:00
|
|
|
|
2018-11-16 22:17:11 +07:00
|
|
|
// Only one DMA can run at a time
|
2018-03-15 17:09:55 +07:00
|
|
|
volatile bool dma_running;
|
2018-03-17 02:17:40 +07:00
|
|
|
}_dcd;
|
2018-03-02 13:41:35 +07:00
|
|
|
|
2018-03-15 17:09:55 +07:00
|
|
|
/*------------------------------------------------------------------*/
|
2018-11-16 22:17:11 +07:00
|
|
|
/* Control / Bulk / Interrupt (CBI) Transfer
|
2018-03-15 17:09:55 +07:00
|
|
|
*------------------------------------------------------------------*/
|
2018-03-14 15:21:47 +07:00
|
|
|
|
2018-11-16 22:17:11 +07:00
|
|
|
// helper to start DMA
|
2018-06-23 13:20:07 +07:00
|
|
|
static void edpt_dma_start(volatile uint32_t* reg_startep)
|
2018-03-15 17:09:55 +07:00
|
|
|
{
|
2018-06-23 13:20:07 +07:00
|
|
|
// Only one dma can be active
|
|
|
|
if ( _dcd.dma_running )
|
2018-04-14 03:39:01 +07:00
|
|
|
{
|
2018-06-23 13:20:07 +07:00
|
|
|
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 ) { }
|
|
|
|
}
|
2018-04-14 03:39:01 +07:00
|
|
|
}
|
2018-03-15 17:09:55 +07:00
|
|
|
|
2018-03-17 02:17:40 +07:00
|
|
|
_dcd.dma_running = true;
|
2018-03-15 17:09:55 +07:00
|
|
|
|
2018-06-23 13:20:07 +07:00
|
|
|
(*reg_startep) = 1;
|
2018-03-17 02:17:40 +07:00
|
|
|
__ISB(); __DSB();
|
2018-03-15 17:09:55 +07:00
|
|
|
}
|
|
|
|
|
2018-11-16 22:17:11 +07:00
|
|
|
// DMA is complete
|
2018-03-15 17:09:55 +07:00
|
|
|
static void edpt_dma_end(void)
|
|
|
|
{
|
2018-06-23 13:20:07 +07:00
|
|
|
TU_ASSERT(_dcd.dma_running, );
|
2018-03-17 02:17:40 +07:00
|
|
|
_dcd.dma_running = false;
|
2018-03-15 17:09:55 +07:00
|
|
|
}
|
2018-03-14 22:01:29 +07:00
|
|
|
|
2018-11-16 22:17:11 +07:00
|
|
|
// helper getting td
|
|
|
|
static inline xfer_td_t* get_td(uint8_t epnum, uint8_t dir)
|
2018-04-12 00:33:31 +07:00
|
|
|
{
|
2018-11-08 13:45:30 -08:00
|
|
|
return &_dcd.xfer[epnum][dir];
|
2018-04-12 00:33:31 +07:00
|
|
|
}
|
2018-03-17 02:17:40 +07:00
|
|
|
|
2018-11-16 22:17:11 +07:00
|
|
|
/*------------- CBI OUT Transfer -------------*/
|
2018-06-13 17:13:12 +07:00
|
|
|
|
2018-11-16 22:17:11 +07:00
|
|
|
// Prepare for a CBI transaction OUT, call at the start
|
|
|
|
// Allow ACK incoming data
|
2018-06-13 17:13:12 +07:00
|
|
|
static void xact_out_prepare(uint8_t epnum)
|
2018-04-12 00:33:31 +07:00
|
|
|
{
|
2018-11-16 21:52:10 +07:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-06-13 17:13:12 +07:00
|
|
|
__ISB(); __DSB();
|
|
|
|
}
|
2018-04-12 00:33:31 +07:00
|
|
|
|
2018-11-16 22:17:11 +07:00
|
|
|
// Start DMA to move data from Endpoint -> RAM
|
2018-06-13 17:13:12 +07:00
|
|
|
static void xact_out_dma(uint8_t epnum)
|
|
|
|
{
|
2018-11-16 22:17:11 +07:00
|
|
|
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_OUT);
|
2018-04-12 00:33:31 +07:00
|
|
|
|
2018-06-13 17:13:12 +07:00
|
|
|
uint8_t const xact_len = NRF_USBD->SIZE.EPOUT[epnum];
|
2018-03-17 02:17:40 +07:00
|
|
|
|
2018-06-13 17:13:12 +07:00
|
|
|
// Trigger DMA move data from Endpoint -> SRAM
|
|
|
|
NRF_USBD->EPOUT[epnum].PTR = (uint32_t) xfer->buffer;
|
|
|
|
NRF_USBD->EPOUT[epnum].MAXCNT = xact_len;
|
2018-03-17 02:17:40 +07:00
|
|
|
|
2018-06-23 13:20:07 +07:00
|
|
|
edpt_dma_start(&NRF_USBD->TASKS_STARTEPOUT[epnum]);
|
2018-06-13 17:13:12 +07:00
|
|
|
|
|
|
|
xfer->buffer += xact_len;
|
|
|
|
xfer->actual_len += xact_len;
|
|
|
|
}
|
|
|
|
|
2018-11-16 22:17:11 +07:00
|
|
|
/*------------- CBI IN Transfer -------------*/
|
2018-06-13 17:13:12 +07:00
|
|
|
|
2018-11-16 22:17:11 +07:00
|
|
|
// Prepare for a CBI transaction IN, call at the start
|
|
|
|
// it start DMA to transfer data from RAM -> Endpoint
|
2018-06-13 17:13:12 +07:00
|
|
|
static void xact_in_prepare(uint8_t epnum)
|
|
|
|
{
|
2018-11-16 22:17:11 +07:00
|
|
|
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_IN);
|
2018-06-13 17:13:12 +07:00
|
|
|
|
|
|
|
// Each transaction is up to Max Packet Size
|
2018-08-23 20:09:28 +07:00
|
|
|
uint8_t const xact_len = tu_min16(xfer->total_len - xfer->actual_len, xfer->mps);
|
2018-06-13 17:13:12 +07:00
|
|
|
|
|
|
|
NRF_USBD->EPIN[epnum].PTR = (uint32_t) xfer->buffer;
|
|
|
|
NRF_USBD->EPIN[epnum].MAXCNT = xact_len;
|
|
|
|
|
|
|
|
xfer->buffer += xact_len;
|
|
|
|
|
2018-06-23 13:20:07 +07:00
|
|
|
edpt_dma_start(&NRF_USBD->TASKS_STARTEPIN[epnum]);
|
2018-03-17 02:17:40 +07:00
|
|
|
}
|
|
|
|
|
2018-11-16 22:17:11 +07:00
|
|
|
//--------------------------------------------------------------------+
|
2018-12-17 12:14:11 +07:00
|
|
|
// Controller API
|
2018-11-16 22:17:11 +07:00
|
|
|
//--------------------------------------------------------------------+
|
|
|
|
bool dcd_init (uint8_t rhport)
|
|
|
|
{
|
|
|
|
(void) rhport;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-12-05 13:20:25 +07:00
|
|
|
void dcd_int_enable(uint8_t rhport)
|
|
|
|
{
|
|
|
|
(void) rhport;
|
|
|
|
NVIC_EnableIRQ(USBD_IRQn);
|
|
|
|
}
|
|
|
|
|
|
|
|
void dcd_int_disable(uint8_t rhport)
|
|
|
|
{
|
|
|
|
(void) rhport;
|
|
|
|
NVIC_DisableIRQ(USBD_IRQn);
|
|
|
|
}
|
|
|
|
|
2018-11-16 22:17:11 +07:00
|
|
|
void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
|
|
|
|
{
|
|
|
|
(void) rhport;
|
2018-11-26 12:25:28 +07:00
|
|
|
(void) dev_addr;
|
2019-03-13 23:14:48 +07:00
|
|
|
// Set Address is automatically update by hw controller, nothing to do
|
2018-11-16 22:17:11 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
void dcd_set_config (uint8_t rhport, uint8_t config_num)
|
|
|
|
{
|
|
|
|
(void) rhport;
|
|
|
|
(void) config_num;
|
|
|
|
// Nothing to do
|
|
|
|
}
|
|
|
|
|
2018-12-17 12:14:11 +07:00
|
|
|
//--------------------------------------------------------------------+
|
|
|
|
// Endpoint API
|
|
|
|
//--------------------------------------------------------------------+
|
2018-03-28 13:47:58 +07:00
|
|
|
bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
|
2018-03-14 15:21:47 +07:00
|
|
|
{
|
2018-03-23 12:17:47 +07:00
|
|
|
(void) rhport;
|
2018-03-15 13:22:28 +07:00
|
|
|
|
2018-12-12 11:51:31 +07:00
|
|
|
uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress);
|
|
|
|
uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
|
2018-03-17 02:17:40 +07:00
|
|
|
|
2018-11-08 13:45:30 -08:00
|
|
|
_dcd.xfer[epnum][dir].mps = desc_edpt->wMaxPacketSize.size;
|
2018-03-17 02:17:40 +07:00
|
|
|
|
|
|
|
if ( dir == TUSB_DIR_OUT )
|
|
|
|
{
|
2018-12-14 15:28:38 +07:00
|
|
|
NRF_USBD->INTENSET = TU_BIT(USBD_INTEN_ENDEPOUT0_Pos + epnum);
|
|
|
|
NRF_USBD->EPOUTEN |= TU_BIT(epnum);
|
2018-03-17 02:17:40 +07:00
|
|
|
}else
|
|
|
|
{
|
2018-12-14 15:28:38 +07:00
|
|
|
NRF_USBD->INTENSET = TU_BIT(USBD_INTEN_ENDEPIN0_Pos + epnum);
|
|
|
|
NRF_USBD->EPINEN |= TU_BIT(epnum);
|
2018-03-17 02:17:40 +07:00
|
|
|
}
|
|
|
|
__ISB(); __DSB();
|
|
|
|
|
2018-03-14 15:21:47 +07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-03-28 13:47:58 +07:00
|
|
|
bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
|
2018-03-14 15:21:47 +07:00
|
|
|
{
|
2018-03-23 12:17:47 +07:00
|
|
|
(void) rhport;
|
2018-03-17 02:17:40 +07:00
|
|
|
|
2018-12-12 11:51:31 +07:00
|
|
|
uint8_t const epnum = tu_edpt_number(ep_addr);
|
|
|
|
uint8_t const dir = tu_edpt_dir(ep_addr);
|
2018-03-17 02:17:40 +07:00
|
|
|
|
2018-11-16 22:17:11 +07:00
|
|
|
xfer_td_t* xfer = get_td(epnum, dir);
|
2018-04-07 15:03:56 +07:00
|
|
|
|
|
|
|
xfer->buffer = buffer;
|
|
|
|
xfer->total_len = total_bytes;
|
|
|
|
xfer->actual_len = 0;
|
|
|
|
|
2018-11-16 21:52:10 +07:00
|
|
|
// 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.
|
2018-11-23 15:22:46 +07:00
|
|
|
dcd_event_xfer_complete(0, ep_addr, 0, XFER_RESULT_SUCCESS, false);
|
2018-11-16 21:52:10 +07:00
|
|
|
}
|
|
|
|
else if ( dir == TUSB_DIR_OUT )
|
2018-06-13 17:13:12 +07:00
|
|
|
{
|
|
|
|
if ( xfer->data_received )
|
|
|
|
{
|
2018-06-23 13:20:07 +07:00
|
|
|
// nrf52840 auto ACK OUT packet after DMA is done
|
|
|
|
// Data already received previously --> trigger DMA to copy to SRAM
|
2018-06-13 17:13:12 +07:00
|
|
|
xact_out_dma(epnum);
|
2018-11-16 21:52:10 +07:00
|
|
|
}
|
|
|
|
else
|
2018-06-13 17:13:12 +07:00
|
|
|
{
|
|
|
|
xact_out_prepare(epnum);
|
|
|
|
}
|
2018-11-16 21:52:10 +07:00
|
|
|
}
|
|
|
|
else
|
2018-06-13 17:13:12 +07:00
|
|
|
{
|
|
|
|
xact_in_prepare(epnum);
|
|
|
|
}
|
2018-03-17 02:17:40 +07:00
|
|
|
|
2018-03-14 15:21:47 +07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-03-28 13:47:58 +07:00
|
|
|
void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
|
2018-03-14 15:21:47 +07:00
|
|
|
{
|
2018-03-23 12:17:47 +07:00
|
|
|
(void) rhport;
|
2018-03-21 16:08:42 +07:00
|
|
|
|
2018-12-12 11:51:31 +07:00
|
|
|
if ( tu_edpt_number(ep_addr) == 0 )
|
2018-03-21 16:08:42 +07:00
|
|
|
{
|
|
|
|
NRF_USBD->TASKS_EP0STALL = 1;
|
|
|
|
}else
|
|
|
|
{
|
|
|
|
NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_Stall << USBD_EPSTALL_STALL_Pos) | ep_addr;
|
|
|
|
}
|
2018-03-14 15:21:47 +07:00
|
|
|
|
2018-03-21 16:08:42 +07:00
|
|
|
__ISB(); __DSB();
|
2018-03-14 15:21:47 +07:00
|
|
|
}
|
|
|
|
|
2018-03-28 13:47:58 +07:00
|
|
|
void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
|
2018-03-14 15:21:47 +07:00
|
|
|
{
|
2018-03-23 12:17:47 +07:00
|
|
|
(void) rhport;
|
2018-07-25 21:21:33 +07:00
|
|
|
|
2018-12-12 11:51:31 +07:00
|
|
|
if ( tu_edpt_number(ep_addr) )
|
2018-03-21 16:08:42 +07:00
|
|
|
{
|
|
|
|
NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_UnStall << USBD_EPSTALL_STALL_Pos) | ep_addr;
|
2018-07-25 21:21:33 +07:00
|
|
|
__ISB(); __DSB();
|
2018-03-21 16:08:42 +07:00
|
|
|
}
|
2018-03-14 15:21:47 +07:00
|
|
|
}
|
|
|
|
|
2018-03-28 13:47:58 +07:00
|
|
|
bool dcd_edpt_busy (uint8_t rhport, uint8_t ep_addr)
|
2018-03-14 15:21:47 +07:00
|
|
|
{
|
2018-03-23 12:17:47 +07:00
|
|
|
(void) rhport;
|
2018-03-20 18:33:06 +07:00
|
|
|
|
|
|
|
// USBD shouldn't check control endpoint state
|
2018-12-12 11:51:31 +07:00
|
|
|
if ( 0 == tu_edpt_number(ep_addr) ) return false;
|
2018-03-20 18:33:06 +07:00
|
|
|
|
2018-12-12 11:51:31 +07:00
|
|
|
uint8_t const epnum = tu_edpt_number(ep_addr);
|
|
|
|
uint8_t const dir = tu_edpt_dir(ep_addr);
|
2018-03-20 18:33:06 +07:00
|
|
|
|
2018-11-16 22:17:11 +07:00
|
|
|
xfer_td_t* xfer = get_td(epnum, dir);
|
2018-03-20 18:33:06 +07:00
|
|
|
|
|
|
|
return xfer->actual_len < xfer->total_len;
|
2018-03-14 15:21:47 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
/*------------------------------------------------------------------*/
|
2018-11-16 22:17:11 +07:00
|
|
|
/* Interrupt Handler
|
2018-03-14 15:21:47 +07:00
|
|
|
*------------------------------------------------------------------*/
|
2018-11-16 22:17:11 +07:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-03-13 16:59:51 +07:00
|
|
|
void USBD_IRQHandler(void)
|
|
|
|
{
|
|
|
|
uint32_t const inten = NRF_USBD->INTEN;
|
|
|
|
uint32_t int_status = 0;
|
|
|
|
|
2018-04-14 03:39:01 +07:00
|
|
|
volatile uint32_t* regevt = &NRF_USBD->EVENTS_USBRESET;
|
2018-03-13 16:59:51 +07:00
|
|
|
|
2018-11-26 12:25:28 +07:00
|
|
|
for(uint8_t i=0; i<USBD_INTEN_EPDATA_Pos+1; i++)
|
2018-03-13 16:59:51 +07:00
|
|
|
{
|
2018-12-14 15:28:38 +07:00
|
|
|
if ( TU_BIT_TEST(inten, i) && regevt[i] )
|
2018-03-13 16:59:51 +07:00
|
|
|
{
|
2018-12-14 15:28:38 +07:00
|
|
|
int_status |= TU_BIT(i);
|
2018-03-13 16:59:51 +07:00
|
|
|
|
2018-04-14 03:39:01 +07:00
|
|
|
// event clear
|
|
|
|
regevt[i] = 0;
|
2018-03-17 02:17:40 +07:00
|
|
|
__ISB(); __DSB();
|
2018-03-13 16:59:51 +07:00
|
|
|
}
|
2018-03-14 22:01:29 +07:00
|
|
|
}
|
2018-03-13 16:59:51 +07:00
|
|
|
|
2018-03-14 22:01:29 +07:00
|
|
|
/*------------- Interrupt Processing -------------*/
|
|
|
|
if ( int_status & USBD_INTEN_USBRESET_Msk )
|
|
|
|
{
|
|
|
|
bus_reset();
|
2018-10-25 15:02:43 +07:00
|
|
|
dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true);
|
2018-03-14 22:01:29 +07:00
|
|
|
}
|
2018-03-14 15:21:47 +07:00
|
|
|
|
2018-03-17 02:17:40 +07:00
|
|
|
if ( int_status & EDPT_END_ALL_MASK )
|
|
|
|
{
|
|
|
|
// DMA complete move data from SRAM -> Endpoint
|
|
|
|
edpt_dma_end();
|
|
|
|
}
|
|
|
|
|
2018-11-08 13:45:30 -08:00
|
|
|
// Setup tokens are specific to the Control endpoint.
|
2018-03-14 22:01:29 +07:00
|
|
|
if ( int_status & USBD_INTEN_EP0SETUP_Msk )
|
|
|
|
{
|
2018-11-16 21:52:10 +07:00
|
|
|
uint8_t const setup[8] = {
|
2018-06-24 00:16:22 +07:00
|
|
|
NRF_USBD->BMREQUESTTYPE , NRF_USBD->BREQUEST, NRF_USBD->WVALUEL , NRF_USBD->WVALUEH,
|
|
|
|
NRF_USBD->WINDEXL , NRF_USBD->WINDEXH , NRF_USBD->WLENGTHL, NRF_USBD->WLENGTHH
|
2018-03-14 22:01:29 +07:00
|
|
|
};
|
2018-11-16 21:52:10 +07:00
|
|
|
|
|
|
|
// 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) )
|
|
|
|
{
|
2018-11-08 13:45:30 -08:00
|
|
|
dcd_event_setup_received(0, setup, true);
|
2018-03-15 13:22:28 +07:00
|
|
|
}
|
2018-03-14 22:01:29 +07:00
|
|
|
}
|
2018-03-17 02:17:40 +07:00
|
|
|
|
2018-11-16 21:52:10 +07:00
|
|
|
//--------------------------------------------------------------------+
|
|
|
|
/* 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
|
|
|
|
*/
|
|
|
|
//--------------------------------------------------------------------+
|
2018-06-23 13:20:07 +07:00
|
|
|
|
2018-11-16 21:52:10 +07:00
|
|
|
/* CBI OUT: Endpoint -> SRAM (aka transaction complete)
|
|
|
|
* Note: Since nRF controller auto ACK next packet without SW awareness
|
2018-06-23 13:20:07 +07:00
|
|
|
* We must handle this stage before Host -> Endpoint just in case
|
|
|
|
* 2 event happens at once
|
|
|
|
*/
|
2018-11-08 13:45:30 -08:00
|
|
|
for(uint8_t epnum=0; epnum<8; epnum++)
|
2018-06-23 13:20:07 +07:00
|
|
|
{
|
2018-12-14 15:28:38 +07:00
|
|
|
if ( TU_BIT_TEST(int_status, USBD_INTEN_ENDEPOUT0_Pos+epnum))
|
2018-06-23 13:20:07 +07:00
|
|
|
{
|
2018-11-16 22:17:11 +07:00
|
|
|
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_OUT);
|
2018-06-23 13:20:07 +07:00
|
|
|
uint8_t const xact_len = NRF_USBD->EPOUT[epnum].AMOUNT;
|
|
|
|
|
2018-11-16 21:52:10 +07:00
|
|
|
// Data in endpoint has been consumed
|
2018-06-23 13:20:07 +07:00
|
|
|
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
|
2018-11-23 15:22:46 +07:00
|
|
|
dcd_event_xfer_complete(0, epnum, xfer->actual_len, XFER_RESULT_SUCCESS, true);
|
2018-06-23 13:20:07 +07:00
|
|
|
}
|
|
|
|
}
|
2018-06-24 00:16:22 +07:00
|
|
|
|
2018-11-16 21:52:10 +07:00
|
|
|
// Ended event for CBI IN : nothing to do
|
2018-06-23 13:20:07 +07:00
|
|
|
}
|
|
|
|
|
2018-11-16 21:52:10 +07:00
|
|
|
// Endpoint <-> Host
|
|
|
|
if ( int_status & (USBD_INTEN_EPDATA_Msk | USBD_INTEN_EP0DATADONE_Msk) )
|
2018-03-17 02:17:40 +07:00
|
|
|
{
|
|
|
|
uint32_t data_status = NRF_USBD->EPDATASTATUS;
|
|
|
|
nrf_usbd_epdatastatus_clear(data_status);
|
|
|
|
|
2018-11-16 21:52:10 +07:00
|
|
|
// 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)
|
2018-11-08 13:45:30 -08:00
|
|
|
for(uint8_t epnum=0; epnum<8; epnum++)
|
2018-03-17 02:17:40 +07:00
|
|
|
{
|
2018-12-14 15:28:38 +07:00
|
|
|
if ( TU_BIT_TEST(data_status, epnum ) || ( epnum == 0 && is_control_in) )
|
2018-03-17 02:17:40 +07:00
|
|
|
{
|
2018-11-16 22:17:11 +07:00
|
|
|
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_IN);
|
2018-03-17 02:17:40 +07:00
|
|
|
|
|
|
|
xfer->actual_len += NRF_USBD->EPIN[epnum].MAXCNT;
|
|
|
|
|
|
|
|
if ( xfer->actual_len < xfer->total_len )
|
|
|
|
{
|
2018-06-23 13:20:07 +07:00
|
|
|
// prepare next transaction
|
2018-06-13 17:13:12 +07:00
|
|
|
xact_in_prepare(epnum);
|
2018-03-17 02:17:40 +07:00
|
|
|
} else
|
|
|
|
{
|
2018-06-23 13:20:07 +07:00
|
|
|
// Bulk/Int IN complete
|
2018-11-23 15:22:46 +07:00
|
|
|
dcd_event_xfer_complete(0, epnum | TUSB_DIR_IN_MASK, xfer->actual_len, XFER_RESULT_SUCCESS, true);
|
2018-03-17 02:17:40 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-16 21:52:10 +07:00
|
|
|
// CBI OUT: Host -> Endpoint
|
2018-11-08 13:45:30 -08:00
|
|
|
for(uint8_t epnum=0; epnum<8; epnum++)
|
2018-03-17 02:17:40 +07:00
|
|
|
{
|
2018-12-14 15:28:38 +07:00
|
|
|
if ( TU_BIT_TEST(data_status, 16+epnum ) || ( epnum == 0 && is_control_out) )
|
2018-03-17 02:17:40 +07:00
|
|
|
{
|
2018-11-16 22:17:11 +07:00
|
|
|
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_OUT);
|
2018-03-17 02:17:40 +07:00
|
|
|
|
2018-06-13 17:13:12 +07:00
|
|
|
if (xfer->actual_len < xfer->total_len)
|
|
|
|
{
|
|
|
|
xact_out_dma(epnum);
|
|
|
|
}else
|
|
|
|
{
|
2018-06-23 13:20:07 +07:00
|
|
|
// Data overflow !!! Nah, nrf52840 will auto ACK OUT packet after DMA is done
|
2018-06-13 17:13:12 +07:00
|
|
|
// Mark this endpoint with data received
|
|
|
|
xfer->data_received = true;
|
|
|
|
}
|
2018-03-17 02:17:40 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-07 15:03:56 +07:00
|
|
|
// SOF interrupt
|
|
|
|
if ( int_status & USBD_INTEN_SOF_Msk )
|
|
|
|
{
|
2018-10-25 15:02:43 +07:00
|
|
|
dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
|
2018-04-07 15:03:56 +07:00
|
|
|
}
|
2018-03-13 16:59:51 +07:00
|
|
|
}
|
2018-03-26 22:54:34 +07:00
|
|
|
|
|
|
|
#endif
|