Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The video capture example exceeds the Metro M0 RAM capacity.
13 changes: 11 additions & 2 deletions src/arduino/Adafruit_USBD_CDC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,11 +266,18 @@ int Adafruit_USBD_CDC::availableForWrite(void) {

extern "C" {

// Optional application observer. The Arduino CDC wrapper retains ownership of
// tud_cdc_line_state_cb() so 1200-baud bootloader touch remains intact.
__attribute__((weak)) void tud_cdc_line_state_app_cb(uint8_t instance, bool dtr,
bool rts) {
(void)instance;
(void)dtr;
(void)rts;
}

// Invoked when cdc when line state changed e.g connected/disconnected
// Use to reset to DFU when disconnect with 1200 bps
void tud_cdc_line_state_cb(uint8_t instance, bool dtr, bool rts) {
(void)rts;

// DTR = false is counted as disconnected
if (!dtr) {
// touch1200 only with first CDC instance (Serial)
Expand All @@ -283,6 +290,8 @@ void tud_cdc_line_state_cb(uint8_t instance, bool dtr, bool rts) {
}
}
}

tud_cdc_line_state_app_cb(instance, dtr, rts);
}
}

Expand Down
13 changes: 11 additions & 2 deletions src/arduino/Adafruit_USBH_Host.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,11 +273,20 @@ void tuh_max3421_int_api(uint8_t rhport, bool enabled) {
(void)host;

#ifdef ARDUINO_ARCH_SAMD
//--- SAMD51 ---//
#ifdef __SAMD51__
//--- SAMD51/SAME51 ---//
#if TU_CHECK_MCU(OPT_MCU_SAMD51)
const IRQn_Type irq =
(IRQn_Type)(EIC_0_IRQn + g_APinDescription[host->_intr].ulExtInt);

if (enabled) {
NVIC_EnableIRQ(irq);
} else {
NVIC_DisableIRQ(irq);
}
#elif TU_CHECK_MCU(OPT_MCU_SAME5X)
const IRQn_Type irq =
(IRQn_Type)(EIC_EXTINT_0_IRQn + g_APinDescription[host->_intr].ulExtInt);

if (enabled) {
NVIC_EnableIRQ(irq);
} else {
Expand Down
39 changes: 35 additions & 4 deletions src/arduino/ports/samd/Adafruit_TinyUSB_samd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,23 @@
//--------------------------------------------------------------------+
extern "C" {

#if CFG_TUSB_MCU == OPT_MCU_SAMD51 || CFG_TUSB_MCU == OPT_MCU_SAME5X
#if TU_CHECK_MCU(OPT_MCU_SAMD51)

// SAMD51
void USB_0_Handler(void) { tud_int_handler(0); }
void USB_1_Handler(void) { tud_int_handler(0); }
void USB_2_Handler(void) { tud_int_handler(0); }
void USB_3_Handler(void) { tud_int_handler(0); }

#elif CFG_TUSB_MCU == OPT_MCU_SAMD21
#elif TU_CHECK_MCU(OPT_MCU_SAME5X)

// SAME53/54
void USB_OTHER_Handler(void) { tud_int_handler(0); }
void USB_SOF_HSOF_Handler(void) { tud_int_handler(0); }
void USB_TRCPT0_Handler(void) { tud_int_handler(0); }
void USB_TRCPT1_Handler(void) { tud_int_handler(0); }

#elif TU_CHECK_MCU(OPT_MCU_SAMD21)

// SAMD21
void USB_Handler(void) { tud_int_handler(0); }
Expand All @@ -61,7 +69,7 @@ void TinyUSB_Port_InitDevice(uint8_t rhport) {
(void)rhport;

/* Enable USB clock */
#if defined(__SAMD51__)
#if TU_CHECK_MCU(OPT_MCU_SAMD51)
MCLK->APBBMASK.reg |= MCLK_APBBMASK_USB;
MCLK->AHBMASK.reg |= MCLK_AHBMASK_USB;

Expand All @@ -84,6 +92,29 @@ void TinyUSB_Port_InitDevice(uint8_t rhport) {
NVIC_SetPriority(USB_1_IRQn, 0UL);
NVIC_SetPriority(USB_2_IRQn, 0UL);
NVIC_SetPriority(USB_3_IRQn, 0UL);
#elif TU_CHECK_MCU(OPT_MCU_SAME5X)
MCLK_REGS->MCLK_APBBMASK |= MCLK_APBBMASK_USB_Msk;
MCLK_REGS->MCLK_AHBMASK |= MCLK_AHBMASK_USB_Msk;

// Set up the USB DP/DN pins
PORT_REGS->GROUP[0].PORT_PINCFG[PIN_PA24H_USB_DM] |= PORT_PINCFG_PMUXEN_Msk;
PORT_REGS->GROUP[0].PORT_PMUX[PIN_PA24H_USB_DM / 2] &=
~(0xF << (4 * (PIN_PA24H_USB_DM & 0x01u)));
PORT_REGS->GROUP[0].PORT_PMUX[PIN_PA24H_USB_DM / 2] |=
MUX_PA24H_USB_DM << (4 * (PIN_PA24H_USB_DM & 0x01u));
PORT_REGS->GROUP[0].PORT_PINCFG[PIN_PA25H_USB_DP] |= PORT_PINCFG_PMUXEN_Msk;
PORT_REGS->GROUP[0].PORT_PMUX[PIN_PA25H_USB_DP / 2] &=
~(0xF << (4 * (PIN_PA25H_USB_DP & 0x01u)));
PORT_REGS->GROUP[0].PORT_PMUX[PIN_PA25H_USB_DP / 2] |=
MUX_PA25H_USB_DP << (4 * (PIN_PA25H_USB_DP & 0x01u));

GCLK_REGS->GCLK_PCHCTRL[USB_GCLK_ID] =
GCLK_PCHCTRL_GEN_GCLK1 | GCLK_PCHCTRL_CHEN_Msk;

NVIC_SetPriority(USB_OTHER_IRQn, 0UL);
NVIC_SetPriority(USB_SOF_HSOF_IRQn, 0UL);
NVIC_SetPriority(USB_TRCPT0_IRQn, 0UL);
NVIC_SetPriority(USB_TRCPT1_IRQn, 0UL);
#else
PM->APBBMASK.reg |= PM_APBBMASK_USB;

Expand Down Expand Up @@ -126,7 +157,7 @@ void TinyUSB_Port_EnterDFU(void) {
}

uint8_t TinyUSB_Port_GetSerialNumber(uint8_t serial_id[16]) {
#ifdef __SAMD51__
#if TU_CHECK_MCU(OPT_MCU_SAMD51, OPT_MCU_SAME5X)
uint32_t *id_addresses[4] = {(uint32_t *)0x008061FC, (uint32_t *)0x00806010,
(uint32_t *)0x00806014, (uint32_t *)0x00806018};
#else // samd21
Expand Down
4 changes: 3 additions & 1 deletion src/arduino/ports/samd/tusb_config_samd.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@ extern "C" {
//--------------------------------------------------------------------
// COMMON CONFIGURATION
//--------------------------------------------------------------------
#ifdef __SAMD51__
#if defined(__SAMD51__) || defined(__SAME51__)
#define CFG_TUSB_MCU OPT_MCU_SAMD51
#elif defined(__SAME53__) || defined(__SAME54__)
#define CFG_TUSB_MCU OPT_MCU_SAME5X
#else
#define CFG_TUSB_MCU OPT_MCU_SAMD21
#endif
Expand Down
110 changes: 109 additions & 1 deletion src/class/cdc/cdc_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ typedef struct {
tu_edpt_stream_t tx_stream;
tu_edpt_stream_t rx_stream;

bool direct_mode;
bool direct_tx_active;
bool direct_rx_active;
const void* direct_tx_buffer;
void* direct_rx_buffer;

uint8_t tx_ff_buf[CFG_TUD_CDC_TX_BUFSIZE];
uint8_t rx_ff_buf[CFG_TUD_CDC_RX_BUFSIZE];
} cdcd_interface_t;
Expand Down Expand Up @@ -92,6 +98,22 @@ TU_ATTR_WEAK void tud_cdc_tx_complete_cb(uint8_t itf) {
(void)itf;
}

TU_ATTR_WEAK void tud_cdc_direct_tx_complete_cb(uint8_t itf, const void* buffer, uint32_t xferred_bytes,
xfer_result_t result) {
(void)itf;
(void)buffer;
(void)xferred_bytes;
(void)result;
}

TU_ATTR_WEAK void tud_cdc_direct_rx_complete_cb(uint8_t itf, void* buffer, uint32_t xferred_bytes,
xfer_result_t result) {
(void)itf;
(void)buffer;
(void)xferred_bytes;
(void)result;
}

TU_ATTR_WEAK void tud_cdc_notify_complete_cb(uint8_t itf) {
(void)itf;
}
Expand Down Expand Up @@ -183,28 +205,85 @@ void tud_cdc_n_set_wanted_char(uint8_t itf, char wanted) {
_cdcd_itf[itf].wanted_char = wanted;
}

bool tud_cdc_n_set_direct_mode(uint8_t itf, bool enabled) {
TU_VERIFY(itf < CFG_TUD_CDC);
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
TU_VERIFY(!tu_edpt_stream_is_opened(&p_cdc->tx_stream));
TU_VERIFY(!tu_edpt_stream_is_opened(&p_cdc->rx_stream));
TU_VERIFY(!p_cdc->direct_tx_active && !p_cdc->direct_rx_active);
p_cdc->direct_mode = enabled;
return true;
}

bool tud_cdc_n_direct_write(uint8_t itf, const void* buffer, uint32_t length) {
TU_VERIFY(itf < CFG_TUD_CDC);
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
TU_VERIFY(p_cdc->direct_mode && tud_ready());
TU_VERIFY(tu_edpt_stream_is_opened(&p_cdc->tx_stream));
TU_VERIFY(buffer != NULL || length == 0);
TU_VERIFY(length <= UINT16_MAX);
TU_VERIFY(!p_cdc->direct_tx_active);
TU_VERIFY(usbd_edpt_claim(p_cdc->rhport, p_cdc->tx_stream.ep_addr));

p_cdc->direct_tx_active = true;
p_cdc->direct_tx_buffer = buffer;
if (!usbd_edpt_xfer(p_cdc->rhport, p_cdc->tx_stream.ep_addr, (uint8_t*)(uintptr_t)buffer,
(uint16_t) length, false)) {
// usbd_edpt_xfer() clears BUSY and CLAIMED when the DCD rejects submission.
p_cdc->direct_tx_active = false;
p_cdc->direct_tx_buffer = NULL;
return false;
}
return true;
}

bool tud_cdc_n_direct_read(uint8_t itf, void* buffer, uint32_t length) {
TU_VERIFY(itf < CFG_TUD_CDC);
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
TU_VERIFY(p_cdc->direct_mode && tud_ready());
TU_VERIFY(tu_edpt_stream_is_opened(&p_cdc->rx_stream));
TU_VERIFY(buffer != NULL && length > 0);
TU_VERIFY(length <= UINT16_MAX);
TU_VERIFY(!p_cdc->direct_rx_active);
TU_VERIFY(usbd_edpt_claim(p_cdc->rhport, p_cdc->rx_stream.ep_addr));

p_cdc->direct_rx_active = true;
p_cdc->direct_rx_buffer = buffer;
if (!usbd_edpt_xfer(p_cdc->rhport, p_cdc->rx_stream.ep_addr, buffer, (uint16_t) length, false)) {
// usbd_edpt_xfer() clears BUSY and CLAIMED when the DCD rejects submission.
p_cdc->direct_rx_active = false;
p_cdc->direct_rx_buffer = NULL;
return false;
}
return true;
}

//--------------------------------------------------------------------+
// READ API
//--------------------------------------------------------------------+
uint32_t tud_cdc_n_available(uint8_t itf) {
TU_VERIFY(itf < CFG_TUD_CDC, 0);
TU_VERIFY(!_cdcd_itf[itf].direct_mode, 0);
return tu_edpt_stream_read_available(&_cdcd_itf[itf].rx_stream);
}

uint32_t tud_cdc_n_read(uint8_t itf, void* buffer, uint32_t bufsize) {
TU_VERIFY(itf < CFG_TUD_CDC, 0);
cdcd_interface_t *p_cdc = &_cdcd_itf[itf];
TU_VERIFY(!p_cdc->direct_mode, 0);
return tu_edpt_stream_read(&p_cdc->rx_stream, buffer, bufsize);
}

bool tud_cdc_n_peek(uint8_t itf, uint8_t *chr) {
TU_VERIFY(itf < CFG_TUD_CDC);
TU_VERIFY(!_cdcd_itf[itf].direct_mode);
return tu_edpt_stream_peek(&_cdcd_itf[itf].rx_stream, chr);
}

void tud_cdc_n_read_flush(uint8_t itf) {
TU_VERIFY(itf < CFG_TUD_CDC, );
cdcd_interface_t *p_cdc = &_cdcd_itf[itf];
TU_VERIFY(!p_cdc->direct_mode, );
tu_edpt_stream_clear(&p_cdc->rx_stream);
tu_edpt_stream_read_xfer(&p_cdc->rx_stream);
}
Expand All @@ -215,24 +294,28 @@ void tud_cdc_n_read_flush(uint8_t itf) {
uint32_t tud_cdc_n_write(uint8_t itf, const void* buffer, uint32_t bufsize) {
TU_VERIFY(itf < CFG_TUD_CDC, 0);
cdcd_interface_t *p_cdc = &_cdcd_itf[itf];
TU_VERIFY(!p_cdc->direct_mode, 0);
return tu_edpt_stream_write(&p_cdc->tx_stream, buffer, bufsize);
}

uint32_t tud_cdc_n_write_flush(uint8_t itf) {
TU_VERIFY(itf < CFG_TUD_CDC, 0);
cdcd_interface_t *p_cdc = &_cdcd_itf[itf];
TU_VERIFY(!p_cdc->direct_mode, 0);
return tu_edpt_stream_write_xfer(&p_cdc->tx_stream);
}

uint32_t tud_cdc_n_write_available(uint8_t itf) {
TU_VERIFY(itf < CFG_TUD_CDC, 0);
cdcd_interface_t *p_cdc = &_cdcd_itf[itf];
TU_VERIFY(!p_cdc->direct_mode, 0);
return tu_edpt_stream_write_available(&p_cdc->tx_stream);
}

bool tud_cdc_n_write_clear(uint8_t itf) {
TU_VERIFY(itf < CFG_TUD_CDC);
cdcd_interface_t *p_cdc = &_cdcd_itf[itf];
TU_VERIFY(!p_cdc->direct_mode);
tu_edpt_stream_clear(&p_cdc->tx_stream);
return true;
}
Expand Down Expand Up @@ -286,6 +369,11 @@ void cdcd_reset(uint8_t rhport) {
cdcd_interface_t* p_cdc = &_cdcd_itf[i];
tu_memclr(p_cdc, ITF_MEM_RESET_SIZE);

p_cdc->direct_tx_active = false;
p_cdc->direct_rx_active = false;
p_cdc->direct_tx_buffer = NULL;
p_cdc->direct_rx_buffer = NULL;

tu_fifo_set_overwritable(&p_cdc->tx_stream.ff, CFG_TUD_CDC_TX_OVERWRITABLE_IF_NOT_CONNECTED); // back to default
tu_edpt_stream_close(&p_cdc->rx_stream);
tu_edpt_stream_close(&p_cdc->tx_stream);
Expand Down Expand Up @@ -361,7 +449,9 @@ uint16_t cdcd_open(uint8_t rhport, const tusb_desc_interface_t* itf_desc, uint16
tu_edpt_stream_clear(stream_rx);
#endif

TU_ASSERT(tu_edpt_stream_read_xfer(stream_rx) > 0, 0); // prepare for incoming data
if (!p_cdc->direct_mode) {
TU_ASSERT(tu_edpt_stream_read_xfer(stream_rx) > 0, 0); // prepare for incoming data
}
}
}

Expand Down Expand Up @@ -469,6 +559,15 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_

// Received new data, move to fifo
if (ep_addr == stream_rx->ep_addr) {
if (p_cdc->direct_mode) {
TU_ASSERT(p_cdc->direct_rx_active);
void* buffer = p_cdc->direct_rx_buffer;
p_cdc->direct_rx_active = false;
p_cdc->direct_rx_buffer = NULL;
tud_cdc_direct_rx_complete_cb(itf, buffer, xferred_bytes, result);
return true;
}

tu_edpt_stream_read_xfer_complete(stream_rx, xferred_bytes);

// Check for wanted char and invoke wanted callback
Expand Down Expand Up @@ -515,6 +614,15 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
// Data sent to host, we continue to fetch from tx fifo to send.
// Note: This will cause incorrect baudrate set in line coding. Though maybe the baudrate is not really important!
if (ep_addr == stream_tx->ep_addr) {
if (p_cdc->direct_mode) {
TU_ASSERT(p_cdc->direct_tx_active);
const void* buffer = p_cdc->direct_tx_buffer;
p_cdc->direct_tx_active = false;
p_cdc->direct_tx_buffer = NULL;
tud_cdc_direct_tx_complete_cb(itf, buffer, xferred_bytes, result);
return true;
}

tud_cdc_tx_complete_cb(itf); // invoke callback to possibly refill tx fifo

if (0 == tu_edpt_stream_write_xfer(stream_tx)) {
Expand Down
Loading
Loading