From 2f0fcf80e0b2d49116a019c02da5bc63dadc763b Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 20 Mar 2018 18:33:06 +0700 Subject: [PATCH] nrf52 cdc example work on nrf52840pdk - add tud_cdc_flush(), auto flush with sof is enabled by default. - --- hw/mcu/nordic/nrf52/tusb_port/dcd_nrf52.c | 56 +++++++++++++++++------ tinyusb/class/cdc/cdc_device.c | 20 +++++--- tinyusb/class/cdc/cdc_device.h | 12 +++-- tinyusb/tusb_dcd.h | 4 +- 4 files changed, 64 insertions(+), 28 deletions(-) diff --git a/hw/mcu/nordic/nrf52/tusb_port/dcd_nrf52.c b/hw/mcu/nordic/nrf52/tusb_port/dcd_nrf52.c index 3377f30a6..b65caf807 100644 --- a/hw/mcu/nordic/nrf52/tusb_port/dcd_nrf52.c +++ b/hw/mcu/nordic/nrf52/tusb_port/dcd_nrf52.c @@ -134,12 +134,10 @@ static void power_usb_event_handler(nrf_drv_power_usb_evt_t event) nrf_usbd_isosplit_set(NRF_USBD_ISOSPLIT_Half); - // Enable interrupt + // Enable interrupt. SOF is used as CDC auto flush NRF_USBD->INTENSET = USBD_INTEN_USBRESET_Msk | USBD_INTEN_USBEVENT_Msk | USBD_INTEN_ACCESSFAULT_Msk | - USBD_INTEN_EP0SETUP_Msk | USBD_INTEN_EP0DATADONE_Msk | - USBD_INTEN_ENDEPIN0_Msk | USBD_INTEN_ENDEPOUT0_Msk | - /*USBD_INTEN_STARTED_Msk |*/ USBD_INTEN_EPDATA_Msk ; - //USBD_INTEN_SOF_Msk + USBD_INTEN_EP0SETUP_Msk | USBD_INTEN_EP0DATADONE_Msk | USBD_INTEN_ENDEPIN0_Msk | USBD_INTEN_ENDEPOUT0_Msk | + USBD_INTEN_EPDATA_Msk | USBD_INTEN_SOF_Msk; // if (enable_sof || nrf_drv_usbd_errata_104()) // { @@ -200,7 +198,7 @@ bool tusb_dcd_init (uint8_t port) { .handler = power_usb_event_handler }; - VERIFY( NRF_SUCCESS == nrf_drv_power_usbevt_init(&config) ); + return ( NRF_SUCCESS == nrf_drv_power_usbevt_init(&config) ); } void tusb_dcd_connect (uint8_t port) @@ -215,7 +213,6 @@ void tusb_dcd_disconnect (uint8_t port) void tusb_dcd_set_address (uint8_t port, uint8_t dev_addr) { (void) port; - // Set Address is automatically update by hw controller } @@ -223,7 +220,6 @@ void tusb_dcd_set_config (uint8_t port, uint8_t config_num) { (void) port; (void) config_num; - // Nothing to do } @@ -330,16 +326,24 @@ void tusb_dcd_control_stall (uint8_t port) *------------------------------------------------------------------*/ static void normal_xact_start(uint8_t epnum, uint8_t dir) { - // Each transaction is up to Max Packet Size nom_xfer_t* xfer = &_dcd.xfer[dir][epnum-1]; + // Each transaction is up to Max Packet Size uint8_t const xact_len = min16_of(xfer->total_len - xfer->actual_len, xfer->mps); if ( dir == TUSB_DIR_OUT ) { + // HW issue on nrf5284 sample, SIZE.EPOUT won't trigger ACK as spec + // use the back door interface as sdk for walk around + #if 0 // Overwrite size will allow hw to accept data NRF_USBD->SIZE.EPOUT[epnum] = 0; __ISB(); __DSB(); + #else + *((volatile uint32_t *)(NRF_USBD_BASE + 0x800)) = 0x7C5 + 2*epnum; + *((volatile uint32_t *)(NRF_USBD_BASE + 0x804)) = 0; + (void) (((volatile uint32_t *)(NRF_USBD_BASE + 0x804))); + #endif }else { NRF_USBD->EPIN[epnum].PTR = (uint32_t) xfer->buffer; @@ -413,10 +417,19 @@ void tusb_dcd_edpt_clear_stall (uint8_t port, uint8_t ep_addr) } -// TODO may remove bool tusb_dcd_edpt_busy (uint8_t port, uint8_t ep_addr) { - return true; + (void) port; + + // USBD shouldn't check control endpoint state + if ( 0 == ep_addr ) return false; + + uint8_t const epnum = edpt_number(ep_addr); + uint8_t const dir = edpt_dir(ep_addr); + + nom_xfer_t* xfer = &_dcd.xfer[dir][epnum-1]; + + return xfer->actual_len < xfer->total_len; } /*------------------------------------------------------------------*/ @@ -443,7 +456,6 @@ void USBD_IRQHandler(void) } /*------------- Interrupt Processing -------------*/ - if ( int_status & USBD_INTEN_USBRESET_Msk ) { bus_reset(); @@ -451,6 +463,11 @@ void USBD_IRQHandler(void) tusb_dcd_bus_event(0, USBD_BUS_EVENT_RESET); } + if ( int_status & USBD_INTEN_SOF_Msk ) + { + tusb_dcd_bus_event(0, USBD_BUS_EVENT_SOF); + } + if ( int_status & EDPT_END_ALL_MASK ) { // DMA complete move data from SRAM -> Endpoint @@ -524,7 +541,7 @@ void USBD_IRQHandler(void) normal_xact_start(epnum, TUSB_DIR_IN); } else { - // xfer complete + // BULK/INT IN complete tusb_dcd_xfer_complete(0, epnum | TUSB_DIR_IN_MASK, xfer->actual_len, true); } } @@ -562,10 +579,23 @@ void USBD_IRQHandler(void) if ( (NRF_USBD->EPOUT[epnum].AMOUNT == xfer->mps) && (xfer->actual_len < xfer->total_len) ) { // Allow Host -> Endpoint + + // HW issue on nrf5284 sample, SIZE.EPOUT won't trigger ACK as spec + // use the back door interface as sdk for walk around + #if 0 + // Overwrite size will allow hw to accept data NRF_USBD->SIZE.EPOUT[epnum] = 0; __ISB(); __DSB(); + #else + *((volatile uint32_t *)(NRF_USBD_BASE + 0x800)) = 0x7C5 + 2*epnum; + *((volatile uint32_t *)(NRF_USBD_BASE + 0x804)) = 0; + (void) (((volatile uint32_t *)(NRF_USBD_BASE + 0x804))); + #endif }else { + xfer->total_len = xfer->actual_len; + + // BULK/INT OUT complete tusb_dcd_xfer_complete(0, epnum, xfer->actual_len, true); } } diff --git a/tinyusb/class/cdc/cdc_device.c b/tinyusb/class/cdc/cdc_device.c index d798560be..a4f934e83 100644 --- a/tinyusb/class/cdc/cdc_device.c +++ b/tinyusb/class/cdc/cdc_device.c @@ -280,18 +280,24 @@ tusb_error_t cdcd_xfer_cb(uint8_t port, uint8_t ep_addr, tusb_event_t event, uin return TUSB_ERROR_NONE; } -void cdcd_sof(uint8_t port) +bool tud_n_cdc_flush (uint8_t port) { - if ( !tud_n_cdc_connected(port) ) return; + VERIFY( tud_n_cdc_connected(port) ); uint8_t edpt = cdcd_data[port].ep_addr[CDC_PIPE_DATA_IN]; - if ( !tusb_dcd_edpt_busy(port, edpt) ) - { - uint16_t count = fifo_read_n(&_tx_ff, _tmp_tx_buf, sizeof(_tmp_tx_buf)); + VERIFY( !tusb_dcd_edpt_busy(port, edpt) ); - TU_ASSERT( tusb_dcd_edpt_xfer(port, edpt, _tmp_tx_buf, count, false), TUSB_ERROR_DCD_EDPT_XFER); - } + + uint16_t count = fifo_read_n(&_tx_ff, _tmp_tx_buf, sizeof(_tmp_tx_buf)); + TU_ASSERT( tusb_dcd_edpt_xfer(port, edpt, _tmp_tx_buf, count, false) ); + + return true; +} + +void cdcd_sof(uint8_t port) +{ + tud_n_cdc_flush(port); } #endif diff --git a/tinyusb/class/cdc/cdc_device.h b/tinyusb/class/cdc/cdc_device.h index 4ae9be7c1..44768d1a2 100644 --- a/tinyusb/class/cdc/cdc_device.h +++ b/tinyusb/class/cdc/cdc_device.h @@ -63,18 +63,20 @@ uint32_t tud_n_cdc_read (uint8_t port, void* buffer, uint32_t bufsize); uint32_t tud_n_cdc_write_char (uint8_t port, char ch); uint32_t tud_n_cdc_write (uint8_t port, void const* buffer, uint32_t bufsize); +bool tud_n_cdc_flush (uint8_t port); //--------------------------------------------------------------------+ // APPLICATION API (Single Port) //--------------------------------------------------------------------+ -static inline bool tud_cdc_connected (void) { return tud_n_cdc_connected(0); } -static inline uint32_t tud_cdc_available (void) { return tud_n_cdc_available(0); } +static inline bool tud_cdc_connected (void) { return tud_n_cdc_connected(0); } +static inline uint32_t tud_cdc_available (void) { return tud_n_cdc_available(0); } -static inline int tud_cdc_read_char (void) { return tud_n_cdc_read_char(0); } -static inline uint32_t tud_cdc_read (void* buffer, uint32_t bufsize) { return tud_n_cdc_read(0, buffer, bufsize); } +static inline int tud_cdc_read_char (void) { return tud_n_cdc_read_char(0); } +static inline uint32_t tud_cdc_read (void* buffer, uint32_t bufsize) { return tud_n_cdc_read(0, buffer, bufsize); } -static inline uint32_t tud_cdc_write_char (char ch) { return tud_n_cdc_write_char(0, ch); } +static inline uint32_t tud_cdc_write_char (char ch) { return tud_n_cdc_write_char(0, ch); } static inline uint32_t tud_cdc_write (void const* buffer, uint32_t bufsize) { return tud_n_cdc_write(0, buffer, bufsize); } +static inline bool tud_cdc_flush (void) { return tud_n_cdc_flush(0); } //--------------------------------------------------------------------+ // APPLICATION CALLBACK API diff --git a/tinyusb/tusb_dcd.h b/tinyusb/tusb_dcd.h index 635522b95..5f79693ca 100644 --- a/tinyusb/tusb_dcd.h +++ b/tinyusb/tusb_dcd.h @@ -87,13 +87,11 @@ void tusb_dcd_control_stall (uint8_t port); bool tusb_dcd_edpt_open (uint8_t port, tusb_descriptor_endpoint_t const * p_endpoint_desc); bool tusb_dcd_edpt_xfer (uint8_t port, uint8_t edpt_addr, uint8_t * buffer, uint16_t total_bytes, bool int_on_complete); bool tusb_dcd_edpt_queue_xfer (uint8_t port, uint8_t edpt_addr, uint8_t * buffer, uint16_t total_bytes); // only queue, not transferring yet +bool tusb_dcd_edpt_busy (uint8_t port, uint8_t edpt_addr); void tusb_dcd_edpt_stall (uint8_t port, uint8_t edpt_addr); void tusb_dcd_edpt_clear_stall (uint8_t port, uint8_t edpt_addr); -// TODO may remove -bool tusb_dcd_edpt_busy (uint8_t port, uint8_t edpt_addr); - #ifdef __cplusplus } #endif