From 09d8ead4b86049260dd6ee7e61d137b6bdccaa28 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Mon, 4 Jan 2021 12:02:08 +0100 Subject: [PATCH 001/121] Start changes - not yet finished --- src/device/usbd.c | 29 ++++++++++++++++++ src/device/usbd_pvt.h | 3 ++ src/portable/st/synopsys/dcd_synopsys.c | 39 +++++++++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/src/device/usbd.c b/src/device/usbd.c index 791d533ae..55e76bb66 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -1188,6 +1188,35 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t } } +bool usbd_edpt_ISO_xfer(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +{ + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + TU_LOG2(" Queue ISO EP %02X with %u bytes ... ", ep_addr, total_bytes); + + // Attempt to transfer on a busy endpoint, sound like an race condition ! + TU_ASSERT(_usbd_dev.ep_status[epnum][dir].busy == 0); + + // Set busy first since the actual transfer can be complete before dcd_edpt_xfer() could return + // and usbd task can preempt and clear the busy + _usbd_dev.ep_status[epnum][dir].busy = true; + + if ( dcd_edpt_ISO_xfer(rhport, ep_addr, ff, total_bytes) ) + { + TU_LOG2("OK\r\n"); + return true; + }else + { + // DCD error, mark endpoint as ready to allow next transfer + _usbd_dev.ep_status[epnum][dir].busy = false; + _usbd_dev.ep_status[epnum][dir].claimed = 0; + TU_LOG2("failed\r\n"); + TU_BREAKPOINT(); + return false; + } +} + bool usbd_edpt_busy(uint8_t rhport, uint8_t ep_addr) { (void) rhport; diff --git a/src/device/usbd_pvt.h b/src/device/usbd_pvt.h index 212c3a202..de2f37281 100644 --- a/src/device/usbd_pvt.h +++ b/src/device/usbd_pvt.h @@ -72,6 +72,9 @@ void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr); // Submit a usb transfer bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes); +// Submit a usb ISO transfer by use of a FIFO (ring buffer) +bool usbd_edpt_ISO_xfer(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes); + // Claim an endpoint before submitting a transfer. // If caller does not make any transfer, it must release endpoint for others. bool usbd_edpt_claim(uint8_t rhport, uint8_t ep_addr); diff --git a/src/portable/st/synopsys/dcd_synopsys.c b/src/portable/st/synopsys/dcd_synopsys.c index 35c814460..0aee6a919 100644 --- a/src/portable/st/synopsys/dcd_synopsys.c +++ b/src/portable/st/synopsys/dcd_synopsys.c @@ -28,6 +28,7 @@ */ #include "tusb_option.h" +#include "tusb_fifo.h" // Since TinyUSB doesn't use SOF for now, and this interrupt too often (1ms interval) // We disable SOF for now until needed later on @@ -134,6 +135,7 @@ static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[2]; typedef struct { uint8_t * buffer; + tu_fifo_t * ff; uint16_t total_len; uint16_t max_size; uint8_t interval; @@ -659,6 +661,38 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t return true; } +bool dcd_edpt_ISO_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +{ + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); + xfer->buffer = NULL; // Indicates a FIFO shall be used + xfer->ff = ff; + xfer->total_len = total_bytes; + + // EP0 can only handle one packet + if(epnum == 0) { + ep0_pending[dir] = total_bytes; + // Schedule the first transaction for EP0 transfer + edpt_schedule_packets(rhport, epnum, dir, 1, ep0_pending[dir]); + return true; + } + + uint16_t num_packets = (total_bytes / xfer->max_size); + uint8_t const short_packet_size = total_bytes % xfer->max_size; + + // Zero-size packet is special case. + if(short_packet_size > 0 || (total_bytes == 0)) { + num_packets++; + } + + // Schedule packets to be sent within interrupt + edpt_schedule_packets(rhport, epnum, dir, num_packets, total_bytes); + + return true; +} + static void dcd_edpt_disable (uint8_t rhport, uint8_t ep_addr, bool stall) { (void) rhport; @@ -849,6 +883,9 @@ static void handle_rxflvl_ints(uint8_t rhport, USB_OTG_OUTEndpointTypeDef * out_ { xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT); + + // TODO: TAKE CARE OF ISO FIFO! + // Read packet off RxFIFO read_fifo_packet(rhport, xfer->buffer, bcnt); @@ -960,6 +997,8 @@ static void handle_epin_ints(uint8_t rhport, USB_OTG_DeviceTypeDef * dev, USB_OT break; } + // TODO: TAKE CARE OF ISO FIFO! + // Push packet to Tx-FIFO write_fifo_packet(rhport, n, xfer->buffer, packet_size); From bdbcb8df394a14ac077e5210772cff91c1f76d25 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sun, 17 Jan 2021 11:55:33 +0100 Subject: [PATCH 002/121] Add tu_fifo_read_n_into_other_fifo() to copy into from FIFO into another Fix overflow in tu_fifo_write_n() --- src/common/tusb_fifo.c | 163 ++++++++++++++++++++++++++++++++++++----- src/common/tusb_fifo.h | 6 +- 2 files changed, 148 insertions(+), 21 deletions(-) diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 00f2434a7..a1cf0e289 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -179,7 +179,7 @@ static uint16_t get_relative_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset) return _ff_mod(advance_pointer(f, p, offset), f->depth); } -// Works on local copies of w and r +// Works on local copies of w and r - return only the difference and as such can be used to determine an overflow static inline uint16_t _tu_fifo_count(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs) { uint16_t cnt = wAbs-rAbs; @@ -287,7 +287,9 @@ static inline uint16_t _tu_fifo_remaining(tu_fifo_t* f, uint16_t wAbs, uint16_t @brief Get number of items in FIFO. As this function only reads the read and write pointers once, this function is - reentrant and thus thread and ISR save without any mutexes. + reentrant and thus thread and ISR save without any mutexes. In case an + overflow occurred, this function return f.depth at maximum. Overflows are + checked and corrected for in the read functions! @param[in] f Pointer to the FIFO buffer to manipulate @@ -297,7 +299,7 @@ static inline uint16_t _tu_fifo_remaining(tu_fifo_t* f, uint16_t wAbs, uint16_t /******************************************************************************/ uint16_t tu_fifo_count(tu_fifo_t* f) { - return _tu_fifo_count(f, f->wr_idx, f->rd_idx); + return tu_min16(_tu_fifo_count(f, f->wr_idx, f->rd_idx), f->depth); } /******************************************************************************/ @@ -361,7 +363,7 @@ uint16_t tu_fifo_remaining(tu_fifo_t* f) BE AWARE - THIS FUNCTION MIGHT NOT GIVE A CORRECT ANSWERE IN CASE WRITE POINTER "OVERFLOWS" Only one overflow is allowed for this function to work e.g. if depth = 100, you must not write more than 2*depth-1 items in one rush without updating write pointer. Otherwise - write pointer wraps and you pointer states are messed up. This can only happen if you + write pointer wraps and your pointer states are messed up. This can only happen if you use DMAs, write functions do not allow such an error. Avoid such nasty things! All reading functions (read, peek) check for overflows and correct read pointer on their own such @@ -428,24 +430,58 @@ bool tu_fifo_read(tu_fifo_t* f, void * buffer) Pointer to the FIFO buffer to manipulate @param[in] buffer The pointer to data location - @param[in] count + @param[in] n Number of element that buffer can afford @returns number of items read from the FIFO */ /******************************************************************************/ -uint16_t tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t count) +uint16_t tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n) { tu_fifo_lock(f); // TODO: Here we may distinguish for read and write pointer mutexes! // Peek the data - count = _tu_fifo_peek_at_n(f, 0, buffer, count, f->wr_idx, f->rd_idx); // f->rd_idx might get modified in case of an overflow so we can not use a local variable + n = _tu_fifo_peek_at_n(f, 0, buffer, n, f->wr_idx, f->rd_idx); // f->rd_idx might get modified in case of an overflow so we can not use a local variable // Advance read pointer - f->rd_idx = advance_pointer(f, f->rd_idx, count); + f->rd_idx = advance_pointer(f, f->rd_idx, n); tu_fifo_unlock(f); - return count; + return n; +} + +/******************************************************************************/ +/*! + @brief This function will read n elements from the array index specified by + the read pointer and increment the read index. It copies the elements + into another FIFO and as such takes care of wraps etc. + This function checks for an overflow and corrects read pointer if required. + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] f_target + Pointer to target FIFO i.e. to copy into + @param[in] offset + Position to read from in the FIFO buffer with respect to read pointer + @param[in] n + Number of items to peek + + @returns number of items read from the FIFO + */ +/******************************************************************************/ +uint16_t tu_fifo_read_n_into_other_fifo(tu_fifo_t* f, tu_fifo_t* f_target, uint16_t offset, uint16_t n) +{ + tu_fifo_lock(f); // TODO: Here we may distinguish for read and write pointer mutexes! + + // Conduct copy + n = tu_fifo_peek_n_into_other_fifo(f, f_target, offset, n); + + // Advance read pointer + f->rd_idx = advance_pointer(f, f->rd_idx, n); + + tu_fifo_unlock(f); + + return n; } /******************************************************************************/ @@ -496,6 +532,95 @@ uint16_t tu_fifo_peek_at_n(tu_fifo_t* f, uint16_t offset, void * p_buffer, uint1 return ret; } +/******************************************************************************/ +/*! + @brief Read n items without removing it from the FIFO and copy them into another FIFO. + This function checks for an overflow and corrects read pointer if required. + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] f_target + Pointer to target FIFO i.e. to copy into + @param[in] offset + Position to read from in the FIFO buffer with respect to read pointer + @param[in] n + Number of items to peek + + @returns Number of bytes written to p_buffer + */ +/******************************************************************************/ +uint16_t tu_fifo_peek_n_into_other_fifo (tu_fifo_t* f, tu_fifo_t* f_target, uint16_t offset, uint16_t n) +{ + // Copy is only possible if both FIFOs have common element size + TU_VERIFY(f->item_size == f_target->item_size); + + // Work on local copies on case any pointer changes in between (only necessary if something is written into FIFO f in the meantime) + uint16_t f_wr_idx = f->wr_idx; + uint16_t f_rd_idx = f->rd_idx; + + uint16_t cnt = _tu_fifo_count(f, f_wr_idx, f_rd_idx); + + // Check overflow and correct if required + if (cnt > f->depth) + { + _tu_fifo_correct_read_pointer(f, f->wr_idx); + f_rd_idx = f->rd_idx; + cnt = f->depth; + } + + // Skip beginning of buffer + if (cnt == 0 || offset >= cnt) return 0; + + // Check if we can read something at and after offset - if too less is available we read what remains + cnt -= offset; + if (cnt < n) { + if (cnt == 0) return 0; + n = cnt; + } + + tu_fifo_lock(f_target); // Lock both read and write pointers - in case of an overwritable FIFO both may be modified + + uint16_t wr_rel_tgt = get_relative_pointer(f_target, f_target->wr_idx, 0); + + if (!f_target->overwritable) + { + // Not overwritable limit up to full + n = tu_min16(n, tu_fifo_remaining(f_target)); + } + + // Advance write pointer - not required for later + f_target->wr_idx = advance_pointer(f_target, f_target->wr_idx, n); + + if (n >= f_target->depth) + { + offset += n - f_target->depth; + + // We start writing at the read pointer's position since we fill the complete + // buffer and we do not want to modify the read pointer within a write function! + // This would end up in a race condition with read functions! + wr_rel_tgt = get_relative_pointer(f_target, f_target->rd_idx, 0); + + n = f_target->depth; + + // Update write pointer + f_target->wr_idx = advance_pointer(f_target, f_target->rd_idx, n); + } + + // Copy linear size + uint16_t sz = f_target->depth - wr_rel_tgt; + _tu_fifo_peek_at_n(f, offset, &f_target->buffer[wr_rel_tgt], sz, f_wr_idx, f_rd_idx); + + if (n > sz) + { + // Copy remaining, now wrapped part, into target buffer + _tu_fifo_peek_at_n(f, offset + sz, f_target->buffer, n-sz, f_wr_idx, f_rd_idx); + } + + tu_fifo_unlock(f_target); + + return n; +} + /******************************************************************************/ /*! @brief Write one element into the buffer. @@ -547,9 +672,9 @@ bool tu_fifo_write(tu_fifo_t* f, const void * data) @return Number of written elements */ /******************************************************************************/ -uint16_t tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t count) +uint16_t tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n) { - if ( count == 0 ) return 0; + if ( n == 0 ) return 0; tu_fifo_lock(f); @@ -559,31 +684,31 @@ uint16_t tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t count) if (!f->overwritable) { // Not overwritable limit up to full - count = tu_min16(count, _tu_fifo_remaining(f, w, r)); + n = tu_min16(n, _tu_fifo_remaining(f, w, r)); } - else if (count > f->depth) + else if (n >= f->depth) { // Only copy last part - buf8 = buf8 + (count - f->depth) * f->item_size; - count = f->depth; + buf8 = buf8 + (n - f->depth) * f->item_size; + n = f->depth; // We start writing at the read pointer's position since we fill the complete // buffer and we do not want to modify the read pointer within a write function! // This would end up in a race condition with read functions! - f->wr_idx = r; + w = r; } uint16_t wRel = get_relative_pointer(f, w, 0); // Write data - _ff_push_n(f, buf8, count, wRel); + _ff_push_n(f, buf8, n, wRel); // Advance pointer - f->wr_idx = advance_pointer(f, w, count); + f->wr_idx = advance_pointer(f, w, n); tu_fifo_unlock(f); - return count; + return n; } /******************************************************************************/ diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h index b965386ab..260bd4227 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -101,13 +101,15 @@ static inline void tu_fifo_config_mutex(tu_fifo_t *f, tu_fifo_mutex_t mutex_hdl) #endif bool tu_fifo_write (tu_fifo_t* f, void const * p_data); -uint16_t tu_fifo_write_n (tu_fifo_t* f, void const * p_data, uint16_t count); +uint16_t tu_fifo_write_n (tu_fifo_t* f, void const * p_data, uint16_t n); bool tu_fifo_read (tu_fifo_t* f, void * p_buffer); -uint16_t tu_fifo_read_n (tu_fifo_t* f, void * p_buffer, uint16_t count); +uint16_t tu_fifo_read_n (tu_fifo_t* f, void * p_buffer, uint16_t n); +uint16_t tu_fifo_read_n_into_other_fifo (tu_fifo_t* f, tu_fifo_t* f_target, uint16_t offset, uint16_t n); bool tu_fifo_peek_at (tu_fifo_t* f, uint16_t pos, void * p_buffer); uint16_t tu_fifo_peek_at_n (tu_fifo_t* f, uint16_t pos, void * p_buffer, uint16_t n); +uint16_t tu_fifo_peek_n_into_other_fifo (tu_fifo_t* f, tu_fifo_t* f_target, uint16_t offset, uint16_t n); uint16_t tu_fifo_count (tu_fifo_t* f); bool tu_fifo_empty (tu_fifo_t* f); From 3a3ada0c57013fb64f69178a1c6299abc74e4f40 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Mon, 18 Jan 2021 17:07:15 +0100 Subject: [PATCH 003/121] Implement the usage of usbd_edpt_ISO_xfer() --- src/class/audio/audio_device.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 8581925e4..8dd1a8fef 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -32,6 +32,8 @@ * * */ +// TODO: Rename CFG_TUD_AUDIO_EPSIZE_IN to CFG_TUD_AUDIO_EP_IN_BUFFER_SIZE + #include "tusb_option.h" #if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_AUDIO) @@ -129,6 +131,7 @@ typedef struct #if CFG_TUD_AUDIO_EPSIZE_IN CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_AUDIO_EPSIZE_IN]; // Bigger makes no sense for isochronous EP's (but technically possible here) + tu_fifo_t epin_ff; #endif #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN @@ -531,7 +534,14 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint16_ // THIS FUNCTION IS NOT EXECUTED WITHIN AN INTERRUPT SO IT DOES NOT INTERRUPT tud_audio_n_write_ep_in_buffer()! AS LONG AS tud_audio_n_write_ep_in_buffer() IS NOT EXECUTED WITHIN AN INTERRUPT ALL IS FINE! // Schedule transmit - TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->epin_buf, audio->epin_buf_cnt)); + // TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->epin_buf, audio->epin_buf_cnt)); + + + TU_VERIFY(usbd_edpt_ISO_xfer(rhport, audio->ep_in, &audio->epin_ff)); + + + + // Inform how many bytes were copied *n_bytes_copied = audio->epin_buf_cnt; @@ -631,7 +641,9 @@ static bool audiod_tx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* return true; } - nByteCount = tu_fifo_read_n(&audio->tx_ff[0], audio->epin_buf, nByteCount); + nByteCount = tu_fifo_read_n_into_other_fifo(&audio->tx_ff[0], &audio->epin_ff, 0, nByteCount); +// nByteCount = tu_fifo_read_n(&audio->tx_ff[0], audio->epin_buf, nByteCount); + audio->epin_buf_cnt = nByteCount; return true; @@ -735,6 +747,10 @@ void audiod_init(void) tu_fifo_config_mutex(&audio->tx_ff[cnt], osal_mutex_create(&audio->tx_ff_mutex[cnt])); #endif } + + // Initialize IN EP FIFO + tu_fifo_config(&audio->epin_ff, &audio->epin_buf, CFG_TUD_AUDIO_EPSIZE_IN, 1, true); + #endif #if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_FIFO_SIZE @@ -765,6 +781,10 @@ void audiod_reset(uint8_t rhport) audiod_interface_t* audio = &_audiod_itf[i]; tu_memclr(audio, ITF_MEM_RESET_SIZE); +#if CFG_TUD_AUDIO_EPSIZE_IN + tu_fifo_clear(&audio->epin_ff); +#endif + #if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_FIFO_SIZE for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_TX_FIFO_COUNT; cnt++) { From 84c383061f4af9e0fa66326a09c6c332920df6a7 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Mon, 18 Jan 2021 17:08:59 +0100 Subject: [PATCH 004/121] Add tusb_fifo.h header file to dcd.h --- src/device/dcd.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/device/dcd.h b/src/device/dcd.h index b7e5a8da0..1b2d2b941 100644 --- a/src/device/dcd.h +++ b/src/device/dcd.h @@ -32,6 +32,7 @@ #define _TUSB_DCD_H_ #include "common/tusb_common.h" +#include "common/tusb_fifo.h" #ifdef __cplusplus extern "C" { @@ -133,6 +134,9 @@ void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) TU_ATTR_WEAK; // Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes); +// Submit an ISO transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack +bool dcd_edpt_ISO_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff); + // Stall endpoint void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr); From 8450bc3225856fe6f32ef8a4b3d8038163bc0cb1 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Mon, 18 Jan 2021 17:12:39 +0100 Subject: [PATCH 005/121] Add FIFO copy modes: tu_fifo_copy_mode_t Allows to copy from/to constant pointers required for STM32 hardware FIFO copies. --- src/common/tusb_fifo.c | 103 ++++++++++++++++++++++++++++++++++++++--- src/common/tusb_fifo.h | 30 ++++++++++++ 2 files changed, 127 insertions(+), 6 deletions(-) diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index a1cf0e289..522fc1883 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -76,6 +76,8 @@ bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_si f->max_pointer_idx = 2*depth - 1; // Limit index space to 2*depth - this allows for a fast "modulo" calculation but limits the maximum depth to 2^16/2 = 2^15 and buffer overflows are detectable only if overflow happens once (important for unsupervised DMA applications) f->non_used_index_space = 0xFFFF - f->max_pointer_idx; + f->rd_mode = f->wr_mode = TU_FIFO_COPY_INC; // Default copy mode is incrementing addresses + f->rd_idx = f->wr_idx = 0; tu_fifo_unlock(f); @@ -91,28 +93,117 @@ static inline uint16_t _ff_mod(uint16_t idx, uint16_t depth) return idx; } +// Intended to be used to read from hardware USB FIFO in e.g. STM32 where all data is read from a constant address +// Code adapted from dcd_synopsis.c +static void _tu_fifo_read_from_const_src_ptr(void * dst, const void * src, uint16_t len) +{ + uint8_t * dst_u8 = (uint8_t *)dst; + volatile uint32_t * rx_fifo = (volatile uint32_t *) src; + + // Reading full available 32 bit words from FIFO + uint16_t full_words = len >> 2; + for(uint16_t i = 0; i < full_words; i++) { + uint32_t tmp = *rx_fifo; + dst_u8[0] = tmp & 0x000000FF; + dst_u8[1] = (tmp & 0x0000FF00) >> 8; + dst_u8[2] = (tmp & 0x00FF0000) >> 16; + dst_u8[3] = (tmp & 0xFF000000) >> 24; + dst_u8 += 4; + } + + // Read the remaining 1-3 bytes from FIFO + uint8_t bytes_rem = len & 0x03; + if(bytes_rem != 0) { + uint32_t tmp = *rx_fifo; + dst_u8[0] = tmp & 0x000000FF; + if(bytes_rem > 1) { + dst_u8[1] = (tmp & 0x0000FF00) >> 8; + } + if(bytes_rem > 2) { + dst_u8[2] = (tmp & 0x00FF0000) >> 16; + } + } +} + +// Intended to be used to write to hardware USB FIFO in e.g. STM32 where all data is written to a constant address +// Code adapted from dcd_synopsis.c +static void _tu_fifo_write_to_const_dst_ptr(void * dst, const void * src, uint16_t len) +{ + volatile uint32_t * tx_fifo = (volatile uint32_t *) dst; + uint8_t * src_u8 = (uint8_t *)src; + + // Pushing full available 32 bit words to FIFO + uint16_t full_words = len >> 2; + for(uint16_t i = 0; i < full_words; i++){ + *tx_fifo = (src_u8[3] << 24) | (src_u8[2] << 16) | (src_u8[1] << 8) | src_u8[0]; + src_u8 += 4; + } + + // Write the remaining 1-3 bytes into FIFO + uint8_t bytes_rem = len & 0x03; + if(bytes_rem){ + uint32_t tmp_word = 0; + tmp_word |= src_u8[0]; + if(bytes_rem > 1){ + tmp_word |= src_u8[1] << 8; + } + if(bytes_rem > 2){ + tmp_word |= src_u8[2] << 16; + } + *tx_fifo = tmp_word; + } +} + // send one item to FIFO WITHOUT updating write pointer static inline void _ff_push(tu_fifo_t* f, void const * data, uint16_t wRel) { memcpy(f->buffer + (wRel * f->item_size), data, f->item_size); } +static inline void _ff_push_copy_fct(tu_fifo_t* f, void * dst, const void * src, uint16_t len) +{ + switch (f->rd_mode) + { + case TU_FIFO_COPY_INC: + memcpy(dst, src, len); + break; + + case TU_FIFO_COPY_CST: + _tu_fifo_read_from_const_src_ptr(dst, src, len); + break; + } +} + +static inline void _ff_pull_copy_fct(tu_fifo_t* f, void * dst, const void * src, uint16_t len) +{ + switch (f->wr_mode) + { + case TU_FIFO_COPY_INC: + memcpy(dst, src, len); + break; + + case TU_FIFO_COPY_CST: + _tu_fifo_write_to_const_dst_ptr(dst, src, len); + break; + } +} + // send n items to FIFO WITHOUT updating write pointer static void _ff_push_n(tu_fifo_t* f, void const * data, uint16_t n, uint16_t wRel) { if(wRel + n <= f->depth) // Linear mode only { - memcpy(f->buffer + (wRel * f->item_size), data, n*f->item_size); + _ff_push_copy_fct(f, f->buffer + (wRel * f->item_size), data, n*f->item_size); } else // Wrap around { uint16_t nLin = f->depth - wRel; // Write data to linear part of buffer - memcpy(f->buffer + (wRel * f->item_size), data, nLin*f->item_size); + _ff_push_copy_fct(f, f->buffer + (wRel * f->item_size), data, nLin*f->item_size); // Write data wrapped around - memcpy(f->buffer, ((uint8_t const*) data) + nLin*f->item_size, (n - nLin) * f->item_size); + _ff_push_copy_fct(f, f->buffer, ((uint8_t const*) data) + nLin*f->item_size, (n - nLin) * f->item_size); } } @@ -127,17 +218,17 @@ static void _ff_pull_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint16_t rRel) { if(rRel + n <= f->depth) // Linear mode only { - memcpy(p_buffer, f->buffer + (rRel * f->item_size), n*f->item_size); + _ff_pull_copy_fct(f, p_buffer, f->buffer + (rRel * f->item_size), n*f->item_size); } else // Wrap around { uint16_t nLin = f->depth - rRel; // Read data from linear part of buffer - memcpy(p_buffer, f->buffer + (rRel * f->item_size), nLin*f->item_size); + _ff_pull_copy_fct(f, p_buffer, f->buffer + (rRel * f->item_size), nLin*f->item_size); // Read data wrapped part - memcpy((uint8_t*)p_buffer + nLin*f->item_size, f->buffer, (n - nLin) * f->item_size); + _ff_pull_copy_fct(f, (uint8_t*)p_buffer + nLin*f->item_size, f->buffer, (n - nLin) * f->item_size); } } diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h index 260bd4227..2ce433718 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -55,6 +55,19 @@ extern "C" { #define tu_fifo_mutex_t osal_mutex_t #endif +/** \enum tu_fifo_copy_mode_t + * \brief Write modes intended to allow special read and write functions to be able to copy data to and from USB hardware FIFOs as needed for e.g. STM32s + */ +typedef enum +{ + TU_FIFO_COPY_INC, ///< Copy from/to an increasing source/destination address - default mode + TU_FIFO_COPY_CST, ///< Copy from/to a constant source/destination address - required for e.g. STM32 to write into USB hardware FIFO +} tu_fifo_copy_mode_t; + +//TU_FIFO_WRITE_INC_DST, ///< Write to an increasing destination address - default mode +// TU_FIFO_WRITE_CONST_DST, ///< Write to a constant destination address - required for e.g. STM32 to write into USB hardware FIFO +// TU_FIFO_READ_INC_SRC, ///< Read from an increasing source address - default mode +// TU_FIFO_READ_CONST_SRC, ///< Read from a constant source address - required for e.g. STM32 to read from USB hardware FIFO /** \struct tu_fifo_t * \brief Simple Circular FIFO @@ -72,6 +85,9 @@ typedef struct volatile uint16_t wr_idx ; ///< write pointer volatile uint16_t rd_idx ; ///< read pointer + tu_fifo_copy_mode_t wr_mode ; ///< write mode - default is TU_FIFO_COPY_INC + tu_fifo_copy_mode_t rd_mode ; ///< read mode - default is TU_FIFO_COPY_INC + #if CFG_FIFO_MUTEX tu_fifo_mutex_t mutex; #endif @@ -87,6 +103,8 @@ typedef struct .overwritable = _overwritable, \ .max_pointer_idx = 2*_depth-1, \ .non_used_index_space = 0xFFFF - 2*_depth-1, \ + .wr_mode = TU_FIFO_COPY_INC, \ + .rd_mode = TU_FIFO_COPY_INC, \ } bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable); @@ -133,6 +151,18 @@ static inline uint16_t tu_fifo_depth(tu_fifo_t* f) return f->depth; } +// When writing into the FIFO by fifo_write_n(), rd_mode determines how the pointer read from is modified +static inline void tu_fifo_set_copy_mode_read(tu_fifo_t* f, tu_fifo_copy_mode_t rd_mode) +{ + f->rd_mode = rd_mode; +} + +// When reading from the FIFO by fifo_read_n() or fifo_peek_n(), wr_mode determines how the pointer written to is modified +static inline void tu_fifo_set_copy_mode_write(tu_fifo_t* f, tu_fifo_copy_mode_t wr_mode) +{ + f->wr_mode = wr_mode; +} + #ifdef __cplusplus } #endif From 51c80630f5c67cd2f67c2282a46520ef517f7234 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Mon, 18 Jan 2021 17:13:06 +0100 Subject: [PATCH 006/121] Clean up --- src/common/tusb_fifo.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h index 2ce433718..7ece30b74 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -64,11 +64,6 @@ typedef enum TU_FIFO_COPY_CST, ///< Copy from/to a constant source/destination address - required for e.g. STM32 to write into USB hardware FIFO } tu_fifo_copy_mode_t; -//TU_FIFO_WRITE_INC_DST, ///< Write to an increasing destination address - default mode -// TU_FIFO_WRITE_CONST_DST, ///< Write to a constant destination address - required for e.g. STM32 to write into USB hardware FIFO -// TU_FIFO_READ_INC_SRC, ///< Read from an increasing source address - default mode -// TU_FIFO_READ_CONST_SRC, ///< Read from a constant source address - required for e.g. STM32 to read from USB hardware FIFO - /** \struct tu_fifo_t * \brief Simple Circular FIFO */ From 2284db1fb5d99c91b31ef7176ea04a8a01b3206a Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Mon, 18 Jan 2021 17:14:17 +0100 Subject: [PATCH 007/121] Add usbd_edpt_ISO_xfer() --- src/device/usbd.c | 6 +++--- src/device/usbd_pvt.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/device/usbd.c b/src/device/usbd.c index 05acb7019..e0546ac39 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -1206,12 +1206,12 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t } } -bool usbd_edpt_ISO_xfer(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +bool usbd_edpt_ISO_xfer(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff) { uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr); - TU_LOG2(" Queue ISO EP %02X with %u bytes ... ", ep_addr, total_bytes); + TU_LOG2(" Queue ISO EP %02X with %u bytes ... ", ep_addr, tu_fifo_count(ff)); // Attempt to transfer on a busy endpoint, sound like an race condition ! TU_ASSERT(_usbd_dev.ep_status[epnum][dir].busy == 0); @@ -1220,7 +1220,7 @@ bool usbd_edpt_ISO_xfer(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_ // and usbd task can preempt and clear the busy _usbd_dev.ep_status[epnum][dir].busy = true; - if ( dcd_edpt_ISO_xfer(rhport, ep_addr, ff, total_bytes) ) + if ( dcd_edpt_ISO_xfer(rhport, ep_addr, ff) ) { TU_LOG2("OK\r\n"); return true; diff --git a/src/device/usbd_pvt.h b/src/device/usbd_pvt.h index de2f37281..4ae55aecc 100644 --- a/src/device/usbd_pvt.h +++ b/src/device/usbd_pvt.h @@ -72,8 +72,8 @@ void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr); // Submit a usb transfer bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes); -// Submit a usb ISO transfer by use of a FIFO (ring buffer) -bool usbd_edpt_ISO_xfer(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes); +// Submit a usb ISO transfer by use of a FIFO (ring buffer) - all bytes in FIFO get transmitted +bool usbd_edpt_ISO_xfer(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff); // Claim an endpoint before submitting a transfer. // If caller does not make any transfer, it must release endpoint for others. From dff588d7727f63b7e8819a89c259b5edddb079e9 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Mon, 18 Jan 2021 17:15:23 +0100 Subject: [PATCH 008/121] Implement dcd_edpt_ISO_xfer() and adapt transmission scheme --- src/portable/st/synopsys/dcd_synopsys.c | 55 ++++++++++++++++++------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/src/portable/st/synopsys/dcd_synopsys.c b/src/portable/st/synopsys/dcd_synopsys.c index 507e5246a..49345869e 100644 --- a/src/portable/st/synopsys/dcd_synopsys.c +++ b/src/portable/st/synopsys/dcd_synopsys.c @@ -670,8 +670,13 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t return true; } -bool dcd_edpt_ISO_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +bool dcd_edpt_ISO_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff) { + // USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1 + TU_ASSERT(ff->item_size == 1); + + uint16_t total_bytes = tu_fifo_count(ff); + uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr); @@ -680,6 +685,16 @@ bool dcd_edpt_ISO_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_ xfer->ff = ff; xfer->total_len = total_bytes; + // Set copy mode to constant address - required since data copied to or from the hardware USB FIFO needs to be written at a constant address + if (dir == TUSB_DIR_IN) + { + tu_fifo_set_copy_mode_write(ff, TU_FIFO_COPY_CST); + } + else + { + tu_fifo_set_copy_mode_read(ff, TU_FIFO_COPY_CST); + } + // EP0 can only handle one packet if(epnum == 0) { ep0_pending[dir] = total_bytes; @@ -692,9 +707,7 @@ bool dcd_edpt_ISO_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_ uint8_t const short_packet_size = total_bytes % xfer->max_size; // Zero-size packet is special case. - if(short_packet_size > 0 || (total_bytes == 0)) { - num_packets++; - } + if(short_packet_size > 0 || (total_bytes == 0)) num_packets++; // Schedule packets to be sent within interrupt edpt_schedule_packets(rhport, epnum, dir, num_packets, total_bytes); @@ -900,14 +913,20 @@ static void handle_rxflvl_ints(uint8_t rhport, USB_OTG_OUTEndpointTypeDef * out_ { xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT); - - // TODO: TAKE CARE OF ISO FIFO! - // Read packet off RxFIFO - read_fifo_packet(rhport, xfer->buffer, bcnt); + if (xfer->buffer) + { + // Linear buffer + read_fifo_packet(rhport, xfer->buffer, bcnt); - // Increment pointer to xfer data - xfer->buffer += bcnt; + // Increment pointer to xfer data + xfer->buffer += bcnt; + } + else + { + // Ring buffer + tu_fifo_write_n(xfer->ff, (const void *) rx_fifo, bcnt); + } // Truncate transfer length in case of short packet if(bcnt < xfer->max_size) { @@ -1014,13 +1033,19 @@ static void handle_epin_ints(uint8_t rhport, USB_OTG_DeviceTypeDef * dev, USB_OT break; } - // TODO: TAKE CARE OF ISO FIFO! - // Push packet to Tx-FIFO - write_fifo_packet(rhport, n, xfer->buffer, packet_size); + if (xfer->buffer) + { + write_fifo_packet(rhport, n, xfer->buffer, packet_size); - // Increment pointer to xfer data - xfer->buffer += packet_size; + // Increment pointer to xfer data + xfer->buffer += packet_size; + } + else + { + usb_fifo_t tx_fifo = FIFO_BASE(rhport, n); + tu_fifo_read_n(xfer->ff, (void *) tx_fifo, packet_size); + } } // Turn off TXFE if all bytes are written. From 595a88b34c700bfdb5bf2db04c731de06a995f5f Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Mon, 18 Jan 2021 17:38:32 +0100 Subject: [PATCH 009/121] Correct include path to #include "common/tusb_fifo.h" --- src/portable/st/synopsys/dcd_synopsys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/portable/st/synopsys/dcd_synopsys.c b/src/portable/st/synopsys/dcd_synopsys.c index 49345869e..5f9dc267b 100644 --- a/src/portable/st/synopsys/dcd_synopsys.c +++ b/src/portable/st/synopsys/dcd_synopsys.c @@ -28,7 +28,7 @@ */ #include "tusb_option.h" -#include "tusb_fifo.h" +#include "common/tusb_fifo.h" // Since TinyUSB doesn't use SOF for now, and this interrupt too often (1ms interval) // We disable SOF for now until needed later on From 99e6bc37207bc3239d00fc7e47e42b8d22b8adff Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Mon, 18 Jan 2021 17:54:08 +0100 Subject: [PATCH 010/121] Explicitly add cast to uint32_t before shifting uint8 to left --- src/common/tusb_fifo.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 522fc1883..ca03864eb 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -135,7 +135,7 @@ static void _tu_fifo_write_to_const_dst_ptr(void * dst, const void * src, uint16 // Pushing full available 32 bit words to FIFO uint16_t full_words = len >> 2; for(uint16_t i = 0; i < full_words; i++){ - *tx_fifo = (src_u8[3] << 24) | (src_u8[2] << 16) | (src_u8[1] << 8) | src_u8[0]; + *tx_fifo = ((uint32_t)(src_u8[3]) << 24) | ((uint32_t)(src_u8[2]) << 16) | ((uint32_t)(src_u8[1]) << 8) | (uint32_t)src_u8[0]; src_u8 += 4; } @@ -145,10 +145,10 @@ static void _tu_fifo_write_to_const_dst_ptr(void * dst, const void * src, uint16 uint32_t tmp_word = 0; tmp_word |= src_u8[0]; if(bytes_rem > 1){ - tmp_word |= src_u8[1] << 8; + tmp_word |= (uint32_t)(src_u8[1]) << 8; } if(bytes_rem > 2){ - tmp_word |= src_u8[2] << 16; + tmp_word |= (uint32_t)(src_u8[2]) << 16; } *tx_fifo = tmp_word; } From 56edc2b2618e542b73c284a3116cf88fd70303e2 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Tue, 19 Jan 2021 10:50:19 +0100 Subject: [PATCH 011/121] Change names from edpt_ISO_xfer to edpt_iso_xfer --- src/class/audio/audio_device.c | 2 +- src/device/dcd.h | 2 +- src/device/usbd.c | 4 ++-- src/device/usbd_pvt.h | 2 +- src/portable/st/synopsys/dcd_synopsys.c | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 8dd1a8fef..616760223 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -537,7 +537,7 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint16_ // TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->epin_buf, audio->epin_buf_cnt)); - TU_VERIFY(usbd_edpt_ISO_xfer(rhport, audio->ep_in, &audio->epin_ff)); + TU_VERIFY(usbd_edpt_iso_xfer(rhport, audio->ep_in, &audio->epin_ff)); diff --git a/src/device/dcd.h b/src/device/dcd.h index 1b2d2b941..30224e16e 100644 --- a/src/device/dcd.h +++ b/src/device/dcd.h @@ -135,7 +135,7 @@ void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) TU_ATTR_WEAK; bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes); // Submit an ISO transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack -bool dcd_edpt_ISO_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff); +bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff); // Stall endpoint void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr); diff --git a/src/device/usbd.c b/src/device/usbd.c index e0546ac39..c2b5b65d1 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -1206,7 +1206,7 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t } } -bool usbd_edpt_ISO_xfer(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff) +bool usbd_edpt_iso_xfer(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff) { uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr); @@ -1220,7 +1220,7 @@ bool usbd_edpt_ISO_xfer(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff) // and usbd task can preempt and clear the busy _usbd_dev.ep_status[epnum][dir].busy = true; - if ( dcd_edpt_ISO_xfer(rhport, ep_addr, ff) ) + if ( dcd_edpt_iso_xfer(rhport, ep_addr, ff) ) { TU_LOG2("OK\r\n"); return true; diff --git a/src/device/usbd_pvt.h b/src/device/usbd_pvt.h index 4ae55aecc..1d24957a9 100644 --- a/src/device/usbd_pvt.h +++ b/src/device/usbd_pvt.h @@ -73,7 +73,7 @@ void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr); bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes); // Submit a usb ISO transfer by use of a FIFO (ring buffer) - all bytes in FIFO get transmitted -bool usbd_edpt_ISO_xfer(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff); +bool usbd_edpt_iso_xfer(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff); // Claim an endpoint before submitting a transfer. // If caller does not make any transfer, it must release endpoint for others. diff --git a/src/portable/st/synopsys/dcd_synopsys.c b/src/portable/st/synopsys/dcd_synopsys.c index 5f9dc267b..90fcd51e7 100644 --- a/src/portable/st/synopsys/dcd_synopsys.c +++ b/src/portable/st/synopsys/dcd_synopsys.c @@ -670,7 +670,7 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t return true; } -bool dcd_edpt_ISO_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff) +bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff) { // USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1 TU_ASSERT(ff->item_size == 1); From 93ec6f3735b30193f368458cf10d1af6c833c230 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Tue, 19 Jan 2021 17:10:08 +0100 Subject: [PATCH 012/121] Adjust #include "dcd.h" to "device/dcd.h", the same for usbd.h in usbd.c --- src/device/usbd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/device/usbd.c b/src/device/usbd.c index c2b5b65d1..4e18df757 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -29,9 +29,9 @@ #if TUSB_OPT_DEVICE_ENABLED #include "tusb.h" -#include "usbd.h" +#include "device/usbd.h" #include "device/usbd_pvt.h" -#include "dcd.h" +#include "device/dcd.h" #ifndef CFG_TUD_TASK_QUEUE_SZ #define CFG_TUD_TASK_QUEUE_SZ 16 From f1551d7a5fe5faccad9c1ef3f5d374869a1874e6 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Wed, 20 Jan 2021 20:14:23 +0100 Subject: [PATCH 013/121] Add __restrict keyword and memore alignment to src/dst pointer of _tu_fifo_read_from_const_src_ptr() _tu_fifo_write_to_const_dst_ptr() --- src/common/tusb_fifo.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index ca03864eb..ff2e2c6fd 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -95,9 +95,9 @@ static inline uint16_t _ff_mod(uint16_t idx, uint16_t depth) // Intended to be used to read from hardware USB FIFO in e.g. STM32 where all data is read from a constant address // Code adapted from dcd_synopsis.c -static void _tu_fifo_read_from_const_src_ptr(void * dst, const void * src, uint16_t len) +static void _tu_fifo_read_from_const_src_ptr(void * __restrict dst, const void * __restrict src, uint16_t len) { - uint8_t * dst_u8 = (uint8_t *)dst; + uint8_t CFG_TUSB_MEM_ALIGN * dst_u8 = (uint8_t *)dst; volatile uint32_t * rx_fifo = (volatile uint32_t *) src; // Reading full available 32 bit words from FIFO @@ -127,10 +127,10 @@ static void _tu_fifo_read_from_const_src_ptr(void * dst, const void * src, uint1 // Intended to be used to write to hardware USB FIFO in e.g. STM32 where all data is written to a constant address // Code adapted from dcd_synopsis.c -static void _tu_fifo_write_to_const_dst_ptr(void * dst, const void * src, uint16_t len) +static void _tu_fifo_write_to_const_dst_ptr(void * __restrict dst, const void * __restrict src, uint16_t len) { volatile uint32_t * tx_fifo = (volatile uint32_t *) dst; - uint8_t * src_u8 = (uint8_t *)src; + uint8_t CFG_TUSB_MEM_ALIGN * src_u8 = (uint8_t *)src; // Pushing full available 32 bit words to FIFO uint16_t full_words = len >> 2; From 84406f1654ca757ecd7294f4b98b56146583be49 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sun, 31 Jan 2021 19:08:23 +0100 Subject: [PATCH 014/121] Rework audio driver --- src/class/audio/audio_device.c | 422 ++++++++++++------------ src/class/audio/audio_device.h | 351 ++++++++++++-------- src/device/dcd.h | 12 +- src/device/usbd.c | 10 +- src/device/usbd_pvt.h | 2 +- src/portable/st/synopsys/dcd_synopsys.c | 8 +- 6 files changed, 442 insertions(+), 363 deletions(-) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 616760223..07bfe6158 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -32,8 +32,6 @@ * * */ -// TODO: Rename CFG_TUD_AUDIO_EPSIZE_IN to CFG_TUD_AUDIO_EP_IN_BUFFER_SIZE - #include "tusb_option.h" #if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_AUDIO) @@ -49,30 +47,17 @@ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ -#if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_FIFO_SIZE -#ifndef CFG_TUD_AUDIO_TX_FIFO_COUNT -#define CFG_TUD_AUDIO_TX_FIFO_COUNT CFG_TUD_AUDIO_N_CHANNELS_TX -#endif -#endif - -#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_FIFO_SIZE -#ifndef CFG_TUD_AUDIO_RX_FIFO_COUNT -#define CFG_TUD_AUDIO_RX_FIFO_COUNT CFG_TUD_AUDIO_N_CHANNELS_RX -#endif -#endif - typedef struct { uint8_t rhport; uint8_t const * p_desc; // Pointer pointing to Standard AC Interface Descriptor(4.7.1) - Audio Control descriptor defining audio function -#if CFG_TUD_AUDIO_EPSIZE_IN - uint8_t ep_in; // Outgoing (out of uC) audio data EP. - uint16_t epin_buf_cnt; // Count filling status of EP in buffer - this is a shared state currently and is intended to be removed once EP buffers can be implemented as FIFOs! +#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE + uint8_t ep_in; // TX audio data EP. uint8_t ep_in_as_intf_num; // Corresponding Standard AS Interface Descriptor (4.9.1) belonging to output terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero) #endif -#if CFG_TUD_AUDIO_EPSIZE_OUT +#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE uint8_t ep_out; // Incoming (into uC) audio data EP. uint8_t ep_out_as_intf_num; // Corresponding Standard AS Interface Descriptor (4.9.1) belonging to input terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero) @@ -89,25 +74,51 @@ typedef struct #if CFG_TUD_AUDIO_N_AS_INT uint8_t altSetting[CFG_TUD_AUDIO_N_AS_INT]; // We need to save the current alternate setting this way, because it is possible that there are AS interfaces which do not have an EP! #endif + /*------------- From this point, data is not cleared by bus reset -------------*/ // Buffer for control requests CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf[CFG_TUD_AUDIO_CTRL_BUF_SIZE]; - // FIFO -#if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_FIFO_SIZE - tu_fifo_t tx_ff[CFG_TUD_AUDIO_TX_FIFO_COUNT]; - CFG_TUSB_MEM_ALIGN uint8_t tx_ff_buf[CFG_TUD_AUDIO_TX_FIFO_COUNT][CFG_TUD_AUDIO_TX_FIFO_SIZE]; + // EP Transfer buffers and FIFOs +#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE + CFG_TUSB_MEM_ALIGN uint8_t ep_out_buf[CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE]; + tu_fifo_t ep_out_ff; + #if CFG_FIFO_MUTEX - osal_mutex_def_t tx_ff_mutex[CFG_TUD_AUDIO_TX_FIFO_COUNT]; + osal_mutex_def_t ep_out_ff_mutex; +#endif + +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + uint32_t fb_val; // Feedback value for asynchronous mode (in 16.16 format). +#endif + +#endif + +#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE + CFG_TUSB_MEM_ALIGN uint8_t ep_in_buf[CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE]; + tu_fifo_t ep_in_ff; + +#if CFG_FIFO_MUTEX + osal_mutex_def_t ep_in_ff_mutex; +#endif + +#endif + + // Support FIFOs +#if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE + tu_fifo_t tx_ff[CFG_TUD_AUDIO_N_CHANNELS_TX]; + CFG_TUSB_MEM_ALIGN uint8_t tx_ff_buf[CFG_TUD_AUDIO_N_CHANNELS_TX][CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE]; +#if CFG_FIFO_MUTEX + osal_mutex_def_t tx_ff_mutex[CFG_TUD_AUDIO_N_CHANNELS_TX]; #endif #endif -#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_FIFO_SIZE - tu_fifo_t rx_ff[CFG_TUD_AUDIO_RX_FIFO_COUNT]; - CFG_TUSB_MEM_ALIGN uint8_t rx_ff_buf[CFG_TUD_AUDIO_RX_FIFO_COUNT][CFG_TUD_AUDIO_RX_FIFO_SIZE]; +#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE + tu_fifo_t rx_ff[CFG_TUD_AUDIO_N_CHANNELS_RX]; + CFG_TUSB_MEM_ALIGN uint8_t rx_ff_buf[CFG_TUD_AUDIO_N_CHANNELS_RX][CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE]; #if CFG_FIFO_MUTEX - osal_mutex_def_t rx_ff_mutex[CFG_TUD_AUDIO_RX_FIFO_COUNT]; + osal_mutex_def_t rx_ff_mutex[CFG_TUD_AUDIO_N_CHANNELS_RX]; #endif #endif @@ -119,21 +130,6 @@ typedef struct #endif #endif - // Endpoint Transfer buffers -#if CFG_TUD_AUDIO_EPSIZE_OUT - CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_AUDIO_EPSIZE_OUT]; // Bigger makes no sense for isochronous EP's (but technically possible here) - -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - uint32_t fb_val; // Feedback value for asynchronous mode (in 16.16 format). -#endif - -#endif - -#if CFG_TUD_AUDIO_EPSIZE_IN - CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_AUDIO_EPSIZE_IN]; // Bigger makes no sense for isochronous EP's (but technically possible here) - tu_fifo_t epin_ff; -#endif - #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN]; #endif @@ -149,11 +145,11 @@ CFG_TUSB_MEM_SECTION audiod_interface_t _audiod_itf[CFG_TUD_AUDIO]; extern const uint16_t tud_audio_desc_lengths[]; -#if CFG_TUD_AUDIO_EPSIZE_OUT +#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE static bool audio_rx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* audio, uint8_t * buffer, uint16_t bufsize); #endif -#if CFG_TUD_AUDIO_EPSIZE_IN +#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE static bool audiod_tx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* audio); #endif @@ -167,34 +163,23 @@ static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *idxDriver); bool tud_audio_n_mounted(uint8_t itf) { + TU_VERIFY(itf < CFG_TUD_AUDIO); audiod_interface_t* audio = &_audiod_itf[itf]; -#if CFG_TUD_AUDIO_EPSIZE_OUT - if (audio->ep_out == 0) - { - return false; - } +#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE + if (audio->ep_out == 0) return false; #endif -#if CFG_TUD_AUDIO_EPSIZE_IN - if (audio->ep_in == 0) - { - return false; - } +#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE + if (audio->ep_in == 0) return false; #endif #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN - if (audio->ep_int_ctr == 0) - { - return false; - } + if (audio->ep_int_ctr == 0) return false; #endif #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - if (audio->ep_fb == 0) - { - return false; - } + if (audio->ep_fb == 0) return false; #endif return true; @@ -204,43 +189,58 @@ bool tud_audio_n_mounted(uint8_t itf) // READ API //--------------------------------------------------------------------+ -#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_FIFO_SIZE -#if CFG_TUD_AUDIO_RX_FIFO_COUNT > 1 -uint16_t tud_audio_n_available(uint8_t itf, uint8_t channelId) -{ - TU_VERIFY(channelId < CFG_TUD_AUDIO_N_CHANNELS_RX); - return tu_fifo_count(&_audiod_itf[itf].rx_ff[channelId]); -} +#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE -uint16_t tud_audio_n_read(uint8_t itf, uint8_t channelId, void* buffer, uint16_t bufsize) -{ - TU_VERIFY(channelId < CFG_TUD_AUDIO_N_CHANNELS_RX); - return tu_fifo_read_n(&_audiod_itf[itf].rx_ff[channelId], buffer, bufsize); -} - -void tud_audio_n_read_flush (uint8_t itf, uint8_t channelId) -{ - TU_VERIFY(channelId < CFG_TUD_AUDIO_N_CHANNELS_RX, ); - tu_fifo_clear(&_audiod_itf[itf].rx_ff[channelId]); -} -#else uint16_t tud_audio_n_available(uint8_t itf) { - return tu_fifo_count(&_audiod_itf[itf].rx_ff[0]); + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, ); + return tu_fifo_count(&_audiod_itf[itf].ep_out_ff); } uint16_t tud_audio_n_read(uint8_t itf, void* buffer, uint16_t bufsize) { - return tu_fifo_read_n(&_audiod_itf[itf].rx_ff[0], buffer, bufsize); + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, ); + return tu_fifo_read_n(&_audiod_itf[itf].ep_out_ff, buffer, bufsize); } -void tud_audio_n_read_flush (uint8_t itf) +void tud_audio_n_clear_ep_out_ff(uint8_t itf) { - tu_fifo_clear(&_audiod_itf[itf].rx_ff[0]); + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, ); + return tu_fifo_clear(&_audiod_itf[itf].ep_out_ff); +} + +#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE +// Delete all content in the support RX FIFOs +void tud_audio_n_clear_rx_support_ff(uint8_t itf, uint8_t channelId) +{ + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_RX, ); + tu_fifo_clear(&_audiod_itf[itf].rx_ff[channelId]); +} + +uint16_t tud_audio_n_available_support_ff(uint8_t itf, uint8_t channelId) +{ + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_RX, ); + tu_fifo_count(&_audiod_itf[itf].rx_ff[channelId]); +} + +uint16_t tud_audio_n_read_support_ff(uint8_t itf, uint8_t channelId, void* buffer, uint16_t bufsize) +{ + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_RX, ); + return tu_fifo_read_n(&_audiod_itf[itf].rx_ff[channelId], buffer, bufsize); } #endif + #endif + + + + + + + + + #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN uint16_t tud_audio_int_ctr_n_available(uint8_t itf) @@ -261,9 +261,9 @@ void tud_audio_int_ctr_n_read_flush (uint8_t itf) #endif // This function is called once something is received by USB and is responsible for decoding received stream into audio channels. -// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_RX_FIFO_SIZE = 0. +// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE = 0. -#if CFG_TUD_AUDIO_EPSIZE_OUT +#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE static bool audio_rx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint8_t* buffer, uint16_t bufsize) { @@ -281,7 +281,7 @@ static bool audio_rx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint8_t* { case AUDIO_DATA_FORMAT_TYPE_I_PCM: -#if CFG_TUD_AUDIO_RX_FIFO_SIZE +#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE TU_VERIFY(audio_rx_done_type_I_pcm_ff_cb(rhport, audio, buffer, bufsize)); #else #error YOUR DECODING AND BUFFERING IS REQUIRED HERE! @@ -309,11 +309,11 @@ static bool audio_rx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint8_t* return true; } -#endif //CFG_TUD_AUDIO_EPSIZE_OUT +#endif //CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE -// The following functions are used in case CFG_TUD_AUDIO_RX_FIFO_SIZE != 0 -#if CFG_TUD_AUDIO_RX_FIFO_SIZE -#if CFG_TUD_AUDIO_RX_FIFO_COUNT > 1 +// The following functions are used in case CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE != 0 +#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE +#if CFG_TUD_AUDIO_N_CHANNELS_RX > 1 static bool audio_rx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* audio, uint8_t * buffer, uint16_t bufsize) { (void) rhport; @@ -365,13 +365,53 @@ static bool audio_rx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t *a tu_fifo_write_n(&audio->rx_ff[0], buffer, bufsize); return true; } -#endif // CFG_TUD_AUDIO_RX_FIFO_COUNT > 1 -#endif //CFG_TUD_AUDIO_RX_FIFO_SIZE +#endif // CFG_TUD_AUDIO_N_CHANNELS_RX > 1 +#endif //CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE //--------------------------------------------------------------------+ // WRITE API //--------------------------------------------------------------------+ +#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE + +uint16_t tud_audio_n_write(uint8_t itf, const void * data, uint16_t len) +{ + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, ); + return tu_fifo_write_n(&_audiod_itf[itf].ep_in_ff, data, len); +} + +void tud_audio_n_clear_ep_in_ff(uint8_t itf) // Delete all content in the EP IN FIFO +{ + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, ); + tu_fifo_clear(&_audiod_itf[itf].ep_in_ff); +} + +#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE +uint16_t tud_audio_n_flush_tx_support_ff(uint8_t itf) // Force all content in the support TX FIFOs to be written into EP SW FIFO +{ + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, ); + audiod_interface_t* audio = &_audiod_itf[itf]; + uint16_t n_bytes_copied; + TU_VERIFY(audiod_tx_done_cb(audio->rhport, audio, &n_bytes_copied)); + return n_bytes_copied; +} + +uint16_t tud_audio_n_clear_tx_support_ff (uint8_t itf, uint8_t channelId); + +uint16_t tud_audio_n_write_support_ff(uint8_t itf, uint8_t channelId, const void * data, uint16_t len) +{ + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_TX, ); + return tu_fifo_write_n(&audio->tx_ff[channelId], data, len); +} +#endif + +#endif + + + + + + /** * \brief Write data to EP in buffer * @@ -383,50 +423,28 @@ static bool audio_rx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t *a * \param[in] len: # of array elements to copy * \return Number of bytes actually written */ -#if CFG_TUD_AUDIO_EPSIZE_IN -#if !CFG_TUD_AUDIO_TX_FIFO_SIZE -/* This function is intended for later use once EP buffers (at least for ISO EPs) are implemented as ring buffers +#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE +#if !CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE +This function is intended for later use once EP buffers (at least for ISO EPs) are implemented as ring buffers uint16_t tud_audio_n_write_ep_in_buffer(uint8_t itf, const void * data, uint16_t len) { audiod_interface_t* audio = &_audiod_itf[itf]; - if (audio->p_desc == NULL) { - return 0; - } + if (audio->p_desc == NULL) return 0; - // THIS IS A CRITICAL SECTION - audio->epin_buf_cnt MUST NOT BE MODIFIED FROM HERE - happens if audiod_tx_done_cb() is executed in between! - - // FOR SINGLE THREADED OPERATION: - // AS LONG AS THIS FUNCTION IS NOT EXECUTED WITHIN AN INTERRUPT ALL IS FINE! - - // Determine free space - uint16_t free = CFG_TUD_AUDIO_EPSIZE_IN - audio->epin_buf_cnt; - - // Clip length if needed - if (len > free) len = free; - - // Write data - memcpy((void *) &audio->epin_buf[audio->epin_buf_cnt], data, len); - - audio->epin_buf_cnt += len; - - // Return number of bytes written - return len; + return tu_fifo_write_n(&audio->ep_in_ff, data, len); } -*/ #else -#if CFG_TUD_AUDIO_TX_FIFO_COUNT == 1 +#if CFG_TUD_AUDIO_N_CHANNELS_TX == 1 uint16_t tud_audio_n_write(uint8_t itf, void const* data, uint16_t len) { + audiod_interface_t* audio = &_audiod_itf[itf]; + if (audio->p_desc == NULL) { - audiod_interface_t* audio = &_audiod_itf[itf]; - if (audio->p_desc == NULL) - { - return 0; - } - return tu_fifo_write_n(&audio->tx_ff[0], data, len); + return 0; } + return tu_fifo_write_n(&audio->tx_ff[0], data, len); } #else uint16_t tud_audio_n_write(uint8_t itf, uint8_t channelId, const void * data, uint16_t len) @@ -471,11 +489,11 @@ uint32_t tud_audio_int_ctr_n_write(uint8_t itf, uint8_t const* buffer, uint32_t // This function is called once a transmit of an audio packet was successfully completed. Here, we encode samples and place it in IN EP's buffer for next transmission. -// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_TX_FIFO_SIZE = 0 and use tud_audio_n_write_ep_in_buffer() (NOT IMPLEMENTED SO FAR). +// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE = 0 and use tud_audio_n_write_ep_in_buffer() (NOT IMPLEMENTED SO FAR). // n_bytes_copied - Informs caller how many bytes were loaded. In case n_bytes_copied = 0, a ZLP is scheduled to inform host no data is available for current frame. -#if CFG_TUD_AUDIO_EPSIZE_IN -static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint16_t * n_bytes_copied) +#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE +static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t * audio, uint16_t * n_bytes_copied) { uint8_t idxDriver, idxItf; uint8_t const *dummy2; @@ -488,10 +506,10 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint16_ } // Call a weak callback here - a possibility for user to get informed former TX was completed and data gets now loaded into EP in buffer (in case FIFOs are used) or - // if no FIFOs are used the user may use this call back to load its data into the EP in buffer by use of tud_audio_n_write_ep_in_buffer(). + // if no FIFOs are used the user may use this call back to load its data into the EP IN buffer by use of tud_audio_n_write_ep_in_buffer(). if (tud_audio_tx_done_pre_load_cb) TU_VERIFY(tud_audio_tx_done_pre_load_cb(rhport, idxDriver, audio->ep_in, audio->altSetting[idxItf])); -#if CFG_TUD_AUDIO_TX_FIFO_SIZE +#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE switch (CFG_TUD_AUDIO_FORMAT_TYPE_TX) { case AUDIO_FORMAT_TYPE_UNDEFINED: @@ -526,30 +544,11 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint16_ } #endif - // THIS IS A CRITICAL SECTION - audio->epin_buf_cnt MUST NOT BE MODIFIED FROM HERE - happens if tud_audio_n_write_ep_in_buffer() is executed in between! - - // THIS IS NOT SOLVED SO FAR! - - // FOR SINGLE THREADED OPERATION: - // THIS FUNCTION IS NOT EXECUTED WITHIN AN INTERRUPT SO IT DOES NOT INTERRUPT tud_audio_n_write_ep_in_buffer()! AS LONG AS tud_audio_n_write_ep_in_buffer() IS NOT EXECUTED WITHIN AN INTERRUPT ALL IS FINE! + // Inform how many bytes will be copied + *n_bytes_copied = tu_fifo_count(&audio->ep_in_ff); // Schedule transmit - // TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->epin_buf, audio->epin_buf_cnt)); - - - TU_VERIFY(usbd_edpt_iso_xfer(rhport, audio->ep_in, &audio->epin_ff)); - - - - - - // Inform how many bytes were copied - *n_bytes_copied = audio->epin_buf_cnt; - - // Declare EP in buffer empty - audio->epin_buf_cnt = 0; - - // TO HERE + TU_VERIFY(usbd_edpt_iso_xfer(rhport, audio->ep_in, &audio->ep_in_ff, *n_bytes_copied)); // Call a weak callback here - a possibility for user to get informed former TX was completed and how many bytes were loaded for the next frame if (tud_audio_tx_done_post_load_cb) TU_VERIFY(tud_audio_tx_done_post_load_cb(rhport, *n_bytes_copied, idxDriver, audio->ep_in, audio->altSetting[idxItf])); @@ -557,19 +556,18 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint16_ return true; } -#endif //CFG_TUD_AUDIO_EPSIZE_IN +#endif //CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE -#if CFG_TUD_AUDIO_TX_FIFO_SIZE -#if CFG_TUD_AUDIO_TX_FIFO_COUNT > 1 || (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX != CFG_TUD_AUDIO_TX_ITEMSIZE) +#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE +#if CFG_TUD_AUDIO_N_CHANNELS_TX > 1 || (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX != CFG_TUD_AUDIO_TX_ITEMSIZE) static bool audiod_tx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* audio) { - // We encode directly into IN EP's buffer - abort if previous transfer not complete + // We encode directly into IN EP's FIFO - abort if previous transfer not complete TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_in)); // Determine amount of samples - uint16_t const nEndpointSampleCapacity = CFG_TUD_AUDIO_EPSIZE_IN / CFG_TUD_AUDIO_N_CHANNELS_TX / CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX; + uint16_t const nEndpointSampleCapacity = CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE / CFG_TUD_AUDIO_N_CHANNELS_TX / CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX; uint16_t nSamplesPerChannelToSend = tu_fifo_count(&audio->tx_ff[0]) / CFG_TUD_AUDIO_TX_ITEMSIZE; - uint16_t nBytesToSend; uint8_t cntChannel; for (cntChannel = 1; cntChannel < CFG_TUD_AUDIO_N_CHANNELS_TX; cntChannel++) @@ -582,58 +580,47 @@ static bool audiod_tx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* } // Check if there is enough - if (nSamplesPerChannelToSend == 0) - { - audio->epin_buf_cnt = 0; - return true; - } + if (nSamplesPerChannelToSend == 0) return true; // Limit to maximum sample number - THIS IS A POSSIBLE ERROR SOURCE IF TOO MANY SAMPLE WOULD NEED TO BE SENT BUT CAN NOT! nSamplesPerChannelToSend = tu_min16(nSamplesPerChannelToSend, nEndpointSampleCapacity); - nBytesToSend = nSamplesPerChannelToSend * CFG_TUD_AUDIO_N_CHANNELS_TX * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX; // Encode uint16_t cntSample; - uint8_t * pBuff = audio->epin_buf; -#if CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX == 1 - uint8_t sample; -#elif CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX == 2 - uint16_t sample; -#else - uint32_t sample; -#endif - // TODO: Big endianess handling for (cntSample = 0; cntSample < nSamplesPerChannelToSend; cntSample++) { for (cntChannel = 0; cntChannel < CFG_TUD_AUDIO_N_CHANNELS_TX; cntChannel++) { + // If 8, 16, or 32 bit values are to be copied +#if CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX == CFG_TUD_AUDIO_TX_ITEMSIZE + tu_fifo_read_n_into_other_fifo(&audio->tx_ff[cntChannel], &audio->ep_in_ff, 0, CFG_TUD_AUDIO_TX_ITEMSIZE); +#else + // TODO: Implement a left and right justified 24 to 32 and vice versa copy process from FIFO to FIFO + uint32_t sample = 0; + // Get sample from buffer - tu_fifo_read_n(&audio->tx_ff[cntChannel], &sample, CFG_TUD_AUDIO_TX_ITEMSIZE); + tu_fifo_read_n(&audio->tx_ff[cntChannel], &sample, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX); - // Put it into EP's buffer - Let alignment problems be handled by memcpy - memcpy(pBuff, &sample, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX); - - // Advance pointer - pBuff += CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX; + tu_fifo_write_n(&audio->ep_in_ff, &sample, CFG_TUD_AUDIO_TX_ITEMSIZE); +#endif } } - - audio->epin_buf_cnt = nBytesToSend; - return true; } #else static bool audiod_tx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* audio) { + // TODO GET RID OF SINGLE TX_FIFO! + // We encode directly into IN EP's buffer - abort if previous transfer not complete TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_in)); // Determine amount of samples uint16_t nByteCount = tu_fifo_count(&audio->tx_ff[0]); - nByteCount = tu_min16(nByteCount, CFG_TUD_AUDIO_EPSIZE_IN); + nByteCount = tu_min16(nByteCount, CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE); // Check if there is enough if (nByteCount == 0) @@ -641,20 +628,17 @@ static bool audiod_tx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* return true; } - nByteCount = tu_fifo_read_n_into_other_fifo(&audio->tx_ff[0], &audio->epin_ff, 0, nByteCount); -// nByteCount = tu_fifo_read_n(&audio->tx_ff[0], audio->epin_buf, nByteCount); - - audio->epin_buf_cnt = nByteCount; + nByteCount = tu_fifo_read_n_into_other_fifo(&audio->tx_ff[0], &audio->ep_in_ff, 0, nByteCount); return true; } -#endif // CFG_TUD_AUDIO_TX_FIFO_COUNT > 1 || (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX != CFG_TUD_AUDIO_TX_ITEMSIZE) +#endif // CFG_TUD_AUDIO_N_CHANNELS_TX > 1 || (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX != CFG_TUD_AUDIO_TX_ITEMSIZE) -#endif //CFG_TUD_AUDIO_TX_FIFO_SIZE +#endif //CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE // This function is called once a transmit of an feedback packet was successfully completed. Here, we get the next feedback value to be sent -#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP static bool audio_fb_send(uint8_t rhport, audiod_interface_t *audio) { uint8_t fb[4]; @@ -738,28 +722,34 @@ void audiod_init(void) { audiod_interface_t* audio = &_audiod_itf[i]; + // Initialize IN EP FIFO if required +#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE + // Initialize IN EP FIFO + tu_fifo_config(&audio->ep_in_ff, &audio->ep_in_buf, CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE, 1, true); +#endif + // Initialize TX FIFOs if required -#if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_FIFO_SIZE - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_TX_FIFO_COUNT; cnt++) +#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE && CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_TX; cnt++) { - tu_fifo_config(&audio->tx_ff[cnt], &audio->tx_ff_buf[cnt], CFG_TUD_AUDIO_TX_FIFO_SIZE, 1, true); + tu_fifo_config(&audio->tx_ff[cnt], &audio->tx_ff_buf[cnt], CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE, 1, true); #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&audio->tx_ff[cnt], osal_mutex_create(&audio->tx_ff_mutex[cnt])); #endif } - - // Initialize IN EP FIFO - tu_fifo_config(&audio->epin_ff, &audio->epin_buf, CFG_TUD_AUDIO_EPSIZE_IN, 1, true); - #endif -#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_FIFO_SIZE - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_RX_FIFO_COUNT; cnt++) +#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_RX; cnt++) { - tu_fifo_config(&audio->rx_ff[cnt], &audio->rx_ff_buf[cnt], CFG_TUD_AUDIO_RX_FIFO_SIZE, 1, true); + tu_fifo_config(&audio->rx_ff[cnt], &audio->rx_ff_buf[cnt], CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE, 1, true); #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&audio->rx_ff[cnt], osal_mutex_create(&audio->rx_ff_mutex[cnt])); #endif + + // Initialize OUT EP FIFO + tu_fifo_config(&audio->ep_out_ff, &audio->ep_out_buf, CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE, 1, true); + } #endif @@ -781,19 +771,19 @@ void audiod_reset(uint8_t rhport) audiod_interface_t* audio = &_audiod_itf[i]; tu_memclr(audio, ITF_MEM_RESET_SIZE); -#if CFG_TUD_AUDIO_EPSIZE_IN - tu_fifo_clear(&audio->epin_ff); +#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE + tu_fifo_clear(&audio->ep_in_ff); #endif -#if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_FIFO_SIZE - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_TX_FIFO_COUNT; cnt++) +#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE && CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_TX; cnt++) { tu_fifo_clear(&audio->tx_ff[cnt]); } #endif -#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_FIFO_SIZE - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_RX_FIFO_COUNT; cnt++) +#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_RX; cnt++) { tu_fifo_clear(&audio->rx_ff[cnt]); } @@ -891,7 +881,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * TU_VERIFY(audiod_get_AS_interface_index(itf, &idxDriver, &idxItf, &p_desc)); // Look if there is an EP to be closed - for this driver, there are only 3 possible EPs which may be closed (only AS related EPs can be closed, AC EP (if present) is always open) -#if CFG_TUD_AUDIO_EPSIZE_IN > 0 +#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE > 0 if (_audiod_itf[idxDriver].ep_in_as_intf_num == itf) { _audiod_itf[idxDriver].ep_in_as_intf_num = 0; @@ -904,7 +894,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * } #endif -#if CFG_TUD_AUDIO_EPSIZE_OUT +#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE if (_audiod_itf[idxDriver].ep_out_as_intf_num == itf) { _audiod_itf[idxDriver].ep_out_as_intf_num = 0; @@ -945,7 +935,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * // We need to set EP non busy since this is not taken care of right now in ep_close() - THIS IS A WORKAROUND! usbd_edpt_clear_stall(rhport, ep_addr); -#if CFG_TUD_AUDIO_EPSIZE_IN > 0 +#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE > 0 if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && ((tusb_desc_endpoint_t const *) p_desc)->bmAttributes.usage == 0x00) // Check if usage is data EP { // Save address @@ -961,7 +951,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * } #endif -#if CFG_TUD_AUDIO_EPSIZE_OUT +#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) // Checking usage not necessary { @@ -973,7 +963,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request)); // Prepare for incoming data - TU_ASSERT(usbd_edpt_xfer(rhport, ep_addr, _audiod_itf[idxDriver].epout_buf, CFG_TUD_AUDIO_EPSIZE_OUT), false); + TU_ASSERT(usbd_edpt_xfer(rhport, ep_addr, _audiod_itf[idxDriver].ep_out_buf, CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE), false); } #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP @@ -1242,7 +1232,7 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 #endif -#if CFG_TUD_AUDIO_EPSIZE_IN +#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE // Data transmission of audio packet finished if (_audiod_itf[idxDriver].ep_in == ep_addr) @@ -1264,16 +1254,16 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 } #endif -#if CFG_TUD_AUDIO_EPSIZE_OUT +#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE // New audio packet received if (_audiod_itf[idxDriver].ep_out == ep_addr) { // Save into buffer - do whatever has to be done - TU_VERIFY(audio_rx_done_cb(rhport, &_audiod_itf[idxDriver], _audiod_itf[idxDriver].epout_buf, xferred_bytes)); + TU_VERIFY(audio_rx_done_cb(rhport, &_audiod_itf[idxDriver], _audiod_itf[idxDriver].ep_out_buf, xferred_bytes)); // prepare for next transmission - TU_ASSERT(usbd_edpt_xfer(rhport, ep_addr, _audiod_itf[idxDriver].epout_buf, CFG_TUD_AUDIO_EPSIZE_OUT), false); + TU_ASSERT(usbd_edpt_xfer(rhport, ep_addr, _audiod_itf[idxDriver].ep_out_buf, CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE), false); return true; } diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index 5061501ce..fdd4c15d4 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -38,9 +38,11 @@ // Class Driver Configuration //--------------------------------------------------------------------+ +// All sizes are in bytes! + // Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just waste a few bytes) #ifndef CFG_TUD_AUDIO_N_AS_INT -#define CFG_TUD_AUDIO_N_AS_INT 0 +#error You must tell the driver the number of Standard AS Interface Descriptors you have defined in the descriptors! #endif // Size of control buffer used to receive and send control messages via EP0 - has to be big enough to hold your biggest request structure e.g. range requests with multiple intervals defined or cluster descriptors @@ -48,20 +50,6 @@ #error You must define an audio class control request buffer size! #endif -// Use of TX/RX FIFOs - If sizes are not zero, audio.c implements FIFOs for RX and TX (whatever defined). -// For RX: the input stream gets decoded into its corresponding channels, where for each channel a FIFO is setup to hold its data -> see: audio_rx_done_cb(). -// For TX: the output stream is composed from CFG_TUD_AUDIO_N_CHANNELS_TX channels, where for each channel a FIFO is defined. -// Further, it implements encoding and decoding of the individual channels (parameterized by the defines below). -// If you don't use the FIFOs you need to handle encoding and decoding on your own in audio_rx_done_cb() and audio_tx_done_cb(). This, however, allows for optimizations. - -#ifndef CFG_TUD_AUDIO_TX_FIFO_SIZE -#define CFG_TUD_AUDIO_TX_FIFO_SIZE 0 // Buffer size per channel -#endif - -#ifndef CFG_TUD_AUDIO_RX_FIFO_SIZE -#define CFG_TUD_AUDIO_RX_FIFO_SIZE 0 // Buffer size per channel -#endif - // End point sizes - Limits: Full Speed <= 1023, High Speed <= 1024 #ifndef CFG_TUD_AUDIO_EPSIZE_IN #define CFG_TUD_AUDIO_EPSIZE_IN 0 // TX @@ -71,12 +59,80 @@ #define CFG_TUD_AUDIO_EPSIZE_OUT 0 // RX #endif -#ifndef CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 0 // Feedback +// Software EP FIFO buffer sizes - must be >= EP SIZEs! +#if CFG_TUD_AUDIO_EPSIZE_IN +#ifndef CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE +#define CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE CFG_TUD_AUDIO_EPSIZE_IN // TX +#endif #endif +#if CFG_TUD_AUDIO_EPSIZE_OUT +#ifndef CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE +#define CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE CFG_TUD_AUDIO_EPSIZE_OUT // RX +#endif +#endif + +// General information of number of TX and/or RX channels - is used in case support FIFOs (see below) are used and can be used for descriptor definitions +#ifndef CFG_TUD_AUDIO_N_CHANNELS_TX +#define CFG_TUD_AUDIO_N_CHANNELS_TX 0 +#endif + +#ifndef CFG_TUD_AUDIO_N_CHANNELS_RX +#define CFG_TUD_AUDIO_N_CHANNELS_RX 0 +#endif + +// Use of TX/RX support FIFOs + +// Support FIFOs are not mandatory for the audio driver, rather they are intended to be of use in +// - TX case: CFG_TUD_AUDIO_N_CHANNELS_TX channels need to be encoded into one USB output stream (currently PCM type I is implemented) +// - RX case: CFG_TUD_AUDIO_N_CHANNELS_RX channels need to be decoded from a single USB input stream (currently PCM type I is implemented) +// +// This encoding/decoding is done in software and thus time consuming. If you can encode/decode your stream more efficiently do not use the +// support FIFOs but write/read directly into/from the EP_X_SW_BUFFER_FIFOs using +// - tud_audio_n_write() or +// - tud_audio_n_read(). +// To write/read to/from the support FIFOs use +// - tud_audio_n_write_support_ff() or +// - tud_audio_n_read_support_ff(). +// +// The encoding/decoding format type done is defined below. +// +// The encoding/decoding starts when the private callback functions +// - audio_tx_done_cb() +// - audio_rx_done_cb() +// are invoked. If support FIFOs are used the corresponding encoding/decoding functions are called from there. +// Once encoding/decoding is done the result is put directly into the EP_X_SW_BUFFER_FIFOs. You can use the public callback functions +// - tud_audio_tx_done_pre_load_cb() or tud_audio_tx_done_post_load_cb() +// - tud_audio_rx_done_pre_read_cb() or tud_audio_rx_done_post_read_cb() +// if you want to get informed what happened. +// +// If you don't use the support FIFOs you may use the public callback functions +// - tud_audio_tx_done_pre_load_cb() or tud_audio_tx_done_post_load_cb() +// - tud_audio_rx_done_pre_read_cb() or tud_audio_rx_done_post_read_cb() +// to write/read from/into the EP_X_SW_BUFFER_FIFOs at the right time. +// +// If you need a different encoding which is not support so far implement it in the +// - audio_tx_done_cb() +// - audio_rx_done_cb() +// functions. + +// Size of support FIFOs - if size > 0 there are as many FIFOs set up as TX/RX channels defined +#ifndef CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE +#define CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE 0 // Buffer size per channel - minimum size: ceil(f_s/1000)*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX +#endif + +#ifndef CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE +#define CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE 0 // Buffer size per channel - minimum size: ceil(f_s/1000)*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX +#endif + +// Enable/disable feedback EP (required for asynchronous RX applications) +#ifndef CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 0 // Feedback - 0 or 1 +#endif + +// Audio interrupt control EP size - disabled if 0 #ifndef CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN -#define CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN 0 // Audio interrupt control +#define CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN 0 // Audio interrupt control - if required - 6 Bytes according to UAC 2 specification (p. 74) #endif #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN @@ -85,15 +141,8 @@ #endif #endif -#ifndef CFG_TUD_AUDIO_N_CHANNELS_TX -#define CFG_TUD_AUDIO_N_CHANNELS_TX 1 -#endif - -#ifndef CFG_TUD_AUDIO_N_CHANNELS_RX -#define CFG_TUD_AUDIO_N_CHANNELS_RX 1 -#endif - -// Audio data format types +// Audio data format types - look in audio.h for existing types +// Used in case support FIFOs are used #ifndef CFG_TUD_AUDIO_FORMAT_TYPE_TX #define CFG_TUD_AUDIO_FORMAT_TYPE_TX AUDIO_FORMAT_TYPE_UNDEFINED // If this option is used, an encoding function has to be implemented in audio_device.c #endif @@ -110,8 +159,8 @@ #define CFG_TUD_AUDIO_FORMAT_TYPE_I_TX AUDIO_DATA_FORMAT_TYPE_I_PCM #endif -#ifndef CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX // bSubslotSize -#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX 1 +#ifndef CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX // bSubslotSize +#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX 1 #endif #ifndef CFG_TUD_AUDIO_TX_ITEMSIZE @@ -136,8 +185,8 @@ #define CFG_TUD_AUDIO_FORMAT_TYPE_I_RX AUDIO_DATA_FORMAT_TYPE_I_PCM #endif -#ifndef CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX // bSubslotSize -#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX 1 +#ifndef CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX // bSubslotSize +#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX 1 #endif #if CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX == 1 @@ -170,69 +219,84 @@ extern "C" { //--------------------------------------------------------------------+ bool tud_audio_n_mounted (uint8_t itf); -#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_FIFO_SIZE -#if CFG_TUD_AUDIO_RX_FIFO_COUNT > 1 -uint16_t tud_audio_n_available (uint8_t itf, uint8_t channelId); -uint16_t tud_audio_n_read (uint8_t itf, uint8_t channelId, void* buffer, uint16_t bufsize); -void tud_audio_n_read_flush (uint8_t itf, uint8_t channelId); -#else -uint16_t tud_audio_n_available (uint8_t itf); -uint16_t tud_audio_n_read (uint8_t itf, void* buffer, uint16_t bufsize); -void tud_audio_n_read_flush (uint8_t itf); -#endif +#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE + +uint16_t tud_audio_n_available (uint8_t itf); +uint16_t tud_audio_n_read (uint8_t itf, void* buffer, uint16_t bufsize); +void tud_audio_n_clear_ep_out_ff (uint8_t itf); // Delete all content in the EP OUT FIFO + +#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE +void tud_audio_n_clear_rx_support_ff (uint8_t itf, uint8_t channelId); // Delete all content in the support RX FIFOs +uint16_t tud_audio_n_available_support_ff (uint8_t itf, uint8_t channelId); +uint16_t tud_audio_n_read_support_ff (uint8_t itf, uint8_t channelId, void* buffer, uint16_t bufsize); #endif -/* This function is intended for later use once EP buffers (at least for ISO EPs) are implemented as ring buffers -#if CFG_TUD_AUDIO_EPSIZE_IN && !CFG_TUD_AUDIO_TX_FIFO_SIZE -uint16_t tud_audio_n_write_ep_in_buffer(uint8_t itf, const void * data, uint16_t len) -#endif -*/ - -#ifndef CFG_TUD_AUDIO_TX_FIFO_COUNT -#define CFG_TUD_AUDIO_TX_FIFO_COUNT 1 #endif -#if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_FIFO_SIZE -#if CFG_TUD_AUDIO_TX_FIFO_COUNT > 1 -uint16_t tud_audio_n_write (uint8_t itf, uint8_t channelId, const void * data, uint16_t len); -#else -uint16_t tud_audio_n_write (uint8_t itf, const void * data, uint16_t len); -#endif -uint16_t tud_audio_n_write_flush(uint8_t itf); +#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE + +uint16_t tud_audio_n_write (uint8_t itf, const void * data, uint16_t len); +void tud_audio_n_clear_ep_in_ff (uint8_t itf); // Delete all content in the EP IN FIFO + +#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE +uint16_t tud_audio_n_flush_tx_support_ff (uint8_t itf); // Force all content in the support TX FIFOs to be written into EP SW FIFO +uint16_t tud_audio_n_clear_tx_support_ff (uint8_t itf, uint8_t channelId); +uint16_t tud_audio_n_write_support_ff (uint8_t itf, uint8_t channelId, const void * data, uint16_t len); #endif -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN > 0 -uint16_t tud_audio_int_ctr_n_available (uint8_t itf); -uint16_t tud_audio_int_ctr_n_read (uint8_t itf, void* buffer, uint16_t bufsize); -void tud_audio_int_ctr_n_read_flush (uint8_t itf); -uint16_t tud_audio_int_ctr_n_write (uint8_t itf, uint8_t const* buffer, uint16_t bufsize); +#endif + +#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN +uint16_t tud_audio_int_ctr_n_available (uint8_t itf); +uint16_t tud_audio_int_ctr_n_read (uint8_t itf, void* buffer, uint16_t bufsize); +void tud_audio_int_ctr_n_clear (uint8_t itf); // Delete all content in the AUDIO_INT_CTR FIFO +uint16_t tud_audio_int_ctr_n_write (uint8_t itf, uint8_t const* buffer, uint16_t len); #endif //--------------------------------------------------------------------+ // Application API (Interface0) //--------------------------------------------------------------------+ -static inline bool tud_audio_mounted (void); +static inline bool tud_audio_mounted (void); -#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_FIFO_SIZE -static inline uint16_t tud_audio_available (void); -static inline uint16_t tud_audio_read (void* buffer, uint16_t bufsize); -static inline void tud_audio_read_flush (void); +// RX API + +#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE + +static inline uint16_t tud_audio_available (void); +static inline void tud_audio_clear_ep_out_ff (void); // Delete all content in the EP OUT FIFO +static inline uint16_t tud_audio_read (void* buffer, uint16_t bufsize); + +#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE +static inline void tud_audio_clear_rx_support_ff (uint8_t channelId); +static inline uint16_t tud_audio_available_support_ff (uint8_t channelId); +static inline uint16_t tud_audio_read_support_ff (uint8_t channelId, void* buffer, uint16_t bufsize); #endif -#if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_FIFO_SIZE -#if CFG_TUD_AUDIO_TX_FIFO_COUNT > 1 -static inline uint16_t tud_audio_write (uint8_t channelId, uint8_t const* buffer, uint16_t bufsize); -#else -static inline uint16_t tud_audio_write (uint8_t const* buffer, uint16_t bufsize); -#endif #endif -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN > 0 -static inline uint32_t tud_audio_int_ctr_available (void); -static inline uint32_t tud_audio_int_ctr_read (void* buffer, uint32_t bufsize); -static inline void tud_audio_int_ctr_read_flush (void); -static inline uint32_t tud_audio_int_ctr_write (uint8_t const* buffer, uint32_t bufsize); +// TX API + +#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE + +static inline uint16_t tud_audio_write (const void * data, uint16_t len); +static inline uint16_t tud_audio_clear_ep_in_ff (void); + +#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE +static inline uint16_t tud_audio_flush_tx_support_ff (void); +static inline uint16_t tud_audio_clear_tx_support_ff (uint8_t channelId); +static inline uint16_t tud_audio_write_support_ff (uint8_t channelId, const void * data, uint16_t len); +#endif + +#endif + +// INT CTR API + +#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN +static inline uint16_t tud_audio_int_ctr_available (void); +static inline uint16_t tud_audio_int_ctr_read (void* buffer, uint16_t bufsize); +static inline void tud_audio_int_ctr_clear (void); +static inline uint16_t tud_audio_int_ctr_write (uint8_t const* buffer, uint16_t len); #endif // Buffer control EP data and schedule a transmit @@ -247,16 +311,17 @@ bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_req // Application Callback API (weak is optional) //--------------------------------------------------------------------+ -#if CFG_TUD_AUDIO_EPSIZE_IN +#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE TU_ATTR_WEAK bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t itf, uint8_t ep_in, uint8_t cur_alt_setting); TU_ATTR_WEAK bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uint8_t itf, uint8_t ep_in, uint8_t cur_alt_setting); #endif -#if CFG_TUD_AUDIO_EPSIZE_OUT -TU_ATTR_WEAK bool tud_audio_rx_done_cb(uint8_t rhport, uint8_t * buffer, uint16_t bufsize); +#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE +TU_ATTR_WEAK bool tud_audio_rx_done_pre_read_cb(uint8_t rhport, uint8_t itf, uint8_t ep_out, uint8_t cur_alt_setting); +TU_ATTR_WEAK bool tud_audio_rx_done_post_read_cb(uint8_t rhport, uint16_t n_bytes_copied, uint8_t itf, uint8_t ep_out, uint8_t cur_alt_setting); #endif -#if CFG_TUD_AUDIO_EPSIZE_OUT > 0 && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP TU_ATTR_WEAK bool tud_audio_fb_done_cb(uint8_t rhport); // User code should call this function with feedback value in 16.16 format for FS and HS. // Value will be corrected for FS to 10.14 format automatically. @@ -302,64 +367,82 @@ static inline bool tud_audio_mounted(void) return tud_audio_n_mounted(0); } -#if CFG_TUD_AUDIO_EPSIZE_IN -#if CFG_TUD_AUDIO_TX_FIFO_SIZE && CFG_TUD_AUDIO_TX_FIFO_COUNT > 1 -static inline uint16_t tud_audio_write (uint8_t channelId, uint8_t const* buffer, uint16_t n_bytes) // Short version if only one audio function is used -{ - return tud_audio_n_write(0, channelId, buffer, n_bytes); -} -#else -static inline uint16_t tud_audio_write (uint8_t const* buffer, uint16_t n_bytes) // Short version if only one audio function is used -{ - return tud_audio_n_write(0, buffer, n_bytes); -} -#endif +// RX API -static inline uint16_t tud_audio_write_flush (void) // Short version if only one audio function is used -{ -#if CFG_TUD_AUDIO_TX_FIFO_SIZE - return tud_audio_n_write_flush(0); -#else - return 0; -#endif -} -#endif // CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_FIFO_SIZE +#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE -#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_FIFO_SIZE -#if CFG_TUD_AUDIO_RX_FIFO_COUNT > 1 -static inline uint16_t tud_audio_available(uint8_t channelId) -{ - return tud_audio_n_available(0, channelId); -} - -static inline uint16_t tud_audio_read(uint8_t channelId, void* buffer, uint16_t bufsize) -{ - return tud_audio_n_read(0, channelId, buffer, bufsize); -} - -static inline void tud_audio_read_flush(uint8_t channelId) -{ - tud_audio_n_read_flush(0, channelId); -} -#else -static inline uint16_t tud_audio_available(void) +static inline uint16_t tud_audio_available (void) { return tud_audio_n_available(0); } -static inline uint16_t tud_audio_read(void *buffer, uint16_t bufsize) +static inline uint16_t tud_audio_read (void* buffer, uint16_t bufsize) { return tud_audio_n_read(0, buffer, bufsize); } -static inline void tud_audio_read_flush(void) +static inline uint16_t tud_audio_clear_ep_out_ff (void) { - tud_audio_n_read_flush(0); + return tud_audio_n_clear_ep_out_ff(0); } -#endif + +#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE + +static inline void tud_audio_clear_rx_support_ff (uint8_t channelId) +{ + tud_audio_n_clear_rx_support_ff(0, channelId); +} + +static inline uint16_t tud_audio_available_support_ff (uint8_t channelId) +{ + return tud_audio_n_available_support_ff(0, channelId); +} + +static inline uint16_t tud_audio_read_support_ff (uint8_t channelId, void* buffer, uint16_t bufsize) +{ + return tud_audio_n_read_support_ff(0, channelId, buffer, bufsize); +} + #endif -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN > 0 +#endif + +// TX API + +#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE + +static inline uint16_t tud_audio_write (const void * data, uint16_t len) +{ + return tud_audio_n_write(0, data, len); +} + +static inline uint16_t tud_audio_clear_ep_in_ff (void) +{ + return tud_audio_n_clear_ep_in_ff(0); +} + +#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE + +static inline uint16_t tud_audio_flush_tx_support_ff (void) +{ + return tud_audio_n_flush_tx_support_ff(0); +} + +static inline uint16_t tud_audio_clear_tx_support_ff (uint8_t channelId) +{ + return tud_audio_n_clear_tx_support_ff(0, channelId); +} + +static inline uint16_t tud_audio_write_support_ff (uint8_t channelId, const void * data, uint16_t len) +{ + return tud_audio_n_write_support_ff(0, channelId, data, len); +} + +#endif + +#endif + +#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN static inline uint16_t tud_audio_int_ctr_available(void) { return tud_audio_int_ctr_n_available(0); @@ -370,25 +453,25 @@ static inline uint16_t tud_audio_int_ctr_read(void* buffer, uint16_t bufsize) return tud_audio_int_ctr_n_read(0, buffer, bufsize); } -static inline void tud_audio_int_ctr_read_flush(void) +static inline void tud_audio_int_ctr_clear(void) { - return tud_audio_int_ctr_n_read_flush(0); + return tud_audio_int_ctr_n_clear(0); } -static inline uint16_t tud_audio_int_ctr_write(uint8_t const* buffer, uint16_t bufsize) +static inline uint16_t tud_audio_int_ctr_write(uint8_t const* buffer, uint16_t len) { - return tud_audio_int_ctr_n_write(0, buffer, bufsize); + return tud_audio_int_ctr_n_write(0, buffer, len); } #endif //--------------------------------------------------------------------+ // Internal Class Driver API //--------------------------------------------------------------------+ -void audiod_init (void); -void audiod_reset (uint8_t rhport); -uint16_t audiod_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -bool audiod_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); -bool audiod_xfer_cb (uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes); +void audiod_init (void); +void audiod_reset (uint8_t rhport); +uint16_t audiod_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +bool audiod_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); +bool audiod_xfer_cb (uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes); #ifdef __cplusplus } diff --git a/src/device/dcd.h b/src/device/dcd.h index 30224e16e..f0a552434 100644 --- a/src/device/dcd.h +++ b/src/device/dcd.h @@ -125,23 +125,23 @@ void dcd_disconnect(uint8_t rhport) TU_ATTR_WEAK; void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request) TU_ATTR_WEAK; // Configure endpoint's registers according to descriptor -bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc); +bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc); // Close an endpoint. // Since it is weak, caller must TU_ASSERT this function's existence before calling it. -void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) TU_ATTR_WEAK; +void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) TU_ATTR_WEAK; // Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack -bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes); +bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes); // Submit an ISO transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack -bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff); +bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes); // Stall endpoint -void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr); +void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr); // clear stall, data toggle is also reset to DATA0 -void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr); +void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr); //--------------------------------------------------------------------+ // Event API (implemented by stack) diff --git a/src/device/usbd.c b/src/device/usbd.c index 4e18df757..2e2f9cf65 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -1206,12 +1206,16 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t } } -bool usbd_edpt_iso_xfer(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff) +// The number of bytes has to be given explicitly to allow more flexible control of how many +// bytes should be written and second to keep the return value free to give back a boolean +// success message. If total_bytes is too big, the FIFO will copy only what is available +// into the USB buffer! +bool usbd_edpt_iso_xfer(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) { uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr); - TU_LOG2(" Queue ISO EP %02X with %u bytes ... ", ep_addr, tu_fifo_count(ff)); + TU_LOG2(" Queue ISO EP %02X with %u bytes ... ", ep_addr, count); // Attempt to transfer on a busy endpoint, sound like an race condition ! TU_ASSERT(_usbd_dev.ep_status[epnum][dir].busy == 0); @@ -1220,7 +1224,7 @@ bool usbd_edpt_iso_xfer(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff) // and usbd task can preempt and clear the busy _usbd_dev.ep_status[epnum][dir].busy = true; - if ( dcd_edpt_iso_xfer(rhport, ep_addr, ff) ) + if (dcd_edpt_iso_xfer(rhport, ep_addr, ff, total_bytes)) { TU_LOG2("OK\r\n"); return true; diff --git a/src/device/usbd_pvt.h b/src/device/usbd_pvt.h index 1d24957a9..412a97a5d 100644 --- a/src/device/usbd_pvt.h +++ b/src/device/usbd_pvt.h @@ -73,7 +73,7 @@ void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr); bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes); // Submit a usb ISO transfer by use of a FIFO (ring buffer) - all bytes in FIFO get transmitted -bool usbd_edpt_iso_xfer(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff); +bool usbd_edpt_iso_xfer(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes); // Claim an endpoint before submitting a transfer. // If caller does not make any transfer, it must release endpoint for others. diff --git a/src/portable/st/synopsys/dcd_synopsys.c b/src/portable/st/synopsys/dcd_synopsys.c index 90fcd51e7..4cb6028cc 100644 --- a/src/portable/st/synopsys/dcd_synopsys.c +++ b/src/portable/st/synopsys/dcd_synopsys.c @@ -670,13 +670,15 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t return true; } -bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff) +// The number of bytes has to be given explicitly to allow more flexible control of how many +// bytes should be written and second to keep the return value free to give back a boolean +// success message. If total_bytes is too big, the FIFO will copy only what is available +// into the USB buffer! +bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) { // USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1 TU_ASSERT(ff->item_size == 1); - uint16_t total_bytes = tu_fifo_count(ff); - uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr); From a9fd0a454a96c599cb42f741c2e3e893b6c7306c Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Fri, 12 Feb 2021 16:28:41 +0100 Subject: [PATCH 015/121] Complete redesign of audio driver. --- examples/device/audio_test/src/main.c | 12 +- examples/device/audio_test/src/tusb_config.h | 7 +- .../device/audio_test/src/usb_descriptors.c | 2 +- .../device/uac2_headset/src/tusb_config.h | 14 +- src/class/audio/audio_device.c | 536 +++++++----------- src/class/audio/audio_device.h | 63 +- src/portable/st/synopsys/dcd_synopsys.c | 8 - 7 files changed, 242 insertions(+), 400 deletions(-) diff --git a/examples/device/audio_test/src/main.c b/examples/device/audio_test/src/main.c index 7f0ce3652..c63e64934 100644 --- a/examples/device/audio_test/src/main.c +++ b/examples/device/audio_test/src/main.c @@ -59,7 +59,7 @@ audio_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_N_CHANNELS_TX+1]; // Vol audio_control_range_4_n_t(1) sampleFreqRng; // Sample frequency range state // Audio test data -uint16_t test_buffer_audio[CFG_TUD_AUDIO_TX_FIFO_SIZE/2]; +uint16_t test_buffer_audio[CFG_TUD_AUDIO_EPSIZE_IN/2]; uint16_t startVal = 0; void led_blinking_task(void); @@ -73,12 +73,12 @@ int main(void) tusb_init(); // Init values - sampFreq = 44100; + sampFreq = 48000; clkValid = 1; sampleFreqRng.wNumSubRanges = 1; - sampleFreqRng.subrange[0].bMin = 44100; - sampleFreqRng.subrange[0].bMax = 44100; + sampleFreqRng.subrange[0].bMin = 48000; + sampleFreqRng.subrange[0].bMax = 48000; sampleFreqRng.subrange[0].bRes = 0; while (1) @@ -375,7 +375,7 @@ bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t itf, uint8_t ep_in, u (void) ep_in; (void) cur_alt_setting; - tud_audio_write ((uint8_t *)test_buffer_audio, CFG_TUD_AUDIO_TX_FIFO_SIZE); + tud_audio_write ((uint8_t *)test_buffer_audio, CFG_TUD_AUDIO_EPSIZE_IN); return true; } @@ -388,7 +388,7 @@ bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uin (void) ep_in; (void) cur_alt_setting; - for (size_t cnt = 0; cnt < CFG_TUD_AUDIO_TX_FIFO_SIZE/2; cnt++) + for (size_t cnt = 0; cnt < CFG_TUD_AUDIO_EPSIZE_IN/2; cnt++) { test_buffer_audio[cnt] = startVal++; } diff --git a/examples/device/audio_test/src/tusb_config.h b/examples/device/audio_test/src/tusb_config.h index 5d94858ea..0744afdf0 100644 --- a/examples/device/audio_test/src/tusb_config.h +++ b/examples/device/audio_test/src/tusb_config.h @@ -90,7 +90,6 @@ extern "C" { //-------------------------------------------------------------------- // Audio format type -#define CFG_TUD_AUDIO_USE_TX_FIFO 1 #define CFG_TUD_AUDIO_FORMAT_TYPE_TX AUDIO_FORMAT_TYPE_I #define CFG_TUD_AUDIO_FORMAT_TYPE_RX AUDIO_FORMAT_TYPE_UNDEFINED @@ -100,11 +99,11 @@ extern "C" { #define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX 2 // EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense) -#define CFG_TUD_AUDIO_EPSIZE_IN 48*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX*CFG_TUD_AUDIO_N_CHANNELS_TX // 48 Samples (48 kHz) x 2 Bytes/Sample x 1 Channels -#define CFG_TUD_AUDIO_TX_FIFO_SIZE 48*2 // 48 Samples (48 kHz) x 2 Bytes/Sample (1/2 word) +#define CFG_TUD_AUDIO_EPSIZE_IN 48*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX*CFG_TUD_AUDIO_N_CHANNELS_TX // 48 Samples (48 kHz) x 2 Bytes/Sample x 1 Channels +#define CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE CFG_TUD_AUDIO_EPSIZE_IN + 1; // Just for safety one sample more space // Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes) -#define CFG_TUD_AUDIO_N_AS_INT 1 +#define CFG_TUD_AUDIO_N_AS_INT 1 // Size of control request buffer #define CFG_TUD_AUDIO_CTRL_BUF_SIZE 64 diff --git a/examples/device/audio_test/src/usb_descriptors.c b/examples/device/audio_test/src/usb_descriptors.c index 02d018823..d4869a940 100644 --- a/examples/device/audio_test/src/usb_descriptors.c +++ b/examples/device/audio_test/src/usb_descriptors.c @@ -102,7 +102,7 @@ uint8_t const desc_configuration[] = TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), // Interface number, string index, EP Out & EP In address, EP size - TUD_AUDIO_MIC_DESCRIPTOR(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_stridx*/ 0, /*_nBytesPerSample*/ 3, /*_nBitsUsedPerSample*/ 24, /*_epin*/ 0x80 | EPNUM_AUDIO, /*_epsize*/ 48*4) + TUD_AUDIO_MIC_DESCRIPTOR(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_stridx*/ 0, /*_nBytesPerSample*/ CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX, /*_nBitsUsedPerSample*/ 16, /*_epin*/ 0x80 | EPNUM_AUDIO, /*_epsize*/ CFG_TUD_AUDIO_EPSIZE_IN) }; // Invoked when received GET CONFIGURATION DESCRIPTOR diff --git a/examples/device/uac2_headset/src/tusb_config.h b/examples/device/uac2_headset/src/tusb_config.h index d19feeb86..2ecfd59f6 100644 --- a/examples/device/uac2_headset/src/tusb_config.h +++ b/examples/device/uac2_headset/src/tusb_config.h @@ -112,20 +112,18 @@ extern "C" { #define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 0 // EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense) -#define CFG_TUD_AUDIO_EPSIZE_IN (CFG_TUD_AUDIO_IN_PATH * (48 + 1) * (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX) * (CFG_TUD_AUDIO_N_CHANNELS_TX)) // 48 Samples (48 kHz) x 2 Bytes/Sample x n Channels -#define CFG_TUD_AUDIO_TX_FIFO_COUNT (CFG_TUD_AUDIO_IN_PATH * 1) -#define CFG_TUD_AUDIO_TX_FIFO_SIZE (CFG_TUD_AUDIO_IN_PATH ? ((CFG_TUD_AUDIO_EPSIZE_IN)) : 0) +#define CFG_TUD_AUDIO_EPSIZE_IN (CFG_TUD_AUDIO_IN_PATH * (48 + 1) * (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX) * (CFG_TUD_AUDIO_N_CHANNELS_TX)) // 48 Samples (48 kHz) x 2 Bytes/Sample x n Channels +#define CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE CFG_TUD_AUDIO_EPSIZE_IN // EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense) -#define CFG_TUD_AUDIO_EPSIZE_OUT (CFG_TUD_AUDIO_OUT_PATH * ((48 + CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP) * (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX) * (CFG_TUD_AUDIO_N_CHANNELS_RX))) // N Samples (N kHz) x 2 Bytes/Sample x n Channels -#define CFG_TUD_AUDIO_RX_FIFO_COUNT (CFG_TUD_AUDIO_OUT_PATH * 1) -#define CFG_TUD_AUDIO_RX_FIFO_SIZE (CFG_TUD_AUDIO_OUT_PATH ? (3 * (CFG_TUD_AUDIO_EPSIZE_OUT / CFG_TUD_AUDIO_RX_FIFO_COUNT)) : 0) +#define CFG_TUD_AUDIO_EPSIZE_OUT (CFG_TUD_AUDIO_OUT_PATH * ((48 + CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP) * (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX) * (CFG_TUD_AUDIO_N_CHANNELS_RX))) // N Samples (N kHz) x 2 Bytes/Sample x n Channels +#define CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE CFG_TUD_AUDIO_EPSIZE_OUT*3 // Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes) -#define CFG_TUD_AUDIO_N_AS_INT 1 +#define CFG_TUD_AUDIO_N_AS_INT 1 // Size of control request buffer -#define CFG_TUD_AUDIO_CTRL_BUF_SIZE 64 +#define CFG_TUD_AUDIO_CTRL_BUF_SIZE 64 #ifdef __cplusplus } diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 07bfe6158..d1666056f 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -103,6 +103,11 @@ typedef struct osal_mutex_def_t ep_in_ff_mutex; #endif +#endif + + // Audio control interrupt buffer - no FIFO +#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN + CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE]; #endif // Support FIFOs @@ -122,18 +127,6 @@ typedef struct #endif #endif -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN - tu_fifo_t int_ctr_ff; - CFG_TUSB_MEM_ALIGN uint8_t int_ctr_ff_buf[CFG_TUD_AUDIO_INT_CTR_BUFSIZE]; -#if CFG_FIFO_MUTEX - osal_mutex_def_t int_ctr_ff_mutex; -#endif -#endif - -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN - CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN]; -#endif - } audiod_interface_t; #define ITF_MEM_RESET_SIZE offsetof(audiod_interface_t, ctrl_buf) @@ -146,11 +139,19 @@ CFG_TUSB_MEM_SECTION audiod_interface_t _audiod_itf[CFG_TUD_AUDIO]; extern const uint16_t tud_audio_desc_lengths[]; #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE -static bool audio_rx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* audio, uint8_t * buffer, uint16_t bufsize); +static bool audiod_rx_done_cb(uint8_t rhport, audiod_interface_t* audio); +#endif + +#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE +static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio); #endif #if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE -static bool audiod_tx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* audio); +static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t* audio); +#endif + +#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE +static bool audiod_encode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio); #endif static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const * p_request); @@ -193,80 +194,70 @@ bool tud_audio_n_mounted(uint8_t itf) uint16_t tud_audio_n_available(uint8_t itf) { - TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, ); + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL); return tu_fifo_count(&_audiod_itf[itf].ep_out_ff); } uint16_t tud_audio_n_read(uint8_t itf, void* buffer, uint16_t bufsize) { - TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, ); + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL); return tu_fifo_read_n(&_audiod_itf[itf].ep_out_ff, buffer, bufsize); } -void tud_audio_n_clear_ep_out_ff(uint8_t itf) +bool tud_audio_n_clear_ep_out_ff(uint8_t itf) { - TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, ); + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL); return tu_fifo_clear(&_audiod_itf[itf].ep_out_ff); } #if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE // Delete all content in the support RX FIFOs -void tud_audio_n_clear_rx_support_ff(uint8_t itf, uint8_t channelId) +bool tud_audio_n_clear_rx_support_ff(uint8_t itf, uint8_t channelId) { - TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_RX, ); - tu_fifo_clear(&_audiod_itf[itf].rx_ff[channelId]); + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_RX); + return tu_fifo_clear(&_audiod_itf[itf].rx_ff[channelId]); } uint16_t tud_audio_n_available_support_ff(uint8_t itf, uint8_t channelId) { - TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_RX, ); - tu_fifo_count(&_audiod_itf[itf].rx_ff[channelId]); + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_RX); + return tu_fifo_count(&_audiod_itf[itf].rx_ff[channelId]); } uint16_t tud_audio_n_read_support_ff(uint8_t itf, uint8_t channelId, void* buffer, uint16_t bufsize) { - TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_RX, ); + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_RX); return tu_fifo_read_n(&_audiod_itf[itf].rx_ff[channelId], buffer, bufsize); } #endif #endif - - - - - - - - - -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN - -uint16_t tud_audio_int_ctr_n_available(uint8_t itf) -{ - return tu_fifo_count(&_audiod_itf[itf].int_ctr_ff); -} - -uint16_t tud_audio_int_ctr_n_read(uint8_t itf, void* buffer, uint16_t bufsize) -{ - return tu_fifo_read_n(&_audiod_itf[itf].int_ctr_ff, buffer, bufsize); -} - -void tud_audio_int_ctr_n_read_flush (uint8_t itf) -{ - tu_fifo_clear(&_audiod_itf[itf].int_ctr_ff); -} - -#endif - -// This function is called once something is received by USB and is responsible for decoding received stream into audio channels. +// This function is called once an audio packet is received by the USB and is responsible for decoding received stream into audio channels. // If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE = 0. #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE -static bool audio_rx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint8_t* buffer, uint16_t bufsize) +static bool audiod_rx_done_cb(uint8_t rhport, audiod_interface_t* audio) { + uint8_t idxDriver, idxItf; + uint8_t const *dummy2; + + // If a callback is used determine current alternate setting of + if (tud_audio_rx_done_pre_read_cb || tud_audio_rx_done_post_read_cb) + { + // Find index of audio streaming interface and index of interface + TU_VERIFY(audiod_get_AS_interface_index(audio->ep_out_as_intf_num, &idxDriver, &idxItf, &dummy2)); + } + + // Get number of bytes in EP OUT SW FIFO + uint16_t n_bytes_received = tu_fifo_count(&audio->ep_out_ff); + + // Call a weak callback here - a possibility for user to get informed an audio packet was received and data gets now decoded into support RX software FIFO + if (tud_audio_rx_done_pre_read_cb) TU_VERIFY(tud_audio_rx_done_pre_read_cb(rhport, n_bytes_received, idxDriver, audio->ep_out, audio->altSetting[idxItf])); + +#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE + switch (CFG_TUD_AUDIO_FORMAT_TYPE_RX) { case AUDIO_FORMAT_TYPE_UNDEFINED: @@ -280,12 +271,7 @@ static bool audio_rx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint8_t* switch (CFG_TUD_AUDIO_FORMAT_TYPE_I_RX) { case AUDIO_DATA_FORMAT_TYPE_I_PCM: - -#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE - TU_VERIFY(audio_rx_done_type_I_pcm_ff_cb(rhport, audio, buffer, bufsize)); -#else -#error YOUR DECODING AND BUFFERING IS REQUIRED HERE! -#endif + TU_VERIFY(audiod_decode_type_I_pcm(rhport, audio)); break; default: @@ -303,8 +289,13 @@ static bool audio_rx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint8_t* break; } - // Call a weak callback here - a possibility for user to get informed RX was completed - if (tud_audio_rx_done_cb) TU_VERIFY(tud_audio_rx_done_cb(rhport, buffer, bufsize)); +#endif + + // Prepare for next transmission + TU_VERIFY(usbd_edpt_iso_xfer(rhport, audio->ep_out, &audio->ep_out_ff, CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE), false); + + // Call a weak callback here - a possibility for user to get informed decoding was completed + if (tud_audio_rx_done_post_read_cb) TU_VERIFY(tud_audio_rx_done_post_read_cb(rhport, n_bytes_received, idxDriver, audio->ep_out, audio->altSetting[idxItf])); return true; } @@ -313,59 +304,42 @@ static bool audio_rx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint8_t* // The following functions are used in case CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE != 0 #if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE -#if CFG_TUD_AUDIO_N_CHANNELS_RX > 1 -static bool audio_rx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* audio, uint8_t * buffer, uint16_t bufsize) +static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio) { (void) rhport; - // We expect to get a multiple of CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX per channel - if (bufsize % (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX) != 0) - { - return false; - } + // We assume there is always the correct number of samples available for decoding - extra checks make no sense here - uint8_t chId = 0; - uint16_t cnt; -#if CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX == 1 - uint8_t sample = 0; -#elif CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX == 2 - uint16_t sample = 0; + uint16_t const n_bytes = tu_fifo_count(&audio->ep_out_ff); + + uint16_t cnt = CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX; + + while (cnt <= n_bytes) + { + for (uint8_t cntChannel = 0; cntChannel < CFG_TUD_AUDIO_N_CHANNELS_RX; cntChannel++) + { + // If 8, 16, or 32 bit values are to be copied +#if CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX == CFG_TUD_AUDIO_RX_ITEMSIZE + // If this aborts then the target buffer is full + TU_VERIFY(tu_fifo_read_n_into_other_fifo(&audio->ep_out_ff, &audio->rx_ff[cntChannel], 0, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX)); #else - uint32_t sample = 0; + // TODO: Implement a left and right justified 24 to 32 and vice versa copy process from FIFO to FIFO + uint32_t sample = 0; + + // Get sample from buffer + TU_VERIFY(tu_fifo_read_n(&audio->ep_out_ff, &sample, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX)); + TU_VERIFY(tu_fifo_write_n(&audio->rx_ff[cntChannel], &sample, CFG_TUD_AUDIO_RX_ITEMSIZE)); #endif + } - for(cnt = 0; cnt < bufsize; cnt += CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX) - { - // Let alignment problems be handled by memcpy - memcpy(&sample, &buffer[cnt], CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX); - if(tu_fifo_write_n(&audio->rx_ff[chId++], &sample, CFG_TUD_AUDIO_RX_ITEMSIZE) != CFG_TUD_AUDIO_RX_ITEMSIZE) - { - // Buffer overflow - return false; - } - - if (chId == CFG_TUD_AUDIO_N_CHANNELS_RX) - { - chId = 0; - } - } - return true; -} -#else -static bool audio_rx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t *audio, uint8_t *buffer, uint16_t bufsize) -{ - (void) rhport; - - // We expect to get a multiple of CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX per channel - if (bufsize % (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX) != 0) - { - return false; + cnt += CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX; } - tu_fifo_write_n(&audio->rx_ff[0], buffer, bufsize); + // Number of bytes should be a multiple of CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX but checking makes no sense - no way to correct it + // TU_VERIFY(cnt != n_bytes); + return true; } -#endif // CFG_TUD_AUDIO_N_CHANNELS_RX > 1 #endif //CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE //--------------------------------------------------------------------+ @@ -374,44 +348,6 @@ static bool audio_rx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t *a #if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE -uint16_t tud_audio_n_write(uint8_t itf, const void * data, uint16_t len) -{ - TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, ); - return tu_fifo_write_n(&_audiod_itf[itf].ep_in_ff, data, len); -} - -void tud_audio_n_clear_ep_in_ff(uint8_t itf) // Delete all content in the EP IN FIFO -{ - TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, ); - tu_fifo_clear(&_audiod_itf[itf].ep_in_ff); -} - -#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE -uint16_t tud_audio_n_flush_tx_support_ff(uint8_t itf) // Force all content in the support TX FIFOs to be written into EP SW FIFO -{ - TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, ); - audiod_interface_t* audio = &_audiod_itf[itf]; - uint16_t n_bytes_copied; - TU_VERIFY(audiod_tx_done_cb(audio->rhport, audio, &n_bytes_copied)); - return n_bytes_copied; -} - -uint16_t tud_audio_n_clear_tx_support_ff (uint8_t itf, uint8_t channelId); - -uint16_t tud_audio_n_write_support_ff(uint8_t itf, uint8_t channelId, const void * data, uint16_t len) -{ - TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_TX, ); - return tu_fifo_write_n(&audio->tx_ff[channelId], data, len); -} -#endif - -#endif - - - - - - /** * \brief Write data to EP in buffer * @@ -423,77 +359,78 @@ uint16_t tud_audio_n_write_support_ff(uint8_t itf, uint8_t channelId, const void * \param[in] len: # of array elements to copy * \return Number of bytes actually written */ -#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE -#if !CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE -This function is intended for later use once EP buffers (at least for ISO EPs) are implemented as ring buffers -uint16_t tud_audio_n_write_ep_in_buffer(uint8_t itf, const void * data, uint16_t len) +uint16_t tud_audio_n_write(uint8_t itf, const void * data, uint16_t len) { - audiod_interface_t* audio = &_audiod_itf[itf]; - if (audio->p_desc == NULL) return 0; - - return tu_fifo_write_n(&audio->ep_in_ff, data, len); + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL); + return tu_fifo_write_n(&_audiod_itf[itf].ep_in_ff, data, len); } -#else - -#if CFG_TUD_AUDIO_N_CHANNELS_TX == 1 -uint16_t tud_audio_n_write(uint8_t itf, void const* data, uint16_t len) +bool tud_audio_n_clear_ep_in_ff(uint8_t itf) // Delete all content in the EP IN FIFO { - audiod_interface_t* audio = &_audiod_itf[itf]; - if (audio->p_desc == NULL) - { - return 0; - } - return tu_fifo_write_n(&audio->tx_ff[0], data, len); + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL); + return tu_fifo_clear(&_audiod_itf[itf].ep_in_ff); } -#else -uint16_t tud_audio_n_write(uint8_t itf, uint8_t channelId, const void * data, uint16_t len) + +#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE +uint16_t tud_audio_n_flush_tx_support_ff(uint8_t itf) // Force all content in the support TX FIFOs to be written into EP SW FIFO { + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL); audiod_interface_t* audio = &_audiod_itf[itf]; - if (audio->p_desc == NULL) { - return 0; - } - return tu_fifo_write_n(&audio->tx_ff[channelId], data, len); -} -#endif + uint16_t n_bytes_copied = tu_fifo_count(&audio->ep_in_ff); -static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint16_t * n_bytes_copied); + TU_VERIFY(audiod_tx_done_cb(audio->rhport, audio)); -uint16_t tud_audio_n_write_flush(uint8_t itf) -{ - audiod_interface_t *audio = &_audiod_itf[itf]; - if (audio->p_desc == NULL) { - return 0; - } + n_bytes_copied -= tu_fifo_count(&audio->ep_in_ff); + n_bytes_copied = n_bytes_copied*audio->ep_in_ff.item_size; - uint16_t n_bytes_copied; - TU_VERIFY(audiod_tx_done_cb(audio->rhport, audio, &n_bytes_copied)); return n_bytes_copied; } -#endif -#endif - -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN > 0 -uint32_t tud_audio_int_ctr_n_write(uint8_t itf, uint8_t const* buffer, uint32_t bufsize) +bool tud_audio_n_clear_tx_support_ff(uint8_t itf, uint8_t channelId) { - audiod_interface_t* audio = &_audiod_itf[itf]; - if (audio->p_desc == NULL) { - return 0; - } + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_TX); + return tu_fifo_clear(&_audiod_itf[itf].tx_ff[channelId]); +} - return tu_fifo_write_n(&audio->int_ctr_ff, buffer, bufsize); +uint16_t tud_audio_n_write_support_ff(uint8_t itf, uint8_t channelId, const void * data, uint16_t len) +{ + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_TX); + return tu_fifo_write_n(&_audiod_itf[itf].tx_ff[channelId], data, len); +} +#endif + +#endif + +#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN + +// If no interrupt transmit is pending bytes get written into buffer and a transmit is scheduled - once transmit completed tud_audio_int_ctr_done_cb() is called in inform user +uint16_t tud_audio_int_ctr_n_write(uint8_t itf, uint8_t const* buffer, uint16_t len) +{ + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL); + + // We write directly into the EP's buffer - abort if previous transfer not complete + TU_VERIFY(!usbd_edpt_busy(_audiod_itf[itf].rhport, _audiod_itf[itf].ep_int_ctr)); + + // Check length + TU_VERIFY(len <= CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE); + + memcpy(_audiod_itf[itf].ep_int_ctr_buf, buffer, len); + + // Schedule transmit + TU_VERIFY(usbd_edpt_xfer(_audiod_itf[itf].rhport, _audiod_itf[itf].ep_int_ctr, _audiod_itf[itf].ep_int_ctr_buf, len)); + + return true; } #endif // This function is called once a transmit of an audio packet was successfully completed. Here, we encode samples and place it in IN EP's buffer for next transmission. -// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE = 0 and use tud_audio_n_write_ep_in_buffer() (NOT IMPLEMENTED SO FAR). +// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE = 0 and use tud_audio_n_write. // n_bytes_copied - Informs caller how many bytes were loaded. In case n_bytes_copied = 0, a ZLP is scheduled to inform host no data is available for current frame. #if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE -static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t * audio, uint16_t * n_bytes_copied) +static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t * audio) { uint8_t idxDriver, idxItf; uint8_t const *dummy2; @@ -524,7 +461,7 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t * audio, uint16 { case AUDIO_DATA_FORMAT_TYPE_I_PCM: - TU_VERIFY(audiod_tx_done_type_I_pcm_ff_cb(rhport, audio)); + TU_VERIFY(audiod_encode_type_I_pcm(rhport, audio)); break; @@ -544,14 +481,14 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t * audio, uint16 } #endif - // Inform how many bytes will be copied - *n_bytes_copied = tu_fifo_count(&audio->ep_in_ff); + // Send everything in ISO EP FIFO + uint16_t n_bytes_tx = tu_fifo_count(&audio->ep_in_ff); // Schedule transmit - TU_VERIFY(usbd_edpt_iso_xfer(rhport, audio->ep_in, &audio->ep_in_ff, *n_bytes_copied)); + TU_VERIFY(usbd_edpt_iso_xfer(rhport, audio->ep_in, &audio->ep_in_ff, n_bytes_tx)); // Call a weak callback here - a possibility for user to get informed former TX was completed and how many bytes were loaded for the next frame - if (tud_audio_tx_done_post_load_cb) TU_VERIFY(tud_audio_tx_done_post_load_cb(rhport, *n_bytes_copied, idxDriver, audio->ep_in, audio->altSetting[idxItf])); + if (tud_audio_tx_done_post_load_cb) TU_VERIFY(tud_audio_tx_done_post_load_cb(rhport, n_bytes_tx, idxDriver, audio->ep_in, audio->altSetting[idxItf])); return true; } @@ -559,26 +496,29 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t * audio, uint16 #endif //CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE #if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE -#if CFG_TUD_AUDIO_N_CHANNELS_TX > 1 || (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX != CFG_TUD_AUDIO_TX_ITEMSIZE) -static bool audiod_tx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* audio) +// Take samples from the support buffer and encode them into the IN EP software FIFO +static bool audiod_encode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio) { // We encode directly into IN EP's FIFO - abort if previous transfer not complete TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_in)); // Determine amount of samples uint16_t const nEndpointSampleCapacity = CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE / CFG_TUD_AUDIO_N_CHANNELS_TX / CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX; - uint16_t nSamplesPerChannelToSend = tu_fifo_count(&audio->tx_ff[0]) / CFG_TUD_AUDIO_TX_ITEMSIZE; + uint16_t nSamplesPerChannelToSend = tu_fifo_count(&audio->tx_ff[0]); // We first look for the minimum number of bytes and afterwards convert it to sample size uint8_t cntChannel; for (cntChannel = 1; cntChannel < CFG_TUD_AUDIO_N_CHANNELS_TX; cntChannel++) { uint16_t const count = tu_fifo_count(&audio->tx_ff[cntChannel]); - if (count / CFG_TUD_AUDIO_TX_ITEMSIZE < nSamplesPerChannelToSend) + if (count < nSamplesPerChannelToSend) { - nSamplesPerChannelToSend = count * CFG_TUD_AUDIO_TX_ITEMSIZE; + nSamplesPerChannelToSend = count; } } + // Convert to sample size + nSamplesPerChannelToSend = nSamplesPerChannelToSend / CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX; + // Check if there is enough if (nSamplesPerChannelToSend == 0) return true; @@ -608,106 +548,14 @@ static bool audiod_tx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* } return true; } - -#else -static bool audiod_tx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* audio) -{ - // TODO GET RID OF SINGLE TX_FIFO! - - // We encode directly into IN EP's buffer - abort if previous transfer not complete - TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_in)); - - // Determine amount of samples - uint16_t nByteCount = tu_fifo_count(&audio->tx_ff[0]); - - nByteCount = tu_min16(nByteCount, CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE); - - // Check if there is enough - if (nByteCount == 0) - { - return true; - } - - nByteCount = tu_fifo_read_n_into_other_fifo(&audio->tx_ff[0], &audio->ep_in_ff, 0, nByteCount); - - return true; -} -#endif // CFG_TUD_AUDIO_N_CHANNELS_TX > 1 || (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX != CFG_TUD_AUDIO_TX_ITEMSIZE) - #endif //CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE -// This function is called once a transmit of an feedback packet was successfully completed. Here, we get the next feedback value to be sent +// This function is called once a transmit of a feedback packet was successfully completed. Here, we get the next feedback value to be sent #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -static bool audio_fb_send(uint8_t rhport, audiod_interface_t *audio) +static inline bool audiod_fb_send(uint8_t rhport, audiod_interface_t *audio) { - uint8_t fb[4]; - uint16_t len; - - if (audio->fb_val == 0) - { - len = 0; - return true; - } - else - { - len = 4; - // Here we need to return the feedback value - if (rhport == 0) - { - // For FS format is 10.14 - fb[0] = (audio->fb_val >> 2) & 0xFF; - fb[1] = (audio->fb_val >> 10) & 0xFF; - fb[2] = (audio->fb_val >> 18) & 0xFF; - // 4th byte is needed to work correctly with MS Windows - fb[3] = 0; - } - else - { - // For HS format is 16.16 - fb[0] = (audio->fb_val >> 0) & 0xFF; - fb[1] = (audio->fb_val >> 8) & 0xFF; - fb[2] = (audio->fb_val >> 16) & 0xFF; - fb[3] = (audio->fb_val >> 24) & 0xFF; - } - return usbd_edpt_xfer(rhport, audio->ep_fb, fb, len); - } - -} - -//static uint16_t audio_fb_done_cb(uint8_t rhport, audiod_interface_t* audio) -//{ -// (void) rhport; -// (void) audio; -// -// if (tud_audio_fb_done_cb) TU_VERIFY(tud_audio_fb_done_cb(rhport)); -// return 0; -//} - -#endif - -// This function is called once a transmit of an interrupt control packet was successfully completed. Here, we get the remaining bytes to send - -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN -static bool audio_int_ctr_done_cb(uint8_t rhport, audiod_interface_t* audio, uint16_t * n_bytes_copied) -{ - // We write directly into the EP's buffer - abort if previous transfer not complete - TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_int_ctr)); - - // TODO: Big endianess handling - uint16_t cnt = tu_fifo_read_n(audio->int_ctr_ff, audio->ep_int_ctr_buf, CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN); - - if (cnt > 0) - { - // Schedule transmit - TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_int_ctr, audio->ep_int_ctr_buf, cnt)); - } - - *n_bytes_copied = cnt; - - if (tud_audio_int_ctr_done_cb) TU_VERIFY(tud_audio_int_ctr_done_cb(rhport, n_bytes_copied)); - - return true; + return usbd_edpt_xfer(rhport, audio->ep_fb, (uint8_t *) &audio->fb_val, 4); } #endif @@ -724,11 +572,21 @@ void audiod_init(void) // Initialize IN EP FIFO if required #if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE - // Initialize IN EP FIFO tu_fifo_config(&audio->ep_in_ff, &audio->ep_in_buf, CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&audio->ep_in_ff_mutex)); +#endif #endif - // Initialize TX FIFOs if required + // Initialize OUT EP FIFO if required +#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE + tu_fifo_config(&audio->ep_out_ff, &audio->ep_out_buf, CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&audio->ep_out_ff, osal_mutex_create(&audio->ep_out_ff_mutex)); +#endif +#endif + + // Initialize TX support FIFOs if required #if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE && CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_TX; cnt++) { @@ -739,6 +597,7 @@ void audiod_init(void) } #endif + // Initialize RX support FIFOs if required #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_RX; cnt++) { @@ -746,18 +605,7 @@ void audiod_init(void) #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&audio->rx_ff[cnt], osal_mutex_create(&audio->rx_ff_mutex[cnt])); #endif - - // Initialize OUT EP FIFO - tu_fifo_config(&audio->ep_out_ff, &audio->ep_out_buf, CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE, 1, true); - } -#endif - -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN > 0 - tu_fifo_config(&audio->int_ctr_ff, &audio->int_ctr_ff_buf, CFG_TUD_AUDIO_INT_CTR_BUFSIZE, 1, true); -#if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->int_ctr_ff, osal_mutex_create(&audio->int_ctr_ff_mutex)); -#endif #endif } } @@ -775,6 +623,10 @@ void audiod_reset(uint8_t rhport) tu_fifo_clear(&audio->ep_in_ff); #endif +#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE + tu_fifo_clear(&audio->ep_out_ff); +#endif + #if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE && CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_TX; cnt++) { @@ -881,7 +733,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * TU_VERIFY(audiod_get_AS_interface_index(itf, &idxDriver, &idxItf, &p_desc)); // Look if there is an EP to be closed - for this driver, there are only 3 possible EPs which may be closed (only AS related EPs can be closed, AC EP (if present) is always open) -#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE > 0 +#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE if (_audiod_itf[idxDriver].ep_in_as_intf_num == itf) { _audiod_itf[idxDriver].ep_in_as_intf_num = 0; @@ -932,10 +784,10 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * uint8_t ep_addr = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress; - // We need to set EP non busy since this is not taken care of right now in ep_close() - THIS IS A WORKAROUND! + //TODO: We need to set EP non busy since this is not taken care of right now in ep_close() - THIS IS A WORKAROUND! usbd_edpt_clear_stall(rhport, ep_addr); -#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE > 0 +#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && ((tusb_desc_endpoint_t const *) p_desc)->bmAttributes.usage == 0x00) // Check if usage is data EP { // Save address @@ -946,8 +798,8 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request)); // Schedule first transmit - in case no sample data is available a ZLP is loaded - uint16_t n_bytes_copied; - TU_VERIFY(audiod_tx_done_cb(rhport, &_audiod_itf[idxDriver], &n_bytes_copied)); + // It is necessary to trigger this here since the refill is done with an TX FIFO empty interrupt which can only trigger if something was in there + TU_VERIFY(audiod_tx_done_cb(rhport, &_audiod_itf[idxDriver])); } #endif @@ -963,7 +815,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request)); // Prepare for incoming data - TU_ASSERT(usbd_edpt_xfer(rhport, ep_addr, _audiod_itf[idxDriver].ep_out_buf, CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE), false); + TU_VERIFY(usbd_edpt_iso_xfer(rhport, _audiod_itf[idxDriver].ep_out, &_audiod_itf[idxDriver].ep_out_ff, CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE), false); } #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP @@ -1218,16 +1070,10 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 // In case there is nothing to send we have to return a NAK - this is taken care of by PHY ??? // In case of an erroneous transmission a retransmission is conducted - this is taken care of by PHY ??? - // Load new data - uint16 *n_bytes_copied; - TU_VERIFY(audio_int_ctr_done_cb(rhport, &_audiod_itf[idxDriver], n_bytes_copied)); + // I assume here, that things above are handled by PHY + // All transmission is done - what remains to do is to inform job was completed - if (*n_bytes_copied == 0 && xferred_bytes && (0 == (xferred_bytes % CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN))) - { - // There is no data left to send, a ZLP should be sent if - // xferred_bytes is multiple of EP size and not zero - return usbd_edpt_xfer(rhport, ep_addr, NULL, 0); - } + if (tud_audio_int_ctr_done_cb) TU_VERIFY(tud_audio_int_ctr_done_cb(rhport, (uint16_t) xferred_bytes)); } #endif @@ -1246,8 +1092,7 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 // This is the only place where we can fill something into the EPs buffer! // Load new data - uint16_t n_bytes_copied; - TU_VERIFY(audiod_tx_done_cb(rhport, &_audiod_itf[idxDriver], &n_bytes_copied)); + TU_VERIFY(audiod_tx_done_cb(rhport, &_audiod_itf[idxDriver])); // Transmission of ZLP is done by audiod_tx_done_cb() return true; @@ -1260,10 +1105,8 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 if (_audiod_itf[idxDriver].ep_out == ep_addr) { // Save into buffer - do whatever has to be done - TU_VERIFY(audio_rx_done_cb(rhport, &_audiod_itf[idxDriver], _audiod_itf[idxDriver].ep_out_buf, xferred_bytes)); - - // prepare for next transmission - TU_ASSERT(usbd_edpt_xfer(rhport, ep_addr, _audiod_itf[idxDriver].ep_out_buf, CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE), false); +// TU_VERIFY(audiod_rx_done_cb(rhport, &_audiod_itf[idxDriver], _audiod_itf[idxDriver].ep_out_buf, xferred_bytes)); + TU_VERIFY(audiod_rx_done_cb(rhport, &_audiod_itf[idxDriver])); return true; } @@ -1275,14 +1118,14 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 { if (tud_audio_fb_done_cb) TU_VERIFY(tud_audio_fb_done_cb(rhport)); - return audio_fb_send(rhport, &_audiod_itf[idxDriver]); + // Schedule next transmission - value is changed bytud_audio_n_fb_set() in the meantime or the old value gets sent + return audiod_fb_send(rhport, &_audiod_itf[idxDriver]); } #endif #endif } return false; - } bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_request_t const * p_request, void* data, uint16_t len) @@ -1458,14 +1301,37 @@ static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *idxDriver) } #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -bool tud_audio_fb_set(uint8_t rhport, uint32_t feedback) + +// Input value feedback has to be in 16.16 format - the format will be converted according to speed settings automatically +bool tud_audio_n_fb_set(uint8_t itf, uint32_t feedback) { - audiod_interface_t *audio = &_audiod_itf[0]; + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL); - audio->fb_val = feedback; - TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_fb), true); + // Format the feedback value + if (_audiod_itf[itf].rhport == 0) + { + uint8_t * fb = (uint8_t *) &_audiod_itf[itf].fb_val; - return audio_fb_send(rhport, audio); + // For FS format is 10.14 + *(fb++) = (feedback >> 2) & 0xFF; + *(fb++) = (feedback >> 10) & 0xFF; + *(fb++) = (feedback >> 18) & 0xFF; + // 4th byte is needed to work correctly with MS Windows + *fb = 0; + } + else + { + // For HS format is 16.16 as originally demanded + _audiod_itf[itf].fb_val = feedback; + } + + // Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value + if (!usbd_edpt_busy(_audiod_itf[itf].rhport, _audiod_itf[itf].ep_fb)) + { + return audiod_fb_send(_audiod_itf[itf].rhport, &_audiod_itf[itf]); + } + + return true; } #endif diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index fdd4c15d4..6e0b3308e 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -136,8 +136,8 @@ #endif #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN -#ifndef CFG_TUD_AUDIO_INT_CTR_BUFSIZE -#define CFG_TUD_AUDIO_INT_CTR_BUFSIZE 6 // Buffer size of audio control interrupt EP - 6 Bytes according to UAC 2 specification (p. 74) +#ifndef CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE +#define CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE 6 // Buffer size of audio control interrupt EP - 6 Bytes according to UAC 2 specification (p. 74) #endif #endif @@ -223,10 +223,10 @@ bool tud_audio_n_mounted (uint8_t itf); uint16_t tud_audio_n_available (uint8_t itf); uint16_t tud_audio_n_read (uint8_t itf, void* buffer, uint16_t bufsize); -void tud_audio_n_clear_ep_out_ff (uint8_t itf); // Delete all content in the EP OUT FIFO +bool tud_audio_n_clear_ep_out_ff (uint8_t itf); // Delete all content in the EP OUT FIFO #if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE -void tud_audio_n_clear_rx_support_ff (uint8_t itf, uint8_t channelId); // Delete all content in the support RX FIFOs +bool tud_audio_n_clear_rx_support_ff (uint8_t itf, uint8_t channelId); // Delete all content in the support RX FIFOs uint16_t tud_audio_n_available_support_ff (uint8_t itf, uint8_t channelId); uint16_t tud_audio_n_read_support_ff (uint8_t itf, uint8_t channelId, void* buffer, uint16_t bufsize); #endif @@ -236,20 +236,17 @@ uint16_t tud_audio_n_read_support_ff (uint8_t itf, uint8_t channelI #if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE uint16_t tud_audio_n_write (uint8_t itf, const void * data, uint16_t len); -void tud_audio_n_clear_ep_in_ff (uint8_t itf); // Delete all content in the EP IN FIFO +bool tud_audio_n_clear_ep_in_ff (uint8_t itf); // Delete all content in the EP IN FIFO #if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE uint16_t tud_audio_n_flush_tx_support_ff (uint8_t itf); // Force all content in the support TX FIFOs to be written into EP SW FIFO -uint16_t tud_audio_n_clear_tx_support_ff (uint8_t itf, uint8_t channelId); +bool tud_audio_n_clear_tx_support_ff (uint8_t itf, uint8_t channelId); uint16_t tud_audio_n_write_support_ff (uint8_t itf, uint8_t channelId, const void * data, uint16_t len); #endif #endif #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN -uint16_t tud_audio_int_ctr_n_available (uint8_t itf); -uint16_t tud_audio_int_ctr_n_read (uint8_t itf, void* buffer, uint16_t bufsize); -void tud_audio_int_ctr_n_clear (uint8_t itf); // Delete all content in the AUDIO_INT_CTR FIFO uint16_t tud_audio_int_ctr_n_write (uint8_t itf, uint8_t const* buffer, uint16_t len); #endif @@ -264,11 +261,11 @@ static inline bool tud_audio_mounted (void); #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE static inline uint16_t tud_audio_available (void); -static inline void tud_audio_clear_ep_out_ff (void); // Delete all content in the EP OUT FIFO +static inline bool tud_audio_clear_ep_out_ff (void); // Delete all content in the EP OUT FIFO static inline uint16_t tud_audio_read (void* buffer, uint16_t bufsize); #if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE -static inline void tud_audio_clear_rx_support_ff (uint8_t channelId); +static inline bool tud_audio_clear_rx_support_ff (uint8_t channelId); static inline uint16_t tud_audio_available_support_ff (uint8_t channelId); static inline uint16_t tud_audio_read_support_ff (uint8_t channelId, void* buffer, uint16_t bufsize); #endif @@ -280,7 +277,7 @@ static inline uint16_t tud_audio_read_support_ff (uint8_t channelId, #if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE static inline uint16_t tud_audio_write (const void * data, uint16_t len); -static inline uint16_t tud_audio_clear_ep_in_ff (void); +static inline bool tud_audio_clear_ep_in_ff (void); #if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE static inline uint16_t tud_audio_flush_tx_support_ff (void); @@ -293,9 +290,6 @@ static inline uint16_t tud_audio_write_support_ff (uint8_t channelId, // INT CTR API #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN -static inline uint16_t tud_audio_int_ctr_available (void); -static inline uint16_t tud_audio_int_ctr_read (void* buffer, uint16_t bufsize); -static inline void tud_audio_int_ctr_clear (void); static inline uint16_t tud_audio_int_ctr_write (uint8_t const* buffer, uint16_t len); #endif @@ -317,8 +311,8 @@ TU_ATTR_WEAK bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_byte #endif #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE -TU_ATTR_WEAK bool tud_audio_rx_done_pre_read_cb(uint8_t rhport, uint8_t itf, uint8_t ep_out, uint8_t cur_alt_setting); -TU_ATTR_WEAK bool tud_audio_rx_done_post_read_cb(uint8_t rhport, uint16_t n_bytes_copied, uint8_t itf, uint8_t ep_out, uint8_t cur_alt_setting); +TU_ATTR_WEAK bool tud_audio_rx_done_pre_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t itf, uint8_t ep_out, uint8_t cur_alt_setting); +TU_ATTR_WEAK bool tud_audio_rx_done_post_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t itf, uint8_t ep_out, uint8_t cur_alt_setting); #endif #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP @@ -327,11 +321,12 @@ TU_ATTR_WEAK bool tud_audio_fb_done_cb(uint8_t rhport); // Value will be corrected for FS to 10.14 format automatically. // (see Universal Serial Bus Specification Revision 2.0 5.12.4.2). // Feedback value will be sent at FB endpoint interval till it's changed. -bool tud_audio_fb_set(uint8_t rhport, uint32_t feedback); +bool tud_audio_n_fb_set(uint8_t itf, uint32_t feedback); +static inline bool tud_audio_fb_set(uint32_t feedback); #endif #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN -TU_ATTR_WEAK bool tud_audio_int_ctr_done_cb(uint8_t rhport, uint16_t * n_bytes_copied); +TU_ATTR_WEAK bool tud_audio_int_ctr_done_cb(uint8_t rhport, uint16_t n_bytes_copied); #endif // Invoked when audio set interface request received @@ -381,16 +376,16 @@ static inline uint16_t tud_audio_read (void* buffer, uint1 return tud_audio_n_read(0, buffer, bufsize); } -static inline uint16_t tud_audio_clear_ep_out_ff (void) +static inline bool tud_audio_clear_ep_out_ff (void) { return tud_audio_n_clear_ep_out_ff(0); } #if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE -static inline void tud_audio_clear_rx_support_ff (uint8_t channelId) +static inline bool tud_audio_clear_rx_support_ff (uint8_t channelId) { - tud_audio_n_clear_rx_support_ff(0, channelId); + return tud_audio_n_clear_rx_support_ff(0, channelId); } static inline uint16_t tud_audio_available_support_ff (uint8_t channelId) @@ -416,7 +411,7 @@ static inline uint16_t tud_audio_write (const void * data, return tud_audio_n_write(0, data, len); } -static inline uint16_t tud_audio_clear_ep_in_ff (void) +static inline bool tud_audio_clear_ep_in_ff (void) { return tud_audio_n_clear_ep_in_ff(0); } @@ -443,27 +438,19 @@ static inline uint16_t tud_audio_write_support_ff (uint8_t channelId, #endif #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN -static inline uint16_t tud_audio_int_ctr_available(void) -{ - return tud_audio_int_ctr_n_available(0); -} - -static inline uint16_t tud_audio_int_ctr_read(void* buffer, uint16_t bufsize) -{ - return tud_audio_int_ctr_n_read(0, buffer, bufsize); -} - -static inline void tud_audio_int_ctr_clear(void) -{ - return tud_audio_int_ctr_n_clear(0); -} - static inline uint16_t tud_audio_int_ctr_write(uint8_t const* buffer, uint16_t len) { return tud_audio_int_ctr_n_write(0, buffer, len); } #endif +#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +static inline bool tud_audio_fb_set(uint32_t feedback) +{ + return tud_audio_n_fb_set(0, feedback); +} +#endif + //--------------------------------------------------------------------+ // Internal Class Driver API //--------------------------------------------------------------------+ diff --git a/src/portable/st/synopsys/dcd_synopsys.c b/src/portable/st/synopsys/dcd_synopsys.c index 4cb6028cc..b6dacd927 100644 --- a/src/portable/st/synopsys/dcd_synopsys.c +++ b/src/portable/st/synopsys/dcd_synopsys.c @@ -697,14 +697,6 @@ bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_ tu_fifo_set_copy_mode_read(ff, TU_FIFO_COPY_CST); } - // EP0 can only handle one packet - if(epnum == 0) { - ep0_pending[dir] = total_bytes; - // Schedule the first transaction for EP0 transfer - edpt_schedule_packets(rhport, epnum, dir, 1, ep0_pending[dir]); - return true; - } - uint16_t num_packets = (total_bytes / xfer->max_size); uint8_t const short_packet_size = total_bytes % xfer->max_size; From 185414721ff549058a199ade40966015e6260996 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Fri, 12 Feb 2021 18:04:45 +0100 Subject: [PATCH 016/121] Formating --- src/class/audio/audio.h | 10 +-- src/class/audio/audio_device.c | 108 ++++++++++++++++----------------- src/class/audio/audio_device.h | 2 +- 3 files changed, 60 insertions(+), 60 deletions(-) diff --git a/src/class/audio/audio.h b/src/class/audio/audio.h index 05e61f8df..af0e86e21 100644 --- a/src/class/audio/audio.h +++ b/src/class/audio/audio.h @@ -901,7 +901,7 @@ typedef struct TU_ATTR_PACKED { } subrange[numSubRanges] ; \ } - /// 5.2.3.2 2-byte Control RANGE Parameter Block +/// 5.2.3.2 2-byte Control RANGE Parameter Block #define audio_control_range_2_n_t(numSubRanges) \ struct TU_ATTR_PACKED { \ uint16_t wNumSubRanges; \ @@ -912,7 +912,7 @@ typedef struct TU_ATTR_PACKED { } subrange[numSubRanges]; \ } - // 5.2.3.3 4-byte Control RANGE Parameter Block +// 5.2.3.3 4-byte Control RANGE Parameter Block #define audio_control_range_4_n_t(numSubRanges) \ struct TU_ATTR_PACKED { \ uint16_t wNumSubRanges; \ @@ -923,12 +923,12 @@ typedef struct TU_ATTR_PACKED { } subrange[numSubRanges]; \ } - /** @} */ +/** @} */ #ifdef __cplusplus - } +} #endif #endif - /** @} */ +/** @} */ diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index d1666056f..622e6d113 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -240,21 +240,21 @@ uint16_t tud_audio_n_read_support_ff(uint8_t itf, uint8_t channelId, void* buffe static bool audiod_rx_done_cb(uint8_t rhport, audiod_interface_t* audio) { - uint8_t idxDriver, idxItf; - uint8_t const *dummy2; + uint8_t idxDriver, idxItf; + uint8_t const *dummy2; - // If a callback is used determine current alternate setting of - if (tud_audio_rx_done_pre_read_cb || tud_audio_rx_done_post_read_cb) - { - // Find index of audio streaming interface and index of interface - TU_VERIFY(audiod_get_AS_interface_index(audio->ep_out_as_intf_num, &idxDriver, &idxItf, &dummy2)); - } + // If a callback is used determine current alternate setting of + if (tud_audio_rx_done_pre_read_cb || tud_audio_rx_done_post_read_cb) + { + // Find index of audio streaming interface and index of interface + TU_VERIFY(audiod_get_AS_interface_index(audio->ep_out_as_intf_num, &idxDriver, &idxItf, &dummy2)); + } - // Get number of bytes in EP OUT SW FIFO - uint16_t n_bytes_received = tu_fifo_count(&audio->ep_out_ff); + // Get number of bytes in EP OUT SW FIFO + uint16_t n_bytes_received = tu_fifo_count(&audio->ep_out_ff); - // Call a weak callback here - a possibility for user to get informed an audio packet was received and data gets now decoded into support RX software FIFO - if (tud_audio_rx_done_pre_read_cb) TU_VERIFY(tud_audio_rx_done_pre_read_cb(rhport, n_bytes_received, idxDriver, audio->ep_out, audio->altSetting[idxItf])); + // Call a weak callback here - a possibility for user to get informed an audio packet was received and data gets now decoded into support RX software FIFO + if (tud_audio_rx_done_pre_read_cb) TU_VERIFY(tud_audio_rx_done_pre_read_cb(rhport, n_bytes_received, idxDriver, audio->ep_out, audio->altSetting[idxItf])); #if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE @@ -316,23 +316,23 @@ static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio) while (cnt <= n_bytes) { - for (uint8_t cntChannel = 0; cntChannel < CFG_TUD_AUDIO_N_CHANNELS_RX; cntChannel++) - { - // If 8, 16, or 32 bit values are to be copied + for (uint8_t cntChannel = 0; cntChannel < CFG_TUD_AUDIO_N_CHANNELS_RX; cntChannel++) + { + // If 8, 16, or 32 bit values are to be copied #if CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX == CFG_TUD_AUDIO_RX_ITEMSIZE - // If this aborts then the target buffer is full - TU_VERIFY(tu_fifo_read_n_into_other_fifo(&audio->ep_out_ff, &audio->rx_ff[cntChannel], 0, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX)); + // If this aborts then the target buffer is full + TU_VERIFY(tu_fifo_read_n_into_other_fifo(&audio->ep_out_ff, &audio->rx_ff[cntChannel], 0, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX)); #else - // TODO: Implement a left and right justified 24 to 32 and vice versa copy process from FIFO to FIFO - uint32_t sample = 0; + // TODO: Implement a left and right justified 24 to 32 and vice versa copy process from FIFO to FIFO + uint32_t sample = 0; - // Get sample from buffer - TU_VERIFY(tu_fifo_read_n(&audio->ep_out_ff, &sample, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX)); - TU_VERIFY(tu_fifo_write_n(&audio->rx_ff[cntChannel], &sample, CFG_TUD_AUDIO_RX_ITEMSIZE)); + // Get sample from buffer + TU_VERIFY(tu_fifo_read_n(&audio->ep_out_ff, &sample, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX)); + TU_VERIFY(tu_fifo_write_n(&audio->rx_ff[cntChannel], &sample, CFG_TUD_AUDIO_RX_ITEMSIZE)); #endif - } + } - cnt += CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX; + cnt += CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX; } // Number of bytes should be a multiple of CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX but checking makes no sense - no way to correct it @@ -389,8 +389,8 @@ uint16_t tud_audio_n_flush_tx_support_ff(uint8_t itf) // Force a bool tud_audio_n_clear_tx_support_ff(uint8_t itf, uint8_t channelId) { - TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_TX); - return tu_fifo_clear(&_audiod_itf[itf].tx_ff[channelId]); + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_TX); + return tu_fifo_clear(&_audiod_itf[itf].tx_ff[channelId]); } uint16_t tud_audio_n_write_support_ff(uint8_t itf, uint8_t channelId, const void * data, uint16_t len) @@ -574,15 +574,15 @@ void audiod_init(void) #if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE tu_fifo_config(&audio->ep_in_ff, &audio->ep_in_buf, CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&audio->ep_in_ff_mutex)); + tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&audio->ep_in_ff_mutex)); #endif #endif // Initialize OUT EP FIFO if required #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE - tu_fifo_config(&audio->ep_out_ff, &audio->ep_out_buf, CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE, 1, true); + tu_fifo_config(&audio->ep_out_ff, &audio->ep_out_buf, CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->ep_out_ff, osal_mutex_create(&audio->ep_out_ff_mutex)); + tu_fifo_config_mutex(&audio->ep_out_ff, osal_mutex_create(&audio->ep_out_ff_mutex)); #endif #endif @@ -1105,8 +1105,8 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 if (_audiod_itf[idxDriver].ep_out == ep_addr) { // Save into buffer - do whatever has to be done -// TU_VERIFY(audiod_rx_done_cb(rhport, &_audiod_itf[idxDriver], _audiod_itf[idxDriver].ep_out_buf, xferred_bytes)); - TU_VERIFY(audiod_rx_done_cb(rhport, &_audiod_itf[idxDriver])); + // TU_VERIFY(audiod_rx_done_cb(rhport, &_audiod_itf[idxDriver], _audiod_itf[idxDriver].ep_out_buf, xferred_bytes)); + TU_VERIFY(audiod_rx_done_cb(rhport, &_audiod_itf[idxDriver])); return true; } @@ -1305,33 +1305,33 @@ static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *idxDriver) // Input value feedback has to be in 16.16 format - the format will be converted according to speed settings automatically bool tud_audio_n_fb_set(uint8_t itf, uint32_t feedback) { - TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL); + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL); - // Format the feedback value - if (_audiod_itf[itf].rhport == 0) - { - uint8_t * fb = (uint8_t *) &_audiod_itf[itf].fb_val; + // Format the feedback value + if (_audiod_itf[itf].rhport == 0) + { + uint8_t * fb = (uint8_t *) &_audiod_itf[itf].fb_val; - // For FS format is 10.14 - *(fb++) = (feedback >> 2) & 0xFF; - *(fb++) = (feedback >> 10) & 0xFF; - *(fb++) = (feedback >> 18) & 0xFF; - // 4th byte is needed to work correctly with MS Windows - *fb = 0; - } - else - { - // For HS format is 16.16 as originally demanded - _audiod_itf[itf].fb_val = feedback; - } + // For FS format is 10.14 + *(fb++) = (feedback >> 2) & 0xFF; + *(fb++) = (feedback >> 10) & 0xFF; + *(fb++) = (feedback >> 18) & 0xFF; + // 4th byte is needed to work correctly with MS Windows + *fb = 0; + } + else + { + // For HS format is 16.16 as originally demanded + _audiod_itf[itf].fb_val = feedback; + } - // Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value - if (!usbd_edpt_busy(_audiod_itf[itf].rhport, _audiod_itf[itf].ep_fb)) - { - return audiod_fb_send(_audiod_itf[itf].rhport, &_audiod_itf[itf]); - } + // Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value + if (!usbd_edpt_busy(_audiod_itf[itf].rhport, _audiod_itf[itf].ep_fb)) + { + return audiod_fb_send(_audiod_itf[itf].rhport, &_audiod_itf[itf]); + } - return true; + return true; } #endif diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index 6e0b3308e..34ba5bb55 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -447,7 +447,7 @@ static inline uint16_t tud_audio_int_ctr_write(uint8_t const* buffer, uint16_t l #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP static inline bool tud_audio_fb_set(uint32_t feedback) { - return tud_audio_n_fb_set(0, feedback); + return tud_audio_n_fb_set(0, feedback); } #endif From 3df61d6755b351d97a5632ee91b1b88f0a6126d9 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Fri, 12 Feb 2021 18:25:01 +0100 Subject: [PATCH 017/121] Fix a ; in #define definition --- examples/device/audio_test/src/tusb_config.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/device/audio_test/src/tusb_config.h b/examples/device/audio_test/src/tusb_config.h index 66a2ae22c..c6d786398 100644 --- a/examples/device/audio_test/src/tusb_config.h +++ b/examples/device/audio_test/src/tusb_config.h @@ -101,11 +101,11 @@ extern "C" { #define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX 2 // EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense) -#define CFG_TUD_AUDIO_EPSIZE_IN 48*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX*CFG_TUD_AUDIO_N_CHANNELS_TX // 48 Samples (48 kHz) x 2 Bytes/Sample x 1 Channels -#define CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE CFG_TUD_AUDIO_EPSIZE_IN + 1; // Just for safety one sample more space +#define CFG_TUD_AUDIO_EPSIZE_IN 48*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX*CFG_TUD_AUDIO_N_CHANNELS_TX // 48 Samples (48 kHz) x 2 Bytes/Sample x 1 Channels +#define CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE CFG_TUD_AUDIO_EPSIZE_IN + 1 // Just for safety one sample more space // Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes) -#define CFG_TUD_AUDIO_N_AS_INT 1 +#define CFG_TUD_AUDIO_N_AS_INT 1 // Size of control request buffer #define CFG_TUD_AUDIO_CTRL_BUF_SIZE 64 From 9e2a1d2e6a22fb1cfb952a62f501403d372bbb45 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Fri, 12 Feb 2021 18:31:54 +0100 Subject: [PATCH 018/121] Fix CFG_TUD_AUDIO_EP_IN/OUT_SW_BUFFER_SIZE to be defined anyway --- src/class/audio/audio_device.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index 34ba5bb55..d1d1157eb 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -64,21 +64,25 @@ #ifndef CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE #define CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE CFG_TUD_AUDIO_EPSIZE_IN // TX #endif +#else +#define CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE 0 #endif #if CFG_TUD_AUDIO_EPSIZE_OUT #ifndef CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE #define CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE CFG_TUD_AUDIO_EPSIZE_OUT // RX #endif +#else +#define CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE 0 #endif // General information of number of TX and/or RX channels - is used in case support FIFOs (see below) are used and can be used for descriptor definitions #ifndef CFG_TUD_AUDIO_N_CHANNELS_TX -#define CFG_TUD_AUDIO_N_CHANNELS_TX 0 +#define CFG_TUD_AUDIO_N_CHANNELS_TX 0 #endif #ifndef CFG_TUD_AUDIO_N_CHANNELS_RX -#define CFG_TUD_AUDIO_N_CHANNELS_RX 0 +#define CFG_TUD_AUDIO_N_CHANNELS_RX 0 #endif // Use of TX/RX support FIFOs From 59d6ed9ea409525899d398789b255ffb7f96660a Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sat, 13 Feb 2021 12:13:10 +0100 Subject: [PATCH 019/121] Implement dcd_edpt_iso_xfer() for dcd_esp32s2.c --- src/portable/espressif/esp32s2/dcd_esp32s2.c | 180 +++++++++++++------ 1 file changed, 129 insertions(+), 51 deletions(-) diff --git a/src/portable/espressif/esp32s2/dcd_esp32s2.c b/src/portable/espressif/esp32s2/dcd_esp32s2.c index 703841759..72fb4ba48 100644 --- a/src/portable/espressif/esp32s2/dcd_esp32s2.c +++ b/src/portable/espressif/esp32s2/dcd_esp32s2.c @@ -27,6 +27,7 @@ */ #include "tusb_option.h" +#include "common/tusb_fifo.h" #if CFG_TUSB_MCU == OPT_MCU_ESP32S2 && TUSB_OPT_DEVICE_ENABLED @@ -59,6 +60,7 @@ typedef struct { uint8_t *buffer; + tu_fifo_t * ff; uint16_t total_len; uint16_t queued_len; uint16_t max_size; @@ -354,6 +356,64 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to return true; } +bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +{ + (void)rhport; + + // USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1 + TU_ASSERT(ff->item_size == 1); + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); + xfer->buffer = NULL; + xfer->ff = ff; + xfer->total_len = total_bytes; + xfer->queued_len = 0; + xfer->short_packet = false; + + uint16_t num_packets = (total_bytes / xfer->max_size); + uint8_t short_packet_size = total_bytes % xfer->max_size; + + // Zero-size packet is special case. + if (short_packet_size > 0 || (total_bytes == 0)) { + num_packets++; + } + + // Set copy mode to constant address - required since data copied to or from the hardware USB FIFO needs to be written at a constant address + if (dir == TUSB_DIR_IN) + { + tu_fifo_set_copy_mode_write(ff, TU_FIFO_COPY_CST); + } + else + { + tu_fifo_set_copy_mode_read(ff, TU_FIFO_COPY_CST); + } + + ESP_LOGV(TAG, "Transfer <-> EP%i, %s, pkgs: %i, bytes: %i", + epnum, ((dir == TUSB_DIR_IN) ? "USB0.HOST (in)" : "HOST->DEV (out)"), + num_packets, total_bytes); + + // IN and OUT endpoint xfers are interrupt-driven, we just schedule them + // here. + if (dir == TUSB_DIR_IN) { + // A full IN transfer (multiple packets, possibly) triggers XFRC. + USB0.in_ep_reg[epnum].dieptsiz = (num_packets << USB_D_PKTCNT0_S) | total_bytes; + USB0.in_ep_reg[epnum].diepctl |= USB_D_EPENA1_M | USB_D_CNAK1_M; // Enable | CNAK + + // Enable fifo empty interrupt only if there are something to put in the fifo. + if(total_bytes != 0) { + USB0.dtknqr4_fifoemptymsk |= (1 << epnum); + } + } else { + // Each complete packet for OUT xfers triggers XFRC. + USB0.out_ep_reg[epnum].doeptsiz |= USB_PKTCNT0_M | ((xfer->max_size & USB_XFERSIZE0_V) << USB_XFERSIZE0_S); + USB0.out_ep_reg[epnum].doepctl |= USB_EPENA0_M | USB_CNAK0_M; + } + return true; +} + void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { (void)rhport; @@ -462,36 +522,46 @@ static void receive_packet(xfer_ctl_t *xfer, /* usb_out_endpoint_t * out_ep, */ to_recv_size = (xfer_size > xfer->max_size) ? xfer->max_size : xfer_size; } - uint8_t to_recv_rem = to_recv_size % 4; - uint16_t to_recv_size_aligned = to_recv_size - to_recv_rem; + // Common buffer read + if (xfer->buffer) + { + uint8_t to_recv_rem = to_recv_size % 4; + uint16_t to_recv_size_aligned = to_recv_size - to_recv_rem; - // Do not assume xfer buffer is aligned. - uint8_t *base = (xfer->buffer + xfer->queued_len); + // Do not assume xfer buffer is aligned. + uint8_t *base = (xfer->buffer + xfer->queued_len); - // This for loop always runs at least once- skip if less than 4 bytes - // to collect. - if (to_recv_size >= 4) { - for (uint16_t i = 0; i < to_recv_size_aligned; i += 4) { + // This for loop always runs at least once- skip if less than 4 bytes + // to collect. + if (to_recv_size >= 4) { + for (uint16_t i = 0; i < to_recv_size_aligned; i += 4) { + uint32_t tmp = (*rx_fifo); + base[i] = tmp & 0x000000FF; + base[i + 1] = (tmp & 0x0000FF00) >> 8; + base[i + 2] = (tmp & 0x00FF0000) >> 16; + base[i + 3] = (tmp & 0xFF000000) >> 24; + } + } + + // Do not read invalid bytes from RX FIFO. + if (to_recv_rem != 0) { uint32_t tmp = (*rx_fifo); - base[i] = tmp & 0x000000FF; - base[i + 1] = (tmp & 0x0000FF00) >> 8; - base[i + 2] = (tmp & 0x00FF0000) >> 16; - base[i + 3] = (tmp & 0xFF000000) >> 24; + uint8_t *last_32b_bound = base + to_recv_size_aligned; + + last_32b_bound[0] = tmp & 0x000000FF; + if (to_recv_rem > 1) { + last_32b_bound[1] = (tmp & 0x0000FF00) >> 8; + } + if (to_recv_rem > 2) { + last_32b_bound[2] = (tmp & 0x00FF0000) >> 16; + } } + } - - // Do not read invalid bytes from RX FIFO. - if (to_recv_rem != 0) { - uint32_t tmp = (*rx_fifo); - uint8_t *last_32b_bound = base + to_recv_size_aligned; - - last_32b_bound[0] = tmp & 0x000000FF; - if (to_recv_rem > 1) { - last_32b_bound[1] = (tmp & 0x0000FF00) >> 8; - } - if (to_recv_rem > 2) { - last_32b_bound[2] = (tmp & 0x00FF0000) >> 16; - } + else + { + // Ring buffer + tu_fifo_write_n(xfer->ff, (const void *) rx_fifo, to_recv_size); } xfer->queued_len += xfer_size; @@ -510,37 +580,45 @@ static void transmit_packet(xfer_ctl_t *xfer, volatile usb_in_endpoint_t *in_ep, xfer->queued_len = xfer->total_len - remaining; uint16_t to_xfer_size = (remaining > xfer->max_size) ? xfer->max_size : remaining; - uint8_t to_xfer_rem = to_xfer_size % 4; - uint16_t to_xfer_size_aligned = to_xfer_size - to_xfer_rem; - // Buffer might not be aligned to 32b, so we need to force alignment - // by copying to a temp var. - uint8_t *base = (xfer->buffer + xfer->queued_len); + if (xfer->buffer) + { + uint8_t to_xfer_rem = to_xfer_size % 4; + uint16_t to_xfer_size_aligned = to_xfer_size - to_xfer_rem; + + // Buffer might not be aligned to 32b, so we need to force alignment + // by copying to a temp var. + uint8_t *base = (xfer->buffer + xfer->queued_len); + + // This for loop always runs at least once- skip if less than 4 bytes + // to send off. + if (to_xfer_size >= 4) { + for (uint16_t i = 0; i < to_xfer_size_aligned; i += 4) { + uint32_t tmp = base[i] | (base[i + 1] << 8) | + (base[i + 2] << 16) | (base[i + 3] << 24); + (*tx_fifo) = tmp; + } + } + + // Do not read beyond end of buffer if not divisible by 4. + if (to_xfer_rem != 0) { + uint32_t tmp = 0; + uint8_t *last_32b_bound = base + to_xfer_size_aligned; + + tmp |= last_32b_bound[0]; + if (to_xfer_rem > 1) { + tmp |= (last_32b_bound[1] << 8); + } + if (to_xfer_rem > 2) { + tmp |= (last_32b_bound[2] << 16); + } - // This for loop always runs at least once- skip if less than 4 bytes - // to send off. - if (to_xfer_size >= 4) { - for (uint16_t i = 0; i < to_xfer_size_aligned; i += 4) { - uint32_t tmp = base[i] | (base[i + 1] << 8) | - (base[i + 2] << 16) | (base[i + 3] << 24); (*tx_fifo) = tmp; } } - - // Do not read beyond end of buffer if not divisible by 4. - if (to_xfer_rem != 0) { - uint32_t tmp = 0; - uint8_t *last_32b_bound = base + to_xfer_size_aligned; - - tmp |= last_32b_bound[0]; - if (to_xfer_rem > 1) { - tmp |= (last_32b_bound[1] << 8); - } - if (to_xfer_rem > 2) { - tmp |= (last_32b_bound[2] << 16); - } - - (*tx_fifo) = tmp; + else + { + tu_fifo_read_n(xfer->ff, (void *) tx_fifo, to_xfer_size); } } From 7ab389db210fdab67bdcc68b5d245606b5146a03 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sat, 13 Feb 2021 16:36:32 +0100 Subject: [PATCH 020/121] Implement dcd_edpt_iso_xfer() for dcd_samg.c. NOTE: ISO EP not supported --- src/portable/microchip/samg/dcd_samg.c | 53 +++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/src/portable/microchip/samg/dcd_samg.c b/src/portable/microchip/samg/dcd_samg.c index 2f9f1097f..465f6419e 100644 --- a/src/portable/microchip/samg/dcd_samg.c +++ b/src/portable/microchip/samg/dcd_samg.c @@ -25,6 +25,7 @@ */ #include "tusb_option.h" +#include "common/tusb_fifo.h" #if CFG_TUSB_MCU == OPT_MCU_SAMG @@ -43,6 +44,7 @@ typedef struct { uint8_t* buffer; + tu_fifo_t* ff; uint16_t total_len; volatile uint16_t actual_len; uint16_t epsize; @@ -293,6 +295,38 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t return true; } +bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +{ + (void) rhport; + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + xfer_desc_t* xfer = &_dcd_xfer[epnum]; + xfer->total_len = total_bytes; + xfer->actual_len = 0; + xfer->buffer = NULL; // Indicates a FIFO shall be used + xfer->ff = ff; + + if (dir == TUSB_DIR_OUT) + { + tu_fifo_set_copy_mode_read(ff, TU_FIFO_COPY_CST); + + // Enable interrupt when starting OUT transfer + if (epnum != 0) UDP->UDP_IER |= (1 << epnum); + } + else + { + tu_fifo_set_copy_mode_write(ff, TU_FIFO_COPY_CST); + tu_fifo_read_n(ff, (void *) &UDP->UDP_FDR[epnum], xfer_packet_len(xfer)); + + // TX ready for transfer + csr_set(epnum, UDP_CSR_TXPKTRDY_Msk); + } + + return true; +} + // Stall endpoint void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr) { @@ -402,7 +436,14 @@ void dcd_int_handler(uint8_t rhport) if (xact_len) { // write to EP fifo - xact_ep_write(epnum, xfer->buffer, xact_len); + if (xfer->buffer) + { + xact_ep_write(epnum, xfer->buffer, xact_len); + } + else + { + tu_fifo_read_n(ff, (void *) &UDP->UDP_FDR[epnum], xact_len); + } // TX ready for transfer csr_set(epnum, UDP_CSR_TXPKTRDY_Msk); @@ -428,7 +469,15 @@ void dcd_int_handler(uint8_t rhport) uint16_t const xact_len = (uint16_t) ((UDP->UDP_CSR[epnum] & UDP_CSR_RXBYTECNT_Msk) >> UDP_CSR_RXBYTECNT_Pos); // Read from EP fifo - xact_ep_read(epnum, xfer->buffer, xact_len); + if (xfer->buffer) + { + xact_ep_read(epnum, xfer->buffer, xact_len); + } + else + { + tu_fifo_write_n(xfer->ff, (const void *) &UDP->UDP_FDR[epnum], xact_len); + } + xfer_packet_done(xfer); if ( 0 == xfer_packet_len(xfer) ) From e6816784021959223ce740ed6946b62136778fec Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sat, 13 Feb 2021 17:06:27 +0100 Subject: [PATCH 021/121] Implement dcd_edpt_iso_xfer() for dcd_nuc120.c --- src/portable/nuvoton/nuc120/dcd_nuc120.c | 58 ++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/src/portable/nuvoton/nuc120/dcd_nuc120.c b/src/portable/nuvoton/nuc120/dcd_nuc120.c index dc48e54cc..0c3bd9a6b 100644 --- a/src/portable/nuvoton/nuc120/dcd_nuc120.c +++ b/src/portable/nuvoton/nuc120/dcd_nuc120.c @@ -34,6 +34,7 @@ */ #include "tusb_option.h" +#include "common/tusb_fifo.h" #if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_NUC120) @@ -76,6 +77,7 @@ static bool active_ep0_xfer; static struct xfer_ctl_t { uint8_t *data_ptr; /* data_ptr tracks where to next copy data to (for OUT) or from (for IN) */ + tu_fifo_t * ff; /* pointer to FIFO required for dcd_edpt_iso_xfer() */ union { uint16_t in_remaining_bytes; /* for IN endpoints, we track how many bytes are left to transfer */ uint16_t out_bytes_so_far; /* but for OUT endpoints, we track how many bytes we've transferred so far */ @@ -142,7 +144,15 @@ static void dcd_in_xfer(struct xfer_ctl_t *xfer, USBD_EP_T *ep) { uint16_t bytes_now = tu_min16(xfer->in_remaining_bytes, xfer->max_packet_size); - memcpy((uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), xfer->data_ptr, bytes_now); + if (xfer->data_ptr) + { + memcpy((uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), xfer->data_ptr, bytes_now); + } + else + { + tu_fifo_read_n(xfer->ff, (void *) (USBD_BUF_BASE + ep->BUFSEG), bytes_now); + } + ep->MXPLD = bytes_now; } @@ -286,6 +296,36 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to return true; } +bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +{ + (void) rhport; + + /* mine the data for the information we need */ + tusb_dir_t dir = tu_edpt_dir(ep_addr); + USBD_EP_T *ep = ep_entry(ep_addr, false); + struct xfer_ctl_t *xfer = &xfer_table[ep - USBD->EP]; + + /* store away the information we'll needing now and later */ + xfer->data_ptr = NULL; // Indicates a FIFO shall be used + xfer->ff = ff; + xfer->in_remaining_bytes = total_bytes; + xfer->total_bytes = total_bytes; + + if (TUSB_DIR_IN == dir) + { + tu_fifo_set_copy_mode_write(ff, TU_FIFO_COPY_INC); // For the PHY in nuc120 the source and destination pointer have to be incremented! + dcd_in_xfer(xfer, ep); + } + else + { + tu_fifo_set_copy_mode_read(ff, TU_FIFO_COPY_INC); // For the PHY in nuc120 the source and destination pointer have to be incremented! + xfer->out_bytes_so_far = 0; + ep->MXPLD = xfer->max_packet_size; + } + + return true; +} + void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { (void) rhport; @@ -389,9 +429,17 @@ void dcd_int_handler(uint8_t rhport) if (out_ep) { /* copy the data from the PC to the previously provided buffer */ - memcpy(xfer->data_ptr, (uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), available_bytes); + if (xfer->data_ptr) + { + memcpy(xfer->data_ptr, (uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), available_bytes); + xfer->data_ptr += available_bytes; + } + else + { + tu_fifo_write_n(xfer->ff, (const void *) (USBD_BUF_BASE + ep->BUFSEG), available_bytes); + } + xfer->out_bytes_so_far += available_bytes; - xfer->data_ptr += available_bytes; /* when the transfer is finished, alert TinyUSB; otherwise, accept more data */ if ( (xfer->total_bytes == xfer->out_bytes_so_far) || (available_bytes < xfer->max_packet_size) ) @@ -403,7 +451,9 @@ void dcd_int_handler(uint8_t rhport) { /* update the bookkeeping to reflect the data that has now been sent to the PC */ xfer->in_remaining_bytes -= available_bytes; - xfer->data_ptr += available_bytes; + + /* increment only if xfer->data_ptr != NULL - if xfer->data_ptr == NULL then a FIFO is used for which xfer->data_ptr MUST STAY ZERO! */ + if (xfer->data_ptr) xfer->data_ptr += available_bytes; /* if more data to send, send it; otherwise, alert TinyUSB that we've finished */ if (xfer->in_remaining_bytes) From 126e46e38ae1f839262160e8e56cd99936c7451d Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sat, 13 Feb 2021 17:37:13 +0100 Subject: [PATCH 022/121] Fix not increment xfer->buffer if xfer->buffer == NULL in dcd_samg.c --- src/portable/microchip/samg/dcd_samg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/portable/microchip/samg/dcd_samg.c b/src/portable/microchip/samg/dcd_samg.c index 465f6419e..6e7e84a99 100644 --- a/src/portable/microchip/samg/dcd_samg.c +++ b/src/portable/microchip/samg/dcd_samg.c @@ -82,7 +82,7 @@ void xfer_packet_done(xfer_desc_t* xfer) { uint16_t const xact_len = xfer_packet_len(xfer); - xfer->buffer += xact_len; + if (xfer->buffer) xfer->buffer += xact_len; xfer->actual_len += xact_len; } From 0c3dc8f99bc3bdce40164904d6705f7112b80d9d Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sat, 13 Feb 2021 17:44:59 +0100 Subject: [PATCH 023/121] Implement dcd_edpt_iso_xfer() for dcd_nuc121.c --- src/portable/nuvoton/nuc121/dcd_nuc121.c | 54 ++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/src/portable/nuvoton/nuc121/dcd_nuc121.c b/src/portable/nuvoton/nuc121/dcd_nuc121.c index c9ead6de0..1560d5642 100644 --- a/src/portable/nuvoton/nuc121/dcd_nuc121.c +++ b/src/portable/nuvoton/nuc121/dcd_nuc121.c @@ -144,7 +144,15 @@ static void dcd_in_xfer(struct xfer_ctl_t *xfer, USBD_EP_T *ep) { uint16_t bytes_now = tu_min16(xfer->in_remaining_bytes, xfer->max_packet_size); - memcpy((uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), xfer->data_ptr, bytes_now); + if (xfer->data_ptr) + { + memcpy((uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), xfer->data_ptr, bytes_now); + } + else + { + tu_fifo_read_n(xfer->ff, (void *) (USBD_BUF_BASE + ep->BUFSEG), bytes_now); + } + ep->MXPLD = bytes_now; } @@ -292,6 +300,36 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to return true; } +bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +{ + (void) rhport; + + /* mine the data for the information we need */ + tusb_dir_t dir = tu_edpt_dir(ep_addr); + USBD_EP_T *ep = ep_entry(ep_addr, false); + struct xfer_ctl_t *xfer = &xfer_table[ep - USBD->EP]; + + /* store away the information we'll needing now and later */ + xfer->data_ptr = NULL; // Indicates a FIFO shall be used + xfer->ff = ff; + xfer->in_remaining_bytes = total_bytes; + xfer->total_bytes = total_bytes; + + if (TUSB_DIR_IN == dir) + { + tu_fifo_set_copy_mode_write(ff, TU_FIFO_COPY_INC); // For the PHY in nuc120 the source and destination pointer have to be incremented! + dcd_in_xfer(xfer, ep); + } + else + { + tu_fifo_set_copy_mode_read(ff, TU_FIFO_COPY_INC); // For the PHY in nuc120 the source and destination pointer have to be incremented! + xfer->out_bytes_so_far = 0; + ep->MXPLD = xfer->max_packet_size; + } + + return true; +} + void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { (void) rhport; @@ -400,9 +438,17 @@ void dcd_int_handler(uint8_t rhport) if (out_ep) { /* copy the data from the PC to the previously provided buffer */ - memcpy(xfer->data_ptr, (uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), available_bytes); + if (xfer->data_ptr) + { + memcpy(xfer->data_ptr, (uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), available_bytes); + xfer->data_ptr += available_bytes; + } + else + { + tu_fifo_write_n(xfer->ff, (const void *) (USBD_BUF_BASE + ep->BUFSEG), available_bytes); + } + xfer->out_bytes_so_far += available_bytes; - xfer->data_ptr += available_bytes; /* when the transfer is finished, alert TinyUSB; otherwise, accept more data */ if ( (xfer->total_bytes == xfer->out_bytes_so_far) || (available_bytes < xfer->max_packet_size) ) @@ -414,7 +460,7 @@ void dcd_int_handler(uint8_t rhport) { /* update the bookkeeping to reflect the data that has now been sent to the PC */ xfer->in_remaining_bytes -= available_bytes; - xfer->data_ptr += available_bytes; + if (xfer->data_ptr) xfer->data_ptr += available_bytes; /* if more data to send, send it; otherwise, alert TinyUSB that we've finished */ if (xfer->in_remaining_bytes) From b634b5958b92fc2352ea20e279e010d8bf4f2df2 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sat, 13 Feb 2021 21:00:55 +0100 Subject: [PATCH 024/121] Implement dcd_edpt_iso_xfer() for INTERRUPT driven dcd_nuc505 --- src/portable/nuvoton/nuc505/dcd_nuc505.c | 68 ++++++++++++++++++++---- 1 file changed, 58 insertions(+), 10 deletions(-) diff --git a/src/portable/nuvoton/nuc505/dcd_nuc505.c b/src/portable/nuvoton/nuc505/dcd_nuc505.c index a7961a687..92656488d 100644 --- a/src/portable/nuvoton/nuc505/dcd_nuc505.c +++ b/src/portable/nuvoton/nuc505/dcd_nuc505.c @@ -34,6 +34,7 @@ */ #include "tusb_option.h" +#include "common/tusb_fifo.h" #if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_NUC505) @@ -94,6 +95,7 @@ static uint32_t bufseg_addr; static struct xfer_ctl_t { uint8_t *data_ptr; /* data_ptr tracks where to next copy data to (for OUT) or from (for IN) */ + tu_fifo_t * ff; /* pointer to FIFO required for dcd_edpt_iso_xfer() */ union { uint16_t in_remaining_bytes; /* for IN endpoints, we track how many bytes are left to transfer */ uint16_t out_bytes_so_far; /* but for OUT endpoints, we track how many bytes we've transferred so far */ @@ -164,7 +166,6 @@ static USBD_EP_T *ep_entry(uint8_t ep_addr, bool add) static void dcd_userEP_in_xfer(struct xfer_ctl_t *xfer, USBD_EP_T *ep) { uint16_t bytes_now = tu_min16(xfer->in_remaining_bytes, xfer->max_packet_size); - uint16_t countdown = bytes_now; /* precompute what amount of data will be left */ xfer->in_remaining_bytes -= bytes_now; @@ -180,16 +181,24 @@ static void dcd_userEP_in_xfer(struct xfer_ctl_t *xfer, USBD_EP_T *ep) } /* provided buffers are thankfully 32-bit aligned, allowing most data to be transfered as 32-bit */ - while (countdown > 3) + if (xfer->data_ptr) { - uint32_t u32; - memcpy(&u32, xfer->data_ptr, 4); + uint16_t countdown = bytes_now; + while (countdown > 3) + { + uint32_t u32; + memcpy(&u32, xfer->data_ptr, 4); - ep->EPDAT = u32; - xfer->data_ptr += 4; countdown -= 4; + ep->EPDAT = u32; + xfer->data_ptr += 4; countdown -= 4; + } + while (countdown--) + ep->EPDAT_BYTE = *xfer->data_ptr++; + } + else + { + tu_fifo_read_n(xfer->ff, (void *) (ep->EPDAT_BYTE), bytes_now); } - while (countdown--) - ep->EPDAT_BYTE = *xfer->data_ptr++; /* for short packets, we must nudge the peripheral to say 'that's all folks' */ if (bytes_now != xfer->max_packet_size) @@ -402,6 +411,38 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to return true; } +bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +{ + (void) rhport; + + TU_ASSERT(0x80 != ep_addr && 0x00 != ep_addr); // Must not be used for control stuff + + /* mine the data for the information we need */ + tusb_dir_t dir = tu_edpt_dir(ep_addr); + USBD_EP_T *ep = ep_entry(ep_addr, false); + struct xfer_ctl_t *xfer = &xfer_table[ep - USBD->EP]; + + /* store away the information we'll needing now and later */ + xfer->data_ptr = NULL; // Indicates a FIFO shall be used + xfer->ff = ff; + xfer->in_remaining_bytes = total_bytes; + xfer->total_bytes = total_bytes; + + if (TUSB_DIR_IN == dir) + { + tu_fifo_set_copy_mode_write(ff, TU_FIFO_COPY_CST); // For the PHY in nuc505 the source and destination pointer have to be constant! + ep->EPINTEN = USBD_EPINTEN_BUFEMPTYIEN_Msk; + } + else + { + tu_fifo_set_copy_mode_read(ff, TU_FIFO_COPY_CST); // For the PHY in nuc505 the source and destination pointer have to be constant! + xfer->out_bytes_so_far = 0; + ep->EPINTEN = USBD_EPINTEN_RXPKIEN_Msk; + } + + return true; +} + void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { (void) rhport; @@ -615,8 +656,15 @@ void dcd_int_handler(uint8_t rhport) #else uint16_t const available_bytes = ep->EPDATCNT & USBD_EPDATCNT_DATCNT_Msk; /* copy the data from the PC to the previously provided buffer */ - for (int count = 0; (count < available_bytes) && (xfer->out_bytes_so_far < xfer->total_bytes); count++, xfer->out_bytes_so_far++) - *xfer->data_ptr++ = ep->EPDAT_BYTE; + if (xfer->data_ptr) + { + for (int count = 0; (count < available_bytes) && (xfer->out_bytes_so_far < xfer->total_bytes); count++, xfer->out_bytes_so_far++) + *xfer->data_ptr++ = ep->EPDAT_BYTE; + } + else + { + tu_fifo_write_n(xfer->ff, (const void *) &ep->EPDAT_BYTE, tu_min16(available_bytes, xfer->total_bytes - xfer->out_bytes_so_far)); + } /* when the transfer is finished, alert TinyUSB; otherwise, continue accepting more data */ if ( (xfer->total_bytes == xfer->out_bytes_so_far) || (available_bytes < xfer->max_packet_size) ) From 893f997dcb09ffef872ab7cb9a5c0a74839f5715 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sun, 14 Feb 2021 09:25:34 +0100 Subject: [PATCH 025/121] Change FIFO use indication to ff == NULL to avoid future errors. This way people don't need to pay attention for the buffer pointer --- src/portable/espressif/esp32s2/dcd_esp32s2.c | 24 +++++++++---------- src/portable/microchip/samg/dcd_samg.c | 16 +++++++------ src/portable/nuvoton/nuc120/dcd_nuc120.c | 18 +++++++------- src/portable/nuvoton/nuc121/dcd_nuc121.c | 17 ++++++------- src/portable/nuvoton/nuc505/dcd_nuc505.c | 20 +++++++++------- src/portable/st/synopsys/dcd_synopsys.c | 25 ++++++++++---------- 6 files changed, 63 insertions(+), 57 deletions(-) diff --git a/src/portable/espressif/esp32s2/dcd_esp32s2.c b/src/portable/espressif/esp32s2/dcd_esp32s2.c index 72fb4ba48..25e54418f 100644 --- a/src/portable/espressif/esp32s2/dcd_esp32s2.c +++ b/src/portable/espressif/esp32s2/dcd_esp32s2.c @@ -321,6 +321,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); xfer->buffer = buffer; + xfer->ff = NULL; xfer->total_len = total_bytes; xfer->queued_len = 0; xfer->short_packet = false; @@ -523,7 +524,12 @@ static void receive_packet(xfer_ctl_t *xfer, /* usb_out_endpoint_t * out_ep, */ } // Common buffer read - if (xfer->buffer) + if (xfer->ff) + { + // Ring buffer + tu_fifo_write_n(xfer->ff, (const void *) rx_fifo, to_recv_size); + } + else { uint8_t to_recv_rem = to_recv_size % 4; uint16_t to_recv_size_aligned = to_recv_size - to_recv_rem; @@ -556,12 +562,6 @@ static void receive_packet(xfer_ctl_t *xfer, /* usb_out_endpoint_t * out_ep, */ last_32b_bound[2] = (tmp & 0x00FF0000) >> 16; } } - - } - else - { - // Ring buffer - tu_fifo_write_n(xfer->ff, (const void *) rx_fifo, to_recv_size); } xfer->queued_len += xfer_size; @@ -581,7 +581,11 @@ static void transmit_packet(xfer_ctl_t *xfer, volatile usb_in_endpoint_t *in_ep, uint16_t to_xfer_size = (remaining > xfer->max_size) ? xfer->max_size : remaining; - if (xfer->buffer) + if (xfer->ff) + { + tu_fifo_read_n(xfer->ff, (void *) tx_fifo, to_xfer_size); + } + else { uint8_t to_xfer_rem = to_xfer_size % 4; uint16_t to_xfer_size_aligned = to_xfer_size - to_xfer_rem; @@ -616,10 +620,6 @@ static void transmit_packet(xfer_ctl_t *xfer, volatile usb_in_endpoint_t *in_ep, (*tx_fifo) = tmp; } } - else - { - tu_fifo_read_n(xfer->ff, (void *) tx_fifo, to_xfer_size); - } } static void read_rx_fifo(void) diff --git a/src/portable/microchip/samg/dcd_samg.c b/src/portable/microchip/samg/dcd_samg.c index 6e7e84a99..12b2633a0 100644 --- a/src/portable/microchip/samg/dcd_samg.c +++ b/src/portable/microchip/samg/dcd_samg.c @@ -61,6 +61,7 @@ void xfer_epsize_set(xfer_desc_t* xfer, uint16_t epsize) void xfer_begin(xfer_desc_t* xfer, uint8_t * buffer, uint16_t total_bytes) { xfer->buffer = buffer; + xfer->ff = NULL; xfer->total_len = total_bytes; xfer->actual_len = 0; } @@ -68,6 +69,7 @@ void xfer_begin(xfer_desc_t* xfer, uint8_t * buffer, uint16_t total_bytes) void xfer_end(xfer_desc_t* xfer) { xfer->buffer = NULL; + xfer->ff = NULL; xfer->total_len = 0; xfer->actual_len = 0; } @@ -82,7 +84,7 @@ void xfer_packet_done(xfer_desc_t* xfer) { uint16_t const xact_len = xfer_packet_len(xfer); - if (xfer->buffer) xfer->buffer += xact_len; + xfer->buffer += xact_len; xfer->actual_len += xact_len; } @@ -436,13 +438,13 @@ void dcd_int_handler(uint8_t rhport) if (xact_len) { // write to EP fifo - if (xfer->buffer) + if (xfer->ff) { - xact_ep_write(epnum, xfer->buffer, xact_len); + tu_fifo_read_n(ff, (void *) &UDP->UDP_FDR[epnum], xact_len); } else { - tu_fifo_read_n(ff, (void *) &UDP->UDP_FDR[epnum], xact_len); + xact_ep_write(epnum, xfer->buffer, xact_len); } // TX ready for transfer @@ -469,13 +471,13 @@ void dcd_int_handler(uint8_t rhport) uint16_t const xact_len = (uint16_t) ((UDP->UDP_CSR[epnum] & UDP_CSR_RXBYTECNT_Msk) >> UDP_CSR_RXBYTECNT_Pos); // Read from EP fifo - if (xfer->buffer) + if (xfer->ff) { - xact_ep_read(epnum, xfer->buffer, xact_len); + tu_fifo_write_n(xfer->ff, (const void *) &UDP->UDP_FDR[epnum], xact_len); } else { - tu_fifo_write_n(xfer->ff, (const void *) &UDP->UDP_FDR[epnum], xact_len); + xact_ep_read(epnum, xfer->buffer, xact_len); } xfer_packet_done(xfer); diff --git a/src/portable/nuvoton/nuc120/dcd_nuc120.c b/src/portable/nuvoton/nuc120/dcd_nuc120.c index 0c3bd9a6b..9ff34e760 100644 --- a/src/portable/nuvoton/nuc120/dcd_nuc120.c +++ b/src/portable/nuvoton/nuc120/dcd_nuc120.c @@ -144,13 +144,13 @@ static void dcd_in_xfer(struct xfer_ctl_t *xfer, USBD_EP_T *ep) { uint16_t bytes_now = tu_min16(xfer->in_remaining_bytes, xfer->max_packet_size); - if (xfer->data_ptr) + if (xfer->ff) { - memcpy((uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), xfer->data_ptr, bytes_now); + tu_fifo_read_n(xfer->ff, (void *) (USBD_BUF_BASE + ep->BUFSEG), bytes_now); } else { - tu_fifo_read_n(xfer->ff, (void *) (USBD_BUF_BASE + ep->BUFSEG), bytes_now); + memcpy((uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), xfer->data_ptr, bytes_now); } ep->MXPLD = bytes_now; @@ -277,6 +277,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to /* store away the information we'll needing now and later */ xfer->data_ptr = buffer; + xfer->ff = NULL; xfer->in_remaining_bytes = total_bytes; xfer->total_bytes = total_bytes; @@ -429,14 +430,14 @@ void dcd_int_handler(uint8_t rhport) if (out_ep) { /* copy the data from the PC to the previously provided buffer */ - if (xfer->data_ptr) + if (xfer->ff) { - memcpy(xfer->data_ptr, (uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), available_bytes); - xfer->data_ptr += available_bytes; + tu_fifo_write_n(xfer->ff, (const void *) (USBD_BUF_BASE + ep->BUFSEG), available_bytes); } else { - tu_fifo_write_n(xfer->ff, (const void *) (USBD_BUF_BASE + ep->BUFSEG), available_bytes); + memcpy(xfer->data_ptr, (uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), available_bytes); + xfer->data_ptr += available_bytes; } xfer->out_bytes_so_far += available_bytes; @@ -452,8 +453,7 @@ void dcd_int_handler(uint8_t rhport) /* update the bookkeeping to reflect the data that has now been sent to the PC */ xfer->in_remaining_bytes -= available_bytes; - /* increment only if xfer->data_ptr != NULL - if xfer->data_ptr == NULL then a FIFO is used for which xfer->data_ptr MUST STAY ZERO! */ - if (xfer->data_ptr) xfer->data_ptr += available_bytes; + xfer->data_ptr += available_bytes; /* if more data to send, send it; otherwise, alert TinyUSB that we've finished */ if (xfer->in_remaining_bytes) diff --git a/src/portable/nuvoton/nuc121/dcd_nuc121.c b/src/portable/nuvoton/nuc121/dcd_nuc121.c index 1560d5642..a689470d6 100644 --- a/src/portable/nuvoton/nuc121/dcd_nuc121.c +++ b/src/portable/nuvoton/nuc121/dcd_nuc121.c @@ -144,13 +144,13 @@ static void dcd_in_xfer(struct xfer_ctl_t *xfer, USBD_EP_T *ep) { uint16_t bytes_now = tu_min16(xfer->in_remaining_bytes, xfer->max_packet_size); - if (xfer->data_ptr) + if (xfer->ff) { - memcpy((uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), xfer->data_ptr, bytes_now); + tu_fifo_read_n(xfer->ff, (void *) (USBD_BUF_BASE + ep->BUFSEG), bytes_now); } else { - tu_fifo_read_n(xfer->ff, (void *) (USBD_BUF_BASE + ep->BUFSEG), bytes_now); + memcpy((uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), xfer->data_ptr, bytes_now); } ep->MXPLD = bytes_now; @@ -281,6 +281,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to /* store away the information we'll needing now and later */ xfer->data_ptr = buffer; + xfer->ff = NULL; xfer->in_remaining_bytes = total_bytes; xfer->total_bytes = total_bytes; @@ -438,14 +439,14 @@ void dcd_int_handler(uint8_t rhport) if (out_ep) { /* copy the data from the PC to the previously provided buffer */ - if (xfer->data_ptr) + if (xfer->ff) { - memcpy(xfer->data_ptr, (uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), available_bytes); - xfer->data_ptr += available_bytes; + tu_fifo_write_n(xfer->ff, (const void *) (USBD_BUF_BASE + ep->BUFSEG), available_bytes); } else { - tu_fifo_write_n(xfer->ff, (const void *) (USBD_BUF_BASE + ep->BUFSEG), available_bytes); + memcpy(xfer->data_ptr, (uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), available_bytes); + xfer->data_ptr += available_bytes; } xfer->out_bytes_so_far += available_bytes; @@ -460,7 +461,7 @@ void dcd_int_handler(uint8_t rhport) { /* update the bookkeeping to reflect the data that has now been sent to the PC */ xfer->in_remaining_bytes -= available_bytes; - if (xfer->data_ptr) xfer->data_ptr += available_bytes; + xfer->data_ptr += available_bytes; /* if more data to send, send it; otherwise, alert TinyUSB that we've finished */ if (xfer->in_remaining_bytes) diff --git a/src/portable/nuvoton/nuc505/dcd_nuc505.c b/src/portable/nuvoton/nuc505/dcd_nuc505.c index 92656488d..3641b7047 100644 --- a/src/portable/nuvoton/nuc505/dcd_nuc505.c +++ b/src/portable/nuvoton/nuc505/dcd_nuc505.c @@ -181,7 +181,11 @@ static void dcd_userEP_in_xfer(struct xfer_ctl_t *xfer, USBD_EP_T *ep) } /* provided buffers are thankfully 32-bit aligned, allowing most data to be transfered as 32-bit */ - if (xfer->data_ptr) + if (xfer->ff) + { + tu_fifo_read_n(xfer->ff, (void *) (ep->EPDAT_BYTE), bytes_now); + } + else { uint16_t countdown = bytes_now; while (countdown > 3) @@ -195,10 +199,6 @@ static void dcd_userEP_in_xfer(struct xfer_ctl_t *xfer, USBD_EP_T *ep) while (countdown--) ep->EPDAT_BYTE = *xfer->data_ptr++; } - else - { - tu_fifo_read_n(xfer->ff, (void *) (ep->EPDAT_BYTE), bytes_now); - } /* for short packets, we must nudge the peripheral to say 'that's all folks' */ if (bytes_now != xfer->max_packet_size) @@ -394,6 +394,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to /* store away the information we'll needing now and later */ xfer->data_ptr = buffer; + xfer->ff = NULL; xfer->in_remaining_bytes = total_bytes; xfer->total_bytes = total_bytes; @@ -656,14 +657,15 @@ void dcd_int_handler(uint8_t rhport) #else uint16_t const available_bytes = ep->EPDATCNT & USBD_EPDATCNT_DATCNT_Msk; /* copy the data from the PC to the previously provided buffer */ - if (xfer->data_ptr) + if (xfer->ff) { - for (int count = 0; (count < available_bytes) && (xfer->out_bytes_so_far < xfer->total_bytes); count++, xfer->out_bytes_so_far++) - *xfer->data_ptr++ = ep->EPDAT_BYTE; + tu_fifo_write_n(xfer->ff, (const void *) &ep->EPDAT_BYTE, tu_min16(available_bytes, xfer->total_bytes - xfer->out_bytes_so_far)); } else { - tu_fifo_write_n(xfer->ff, (const void *) &ep->EPDAT_BYTE, tu_min16(available_bytes, xfer->total_bytes - xfer->out_bytes_so_far)); + for (int count = 0; (count < available_bytes) && (xfer->out_bytes_so_far < xfer->total_bytes); count++, xfer->out_bytes_so_far++) + *xfer->data_ptr++ = ep->EPDAT_BYTE; + } /* when the transfer is finished, alert TinyUSB; otherwise, continue accepting more data */ diff --git a/src/portable/st/synopsys/dcd_synopsys.c b/src/portable/st/synopsys/dcd_synopsys.c index b6dacd927..5f8c44638 100644 --- a/src/portable/st/synopsys/dcd_synopsys.c +++ b/src/portable/st/synopsys/dcd_synopsys.c @@ -646,6 +646,7 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); xfer->buffer = buffer; + xfer->ff = NULL; xfer->total_len = total_bytes; // EP0 can only handle one packet @@ -908,7 +909,12 @@ static void handle_rxflvl_ints(uint8_t rhport, USB_OTG_OUTEndpointTypeDef * out_ xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT); // Read packet off RxFIFO - if (xfer->buffer) + if (xfer->ff) + { + // Ring buffer + tu_fifo_write_n(xfer->ff, (const void *) rx_fifo, bcnt); + } + else { // Linear buffer read_fifo_packet(rhport, xfer->buffer, bcnt); @@ -916,11 +922,6 @@ static void handle_rxflvl_ints(uint8_t rhport, USB_OTG_OUTEndpointTypeDef * out_ // Increment pointer to xfer data xfer->buffer += bcnt; } - else - { - // Ring buffer - tu_fifo_write_n(xfer->ff, (const void *) rx_fifo, bcnt); - } // Truncate transfer length in case of short packet if(bcnt < xfer->max_size) { @@ -1028,18 +1029,18 @@ static void handle_epin_ints(uint8_t rhport, USB_OTG_DeviceTypeDef * dev, USB_OT } // Push packet to Tx-FIFO - if (xfer->buffer) + if (xfer->ff) + { + usb_fifo_t tx_fifo = FIFO_BASE(rhport, n); + tu_fifo_read_n(xfer->ff, (void *) tx_fifo, packet_size); + } + else { write_fifo_packet(rhport, n, xfer->buffer, packet_size); // Increment pointer to xfer data xfer->buffer += packet_size; } - else - { - usb_fifo_t tx_fifo = FIFO_BASE(rhport, n); - tu_fifo_read_n(xfer->ff, (void *) tx_fifo, packet_size); - } } // Turn off TXFE if all bytes are written. From a5d7b6266dca8a4f79178f5978401b680ddfa637 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sun, 14 Feb 2021 14:05:15 +0100 Subject: [PATCH 026/121] Implement dcd_edpt_iso_xfer() for msp430 --- src/portable/ti/msp430x5xx/dcd_msp430x5xx.c | 77 +++++++++++++++++---- 1 file changed, 63 insertions(+), 14 deletions(-) diff --git a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c index e08c3536a..61cbe1cf7 100644 --- a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c +++ b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c @@ -26,6 +26,7 @@ */ #include "tusb_option.h" +#include "common/tusb_fifo.h" #if TUSB_OPT_DEVICE_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_MSP430x5xx ) @@ -48,6 +49,7 @@ uint8_t _setup_packet[8]; typedef struct { uint8_t * buffer; + tu_fifo_t * ff; uint16_t total_len; uint16_t queued_len; uint16_t max_size; @@ -306,6 +308,7 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); xfer->buffer = buffer; + xfer->ff = NULL; xfer->total_len = total_bytes; xfer->queued_len = 0; xfer->short_packet = false; @@ -344,6 +347,36 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t return true; } +bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +{ + (void) rhport; + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); + xfer->buffer = NULL; + xfer->ff = ff; + xfer->total_len = total_bytes; + xfer->queued_len = 0; + xfer->short_packet = false; + + ep_regs_t ep_regs = EP_REGS(epnum, dir); + + if(dir == TUSB_DIR_OUT) + { + tu_fifo_set_copy_mode_read(ff, TU_FIFO_COPY_INC); // For the PHY in msp430 the source and destination pointer have to be incremented! + ep_regs[BCTX] &= ~NAK; + } + else + { + tu_fifo_set_copy_mode_write(ff, TU_FIFO_COPY_INC); // For the PHY in msp430 the source and destination pointer have to be incremented! + USBIEPIFG |= (1 << epnum); + } + + return true; +} + void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr) { (void) rhport; @@ -443,22 +476,30 @@ static void receive_packet(uint8_t ep_num) to_recv_size = (xfer_size > xfer->max_size) ? xfer->max_size : xfer_size; } - uint8_t * base = (xfer->buffer + xfer->queued_len); - - if(ep_num == 0) + if (xfer->ff) { - volatile uint8_t * ep0out_buf = &USBOEP0BUF; - for(uint16_t i = 0; i < to_recv_size; i++) - { - base[i] = ep0out_buf[i]; - } + volatile uint8_t * ep_buf = &USBSTABUFF + (ep_regs[BBAX] << 3); + tu_fifo_write_n(xfer->ff, (const void *) ep_buf, to_recv_size); } else { - volatile uint8_t * ep_buf = &USBSTABUFF + (ep_regs[BBAX] << 3); - for(uint16_t i = 0; i < to_recv_size ; i++) + uint8_t * base = (xfer->buffer + xfer->queued_len); + + if(ep_num == 0) { - base[i] = ep_buf[i]; + volatile uint8_t * ep0out_buf = &USBOEP0BUF; + for(uint16_t i = 0; i < to_recv_size; i++) + { + base[i] = ep0out_buf[i]; + } + } + else + { + volatile uint8_t * ep_buf = &USBSTABUFF + (ep_regs[BBAX] << 3); + for(uint16_t i = 0; i < to_recv_size ; i++) + { + base[i] = ep_buf[i]; + } } } @@ -499,7 +540,6 @@ static void transmit_packet(uint8_t ep_num) } // Then actually commit to transmit a packet. - uint8_t * base = (xfer->buffer + xfer->queued_len); uint16_t remaining = xfer->total_len - xfer->queued_len; uint8_t xfer_size = (xfer->max_size < xfer->total_len) ? xfer->max_size : remaining; @@ -513,6 +553,7 @@ static void transmit_packet(uint8_t ep_num) if(ep_num == 0) { volatile uint8_t * ep0in_buf = &USBIEP0BUF; + uint8_t * base = (xfer->buffer + xfer->queued_len); for(uint16_t i = 0; i < xfer_size; i++) { ep0in_buf[i] = base[i]; @@ -526,9 +567,17 @@ static void transmit_packet(uint8_t ep_num) ep_regs_t ep_regs = EP_REGS(ep_num, TUSB_DIR_IN); volatile uint8_t * ep_buf = &USBSTABUFF + (ep_regs[BBAX] << 3); - for(int i = 0; i < xfer_size; i++) + if (xfer->ff) { - ep_buf[i] = base[i]; + tu_fifo_read_n(xfer->ff, (void *) ep_buf, xfer_size); + } + else + { + uint8_t * base = (xfer->buffer + xfer->queued_len); + for(int i = 0; i < xfer_size; i++) + { + ep_buf[i] = base[i]; + } } ep_regs[BCTX] = (ep_regs[BCTX] & 0x80) + (xfer_size & 0x7F); From c87357c0257251f2cecfe83a29035648c5a47662 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Wed, 17 Feb 2021 20:44:26 +0100 Subject: [PATCH 027/121] Improve tu_fifo capabilites Added tu_fifo_get_linear_write_info(), tu_fifo_backward_write_pointer(), and tu_fifo_backward_read_pointer() --- src/common/tusb_fifo.c | 202 +++++++++++++++++++++++++++++++++++++++-- src/common/tusb_fifo.h | 11 ++- 2 files changed, 204 insertions(+), 9 deletions(-) diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index ff2e2c6fd..f6def94ab 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -354,10 +354,7 @@ static uint16_t _tu_fifo_peek_at_n(tu_fifo_t* f, uint16_t offset, void * p_buffe // Check if we can read something at and after offset - if too less is available we read what remains cnt -= offset; - if (cnt < n) { - if (cnt == 0) return 0; - n = cnt; - } + if (cnt < n) n = cnt; uint16_t rRel = get_relative_pointer(f, rAbs, offset); @@ -664,10 +661,7 @@ uint16_t tu_fifo_peek_n_into_other_fifo (tu_fifo_t* f, tu_fifo_t* f_target, uint // Check if we can read something at and after offset - if too less is available we read what remains cnt -= offset; - if (cnt < n) { - if (cnt == 0) return 0; - n = cnt; - } + if (cnt < n) n = cnt; tu_fifo_lock(f_target); // Lock both read and write pointers - in case of an overwritable FIFO both may be modified @@ -881,3 +875,195 @@ void tu_fifo_advance_read_pointer(tu_fifo_t *f, uint16_t n) { f->rd_idx = advance_pointer(f, f->rd_idx, n); } + +/******************************************************************************/ +/*! + @brief Move back write pointer - intended to be used in combination with DMA. + It is possible to fill the FIFO by use of a DMA in circular mode. Within + DMA ISRs you may update the write pointer to be able to read from the FIFO. + As long as the DMA is the only process writing into the FIFO this is safe + to use. + + USE WITH CARE - WE DO NOT CONDUCT SAFTY CHECKS HERE! + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] n + Number of items the write pointer moves backward + */ +/******************************************************************************/ +void tu_fifo_backward_write_pointer(tu_fifo_t *f, uint16_t n) +{ + f->wr_idx = backward_pointer(f, f->wr_idx, n); +} + +/******************************************************************************/ +/*! + @brief Move back read pointer - intended to be used in combination with DMA. + It is possible to read from the FIFO by use of a DMA in linear mode. Within + DMA ISRs you may update the read pointer to be able to again write into the + FIFO. As long as the DMA is the only process reading from the FIFO this is + safe to use. + + USE WITH CARE - WE DO NOT CONDUCT SAFTY CHECKS HERE! + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] n + Number of items the read pointer moves backward + */ +/******************************************************************************/ +void tu_fifo_backward_read_pointer(tu_fifo_t *f, uint16_t n) +{ + f->rd_idx = backward_pointer(f, f->rd_idx, n); +} + +/******************************************************************************/ +/*! + @brief Get linear read info + + Returns the length and pointer from which bytes can be read in a linear manner. + This is of major interest for DMA transmissions. If returned length is zero the + corresponding pointer is invalid. The returned length is limited to the number + of BYTES n which the user wants to write into the buffer. + The write pointer does NOT get advanced, use tu_fifo_advance_read_pointer() to + do so! If the length returned is less than n i.e. lenwr_idx, r = f->rd_idx; + + uint16_t cnt = _tu_fifo_count(f, w, r); + + // Check overflow and correct if required + if (cnt > f->depth) + { + tu_fifo_lock(f); + _tu_fifo_correct_read_pointer(f, w); + tu_fifo_unlock(f); + r = f->rd_idx; + cnt = f->depth; + } + + // Convert to bytes + cnt = cnt * f->item_size; + + // Skip beginning of buffer + if (cnt == 0 || offset >= cnt) return 0; + + // Check if we can read something at and after offset - if too less is available we read what remains + cnt -= offset; + if (cnt < n) n = cnt; + + // Get relative pointers + w = get_relative_pointer(f, w, 0); + r = get_relative_pointer(f, r, offset); + + // Check if there is a wrap around necessary + uint16_t len; + + if (w >= r) { + len = w - r; + } + else + { + len = f->depth - r; + } + + len = len * f->item_size; + + // Limit to required length + len = tu_min16(n, len); + + // Copy pointer to buffer to start reading from + *ptr = &f->buffer[r]; + + return len; +} + +/******************************************************************************/ +/*! + @brief Get linear write info + + Returns the length and pointer from which bytes can be written into buffer array in a linear manner. + This is of major interest for DMA transmissions not using circular mode. If returned length is zero the + corresponding pointer is invalid. The returned length is limited to the number of BYTES n which the user + wants to write into the buffer. + The write pointer does NOT get advanced, use tu_fifo_advance_write_pointer() to do so! If the length + returned is less than n i.e. lenwr_idx, r = f->rd_idx; + uint16_t free = _tu_fifo_remaining(f, w, r) * f->item_size; + + if (!f->overwritable) + { + // Not overwritable limit up to full + n = tu_min16(n, free); + } + else if (n >= f->depth * f->item_size) + { + // If overwrite is allowed it must be less than or equal to 2 x buffer length, otherwise the overflow can not be resolved by the read functions + TU_VERIFY(n <= 2*f->depth * f->item_size); + + n = f->depth * f->item_size; + // We start writing at the read pointer's position since we fill the complete + // buffer and we do not want to modify the read pointer within a write function! + // This would end up in a race condition with read functions! + w = r; + } + + // Check if there is room to write to + if (free == 0 || offset >= free) return 0; + + // Get relative pointers + w = get_relative_pointer(f, w, offset); + r = get_relative_pointer(f, r, 0); + uint16_t len; + + if (w < r) + { + len = r-w; + } + else + { + len = f->depth - w; + } + + len = len * f->item_size; + + // Limit to required length + len = tu_min16(n, len); + + // Copy pointer to buffer to start reading from + *ptr = &f->buffer[w]; + + return len; +} diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h index 7ece30b74..833b3eead 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -128,13 +128,22 @@ uint16_t tu_fifo_count (tu_fifo_t* f); bool tu_fifo_empty (tu_fifo_t* f); bool tu_fifo_full (tu_fifo_t* f); uint16_t tu_fifo_remaining (tu_fifo_t* f); -bool tu_fifo_overflowed (tu_fifo_t* f); +bool tu_fifo_overflowed (tu_fifo_t* f); void tu_fifo_correct_read_pointer (tu_fifo_t* f); // Pointer modifications intended to be used in combinations with DMAs. // USE WITH CARE - NO SAFTY CHECKS CONDUCTED HERE! NOT MUTEX PROTECTED! void tu_fifo_advance_write_pointer (tu_fifo_t *f, uint16_t n); +void tu_fifo_backward_write_pointer (tu_fifo_t *f, uint16_t n); void tu_fifo_advance_read_pointer (tu_fifo_t *f, uint16_t n); +void tu_fifo_backward_read_pointer (tu_fifo_t *f, uint16_t n); + +// If you want to read/write from/to the FIFO by use of a DMA, you may need to conduct two copies to handle a possible wrapping part +// This functions deliver a pointer to start reading/writing from/to and a valid linear length along which no wrap occurs. +// In case not all of your data is available within one read/write, update the read/write pointer by +// tu_fifo_advance_read_pointer()/tu_fifo_advance_write_pointer and conduct a second read/write operation +uint16_t tu_fifo_get_linear_read_info (tu_fifo_t *f, uint16_t offset, void **ptr, uint16_t n); +uint16_t tu_fifo_get_linear_write_info (tu_fifo_t *f, uint16_t offset, void **ptr, uint16_t n); static inline bool tu_fifo_peek(tu_fifo_t* f, void * p_buffer) { From 2d7b61972c669040c494899509b02bde49728a65 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Wed, 17 Feb 2021 20:46:31 +0100 Subject: [PATCH 028/121] Implement dcd_edpt_iso_xfer() for dcd_stm32_fsdev Implemented a special copy strategy to copy directly from the FIFO. This function, however, is untested and should be regarded as unreliable until somebody was able to test it --- src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c | 148 +++++++++++++++++- 1 file changed, 144 insertions(+), 4 deletions(-) diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index 18f0bc8e1..9d813d4a5 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -102,6 +102,7 @@ */ #include "tusb_option.h" +#include "common/tusb_fifo.h" #if defined(STM32F102x6) || defined(STM32F102xB) || \ defined(STM32F103x6) || defined(STM32F103xB) || \ @@ -165,6 +166,7 @@ TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) % 8) == 0, "BTABLE base must be aligne typedef struct { uint8_t * buffer; + tu_fifo_t * ff; uint16_t total_len; uint16_t queued_len; uint16_t pma_ptr; @@ -195,7 +197,9 @@ static void dcd_pma_alloc_reset(void); static uint16_t dcd_pma_alloc(uint8_t ep_addr, size_t length); static void dcd_pma_free(uint8_t ep_addr); static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, size_t wNBytes); +static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wNBytes); static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wNBytes); +static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNBytes); // Using a function due to better type checks // This seems better than having to do type casts everywhere else @@ -476,8 +480,16 @@ static void dcd_ep_ctr_rx_handler(uint32_t wIstr) if (count != 0U) { - dcd_read_packet_memory(&(xfer->buffer[xfer->queued_len]), - *pcd_ep_rx_address_ptr(USB,EPindex), count); + if (xfer->ff) + { + dcd_read_packet_memory_ff(xfer->ff, *pcd_ep_rx_address_ptr(USB,EPindex), count); + } + else + { + dcd_read_packet_memory(&(xfer->buffer[xfer->queued_len]), + *pcd_ep_rx_address_ptr(USB,EPindex), count); + } + xfer->queued_len = (uint16_t)(xfer->queued_len + count); } @@ -804,7 +816,14 @@ static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix) len = xfer->max_packet_size; } uint16_t oldAddr = *pcd_ep_tx_address_ptr(USB,ep_ix); - dcd_write_packet_memory(oldAddr, &(xfer->buffer[xfer->queued_len]), len); + if (xfer->ff) + { + dcd_write_packet_memory_ff(xfer->ff, oldAddr, len); + } + else + { + dcd_write_packet_memory(oldAddr, &(xfer->buffer[xfer->queued_len]), len); + } xfer->queued_len = (uint16_t)(xfer->queued_len + len); pcd_set_ep_tx_cnt(USB,ep_ix,len); @@ -821,6 +840,7 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t xfer_ctl_t * xfer = xfer_ctl_ptr(epnum,dir); xfer->buffer = buffer; + xfer->ff = NULL; xfer->total_len = total_bytes; xfer->queued_len = 0; @@ -847,6 +867,37 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t return true; } +bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +{ + (void) rhport; + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + xfer_ctl_t * xfer = xfer_ctl_ptr(epnum,dir); + + xfer->buffer = NULL; + xfer->ff = ff; + xfer->total_len = total_bytes; + xfer->queued_len = 0; + + if ( dir == TUSB_DIR_OUT ) + { + if(total_bytes > xfer->max_packet_size) + { + pcd_set_ep_rx_cnt(USB,epnum,xfer->max_packet_size); + } else { + pcd_set_ep_rx_cnt(USB,epnum,total_bytes); + } + pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_VALID); + } + else // IN + { + dcd_transmit_packet(xfer,epnum); + } + return true; +} + void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr) { (void)rhport; @@ -921,7 +972,52 @@ static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, si } /** - * @brief Copy a buffer from user memory area to packet memory area (PMA). + * @brief Copy from FIFO to packet memory area (PMA). + * Uses byte-access of system memory and 16-bit access of packet memory + * @param wNBytes no. of bytes to be copied. + * @retval None + */ + +// THIS FUNCTION IS UNTESTED + +static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wNBytes) +{ + // Since we copy from a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies + // Check for first linear part + void *__restrict src; + uint16_t len = tu_fifo_get_linear_read_info(ff, 0, &src, wNBytes); // We want to read from the FIFO + TU_VERIFY(len && dcd_write_packet_memory(dst, src, len)); // and write it into the PMA + tu_fifo_advance_read_pointer(ff, len); + + // Check for wrapped part + if (len < wNBytes) + { + // Get remaining wrapped length + uint16_t len2 = tu_fifo_get_linear_read_info(ff, 0, &src, wNBytes - len); + TU_VERIFY(len2); + + // Update destination pointer + dst += len; + + // Since PMA is accessed 16-bit wise we need to handle the case when a 16 bit value was split + if (len % 2) // If len is uneven there is a byte left to copy + { + // Since PMA can accessed only 16 bit-wise we copy the last byte again + tu_fifo_backward_read_pointer(ff, 1); // Move one byte back and copy two bytes for the PMA + pma[PMA_STRIDE*(dst>>1)] = tu_fifo_read_n(ff, 2); // Since EP FIFOs must be of item size 1 this is safe to do + dst++; + len2--; + } + + TU_VERIFY(dcd_write_packet_memory(dst, src, len2)); + tu_fifo_advance_write_pointer(ff, len2); + } + + return true; +} + +/** + * @brief Copy a buffer from packet memory area (PMA) to user memory area. * Uses byte-access of system memory and 16-bit access of packet memory * @param wNBytes no. of bytes to be copied. * @retval None @@ -955,5 +1051,49 @@ static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wN return true; } +/** + * @brief Copy a buffer from user packet memory area (PMA) to FIFO. + * Uses byte-access of system memory and 16-bit access of packet memory + * @param wNBytes no. of bytes to be copied. + * @retval None + */ + +// THIS FUNCTION IS UNTESTED + +static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNBytes) +{ + // Since we copy into a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies + // Check for first linear part + void *__restrict dst; + uint16_t len = tu_fifo_get_linear_write_info(ff, 0, &dst, wNBytes); + TU_VERIFY(len && dcd_read_packet_memory(dst, src, len)); + tu_fifo_advance_write_pointer(ff, len); + + // Check for wrapped part + if (len < wNBytes) + { + // Get remaining wrapped length + uint16_t len2 = tu_fifo_get_linear_write_info(ff, 0, &dst, wNBytes - len); + TU_VERIFY(len2); + + // Update source pointer + src += len; + + // Since PMA is accessed 16-bit wise we need to handle the case when a 16 bit value was split + if (len % 2) // If len is uneven there is a byte left to copy + { + uint32_t temp = pma[PMA_STRIDE*(src>>1)]; + *((uint8_t *)dst++) = ((temp >> 8) & 0xFF); + src++; + len2--; + } + + TU_VERIFY(dcd_read_packet_memory(dst, src, len2)); + tu_fifo_advance_write_pointer(ff, len2); + } + + return true; +} + #endif From 189b357b54614a770232ac9fa95d56d173efe302 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Wed, 17 Feb 2021 21:42:44 +0100 Subject: [PATCH 029/121] Implement an evasion linear buffer for MCUs not capable for EP FIFO Also MCUs using DMAs are within this list, however, these can use an EP FIFO. There is just no time for implementation --- src/class/audio/audio_device.c | 55 +++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 622e6d113..7b7c61750 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -125,6 +125,41 @@ typedef struct #if CFG_FIFO_MUTEX osal_mutex_def_t rx_ff_mutex[CFG_TUD_AUDIO_N_CHANNELS_RX]; #endif +#endif + + // Evasion buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically +#if ( CFG_TUSB_MCU == OPT_MCU_MKL25ZXX || /* Intermediate software buffer required */ \ + CFG_TUSB_MCU == OPT_MCU_LPC18XX || /* No clue how driver works */ \ + CFG_TUSB_MCU == OPT_MCU_LPC43XX || \ + CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \ + CFG_TUSB_MCU == OPT_MCU_RP2040) || /* Don't want to change driver */ \ + CFG_TUSB_MCU == OPT_MCU_VALENTYUSB_EPTRI || /* Intermediate software buffer required */ \ + CFG_TUSB_MCU == OPT_MCU_CXD56 || /* No clue how driver works */ \ + CFG_TUSB_MCU == OPT_MCU_DA1469X || /* Uses DMA - Ok for FIFO, had no time for implementation */ \ + CFG_TUSB_MCU == OPT_MCU_NRF5X || /* Uses DMA - Ok for FIFO, had no time for implementation */ \ + CFG_TUSB_MCU == OPT_MCU_LPC11UXX || /* Uses DMA - Ok for FIFO, had no time for implementation */ \ + CFG_TUSB_MCU == OPT_MCU_LPC13XX || \ + CFG_TUSB_MCU == OPT_MCU_LPC15XX || \ + CFG_TUSB_MCU == OPT_MCU_LPC51UXX || \ + CFG_TUSB_MCU == OPT_MCU_LPC54XXX || \ + CFG_TUSB_MCU == OPT_MCU_LPC55XX || \ + CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || \ + CFG_TUSB_MCU == OPT_MCU_LPC40XX) + +#define USE_EVADE_BUFFER 1 + +#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE + CFG_TUSB_MEM_ALIGN uint8_t evasion_buf_out[CFG_TUD_AUDIO_EPSIZE_OUT]; +#endif + +#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE + CFG_TUSB_MEM_ALIGN uint8_t evasion_buf_in[CFG_TUD_AUDIO_EPSIZE_IN]; +#endif + +#endif + +#ifndef USE_EVADE_BUFFER +#define USE_EVADE_BUFFER 0 #endif } audiod_interface_t; @@ -292,7 +327,11 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_interface_t* audio) #endif // Prepare for next transmission +#if USE_EVADE_BUFFER + TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, &audio->evasion_buf_out, CFG_TUD_AUDIO_EPSIZE_OUT), false); +#else TU_VERIFY(usbd_edpt_iso_xfer(rhport, audio->ep_out, &audio->ep_out_ff, CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE), false); +#endif // Call a weak callback here - a possibility for user to get informed decoding was completed if (tud_audio_rx_done_post_read_cb) TU_VERIFY(tud_audio_rx_done_post_read_cb(rhport, n_bytes_received, idxDriver, audio->ep_out, audio->altSetting[idxItf])); @@ -485,7 +524,12 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t * audio) uint16_t n_bytes_tx = tu_fifo_count(&audio->ep_in_ff); // Schedule transmit +#if USE_EVADE_BUFFER + tu_fifo_write_n(&audio->ep_in_ff, &audio->evasion_buf_in, n_bytes_tx); + TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, &audio->evasion_buf_in, n_bytes_tx)); +#else TU_VERIFY(usbd_edpt_iso_xfer(rhport, audio->ep_in, &audio->ep_in_ff, n_bytes_tx)); +#endif // Call a weak callback here - a possibility for user to get informed former TX was completed and how many bytes were loaded for the next frame if (tud_audio_tx_done_post_load_cb) TU_VERIFY(tud_audio_tx_done_post_load_cb(rhport, n_bytes_tx, idxDriver, audio->ep_in, audio->altSetting[idxItf])); @@ -815,7 +859,11 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request)); // Prepare for incoming data - TU_VERIFY(usbd_edpt_iso_xfer(rhport, _audiod_itf[idxDriver].ep_out, &_audiod_itf[idxDriver].ep_out_ff, CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE), false); +#if USE_EVADE_BUFFER + TU_VERIFY(usbd_edpt_xfer(rhport, _audiod_itf[idxDriver].ep_out, &_audiod_itf[idxDriver].evasion_buf_out, CFG_TUD_AUDIO_EPSIZE_OUT), false); +#else + TU_VERIFY(usbd_edpt_iso_xfer(rhport, _audiod_itf[idxDriver].ep_out, &_audiod_itf[idxDriver].ep_out_ff, CFG_TUD_AUDIO_EPSIZE_OUT), false); +#endif } #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP @@ -1106,6 +1154,11 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 { // Save into buffer - do whatever has to be done // TU_VERIFY(audiod_rx_done_cb(rhport, &_audiod_itf[idxDriver], _audiod_itf[idxDriver].ep_out_buf, xferred_bytes)); + +#if USE_EVADE_BUFFER + TU_VERIFY(tu_fifo_write_n(&_audiod_itf[idxDriver].ep_out_ff, &_audiod_itf[idxDriver].evasion_buf_out, (uint16_t) xferred_bytes)); // Copy data into FIFO +#endif + TU_VERIFY(audiod_rx_done_cb(rhport, &_audiod_itf[idxDriver])); return true; From e407ce463d007231f0d24e55768c1d0ab3b2c049 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Wed, 17 Feb 2021 21:47:01 +0100 Subject: [PATCH 030/121] Add SAMD MCUs to buffer evasion list --- src/class/audio/audio_device.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 7b7c61750..c93de9380 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -144,7 +144,11 @@ typedef struct CFG_TUSB_MCU == OPT_MCU_LPC54XXX || \ CFG_TUSB_MCU == OPT_MCU_LPC55XX || \ CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || \ - CFG_TUSB_MCU == OPT_MCU_LPC40XX) + CFG_TUSB_MCU == OPT_MCU_LPC40XX || \ + CFG_TUSB_MCU == OPT_MCU_SAMD11 || /* Uses DMA - Ok for FIFO, had no time for implementation */ \ + CFG_TUSB_MCU == OPT_MCU_SAMD21 || \ + CFG_TUSB_MCU == OPT_MCU_SAMD51 || \ + CFG_TUSB_MCU == OPT_MCU_SAME5X) #define USE_EVADE_BUFFER 1 From eee47493a336eb334fdd7f1713903e2131a86650 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Wed, 17 Feb 2021 21:59:32 +0100 Subject: [PATCH 031/121] Fix bug in evasion buffer list --- src/class/audio/audio_device.c | 4 ++-- src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index c93de9380..9dd2ee704 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -132,7 +132,7 @@ typedef struct CFG_TUSB_MCU == OPT_MCU_LPC18XX || /* No clue how driver works */ \ CFG_TUSB_MCU == OPT_MCU_LPC43XX || \ CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \ - CFG_TUSB_MCU == OPT_MCU_RP2040) || /* Don't want to change driver */ \ + CFG_TUSB_MCU == OPT_MCU_RP2040 || /* Don't want to change driver */ \ CFG_TUSB_MCU == OPT_MCU_VALENTYUSB_EPTRI || /* Intermediate software buffer required */ \ CFG_TUSB_MCU == OPT_MCU_CXD56 || /* No clue how driver works */ \ CFG_TUSB_MCU == OPT_MCU_DA1469X || /* Uses DMA - Ok for FIFO, had no time for implementation */ \ @@ -148,7 +148,7 @@ typedef struct CFG_TUSB_MCU == OPT_MCU_SAMD11 || /* Uses DMA - Ok for FIFO, had no time for implementation */ \ CFG_TUSB_MCU == OPT_MCU_SAMD21 || \ CFG_TUSB_MCU == OPT_MCU_SAMD51 || \ - CFG_TUSB_MCU == OPT_MCU_SAME5X) + CFG_TUSB_MCU == OPT_MCU_SAME5X ) #define USE_EVADE_BUFFER 1 diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index 9d813d4a5..0d25cceb8 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -984,7 +984,7 @@ static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wN { // Since we copy from a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies // Check for first linear part - void *__restrict src; + void * src; uint16_t len = tu_fifo_get_linear_read_info(ff, 0, &src, wNBytes); // We want to read from the FIFO TU_VERIFY(len && dcd_write_packet_memory(dst, src, len)); // and write it into the PMA tu_fifo_advance_read_pointer(ff, len); @@ -1064,7 +1064,7 @@ static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNB { // Since we copy into a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies // Check for first linear part - void *__restrict dst; + void * dst; uint16_t len = tu_fifo_get_linear_write_info(ff, 0, &dst, wNBytes); TU_VERIFY(len && dcd_read_packet_memory(dst, src, len)); tu_fifo_advance_write_pointer(ff, len); From 53a796a92ea853ea5af16431ba2a6bed8a3c7b5a Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Wed, 17 Feb 2021 22:29:40 +0100 Subject: [PATCH 032/121] Fix wrong pointer type. --- src/class/audio/audio_device.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 9dd2ee704..2db1e8b58 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -332,7 +332,7 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_interface_t* audio) // Prepare for next transmission #if USE_EVADE_BUFFER - TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, &audio->evasion_buf_out, CFG_TUD_AUDIO_EPSIZE_OUT), false); + TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->evasion_buf_out, CFG_TUD_AUDIO_EPSIZE_OUT), false); #else TU_VERIFY(usbd_edpt_iso_xfer(rhport, audio->ep_out, &audio->ep_out_ff, CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE), false); #endif @@ -529,8 +529,8 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t * audio) // Schedule transmit #if USE_EVADE_BUFFER - tu_fifo_write_n(&audio->ep_in_ff, &audio->evasion_buf_in, n_bytes_tx); - TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, &audio->evasion_buf_in, n_bytes_tx)); + tu_fifo_write_n(&audio->ep_in_ff, audio->evasion_buf_in, n_bytes_tx); + TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->evasion_buf_in, n_bytes_tx)); #else TU_VERIFY(usbd_edpt_iso_xfer(rhport, audio->ep_in, &audio->ep_in_ff, n_bytes_tx)); #endif From 94bf4f54dae23f0b0fcd660f0afae374f8e141d5 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Wed, 17 Feb 2021 22:29:51 +0100 Subject: [PATCH 033/121] Fix missing FIFO definitions --- src/portable/nuvoton/nuc121/dcd_nuc121.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/portable/nuvoton/nuc121/dcd_nuc121.c b/src/portable/nuvoton/nuc121/dcd_nuc121.c index a689470d6..8aa97ad10 100644 --- a/src/portable/nuvoton/nuc121/dcd_nuc121.c +++ b/src/portable/nuvoton/nuc121/dcd_nuc121.c @@ -34,6 +34,7 @@ */ #include "tusb_option.h" +#include "common/tusb_fifo.h" #if TUSB_OPT_DEVICE_ENABLED && ( (CFG_TUSB_MCU == OPT_MCU_NUC121) || (CFG_TUSB_MCU == OPT_MCU_NUC126) ) @@ -78,6 +79,7 @@ static bool active_ep0_xfer; static struct xfer_ctl_t { uint8_t *data_ptr; /* data_ptr tracks where to next copy data to (for OUT) or from (for IN) */ + tu_fifo_t * ff; union { uint16_t in_remaining_bytes; /* for IN endpoints, we track how many bytes are left to transfer */ uint16_t out_bytes_so_far; /* but for OUT endpoints, we track how many bytes we've transferred so far */ From 402005c9e0804ef71606edd0490b3f853ca85593 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Wed, 17 Feb 2021 22:49:10 +0100 Subject: [PATCH 034/121] Fix missing pointer operator in dcd_nuc505.c --- src/portable/nuvoton/nuc505/dcd_nuc505.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/portable/nuvoton/nuc505/dcd_nuc505.c b/src/portable/nuvoton/nuc505/dcd_nuc505.c index 3641b7047..0a690d84d 100644 --- a/src/portable/nuvoton/nuc505/dcd_nuc505.c +++ b/src/portable/nuvoton/nuc505/dcd_nuc505.c @@ -183,7 +183,7 @@ static void dcd_userEP_in_xfer(struct xfer_ctl_t *xfer, USBD_EP_T *ep) /* provided buffers are thankfully 32-bit aligned, allowing most data to be transfered as 32-bit */ if (xfer->ff) { - tu_fifo_read_n(xfer->ff, (void *) (ep->EPDAT_BYTE), bytes_now); + tu_fifo_read_n(xfer->ff, (void *) (&ep->EPDAT_BYTE), bytes_now); } else { From 666e0fad358dfdbda01fadc2c04dee5de5a527c0 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Wed, 17 Feb 2021 22:50:49 +0100 Subject: [PATCH 035/121] Fix wrong tu_fifo_read_n() call in dcd_stm32_fsdev.c --- src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index 0d25cceb8..42d34f498 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -1004,7 +1004,7 @@ static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wN { // Since PMA can accessed only 16 bit-wise we copy the last byte again tu_fifo_backward_read_pointer(ff, 1); // Move one byte back and copy two bytes for the PMA - pma[PMA_STRIDE*(dst>>1)] = tu_fifo_read_n(ff, 2); // Since EP FIFOs must be of item size 1 this is safe to do + tu_fifo_read_n(ff, &pma[PMA_STRIDE*(dst>>1)], 2); // Since EP FIFOs must be of item size 1 this is safe to do dst++; len2--; } From d8481ac7e40a2458a7df9394f487218ea35f6c2d Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Wed, 17 Feb 2021 22:52:59 +0100 Subject: [PATCH 036/121] Fix wrong pointer call in dcd_samg.c --- src/portable/microchip/samg/dcd_samg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/portable/microchip/samg/dcd_samg.c b/src/portable/microchip/samg/dcd_samg.c index 12b2633a0..1edbba629 100644 --- a/src/portable/microchip/samg/dcd_samg.c +++ b/src/portable/microchip/samg/dcd_samg.c @@ -440,7 +440,7 @@ void dcd_int_handler(uint8_t rhport) // write to EP fifo if (xfer->ff) { - tu_fifo_read_n(ff, (void *) &UDP->UDP_FDR[epnum], xact_len); + tu_fifo_read_n(xfer->ff, (void *) &UDP->UDP_FDR[epnum], xact_len); } else { From 6cb9a6ebb15c2bfacc15c7e4e6e13ec333067693 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Wed, 17 Feb 2021 23:04:19 +0100 Subject: [PATCH 037/121] Add (void *) for pointer cast. --- src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index 42d34f498..e2fd48d74 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -1004,7 +1004,7 @@ static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wN { // Since PMA can accessed only 16 bit-wise we copy the last byte again tu_fifo_backward_read_pointer(ff, 1); // Move one byte back and copy two bytes for the PMA - tu_fifo_read_n(ff, &pma[PMA_STRIDE*(dst>>1)], 2); // Since EP FIFOs must be of item size 1 this is safe to do + tu_fifo_read_n(ff, (void *) &pma[PMA_STRIDE*(dst>>1)], 2); // Since EP FIFOs must be of item size 1 this is safe to do dst++; len2--; } From 681cfd0bf21cc0e977cb3e5294c7a1edbb4f0928 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Thu, 18 Feb 2021 11:12:16 +0100 Subject: [PATCH 038/121] Correct for wrong pointer type in audio_device.c --- src/class/audio/audio_device.c | 4 ++-- src/common/tusb_fifo.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 2db1e8b58..527aecc0d 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -864,7 +864,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * // Prepare for incoming data #if USE_EVADE_BUFFER - TU_VERIFY(usbd_edpt_xfer(rhport, _audiod_itf[idxDriver].ep_out, &_audiod_itf[idxDriver].evasion_buf_out, CFG_TUD_AUDIO_EPSIZE_OUT), false); + TU_VERIFY(usbd_edpt_xfer(rhport, _audiod_itf[idxDriver].ep_out, _audiod_itf[idxDriver].evasion_buf_out, CFG_TUD_AUDIO_EPSIZE_OUT), false); #else TU_VERIFY(usbd_edpt_iso_xfer(rhport, _audiod_itf[idxDriver].ep_out, &_audiod_itf[idxDriver].ep_out_ff, CFG_TUD_AUDIO_EPSIZE_OUT), false); #endif @@ -1160,7 +1160,7 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 // TU_VERIFY(audiod_rx_done_cb(rhport, &_audiod_itf[idxDriver], _audiod_itf[idxDriver].ep_out_buf, xferred_bytes)); #if USE_EVADE_BUFFER - TU_VERIFY(tu_fifo_write_n(&_audiod_itf[idxDriver].ep_out_ff, &_audiod_itf[idxDriver].evasion_buf_out, (uint16_t) xferred_bytes)); // Copy data into FIFO + TU_VERIFY(tu_fifo_write_n(&_audiod_itf[idxDriver].ep_out_ff, _audiod_itf[idxDriver].evasion_buf_out, (uint16_t) xferred_bytes)); // Copy data into FIFO #endif TU_VERIFY(audiod_rx_done_cb(rhport, &_audiod_itf[idxDriver])); diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h index 19f120a33..eb88538ef 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -2,6 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) + * Copyright (c) 2020 Reinhard Panhuber - rework to unmasked pointers * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal From c098da9803a091c4b2402057ece370975850ef53 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Thu, 18 Feb 2021 19:25:08 +0100 Subject: [PATCH 039/121] Implement left and right justifications for 24 to 32 bit PCM encoding --- src/class/audio/audio_device.c | 10 ++++++++-- src/class/audio/audio_device.h | 12 ++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 527aecc0d..c71ad6b8e 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -366,11 +366,15 @@ static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio) // If this aborts then the target buffer is full TU_VERIFY(tu_fifo_read_n_into_other_fifo(&audio->ep_out_ff, &audio->rx_ff[cntChannel], 0, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX)); #else - // TODO: Implement a left and right justified 24 to 32 and vice versa copy process from FIFO to FIFO uint32_t sample = 0; // Get sample from buffer TU_VERIFY(tu_fifo_read_n(&audio->ep_out_ff, &sample, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX)); + +#if CFG_TUD_AUDIO_JUSTIFICATION_RX == CFG_TUD_AUDIO_LEFT_JUSTIFIED + sample = sample << 8; +#endif + TU_VERIFY(tu_fifo_write_n(&audio->rx_ff[cntChannel], &sample, CFG_TUD_AUDIO_RX_ITEMSIZE)); #endif } @@ -584,12 +588,14 @@ static bool audiod_encode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio) #if CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX == CFG_TUD_AUDIO_TX_ITEMSIZE tu_fifo_read_n_into_other_fifo(&audio->tx_ff[cntChannel], &audio->ep_in_ff, 0, CFG_TUD_AUDIO_TX_ITEMSIZE); #else - // TODO: Implement a left and right justified 24 to 32 and vice versa copy process from FIFO to FIFO uint32_t sample = 0; // Get sample from buffer tu_fifo_read_n(&audio->tx_ff[cntChannel], &sample, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX); +#if CFG_TUD_AUDIO_JUSTIFICATION_TX == CFG_TUD_AUDIO_LEFT_JUSTIFIED + sample = sample << 8; +#endif tu_fifo_write_n(&audio->ep_in_ff, &sample, CFG_TUD_AUDIO_TX_ITEMSIZE); #endif } diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index d1d1157eb..38495f72d 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -203,6 +203,18 @@ #endif +// In case PCM encoding/decoding of 24 into 32 bits, the adjustment needs to be defined +#define CFG_TUD_AUDIO_LEFT_JUSTIFIED +#define CFG_TUD_AUDIO_RIGHT_JUSTIFIED + +#ifndef CFG_TUD_AUDIO_JUSTIFICATION_RX +#define CFG_TUD_AUDIO_JUSTIFICATION_RX CFG_TUD_AUDIO_LEFT_JUSTIFIED +#endif + +#ifndef CFG_TUD_AUDIO_JUSTIFICATION_TX +#define CFG_TUD_AUDIO_JUSTIFICATION_TX CFG_TUD_AUDIO_LEFT_JUSTIFIED +#endif + //static_assert(sizeof(tud_audio_desc_lengths) != CFG_TUD_AUDIO, "Supply audio function descriptor pack length!"); // Supported types of this driver: From 31bf73517e91b4c25c34b8651064602f5adbef3e Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Thu, 18 Feb 2021 20:16:57 +0100 Subject: [PATCH 040/121] Add #include "osal/osal.h" in tu_fifo.h --- src/common/tusb_fifo.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h index eb88538ef..e56bcb844 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -47,6 +47,7 @@ #include #include +#include "osal/osal.h" #ifdef __cplusplus extern "C" { From 8904874f76ba4a476aefcbadfe74d70a6bfb692a Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Thu, 18 Feb 2021 20:52:57 +0100 Subject: [PATCH 041/121] Exclude #include "osal/osal.h" for OPT_OS_NONE --- src/common/tusb_fifo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h index e56bcb844..585ea17d3 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -47,13 +47,13 @@ #include #include -#include "osal/osal.h" #ifdef __cplusplus extern "C" { #endif #if CFG_FIFO_MUTEX +#include "osal/osal.h" #define tu_fifo_mutex_t osal_mutex_t #endif From fff6283bf751ecf8e2ef33745e03d45eb13b354e Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Thu, 18 Feb 2021 21:22:11 +0100 Subject: [PATCH 042/121] Update .non_used_index_space = UINT16_MAX - (2*_depth-1) in osal_none.h --- src/osal/osal_none.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/osal/osal_none.h b/src/osal/osal_none.h index 1d170d2fa..11726c95f 100644 --- a/src/osal/osal_none.h +++ b/src/osal/osal_none.h @@ -140,7 +140,7 @@ typedef osal_queue_def_t* osal_queue_t; .item_size = sizeof(_type), \ .overwritable = false, \ .max_pointer_idx = (2*(_depth))-1, \ - .non_used_index_space = 0xFFFF-((2*(_depth))-1),\ + .non_used_index_space = UINT16_MAX - (2*_depth-1),\ }\ } From 313dd1439db037e676429d11646008f143e6bdb9 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Tue, 23 Feb 2021 19:41:21 +0100 Subject: [PATCH 043/121] Implement dcd_edpt_iso_xfer() for dcd_da146xx.c BUT WITHOUT DMA SUPPORT --- src/class/audio/audio_device.c | 1 - src/portable/dialog/da146xx/dcd_da146xx.c | 102 ++++++++++++++++++++-- src/portable/st/synopsys/dcd_synopsys.c | 2 +- 3 files changed, 94 insertions(+), 11 deletions(-) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index c71ad6b8e..ef533e540 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -135,7 +135,6 @@ typedef struct CFG_TUSB_MCU == OPT_MCU_RP2040 || /* Don't want to change driver */ \ CFG_TUSB_MCU == OPT_MCU_VALENTYUSB_EPTRI || /* Intermediate software buffer required */ \ CFG_TUSB_MCU == OPT_MCU_CXD56 || /* No clue how driver works */ \ - CFG_TUSB_MCU == OPT_MCU_DA1469X || /* Uses DMA - Ok for FIFO, had no time for implementation */ \ CFG_TUSB_MCU == OPT_MCU_NRF5X || /* Uses DMA - Ok for FIFO, had no time for implementation */ \ CFG_TUSB_MCU == OPT_MCU_LPC11UXX || /* Uses DMA - Ok for FIFO, had no time for implementation */ \ CFG_TUSB_MCU == OPT_MCU_LPC13XX || \ diff --git a/src/portable/dialog/da146xx/dcd_da146xx.c b/src/portable/dialog/da146xx/dcd_da146xx.c index 59f728d08..8e1a5ddfd 100644 --- a/src/portable/dialog/da146xx/dcd_da146xx.c +++ b/src/portable/dialog/da146xx/dcd_da146xx.c @@ -25,6 +25,7 @@ */ #include "tusb_option.h" +#include "common/tusb_fifo.h" #if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_DA1469X @@ -196,6 +197,7 @@ typedef struct typedef struct { EPx_REGS * regs; uint8_t * buffer; + tu_fifo_t * ff; // Total length of current transfer uint16_t total_len; // Bytes transferred so far @@ -292,7 +294,6 @@ static void fill_tx_fifo(xfer_ctl_t * xfer) EPx_REGS *regs = xfer->regs; uint8_t const epnum = tu_edpt_number(xfer->ep_addr); - src = &xfer->buffer[xfer->transferred]; left_to_send = xfer->total_len - xfer->transferred; if (left_to_send > xfer->max_packet_size - xfer->last_packet_size) { @@ -301,12 +302,51 @@ static void fill_tx_fifo(xfer_ctl_t * xfer) // Loop checks TCOUNT all the time since this value is saturated to 31 // and can't be read just once before. - while ((regs->txs & USB_USB_TXS1_REG_USB_TCOUNT_Msk) > 0 && left_to_send > 0) + + if (xfer->ff) { - regs->txd = *src++; - xfer->last_packet_size++; - left_to_send--; + // Since TCOUNT is to be considered, we handle the FIFO reading manually here + // As we copy from a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies + // Check for first linear part + uint8_t * src; + uint16_t len = tu_fifo_get_linear_read_info(xfer->ff, 0, &src, left_to_send); // We want to read from the FIFO + uint16_t len1 = len; + while ((regs->txs & USB_USB_TXS1_REG_USB_TCOUNT_Msk) > 0 && len1 > 0) + { + regs->txd = *src++; + xfer->last_packet_size++; + len1--; + } + + tu_fifo_advance_read_pointer(ff, len-len1); + left_to_send -= (len-len1); + + // Check for wrapped part + if ((regs->txs & USB_USB_TXS1_REG_USB_TCOUNT_Msk) && left_to_send > 0) + { + len = tu_fifo_get_linear_read_info(xfer->ff, 0, &src, left_to_send); // We want to read from the FIFO + len1 = len; + while ((regs->txs & USB_USB_TXS1_REG_USB_TCOUNT_Msk) > 0 && len1 > 0) + { + regs->txd = *src++; + xfer->last_packet_size++; + len1--; + } + tu_fifo_advance_read_pointer(ff, len-len1); + left_to_send -= (len-len1); + } } + else + { + src = &xfer->buffer[xfer->transferred]; + while ((regs->txs & USB_USB_TXS1_REG_USB_TCOUNT_Msk) > 0 && left_to_send > 0) + { + regs->txd = *src++; + xfer->last_packet_size++; + left_to_send--; + } + } + if (epnum != 0) { if (left_to_send > 0) @@ -363,13 +403,14 @@ static void start_rx_packet(xfer_ctl_t *xfer) xfer->last_packet_size = 0; if (xfer->max_packet_size > FIFO_SIZE && remaining > FIFO_SIZE) { - if (try_allocate_dma(epnum, TUSB_DIR_OUT)) + if (try_allocate_dma(epnum, TUSB_DIR_OUT) && !xfer->ff) { start_rx_dma(&xfer->regs->rxd, xfer->buffer + xfer->transferred, size); } else { // Other endpoint is using DMA in that direction, fall back to interrupts. + // Or if an ISO EP transfer was scheduled, currently not handled by DMA! // For endpoint size greater then FIFO size enable FIFO level warning interrupt // when FIFO has less then 17 bytes free. xfer->regs->rxc |= USB_USB_RXC1_REG_USB_RFWL_Msk; @@ -409,7 +450,7 @@ static void start_tx_packet(xfer_ctl_t *xfer) regs->txc = USB_USB_TXC1_REG_USB_IGN_ISOMSK_Msk; if (xfer->data1) xfer->regs->txc |= USB_USB_TXC1_REG_USB_TOGGLE_TX_Msk; - if (xfer->max_packet_size > FIFO_SIZE && remaining > FIFO_SIZE && try_allocate_dma(epnum, TUSB_DIR_IN)) + if (xfer->max_packet_size > FIFO_SIZE && remaining > FIFO_SIZE && try_allocate_dma(epnum, TUSB_DIR_IN) && !xfer->ff) { // Whole packet will be put in FIFO by DMA. Set LAST bit before start. start_tx_dma(xfer->buffer + xfer->transferred, ®s->txd, size); @@ -430,9 +471,16 @@ static void read_rx_fifo(xfer_ctl_t *xfer, uint16_t bytes_in_fifo) if (remaining < bytes_in_fifo) receive_this_time = remaining; - uint8_t *buf = xfer->buffer + xfer->transferred + xfer->last_packet_size; + if (xfer->ff) + { + tu_fifo_write_n(xfer->ff, (const void *) ®s->rxd, receive_this_time); + } + else + { + uint8_t *buf = xfer->buffer + xfer->transferred + xfer->last_packet_size; - for (int i = 0; i < receive_this_time; ++i) buf[i] = regs->rxd; + for (int i = 0; i < receive_this_time; ++i) buf[i] = regs->rxd; + } xfer->last_packet_size += receive_this_time; } @@ -918,6 +966,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t (void)rhport; xfer->buffer = buffer; + xfer->ff = NULL; xfer->total_len = total_bytes; xfer->last_packet_size = 0; xfer->transferred = 0; @@ -934,6 +983,41 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t return true; } +bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +{ + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); + + (void)rhport; + + xfer->buffer = NULL; + xfer->ff = ff; + xfer->total_len = total_bytes; + xfer->last_packet_size = 0; + xfer->transferred = 0; + + if (dir == TUSB_DIR_IN) + { + tu_fifo_set_copy_mode_write(ff, TU_FIFO_COPY_CST); + } + else + { + tu_fifo_set_copy_mode_read(ff, TU_FIFO_COPY_CST); + } + + if (dir == TUSB_DIR_OUT) + { + start_rx_packet(xfer); + } + else // IN + { + start_tx_packet(xfer); + } + + return true; +} + void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { uint8_t const epnum = tu_edpt_number(ep_addr); diff --git a/src/portable/st/synopsys/dcd_synopsys.c b/src/portable/st/synopsys/dcd_synopsys.c index 5f8c44638..1d0bb5107 100644 --- a/src/portable/st/synopsys/dcd_synopsys.c +++ b/src/portable/st/synopsys/dcd_synopsys.c @@ -684,7 +684,7 @@ bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_ uint8_t const dir = tu_edpt_dir(ep_addr); xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); - xfer->buffer = NULL; // Indicates a FIFO shall be used + xfer->buffer = NULL; xfer->ff = ff; xfer->total_len = total_bytes; From c76e04f83584c55719a178b8308b3b2d0141b064 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Tue, 23 Feb 2021 19:50:54 +0100 Subject: [PATCH 044/121] Add dcd_edpt_iso_xfer() to dcd_template.c --- src/portable/template/dcd_template.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/portable/template/dcd_template.c b/src/portable/template/dcd_template.c index 618812416..7a9a0ae22 100644 --- a/src/portable/template/dcd_template.c +++ b/src/portable/template/dcd_template.c @@ -25,6 +25,7 @@ */ #include "tusb_option.h" +#include "common/tusb_fifo.h" #if CFG_TUSB_MCU == OPT_MCU_NONE @@ -104,6 +105,16 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t return false; } +// Submit a transfer where is managed by FIFO, When complete dcd_event_xfer_complete() is invoked to notify the stack +bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +{ + (void) rhport; + (void) ep_addr; + (void) ff; + (void) total_bytes; + return false; +} + // Stall endpoint void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr) { From 387bf1478efb89b5df12801dd904f93c374649b1 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Tue, 23 Feb 2021 19:52:31 +0100 Subject: [PATCH 045/121] Fix missing , in tusb_fifo.h --- src/common/tusb_fifo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h index 8e1c015ec..8cc448db0 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -98,7 +98,7 @@ typedef struct .item_size = sizeof(_type), \ .overwritable = _overwritable, \ .max_pointer_idx = 2*(_depth)-1, \ - .non_used_index_space = UINT16_MAX - (2*(_depth)-1) \ + .non_used_index_space = UINT16_MAX - (2*(_depth)-1), \ .wr_mode = TU_FIFO_COPY_INC, \ .rd_mode = TU_FIFO_COPY_INC, \ } From 00248de15a7f95f563503595099d68cd0c08cff5 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Tue, 23 Feb 2021 20:23:26 +0100 Subject: [PATCH 046/121] Fix shadowing declartion in dcd_da146xx.c --- src/portable/dialog/da146xx/dcd_da146xx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/portable/dialog/da146xx/dcd_da146xx.c b/src/portable/dialog/da146xx/dcd_da146xx.c index 8e1a5ddfd..dff2d00fb 100644 --- a/src/portable/dialog/da146xx/dcd_da146xx.c +++ b/src/portable/dialog/da146xx/dcd_da146xx.c @@ -290,7 +290,6 @@ void tusb_vbus_changed(bool present) static void fill_tx_fifo(xfer_ctl_t * xfer) { int left_to_send; - uint8_t const *src; EPx_REGS *regs = xfer->regs; uint8_t const epnum = tu_edpt_number(xfer->ep_addr); @@ -338,7 +337,7 @@ static void fill_tx_fifo(xfer_ctl_t * xfer) } else { - src = &xfer->buffer[xfer->transferred]; + uint8_t const *src = &xfer->buffer[xfer->transferred]; while ((regs->txs & USB_USB_TXS1_REG_USB_TCOUNT_Msk) > 0 && left_to_send > 0) { regs->txd = *src++; From cb33840a9bd2013b3acc1b0fa1088d18e9cc035a Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Tue, 23 Feb 2021 21:15:27 +0100 Subject: [PATCH 047/121] Fix pointer type --- src/portable/dialog/da146xx/dcd_da146xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/portable/dialog/da146xx/dcd_da146xx.c b/src/portable/dialog/da146xx/dcd_da146xx.c index dff2d00fb..53c12787c 100644 --- a/src/portable/dialog/da146xx/dcd_da146xx.c +++ b/src/portable/dialog/da146xx/dcd_da146xx.c @@ -308,7 +308,7 @@ static void fill_tx_fifo(xfer_ctl_t * xfer) // As we copy from a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies // Check for first linear part uint8_t * src; - uint16_t len = tu_fifo_get_linear_read_info(xfer->ff, 0, &src, left_to_send); // We want to read from the FIFO + uint16_t len = tu_fifo_get_linear_read_info(xfer->ff, 0, &((void *) src), left_to_send); // We want to read from the FIFO uint16_t len1 = len; while ((regs->txs & USB_USB_TXS1_REG_USB_TCOUNT_Msk) > 0 && len1 > 0) { @@ -323,7 +323,7 @@ static void fill_tx_fifo(xfer_ctl_t * xfer) // Check for wrapped part if ((regs->txs & USB_USB_TXS1_REG_USB_TCOUNT_Msk) && left_to_send > 0) { - len = tu_fifo_get_linear_read_info(xfer->ff, 0, &src, left_to_send); // We want to read from the FIFO + len = tu_fifo_get_linear_read_info(xfer->ff, 0, &((void *) src), left_to_send); // We want to read from the FIFO len1 = len; while ((regs->txs & USB_USB_TXS1_REG_USB_TCOUNT_Msk) > 0 && len1 > 0) { From 697c9476b75afa22a139325e9ae53d21fa5ed992 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Tue, 23 Feb 2021 21:42:38 +0100 Subject: [PATCH 048/121] Fix pointer type --- src/portable/dialog/da146xx/dcd_da146xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/portable/dialog/da146xx/dcd_da146xx.c b/src/portable/dialog/da146xx/dcd_da146xx.c index 53c12787c..1fa722d63 100644 --- a/src/portable/dialog/da146xx/dcd_da146xx.c +++ b/src/portable/dialog/da146xx/dcd_da146xx.c @@ -308,7 +308,7 @@ static void fill_tx_fifo(xfer_ctl_t * xfer) // As we copy from a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies // Check for first linear part uint8_t * src; - uint16_t len = tu_fifo_get_linear_read_info(xfer->ff, 0, &((void *) src), left_to_send); // We want to read from the FIFO + uint16_t len = tu_fifo_get_linear_read_info(xfer->ff, 0, (void **) &src, left_to_send); // We want to read from the FIFO uint16_t len1 = len; while ((regs->txs & USB_USB_TXS1_REG_USB_TCOUNT_Msk) > 0 && len1 > 0) { @@ -323,7 +323,7 @@ static void fill_tx_fifo(xfer_ctl_t * xfer) // Check for wrapped part if ((regs->txs & USB_USB_TXS1_REG_USB_TCOUNT_Msk) && left_to_send > 0) { - len = tu_fifo_get_linear_read_info(xfer->ff, 0, &((void *) src), left_to_send); // We want to read from the FIFO + len = tu_fifo_get_linear_read_info(xfer->ff, 0, (void **) &src, left_to_send); // We want to read from the FIFO len1 = len; while ((regs->txs & USB_USB_TXS1_REG_USB_TCOUNT_Msk) > 0 && len1 > 0) { From a7f07a1a63a07000a35357194dff7d61890c60c6 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Tue, 23 Feb 2021 21:53:17 +0100 Subject: [PATCH 049/121] Fix pointer type --- src/portable/dialog/da146xx/dcd_da146xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/portable/dialog/da146xx/dcd_da146xx.c b/src/portable/dialog/da146xx/dcd_da146xx.c index 1fa722d63..69ea5d87f 100644 --- a/src/portable/dialog/da146xx/dcd_da146xx.c +++ b/src/portable/dialog/da146xx/dcd_da146xx.c @@ -317,7 +317,7 @@ static void fill_tx_fifo(xfer_ctl_t * xfer) len1--; } - tu_fifo_advance_read_pointer(ff, len-len1); + tu_fifo_advance_read_pointer(xfer->ff, len-len1); left_to_send -= (len-len1); // Check for wrapped part @@ -331,7 +331,7 @@ static void fill_tx_fifo(xfer_ctl_t * xfer) xfer->last_packet_size++; len1--; } - tu_fifo_advance_read_pointer(ff, len-len1); + tu_fifo_advance_read_pointer(xfer->ff, len-len1); left_to_send -= (len-len1); } } From cc948288bd0a56457ffdc521e34bbc71ecbec40a Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Thu, 25 Feb 2021 11:18:37 +0100 Subject: [PATCH 050/121] Revert tusb_fifo.h include form to original. --- src/common/tusb_fifo.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h index 8cc448db0..2cab2abf8 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -53,7 +53,6 @@ extern "C" { #endif #if CFG_FIFO_MUTEX -#include "osal/osal.h" #define tu_fifo_mutex_t osal_mutex_t #endif From 8ec99694d228d31ee0b4033346498238c6605967 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Mon, 1 Mar 2021 09:09:15 +0100 Subject: [PATCH 051/121] audio_decive clean up and bootstrapping of linear (formerly evade) buff. --- src/class/audio/audio_device.c | 304 ++++++++++++++++++--------------- src/class/audio/audio_device.h | 42 ++--- 2 files changed, 190 insertions(+), 156 deletions(-) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index ef533e540..a29abc496 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -30,6 +30,22 @@ * * In case you need more alternate interfaces, you need to define additional defines for this specific alternate interface. Just define them and set them in the set_interface function. * + * There are three data flow structures currently implemented, where at least one SW-FIFO is used to decouple the asynchronous processes MCU vs. host + * + * 1. Input data -> SW-FIFO -> MCU USB + * + * The most easiest version, available in case the target MCU can handle the software FIFO (SW-FIFO) and if it is implemented in the device driver (if yes then dcd_edpt_iso_xfer() is available) + * + * 2. Input data -> SW-FIFO -> Linear buffer -> MCU USB + * + * In case the target MCU can not handle a SW-FIFO, a linear buffer is used. This uses the default function dcd_edpt_xfer(). In this case more memory is required. + * + * 3. (Input data 1 | Input data 2 | ... | Input data N) -> (SW-FIFO 1 | SW-FIFO 2 | ... | SW-FIFO N) -> Linear buffer -> MCU USB + * + * This case is used if you have more channels which need to be combined into one stream. Every channel has its own SW-FIFO. All data is encoded into an Linear buffer. + * + * The same holds in the RX case. + * * */ #include "tusb_option.h" @@ -47,17 +63,45 @@ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ + // Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically +#if ( CFG_TUSB_MCU == OPT_MCU_MKL25ZXX || /* Intermediate software buffer required */ \ + CFG_TUSB_MCU == OPT_MCU_LPC18XX || /* No clue how driver works */ \ + CFG_TUSB_MCU == OPT_MCU_LPC43XX || \ + CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \ + CFG_TUSB_MCU == OPT_MCU_RP2040 || /* Don't want to change driver */ \ + CFG_TUSB_MCU == OPT_MCU_VALENTYUSB_EPTRI || /* Intermediate software buffer required */ \ + CFG_TUSB_MCU == OPT_MCU_CXD56 || /* No clue how driver works */ \ + CFG_TUSB_MCU == OPT_MCU_NRF5X || /* Uses DMA - Ok for FIFO, had no time for implementation */ \ + CFG_TUSB_MCU == OPT_MCU_LPC11UXX || /* Uses DMA - Ok for FIFO, had no time for implementation */ \ + CFG_TUSB_MCU == OPT_MCU_LPC13XX || \ + CFG_TUSB_MCU == OPT_MCU_LPC15XX || \ + CFG_TUSB_MCU == OPT_MCU_LPC51UXX || \ + CFG_TUSB_MCU == OPT_MCU_LPC54XXX || \ + CFG_TUSB_MCU == OPT_MCU_LPC55XX || \ + CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || \ + CFG_TUSB_MCU == OPT_MCU_LPC40XX || \ + CFG_TUSB_MCU == OPT_MCU_SAMD11 || /* Uses DMA - Ok for FIFO, had no time for implementation */ \ + CFG_TUSB_MCU == OPT_MCU_SAMD21 || \ + CFG_TUSB_MCU == OPT_MCU_SAMD51 || \ + CFG_TUSB_MCU == OPT_MCU_SAME5X ) + +#define USE_LINEAR_BUFFER 1 + +#else +#define USE_LINEAR_BUFFER 0 +#endif + typedef struct { uint8_t rhport; uint8_t const * p_desc; // Pointer pointing to Standard AC Interface Descriptor(4.7.1) - Audio Control descriptor defining audio function -#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE +#if CFG_TUD_AUDIO_EPSIZE_IN uint8_t ep_in; // TX audio data EP. uint8_t ep_in_as_intf_num; // Corresponding Standard AS Interface Descriptor (4.9.1) belonging to output terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero) #endif -#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE +#if CFG_TUD_AUDIO_EPSIZE_OUT uint8_t ep_out; // Incoming (into uC) audio data EP. uint8_t ep_out_as_intf_num; // Corresponding Standard AS Interface Descriptor (4.9.1) belonging to input terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero) @@ -82,6 +126,8 @@ typedef struct // EP Transfer buffers and FIFOs #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE + +#if !CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE CFG_TUSB_MEM_ALIGN uint8_t ep_out_buf[CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE]; tu_fifo_t ep_out_ff; @@ -89,13 +135,15 @@ typedef struct osal_mutex_def_t ep_out_ff_mutex; #endif +#endif + #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP uint32_t fb_val; // Feedback value for asynchronous mode (in 16.16 format). #endif #endif -#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE +#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE && !CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE CFG_TUSB_MEM_ALIGN uint8_t ep_in_buf[CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE]; tu_fifo_t ep_in_ff; @@ -112,61 +160,42 @@ typedef struct // Support FIFOs #if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE - tu_fifo_t tx_ff[CFG_TUD_AUDIO_N_CHANNELS_TX]; - CFG_TUSB_MEM_ALIGN uint8_t tx_ff_buf[CFG_TUD_AUDIO_N_CHANNELS_TX][CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE]; + tu_fifo_t tx_supp_ff[CFG_TUD_AUDIO_N_CHANNELS_TX]; + CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf[CFG_TUD_AUDIO_N_CHANNELS_TX][CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE]; #if CFG_FIFO_MUTEX - osal_mutex_def_t tx_ff_mutex[CFG_TUD_AUDIO_N_CHANNELS_TX]; + osal_mutex_def_t tx_supp_ff_mutex[CFG_TUD_AUDIO_N_CHANNELS_TX]; #endif #endif #if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE - tu_fifo_t rx_ff[CFG_TUD_AUDIO_N_CHANNELS_RX]; - CFG_TUSB_MEM_ALIGN uint8_t rx_ff_buf[CFG_TUD_AUDIO_N_CHANNELS_RX][CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE]; + tu_fifo_t rx_supp_ff[CFG_TUD_AUDIO_N_CHANNELS_RX]; + CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf[CFG_TUD_AUDIO_N_CHANNELS_RX][CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE]; #if CFG_FIFO_MUTEX - osal_mutex_def_t rx_ff_mutex[CFG_TUD_AUDIO_N_CHANNELS_RX]; + osal_mutex_def_t rx_supp_ff_mutex[CFG_TUD_AUDIO_N_CHANNELS_RX]; #endif #endif - // Evasion buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically -#if ( CFG_TUSB_MCU == OPT_MCU_MKL25ZXX || /* Intermediate software buffer required */ \ - CFG_TUSB_MCU == OPT_MCU_LPC18XX || /* No clue how driver works */ \ - CFG_TUSB_MCU == OPT_MCU_LPC43XX || \ - CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \ - CFG_TUSB_MCU == OPT_MCU_RP2040 || /* Don't want to change driver */ \ - CFG_TUSB_MCU == OPT_MCU_VALENTYUSB_EPTRI || /* Intermediate software buffer required */ \ - CFG_TUSB_MCU == OPT_MCU_CXD56 || /* No clue how driver works */ \ - CFG_TUSB_MCU == OPT_MCU_NRF5X || /* Uses DMA - Ok for FIFO, had no time for implementation */ \ - CFG_TUSB_MCU == OPT_MCU_LPC11UXX || /* Uses DMA - Ok for FIFO, had no time for implementation */ \ - CFG_TUSB_MCU == OPT_MCU_LPC13XX || \ - CFG_TUSB_MCU == OPT_MCU_LPC15XX || \ - CFG_TUSB_MCU == OPT_MCU_LPC51UXX || \ - CFG_TUSB_MCU == OPT_MCU_LPC54XXX || \ - CFG_TUSB_MCU == OPT_MCU_LPC55XX || \ - CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || \ - CFG_TUSB_MCU == OPT_MCU_LPC40XX || \ - CFG_TUSB_MCU == OPT_MCU_SAMD11 || /* Uses DMA - Ok for FIFO, had no time for implementation */ \ - CFG_TUSB_MCU == OPT_MCU_SAMD21 || \ - CFG_TUSB_MCU == OPT_MCU_SAMD51 || \ - CFG_TUSB_MCU == OPT_MCU_SAME5X ) - -#define USE_EVADE_BUFFER 1 - -#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE - CFG_TUSB_MEM_ALIGN uint8_t evasion_buf_out[CFG_TUD_AUDIO_EPSIZE_OUT]; + // Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR the support FIFOs are used +#if CFG_TUD_AUDIO_EPSIZE_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE) + CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out[CFG_TUD_AUDIO_EPSIZE_OUT]; +#define USE_LINEAR_BUFFER_RX 1 #endif -#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE - CFG_TUSB_MEM_ALIGN uint8_t evasion_buf_in[CFG_TUD_AUDIO_EPSIZE_IN]; -#endif - -#endif - -#ifndef USE_EVADE_BUFFER -#define USE_EVADE_BUFFER 0 +#if CFG_TUD_AUDIO_EPSIZE_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE) + CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in[CFG_TUD_AUDIO_EPSIZE_IN]; +#define USE_LINEAR_BUFFER_TX 1 #endif } audiod_interface_t; +#ifndef USE_LINEAR_BUFFER_TX +#define USE_LINEAR_BUFFER_TX 0 +#endif + +#ifndef USE_LINEAR_BUFFER_RX +#define USE_LINEAR_BUFFER_RX 0 +#endif + #define ITF_MEM_RESET_SIZE offsetof(audiod_interface_t, ctrl_buf) //--------------------------------------------------------------------+ @@ -177,19 +206,19 @@ CFG_TUSB_MEM_SECTION audiod_interface_t _audiod_itf[CFG_TUD_AUDIO]; extern const uint16_t tud_audio_desc_lengths[]; #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE -static bool audiod_rx_done_cb(uint8_t rhport, audiod_interface_t* audio); +static bool audiod_rx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint16_t n_bytes_received); #endif -#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE -static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio); +#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_OUT +static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio, uint16_t n_bytes_received); #endif #if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t* audio); #endif -#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE -static bool audiod_encode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio); +#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_IN +static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio); #endif static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const * p_request); @@ -228,7 +257,7 @@ bool tud_audio_n_mounted(uint8_t itf) // READ API //--------------------------------------------------------------------+ -#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE +#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && !CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE uint16_t tud_audio_n_available(uint8_t itf) { @@ -248,35 +277,35 @@ bool tud_audio_n_clear_ep_out_ff(uint8_t itf) return tu_fifo_clear(&_audiod_itf[itf].ep_out_ff); } -#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE +#endif + +#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_OUT // Delete all content in the support RX FIFOs bool tud_audio_n_clear_rx_support_ff(uint8_t itf, uint8_t channelId) { TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_RX); - return tu_fifo_clear(&_audiod_itf[itf].rx_ff[channelId]); + return tu_fifo_clear(&_audiod_itf[itf].rx_supp_ff[channelId]); } uint16_t tud_audio_n_available_support_ff(uint8_t itf, uint8_t channelId) { TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_RX); - return tu_fifo_count(&_audiod_itf[itf].rx_ff[channelId]); + return tu_fifo_count(&_audiod_itf[itf].rx_supp_ff[channelId]); } uint16_t tud_audio_n_read_support_ff(uint8_t itf, uint8_t channelId, void* buffer, uint16_t bufsize) { TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_RX); - return tu_fifo_read_n(&_audiod_itf[itf].rx_ff[channelId], buffer, bufsize); + return tu_fifo_read_n(&_audiod_itf[itf].rx_supp_ff[channelId], buffer, bufsize); } #endif -#endif - -// This function is called once an audio packet is received by the USB and is responsible for decoding received stream into audio channels. +// This function is called once an audio packet is received by the USB and is responsible for putting data from USB memory into EP_OUT_FIFO (or support FIFOs + decoding of received stream into audio channels). // If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE = 0. #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE -static bool audiod_rx_done_cb(uint8_t rhport, audiod_interface_t* audio) +static bool audiod_rx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint16_t n_bytes_received) { uint8_t idxDriver, idxItf; uint8_t const *dummy2; @@ -288,13 +317,10 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_interface_t* audio) TU_VERIFY(audiod_get_AS_interface_index(audio->ep_out_as_intf_num, &idxDriver, &idxItf, &dummy2)); } - // Get number of bytes in EP OUT SW FIFO - uint16_t n_bytes_received = tu_fifo_count(&audio->ep_out_ff); - - // Call a weak callback here - a possibility for user to get informed an audio packet was received and data gets now decoded into support RX software FIFO + // Call a weak callback here - a possibility for user to get informed an audio packet was received and data gets now loaded into EP FIFO (or decoded into support RX software FIFO) if (tud_audio_rx_done_pre_read_cb) TU_VERIFY(tud_audio_rx_done_pre_read_cb(rhport, n_bytes_received, idxDriver, audio->ep_out, audio->altSetting[idxItf])); -#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE +#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_OUT switch (CFG_TUD_AUDIO_FORMAT_TYPE_RX) { @@ -309,7 +335,7 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_interface_t* audio) switch (CFG_TUD_AUDIO_FORMAT_TYPE_I_RX) { case AUDIO_DATA_FORMAT_TYPE_I_PCM: - TU_VERIFY(audiod_decode_type_I_pcm(rhport, audio)); + TU_VERIFY(audiod_decode_type_I_pcm(rhport, audio, n_bytes_received)); break; default: @@ -327,13 +353,22 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_interface_t* audio) break; } + // Prepare for next transmission + TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, CFG_TUD_AUDIO_EPSIZE_OUT), false); + +#else + +#if USE_LINEAR_BUFFER_RX + // Data currently is in linear buffer, copy into EP OUT FIFO + TU_VERIFY(tu_fifo_write_n(&audio->ep_out_ff, audio->lin_buf_out, n_bytes_received)); + + // Schedule for next receive + TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, CFG_TUD_AUDIO_EPSIZE_OUT), false); +#else + // Data is already placed in EP FIFO, schedule for next receive + TU_VERIFY(usbd_edpt_iso_xfer(rhport, audio->ep_out, &audio->ep_out_ff, CFG_TUD_AUDIO_EPSIZE_OUT), false); #endif - // Prepare for next transmission -#if USE_EVADE_BUFFER - TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->evasion_buf_out, CFG_TUD_AUDIO_EPSIZE_OUT), false); -#else - TU_VERIFY(usbd_edpt_iso_xfer(rhport, audio->ep_out, &audio->ep_out_ff, CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE), false); #endif // Call a weak callback here - a possibility for user to get informed decoding was completed @@ -345,37 +380,33 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_interface_t* audio) #endif //CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE // The following functions are used in case CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE != 0 -#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE -static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio) +#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_OUT +static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio, uint16_t n_bytes_received) { (void) rhport; // We assume there is always the correct number of samples available for decoding - extra checks make no sense here - uint16_t const n_bytes = tu_fifo_count(&audio->ep_out_ff); - uint16_t cnt = CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX; + uint16_t idxSample = 0; - while (cnt <= n_bytes) + while (cnt <= n_bytes_received) { for (uint8_t cntChannel = 0; cntChannel < CFG_TUD_AUDIO_N_CHANNELS_RX; cntChannel++) { // If 8, 16, or 32 bit values are to be copied #if CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX == CFG_TUD_AUDIO_RX_ITEMSIZE // If this aborts then the target buffer is full - TU_VERIFY(tu_fifo_read_n_into_other_fifo(&audio->ep_out_ff, &audio->rx_ff[cntChannel], 0, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX)); + TU_VERIFY(tu_fifo_write_n(&audio->rx_supp_ff[cntChannel], &audio->lin_buf_out[idxSample], CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX)); #else - uint32_t sample = 0; - - // Get sample from buffer - TU_VERIFY(tu_fifo_read_n(&audio->ep_out_ff, &sample, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX)); - + uint32_t sample = audio->lin_buf_out[idxSample]; #if CFG_TUD_AUDIO_JUSTIFICATION_RX == CFG_TUD_AUDIO_LEFT_JUSTIFIED sample = sample << 8; #endif - TU_VERIFY(tu_fifo_write_n(&audio->rx_ff[cntChannel], &sample, CFG_TUD_AUDIO_RX_ITEMSIZE)); + TU_VERIFY(tu_fifo_write_n(&audio->rx_supp_ff[cntChannel], &sample, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX)); #endif + idxSample += CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX; } cnt += CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX; @@ -392,7 +423,7 @@ static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio) // WRITE API //--------------------------------------------------------------------+ -#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE +#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE && !CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE /** * \brief Write data to EP in buffer @@ -417,18 +448,20 @@ bool tud_audio_n_clear_ep_in_ff(uint8_t itf) // Delete return tu_fifo_clear(&_audiod_itf[itf].ep_in_ff); } -#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE -uint16_t tud_audio_n_flush_tx_support_ff(uint8_t itf) // Force all content in the support TX FIFOs to be written into EP SW FIFO +#endif + +#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_IN +uint16_t tud_audio_n_flush_tx_support_ff(uint8_t itf) // Force all content in the support TX FIFOs to be written into linear buffer and schedule a transmit { TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL); audiod_interface_t* audio = &_audiod_itf[itf]; - uint16_t n_bytes_copied = tu_fifo_count(&audio->ep_in_ff); + uint16_t n_bytes_copied = tu_fifo_count(&audio->tx_supp_ff[0]); TU_VERIFY(audiod_tx_done_cb(audio->rhport, audio)); - n_bytes_copied -= tu_fifo_count(&audio->ep_in_ff); - n_bytes_copied = n_bytes_copied*audio->ep_in_ff.item_size; + n_bytes_copied -= tu_fifo_count(&audio->tx_supp_ff[0]); + n_bytes_copied = n_bytes_copied*audio->tx_supp_ff[0].item_size; return n_bytes_copied; } @@ -436,17 +469,16 @@ uint16_t tud_audio_n_flush_tx_support_ff(uint8_t itf) // Force a bool tud_audio_n_clear_tx_support_ff(uint8_t itf, uint8_t channelId) { TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_TX); - return tu_fifo_clear(&_audiod_itf[itf].tx_ff[channelId]); + return tu_fifo_clear(&_audiod_itf[itf].tx_supp_ff[channelId]); } uint16_t tud_audio_n_write_support_ff(uint8_t itf, uint8_t channelId, const void * data, uint16_t len) { TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_TX); - return tu_fifo_write_n(&_audiod_itf[itf].tx_ff[channelId], data, len); + return tu_fifo_write_n(&_audiod_itf[itf].tx_supp_ff[channelId], data, len); } #endif -#endif #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN @@ -492,7 +524,11 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t * audio) // if no FIFOs are used the user may use this call back to load its data into the EP IN buffer by use of tud_audio_n_write_ep_in_buffer(). if (tud_audio_tx_done_pre_load_cb) TU_VERIFY(tud_audio_tx_done_pre_load_cb(rhport, idxDriver, audio->ep_in, audio->altSetting[idxItf])); -#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE + // Send everything in ISO EP FIFO + uint16_t n_bytes_tx; + + // If support FIFOs are used, encode and schedule transmit +#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_IN switch (CFG_TUD_AUDIO_FORMAT_TYPE_TX) { case AUDIO_FORMAT_TYPE_UNDEFINED: @@ -507,8 +543,7 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t * audio) { case AUDIO_DATA_FORMAT_TYPE_I_PCM: - TU_VERIFY(audiod_encode_type_I_pcm(rhport, audio)); - + n_bytes_tx = audiod_encode_type_I_pcm(rhport, audio); break; default: @@ -525,17 +560,22 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t * audio) TU_BREAKPOINT(); break; } -#endif - // Send everything in ISO EP FIFO - uint16_t n_bytes_tx = tu_fifo_count(&audio->ep_in_ff); + TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->lin_buf_in, n_bytes_tx)); - // Schedule transmit -#if USE_EVADE_BUFFER - tu_fifo_write_n(&audio->ep_in_ff, audio->evasion_buf_in, n_bytes_tx); - TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->evasion_buf_in, n_bytes_tx)); #else - TU_VERIFY(usbd_edpt_iso_xfer(rhport, audio->ep_in, &audio->ep_in_ff, n_bytes_tx)); + // No support FIFOs, if no linear buffer required schedule transmit, else put data into linear buffer and schedule + + n_bytes_tx = tu_fifo_count(&audio->ep_in_ff); + + #if USE_LINEAR_BUFFER_TX + tu_fifo_write_n(&audio->ep_in_ff, audio->lin_buf_in, n_bytes_tx); + TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->lin_buf_in, n_bytes_tx)); + #else + // Send everything in ISO EP FIFO + TU_VERIFY(usbd_edpt_iso_xfer(rhport, audio->ep_in, &audio->ep_in_ff, n_bytes_tx)); + #endif + #endif // Call a weak callback here - a possibility for user to get informed former TX was completed and how many bytes were loaded for the next frame @@ -546,21 +586,22 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t * audio) #endif //CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE -#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE +#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_IN // Take samples from the support buffer and encode them into the IN EP software FIFO -static bool audiod_encode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio) +// Returns number of bytes written into linear buffer +static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio) { // We encode directly into IN EP's FIFO - abort if previous transfer not complete TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_in)); // Determine amount of samples uint16_t const nEndpointSampleCapacity = CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE / CFG_TUD_AUDIO_N_CHANNELS_TX / CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX; - uint16_t nSamplesPerChannelToSend = tu_fifo_count(&audio->tx_ff[0]); // We first look for the minimum number of bytes and afterwards convert it to sample size + uint16_t nSamplesPerChannelToSend = tu_fifo_count(&audio->tx_supp_ff[0]); // We first look for the minimum number of bytes and afterwards convert it to sample size uint8_t cntChannel; for (cntChannel = 1; cntChannel < CFG_TUD_AUDIO_N_CHANNELS_TX; cntChannel++) { - uint16_t const count = tu_fifo_count(&audio->tx_ff[cntChannel]); + uint16_t const count = tu_fifo_count(&audio->tx_supp_ff[cntChannel]); if (count < nSamplesPerChannelToSend) { nSamplesPerChannelToSend = count; @@ -571,13 +612,14 @@ static bool audiod_encode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio) nSamplesPerChannelToSend = nSamplesPerChannelToSend / CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX; // Check if there is enough - if (nSamplesPerChannelToSend == 0) return true; + if (nSamplesPerChannelToSend == 0) return 0; // Limit to maximum sample number - THIS IS A POSSIBLE ERROR SOURCE IF TOO MANY SAMPLE WOULD NEED TO BE SENT BUT CAN NOT! nSamplesPerChannelToSend = tu_min16(nSamplesPerChannelToSend, nEndpointSampleCapacity); // Encode uint16_t cntSample; + uint16_t idxSample = 0; for (cntSample = 0; cntSample < nSamplesPerChannelToSend; cntSample++) { @@ -585,21 +627,22 @@ static bool audiod_encode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio) { // If 8, 16, or 32 bit values are to be copied #if CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX == CFG_TUD_AUDIO_TX_ITEMSIZE - tu_fifo_read_n_into_other_fifo(&audio->tx_ff[cntChannel], &audio->ep_in_ff, 0, CFG_TUD_AUDIO_TX_ITEMSIZE); + tu_fifo_read_n(&audio->tx_supp_ff[cntChannel], &audio->lin_buf_in[idxSample], CFG_TUD_AUDIO_TX_ITEMSIZE); #else uint32_t sample = 0; // Get sample from buffer - tu_fifo_read_n(&audio->tx_ff[cntChannel], &sample, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX); + tu_fifo_read_n(&audio->tx_supp_ff[cntChannel], &sample, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX); #if CFG_TUD_AUDIO_JUSTIFICATION_TX == CFG_TUD_AUDIO_LEFT_JUSTIFIED sample = sample << 8; #endif - tu_fifo_write_n(&audio->ep_in_ff, &sample, CFG_TUD_AUDIO_TX_ITEMSIZE); + audio->lin_buf_in[idxSample] = sample; #endif + idxSample += CFG_TUD_AUDIO_TX_ITEMSIZE; } } - return true; + return nSamplesPerChannelToSend * CFG_TUD_AUDIO_N_CHANNELS_TX * CFG_TUD_AUDIO_TX_ITEMSIZE; } #endif //CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE @@ -624,7 +667,7 @@ void audiod_init(void) audiod_interface_t* audio = &_audiod_itf[i]; // Initialize IN EP FIFO if required -#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE +#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE && !CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE tu_fifo_config(&audio->ep_in_ff, &audio->ep_in_buf, CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE, 1, true); #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&audio->ep_in_ff_mutex)); @@ -632,7 +675,7 @@ void audiod_init(void) #endif // Initialize OUT EP FIFO if required -#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE +#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && !CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE tu_fifo_config(&audio->ep_out_ff, &audio->ep_out_buf, CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE, 1, true); #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&audio->ep_out_ff, osal_mutex_create(&audio->ep_out_ff_mutex)); @@ -640,23 +683,23 @@ void audiod_init(void) #endif // Initialize TX support FIFOs if required -#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE && CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE +#if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_TX; cnt++) { - tu_fifo_config(&audio->tx_ff[cnt], &audio->tx_ff_buf[cnt], CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE, 1, true); + tu_fifo_config(&audio->tx_supp_ff[cnt], &audio->tx_supp_ff_buf[cnt], CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->tx_ff[cnt], osal_mutex_create(&audio->tx_ff_mutex[cnt])); + tu_fifo_config_mutex(&audio->tx_supp_ff[cnt], osal_mutex_create(&audio->tx_supp_ff_mutex[cnt])); #endif } #endif // Initialize RX support FIFOs if required -#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE +#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_RX; cnt++) { - tu_fifo_config(&audio->rx_ff[cnt], &audio->rx_ff_buf[cnt], CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE, 1, true); + tu_fifo_config(&audio->rx_supp_ff[cnt], &audio->rx_supp_ff_buf[cnt], CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->rx_ff[cnt], osal_mutex_create(&audio->rx_ff_mutex[cnt])); + tu_fifo_config_mutex(&audio->rx_supp_ff[cnt], osal_mutex_create(&audio->rx_supp_ff_mutex[cnt])); #endif } #endif @@ -672,25 +715,25 @@ void audiod_reset(uint8_t rhport) audiod_interface_t* audio = &_audiod_itf[i]; tu_memclr(audio, ITF_MEM_RESET_SIZE); -#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE +#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE && !CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE tu_fifo_clear(&audio->ep_in_ff); #endif -#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE +#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && !CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE tu_fifo_clear(&audio->ep_out_ff); #endif #if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE && CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_TX; cnt++) { - tu_fifo_clear(&audio->tx_ff[cnt]); + tu_fifo_clear(&audio->tx_supp_ff[cnt]); } #endif #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_RX; cnt++) { - tu_fifo_clear(&audio->rx_ff[cnt]); + tu_fifo_clear(&audio->rx_supp_ff[cnt]); } #endif } @@ -731,7 +774,6 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin TU_ASSERT( i < CFG_TUD_AUDIO ); // This is all we need so far - the EPs are setup by a later set_interface request (as per UAC2 specification) - // TODO: Find a way to find end of current audio function and avoid necessity of tud_audio_desc_lengths - since now max_length is available we could do this surely somehow uint16_t drv_len = tud_audio_desc_lengths[i] - TUD_AUDIO_DESC_IAD_LEN; // - TUD_AUDIO_DESC_IAD_LEN since tinyUSB already handles the IAD descriptor return drv_len; @@ -840,7 +882,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * //TODO: We need to set EP non busy since this is not taken care of right now in ep_close() - THIS IS A WORKAROUND! usbd_edpt_clear_stall(rhport, ep_addr); -#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE +#if CFG_TUD_AUDIO_EPSIZE_IN if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && ((tusb_desc_endpoint_t const *) p_desc)->bmAttributes.usage == 0x00) // Check if usage is data EP { // Save address @@ -856,7 +898,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * } #endif -#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE +#if CFG_TUD_AUDIO_EPSIZE_OUT if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) // Checking usage not necessary { @@ -868,8 +910,8 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request)); // Prepare for incoming data -#if USE_EVADE_BUFFER - TU_VERIFY(usbd_edpt_xfer(rhport, _audiod_itf[idxDriver].ep_out, _audiod_itf[idxDriver].evasion_buf_out, CFG_TUD_AUDIO_EPSIZE_OUT), false); +#if USE_LINEAR_BUFFER_RX + TU_VERIFY(usbd_edpt_xfer(rhport, _audiod_itf[idxDriver].ep_out, _audiod_itf[idxDriver].lin_buf_out, CFG_TUD_AUDIO_EPSIZE_OUT), false); #else TU_VERIFY(usbd_edpt_iso_xfer(rhport, _audiod_itf[idxDriver].ep_out, &_audiod_itf[idxDriver].ep_out_ff, CFG_TUD_AUDIO_EPSIZE_OUT), false); #endif @@ -1161,15 +1203,7 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 // New audio packet received if (_audiod_itf[idxDriver].ep_out == ep_addr) { - // Save into buffer - do whatever has to be done - // TU_VERIFY(audiod_rx_done_cb(rhport, &_audiod_itf[idxDriver], _audiod_itf[idxDriver].ep_out_buf, xferred_bytes)); - -#if USE_EVADE_BUFFER - TU_VERIFY(tu_fifo_write_n(&_audiod_itf[idxDriver].ep_out_ff, _audiod_itf[idxDriver].evasion_buf_out, (uint16_t) xferred_bytes)); // Copy data into FIFO -#endif - - TU_VERIFY(audiod_rx_done_cb(rhport, &_audiod_itf[idxDriver])); - + TU_VERIFY(audiod_rx_done_cb(rhport, &_audiod_itf[idxDriver], (uint16_t) xferred_bytes)); return true; } diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index 38495f72d..ca74d68f4 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -235,26 +235,26 @@ extern "C" { //--------------------------------------------------------------------+ bool tud_audio_n_mounted (uint8_t itf); -#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE +#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && !CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE uint16_t tud_audio_n_available (uint8_t itf); uint16_t tud_audio_n_read (uint8_t itf, void* buffer, uint16_t bufsize); bool tud_audio_n_clear_ep_out_ff (uint8_t itf); // Delete all content in the EP OUT FIFO -#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE +#endif + +#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_OUT bool tud_audio_n_clear_rx_support_ff (uint8_t itf, uint8_t channelId); // Delete all content in the support RX FIFOs uint16_t tud_audio_n_available_support_ff (uint8_t itf, uint8_t channelId); uint16_t tud_audio_n_read_support_ff (uint8_t itf, uint8_t channelId, void* buffer, uint16_t bufsize); #endif -#endif - #if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE uint16_t tud_audio_n_write (uint8_t itf, const void * data, uint16_t len); bool tud_audio_n_clear_ep_in_ff (uint8_t itf); // Delete all content in the EP IN FIFO -#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE +#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_IN uint16_t tud_audio_n_flush_tx_support_ff (uint8_t itf); // Force all content in the support TX FIFOs to be written into EP SW FIFO bool tud_audio_n_clear_tx_support_ff (uint8_t itf, uint8_t channelId); uint16_t tud_audio_n_write_support_ff (uint8_t itf, uint8_t channelId, const void * data, uint16_t len); @@ -274,35 +274,35 @@ static inline bool tud_audio_mounted (void); // RX API -#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE +#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && !CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE static inline uint16_t tud_audio_available (void); static inline bool tud_audio_clear_ep_out_ff (void); // Delete all content in the EP OUT FIFO static inline uint16_t tud_audio_read (void* buffer, uint16_t bufsize); -#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE +#endif + +#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_OUT static inline bool tud_audio_clear_rx_support_ff (uint8_t channelId); static inline uint16_t tud_audio_available_support_ff (uint8_t channelId); static inline uint16_t tud_audio_read_support_ff (uint8_t channelId, void* buffer, uint16_t bufsize); #endif -#endif - // TX API -#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE +#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE && !CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE static inline uint16_t tud_audio_write (const void * data, uint16_t len); static inline bool tud_audio_clear_ep_in_ff (void); -#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE +#endif + +#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_IN static inline uint16_t tud_audio_flush_tx_support_ff (void); static inline uint16_t tud_audio_clear_tx_support_ff (uint8_t channelId); static inline uint16_t tud_audio_write_support_ff (uint8_t channelId, const void * data, uint16_t len); #endif -#endif - // INT CTR API #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN @@ -380,7 +380,7 @@ static inline bool tud_audio_mounted(void) // RX API -#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE +#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && !CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE static inline uint16_t tud_audio_available (void) { @@ -397,7 +397,9 @@ static inline bool tud_audio_clear_ep_out_ff (void) return tud_audio_n_clear_ep_out_ff(0); } -#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE +#endif + +#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_OUT static inline bool tud_audio_clear_rx_support_ff (uint8_t channelId) { @@ -416,11 +418,9 @@ static inline uint16_t tud_audio_read_support_ff (uint8_t channelId, #endif -#endif - // TX API -#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE +#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE && !CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE static inline uint16_t tud_audio_write (const void * data, uint16_t len) { @@ -432,7 +432,9 @@ static inline bool tud_audio_clear_ep_in_ff (void) return tud_audio_n_clear_ep_in_ff(0); } -#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE +#endif + +#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_IN static inline uint16_t tud_audio_flush_tx_support_ff (void) { @@ -451,8 +453,6 @@ static inline uint16_t tud_audio_write_support_ff (uint8_t channelId, #endif -#endif - #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN static inline uint16_t tud_audio_int_ctr_write(uint8_t const* buffer, uint16_t len) { From fc35b3f72dc2f73ecd9df3e14484ef493803fd7b Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Tue, 2 Mar 2021 17:24:58 +0100 Subject: [PATCH 052/121] Switch back OPT_MCU_DA1469X to use linear buffers --- src/class/audio/audio_device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index a29abc496..32745002c 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -65,6 +65,7 @@ // Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically #if ( CFG_TUSB_MCU == OPT_MCU_MKL25ZXX || /* Intermediate software buffer required */ \ + CFG_TUSB_MCU == OPT_MCU_DA1469X || /* Intermediate software buffer required */ \ CFG_TUSB_MCU == OPT_MCU_LPC18XX || /* No clue how driver works */ \ CFG_TUSB_MCU == OPT_MCU_LPC43XX || \ CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \ From c8b6d9b9906f8185ef6edb84962446328c9f68cb Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Tue, 2 Mar 2021 19:28:35 +0100 Subject: [PATCH 053/121] Revert implementation of dcd_edpt_iso_xfer() --- src/portable/dialog/da146xx/dcd_da146xx.c | 103 +++------------------- 1 file changed, 10 insertions(+), 93 deletions(-) diff --git a/src/portable/dialog/da146xx/dcd_da146xx.c b/src/portable/dialog/da146xx/dcd_da146xx.c index 69ea5d87f..59f728d08 100644 --- a/src/portable/dialog/da146xx/dcd_da146xx.c +++ b/src/portable/dialog/da146xx/dcd_da146xx.c @@ -25,7 +25,6 @@ */ #include "tusb_option.h" -#include "common/tusb_fifo.h" #if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_DA1469X @@ -197,7 +196,6 @@ typedef struct typedef struct { EPx_REGS * regs; uint8_t * buffer; - tu_fifo_t * ff; // Total length of current transfer uint16_t total_len; // Bytes transferred so far @@ -290,9 +288,11 @@ void tusb_vbus_changed(bool present) static void fill_tx_fifo(xfer_ctl_t * xfer) { int left_to_send; + uint8_t const *src; EPx_REGS *regs = xfer->regs; uint8_t const epnum = tu_edpt_number(xfer->ep_addr); + src = &xfer->buffer[xfer->transferred]; left_to_send = xfer->total_len - xfer->transferred; if (left_to_send > xfer->max_packet_size - xfer->last_packet_size) { @@ -301,51 +301,12 @@ static void fill_tx_fifo(xfer_ctl_t * xfer) // Loop checks TCOUNT all the time since this value is saturated to 31 // and can't be read just once before. - - if (xfer->ff) + while ((regs->txs & USB_USB_TXS1_REG_USB_TCOUNT_Msk) > 0 && left_to_send > 0) { - // Since TCOUNT is to be considered, we handle the FIFO reading manually here - // As we copy from a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies - // Check for first linear part - uint8_t * src; - uint16_t len = tu_fifo_get_linear_read_info(xfer->ff, 0, (void **) &src, left_to_send); // We want to read from the FIFO - uint16_t len1 = len; - while ((regs->txs & USB_USB_TXS1_REG_USB_TCOUNT_Msk) > 0 && len1 > 0) - { - regs->txd = *src++; - xfer->last_packet_size++; - len1--; - } - - tu_fifo_advance_read_pointer(xfer->ff, len-len1); - left_to_send -= (len-len1); - - // Check for wrapped part - if ((regs->txs & USB_USB_TXS1_REG_USB_TCOUNT_Msk) && left_to_send > 0) - { - len = tu_fifo_get_linear_read_info(xfer->ff, 0, (void **) &src, left_to_send); // We want to read from the FIFO - len1 = len; - while ((regs->txs & USB_USB_TXS1_REG_USB_TCOUNT_Msk) > 0 && len1 > 0) - { - regs->txd = *src++; - xfer->last_packet_size++; - len1--; - } - tu_fifo_advance_read_pointer(xfer->ff, len-len1); - left_to_send -= (len-len1); - } + regs->txd = *src++; + xfer->last_packet_size++; + left_to_send--; } - else - { - uint8_t const *src = &xfer->buffer[xfer->transferred]; - while ((regs->txs & USB_USB_TXS1_REG_USB_TCOUNT_Msk) > 0 && left_to_send > 0) - { - regs->txd = *src++; - xfer->last_packet_size++; - left_to_send--; - } - } - if (epnum != 0) { if (left_to_send > 0) @@ -402,14 +363,13 @@ static void start_rx_packet(xfer_ctl_t *xfer) xfer->last_packet_size = 0; if (xfer->max_packet_size > FIFO_SIZE && remaining > FIFO_SIZE) { - if (try_allocate_dma(epnum, TUSB_DIR_OUT) && !xfer->ff) + if (try_allocate_dma(epnum, TUSB_DIR_OUT)) { start_rx_dma(&xfer->regs->rxd, xfer->buffer + xfer->transferred, size); } else { // Other endpoint is using DMA in that direction, fall back to interrupts. - // Or if an ISO EP transfer was scheduled, currently not handled by DMA! // For endpoint size greater then FIFO size enable FIFO level warning interrupt // when FIFO has less then 17 bytes free. xfer->regs->rxc |= USB_USB_RXC1_REG_USB_RFWL_Msk; @@ -449,7 +409,7 @@ static void start_tx_packet(xfer_ctl_t *xfer) regs->txc = USB_USB_TXC1_REG_USB_IGN_ISOMSK_Msk; if (xfer->data1) xfer->regs->txc |= USB_USB_TXC1_REG_USB_TOGGLE_TX_Msk; - if (xfer->max_packet_size > FIFO_SIZE && remaining > FIFO_SIZE && try_allocate_dma(epnum, TUSB_DIR_IN) && !xfer->ff) + if (xfer->max_packet_size > FIFO_SIZE && remaining > FIFO_SIZE && try_allocate_dma(epnum, TUSB_DIR_IN)) { // Whole packet will be put in FIFO by DMA. Set LAST bit before start. start_tx_dma(xfer->buffer + xfer->transferred, ®s->txd, size); @@ -470,16 +430,9 @@ static void read_rx_fifo(xfer_ctl_t *xfer, uint16_t bytes_in_fifo) if (remaining < bytes_in_fifo) receive_this_time = remaining; - if (xfer->ff) - { - tu_fifo_write_n(xfer->ff, (const void *) ®s->rxd, receive_this_time); - } - else - { - uint8_t *buf = xfer->buffer + xfer->transferred + xfer->last_packet_size; + uint8_t *buf = xfer->buffer + xfer->transferred + xfer->last_packet_size; - for (int i = 0; i < receive_this_time; ++i) buf[i] = regs->rxd; - } + for (int i = 0; i < receive_this_time; ++i) buf[i] = regs->rxd; xfer->last_packet_size += receive_this_time; } @@ -965,7 +918,6 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t (void)rhport; xfer->buffer = buffer; - xfer->ff = NULL; xfer->total_len = total_bytes; xfer->last_packet_size = 0; xfer->transferred = 0; @@ -982,41 +934,6 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t return true; } -bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) -{ - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); - xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); - - (void)rhport; - - xfer->buffer = NULL; - xfer->ff = ff; - xfer->total_len = total_bytes; - xfer->last_packet_size = 0; - xfer->transferred = 0; - - if (dir == TUSB_DIR_IN) - { - tu_fifo_set_copy_mode_write(ff, TU_FIFO_COPY_CST); - } - else - { - tu_fifo_set_copy_mode_read(ff, TU_FIFO_COPY_CST); - } - - if (dir == TUSB_DIR_OUT) - { - start_rx_packet(xfer); - } - else // IN - { - start_tx_packet(xfer); - } - - return true; -} - void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { uint8_t const epnum = tu_edpt_number(ep_addr); From 7b8a08d2e1519afba6045e2a77898afecb1943e1 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Tue, 2 Mar 2021 20:00:39 +0100 Subject: [PATCH 054/121] Rename dcd_edpt_iso_xfer() to dcd_edpt_xfer_fifo() --- src/class/audio/audio_device.c | 2 +- src/device/dcd.h | 2 +- src/device/usbd.c | 2 +- src/portable/espressif/esp32s2/dcd_esp32s2.c | 2 +- src/portable/microchip/samg/dcd_samg.c | 2 +- src/portable/nuvoton/nuc120/dcd_nuc120.c | 4 ++-- src/portable/nuvoton/nuc121/dcd_nuc121.c | 2 +- src/portable/nuvoton/nuc505/dcd_nuc505.c | 4 ++-- src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c | 2 +- src/portable/st/synopsys/dcd_synopsys.c | 2 +- src/portable/template/dcd_template.c | 2 +- src/portable/ti/msp430x5xx/dcd_msp430x5xx.c | 2 +- 12 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 32745002c..37d6a36a7 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -34,7 +34,7 @@ * * 1. Input data -> SW-FIFO -> MCU USB * - * The most easiest version, available in case the target MCU can handle the software FIFO (SW-FIFO) and if it is implemented in the device driver (if yes then dcd_edpt_iso_xfer() is available) + * The most easiest version, available in case the target MCU can handle the software FIFO (SW-FIFO) and if it is implemented in the device driver (if yes then dcd_edpt_xfer_fifo() is available) * * 2. Input data -> SW-FIFO -> Linear buffer -> MCU USB * diff --git a/src/device/dcd.h b/src/device/dcd.h index f0a552434..89f8760d0 100644 --- a/src/device/dcd.h +++ b/src/device/dcd.h @@ -135,7 +135,7 @@ void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) TU_ATTR_WEAK; bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes); // Submit an ISO transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack -bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes); +bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes); // Stall endpoint void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr); diff --git a/src/device/usbd.c b/src/device/usbd.c index c087e2b38..1879729e8 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -1246,7 +1246,7 @@ bool usbd_edpt_iso_xfer(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_ // and usbd task can preempt and clear the busy _usbd_dev.ep_status[epnum][dir].busy = true; - if (dcd_edpt_iso_xfer(rhport, ep_addr, ff, total_bytes)) + if (dcd_edpt_xfer_fifo(rhport, ep_addr, ff, total_bytes)) { TU_LOG2("OK\r\n"); return true; diff --git a/src/portable/espressif/esp32s2/dcd_esp32s2.c b/src/portable/espressif/esp32s2/dcd_esp32s2.c index 25e54418f..ade79f107 100644 --- a/src/portable/espressif/esp32s2/dcd_esp32s2.c +++ b/src/portable/espressif/esp32s2/dcd_esp32s2.c @@ -357,7 +357,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to return true; } -bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) { (void)rhport; diff --git a/src/portable/microchip/samg/dcd_samg.c b/src/portable/microchip/samg/dcd_samg.c index 1edbba629..5866e1ce8 100644 --- a/src/portable/microchip/samg/dcd_samg.c +++ b/src/portable/microchip/samg/dcd_samg.c @@ -297,7 +297,7 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t return true; } -bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) { (void) rhport; diff --git a/src/portable/nuvoton/nuc120/dcd_nuc120.c b/src/portable/nuvoton/nuc120/dcd_nuc120.c index 9ff34e760..0e7157d4c 100644 --- a/src/portable/nuvoton/nuc120/dcd_nuc120.c +++ b/src/portable/nuvoton/nuc120/dcd_nuc120.c @@ -77,7 +77,7 @@ static bool active_ep0_xfer; static struct xfer_ctl_t { uint8_t *data_ptr; /* data_ptr tracks where to next copy data to (for OUT) or from (for IN) */ - tu_fifo_t * ff; /* pointer to FIFO required for dcd_edpt_iso_xfer() */ + tu_fifo_t * ff; /* pointer to FIFO required for dcd_edpt_xfer_fifo() */ union { uint16_t in_remaining_bytes; /* for IN endpoints, we track how many bytes are left to transfer */ uint16_t out_bytes_so_far; /* but for OUT endpoints, we track how many bytes we've transferred so far */ @@ -297,7 +297,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to return true; } -bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) { (void) rhport; diff --git a/src/portable/nuvoton/nuc121/dcd_nuc121.c b/src/portable/nuvoton/nuc121/dcd_nuc121.c index 8aa97ad10..65a41463c 100644 --- a/src/portable/nuvoton/nuc121/dcd_nuc121.c +++ b/src/portable/nuvoton/nuc121/dcd_nuc121.c @@ -303,7 +303,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to return true; } -bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) { (void) rhport; diff --git a/src/portable/nuvoton/nuc505/dcd_nuc505.c b/src/portable/nuvoton/nuc505/dcd_nuc505.c index 0a690d84d..0d82a28c0 100644 --- a/src/portable/nuvoton/nuc505/dcd_nuc505.c +++ b/src/portable/nuvoton/nuc505/dcd_nuc505.c @@ -95,7 +95,7 @@ static uint32_t bufseg_addr; static struct xfer_ctl_t { uint8_t *data_ptr; /* data_ptr tracks where to next copy data to (for OUT) or from (for IN) */ - tu_fifo_t * ff; /* pointer to FIFO required for dcd_edpt_iso_xfer() */ + tu_fifo_t * ff; /* pointer to FIFO required for dcd_edpt_xfer_fifo() */ union { uint16_t in_remaining_bytes; /* for IN endpoints, we track how many bytes are left to transfer */ uint16_t out_bytes_so_far; /* but for OUT endpoints, we track how many bytes we've transferred so far */ @@ -412,7 +412,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to return true; } -bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) { (void) rhport; diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index e2fd48d74..dbd514f86 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -867,7 +867,7 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t return true; } -bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) { (void) rhport; diff --git a/src/portable/st/synopsys/dcd_synopsys.c b/src/portable/st/synopsys/dcd_synopsys.c index 1d0bb5107..6dad05ba1 100644 --- a/src/portable/st/synopsys/dcd_synopsys.c +++ b/src/portable/st/synopsys/dcd_synopsys.c @@ -675,7 +675,7 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t // bytes should be written and second to keep the return value free to give back a boolean // success message. If total_bytes is too big, the FIFO will copy only what is available // into the USB buffer! -bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) { // USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1 TU_ASSERT(ff->item_size == 1); diff --git a/src/portable/template/dcd_template.c b/src/portable/template/dcd_template.c index 7a9a0ae22..ba656385b 100644 --- a/src/portable/template/dcd_template.c +++ b/src/portable/template/dcd_template.c @@ -106,7 +106,7 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t } // Submit a transfer where is managed by FIFO, When complete dcd_event_xfer_complete() is invoked to notify the stack -bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) { (void) rhport; (void) ep_addr; diff --git a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c index 61cbe1cf7..a8da1ae49 100644 --- a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c +++ b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c @@ -347,7 +347,7 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t return true; } -bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) { (void) rhport; From bd2bab7aff4f0e1dc34cace24c90a7755c00d369 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Tue, 2 Mar 2021 21:41:51 +0100 Subject: [PATCH 055/121] Remove set_copy_modes(), implement: tu_fifo_read_n_const_addr(), tu_fifo_write_n_const_addr() --- src/common/tusb_fifo.c | 164 ++++++++++++++++++++++++++--------------- src/common/tusb_fifo.h | 28 +------ 2 files changed, 105 insertions(+), 87 deletions(-) diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index c785a77a6..94e9d90ec 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -62,6 +62,15 @@ static void tu_fifo_unlock(tu_fifo_t *f) #endif +/** \enum tu_fifo_copy_mode_t + * \brief Write modes intended to allow special read and write functions to be able to copy data to and from USB hardware FIFOs as needed for e.g. STM32s + */ +typedef enum +{ + TU_FIFO_COPY_INC, ///< Copy from/to an increasing source/destination address - default mode + TU_FIFO_COPY_CST, ///< Copy from/to a constant source/destination address - required for e.g. STM32 to write into USB hardware FIFO +} tu_fifo_copy_mode_t; + bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable) { if (depth > 0x8000) return false; // Maximum depth is 2^15 items @@ -76,8 +85,6 @@ bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_si f->max_pointer_idx = 2*depth - 1; // Limit index space to 2*depth - this allows for a fast "modulo" calculation but limits the maximum depth to 2^16/2 = 2^15 and buffer overflows are detectable only if overflow happens once (important for unsupervised DMA applications) f->non_used_index_space = UINT16_MAX - f->max_pointer_idx; - f->rd_mode = f->wr_mode = TU_FIFO_COPY_INC; // Default copy mode is incrementing addresses - f->rd_idx = f->wr_idx = 0; tu_fifo_unlock(f); @@ -160,9 +167,9 @@ static inline void _ff_push(tu_fifo_t* f, void const * data, uint16_t wRel) memcpy(f->buffer + (wRel * f->item_size), data, f->item_size); } -static inline void _ff_push_copy_fct(tu_fifo_t* f, void * dst, const void * src, uint16_t len) +static inline void _ff_push_copy_fct(tu_fifo_t* f, void * dst, const void * src, uint16_t len, tu_fifo_copy_mode_t copy_mode) { - switch (f->rd_mode) + switch (copy_mode) { case TU_FIFO_COPY_INC: memcpy(dst, src, len); @@ -174,9 +181,9 @@ static inline void _ff_push_copy_fct(tu_fifo_t* f, void * dst, const void * src, } } -static inline void _ff_pull_copy_fct(tu_fifo_t* f, void * dst, const void * src, uint16_t len) +static inline void _ff_pull_copy_fct(tu_fifo_t* f, void * dst, const void * src, uint16_t len, tu_fifo_copy_mode_t copy_mode) { - switch (f->wr_mode) + switch (copy_mode) { case TU_FIFO_COPY_INC: memcpy(dst, src, len); @@ -189,21 +196,21 @@ static inline void _ff_pull_copy_fct(tu_fifo_t* f, void * dst, const void * src, } // send n items to FIFO WITHOUT updating write pointer -static void _ff_push_n(tu_fifo_t* f, void const * data, uint16_t n, uint16_t wRel) +static void _ff_push_n(tu_fifo_t* f, void const * data, uint16_t n, uint16_t wRel, tu_fifo_copy_mode_t copy_mode) { if(wRel + n <= f->depth) // Linear mode only { - _ff_push_copy_fct(f, f->buffer + (wRel * f->item_size), data, n*f->item_size); + _ff_push_copy_fct(f, f->buffer + (wRel * f->item_size), data, n*f->item_size, copy_mode); } else // Wrap around { uint16_t nLin = f->depth - wRel; // Write data to linear part of buffer - _ff_push_copy_fct(f, f->buffer + (wRel * f->item_size), data, nLin*f->item_size); + _ff_push_copy_fct(f, f->buffer + (wRel * f->item_size), data, nLin*f->item_size, copy_mode); // Write data wrapped around - _ff_push_copy_fct(f, f->buffer, ((uint8_t const*) data) + nLin*f->item_size, (n - nLin) * f->item_size); + _ff_push_copy_fct(f, f->buffer, ((uint8_t const*) data) + nLin*f->item_size, (n - nLin) * f->item_size, copy_mode); } } @@ -214,21 +221,21 @@ static inline void _ff_pull(tu_fifo_t* f, void * p_buffer, uint16_t rRel) } // get n items from FIFO WITHOUT updating read pointer -static void _ff_pull_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint16_t rRel) +static void _ff_pull_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint16_t rRel, tu_fifo_copy_mode_t copy_mode) { if(rRel + n <= f->depth) // Linear mode only { - _ff_pull_copy_fct(f, p_buffer, f->buffer + (rRel * f->item_size), n*f->item_size); + _ff_pull_copy_fct(f, p_buffer, f->buffer + (rRel * f->item_size), n*f->item_size, copy_mode); } else // Wrap around { uint16_t nLin = f->depth - rRel; // Read data from linear part of buffer - _ff_pull_copy_fct(f, p_buffer, f->buffer + (rRel * f->item_size), nLin*f->item_size); + _ff_pull_copy_fct(f, p_buffer, f->buffer + (rRel * f->item_size), nLin*f->item_size, copy_mode); // Read data wrapped part - _ff_pull_copy_fct(f, (uint8_t*)p_buffer + nLin*f->item_size, f->buffer, (n - nLin) * f->item_size); + _ff_pull_copy_fct(f, (uint8_t*)p_buffer + nLin*f->item_size, f->buffer, (n - nLin) * f->item_size, copy_mode); } } @@ -337,7 +344,7 @@ static bool _tu_fifo_peek_at(tu_fifo_t* f, uint16_t offset, void * p_buffer, uin // Works on local copies of w and r // Must be protected by mutexes since in case of an overflow read pointer gets modified -static uint16_t _tu_fifo_peek_at_n(tu_fifo_t* f, uint16_t offset, void * p_buffer, uint16_t n, uint16_t wAbs, uint16_t rAbs) +static uint16_t _tu_fifo_peek_at_n(tu_fifo_t* f, uint16_t offset, void * p_buffer, uint16_t n, uint16_t wAbs, uint16_t rAbs, tu_fifo_copy_mode_t copy_mode) { uint16_t cnt = _tu_fifo_count(f, wAbs, rAbs); @@ -359,7 +366,7 @@ static uint16_t _tu_fifo_peek_at_n(tu_fifo_t* f, uint16_t offset, void * p_buffe uint16_t rRel = get_relative_pointer(f, rAbs, offset); // Peek data - _ff_pull_n(f, p_buffer, n, rRel); + _ff_pull_n(f, p_buffer, n, rRel, copy_mode); return n; } @@ -370,6 +377,59 @@ static inline uint16_t _tu_fifo_remaining(tu_fifo_t* f, uint16_t wAbs, uint16_t return f->depth - _tu_fifo_count(f, wAbs, rAbs); } +static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu_fifo_copy_mode_t copy_mode) +{ + if ( n == 0 ) return 0; + + tu_fifo_lock(f); + + uint16_t w = f->wr_idx, r = f->rd_idx; + uint8_t const* buf8 = (uint8_t const*) data; + + if (!f->overwritable) + { + // Not overwritable limit up to full + n = tu_min16(n, _tu_fifo_remaining(f, w, r)); + } + else if (n >= f->depth) + { + // Only copy last part + buf8 = buf8 + (n - f->depth) * f->item_size; + n = f->depth; + + // We start writing at the read pointer's position since we fill the complete + // buffer and we do not want to modify the read pointer within a write function! + // This would end up in a race condition with read functions! + w = r; + } + + uint16_t wRel = get_relative_pointer(f, w, 0); + + // Write data + _ff_push_n(f, buf8, n, wRel, copy_mode); + + // Advance pointer + f->wr_idx = advance_pointer(f, w, n); + + tu_fifo_unlock(f); + + return n; +} + +static uint16_t _tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n, tu_fifo_copy_mode_t copy_mode) +{ + tu_fifo_lock(f); // TODO: Here we may distinguish for read and write pointer mutexes! + + // Peek the data + n = _tu_fifo_peek_at_n(f, 0, buffer, n, f->wr_idx, f->rd_idx, copy_mode); // f->rd_idx might get modified in case of an overflow so we can not use a local variable + + // Advance read pointer + f->rd_idx = advance_pointer(f, f->rd_idx, n); + + tu_fifo_unlock(f); + return n; +} + /******************************************************************************/ /*! @brief Get number of items in FIFO. @@ -526,16 +586,12 @@ bool tu_fifo_read(tu_fifo_t* f, void * buffer) /******************************************************************************/ uint16_t tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n) { - tu_fifo_lock(f); // TODO: Here we may distinguish for read and write pointer mutexes! + return _tu_fifo_read_n(f, buffer, n, TU_FIFO_COPY_INC); +} - // Peek the data - n = _tu_fifo_peek_at_n(f, 0, buffer, n, f->wr_idx, f->rd_idx); // f->rd_idx might get modified in case of an overflow so we can not use a local variable - - // Advance read pointer - f->rd_idx = advance_pointer(f, f->rd_idx, n); - - tu_fifo_unlock(f); - return n; +uint16_t tu_fifo_read_n_const_addr(tu_fifo_t* f, void * buffer, uint16_t n) +{ + return _tu_fifo_read_n(f, buffer, n, TU_FIFO_COPY_CST); } /******************************************************************************/ @@ -615,7 +671,7 @@ bool tu_fifo_peek_at(tu_fifo_t* f, uint16_t offset, void * p_buffer) uint16_t tu_fifo_peek_at_n(tu_fifo_t* f, uint16_t offset, void * p_buffer, uint16_t n) { tu_fifo_lock(f); // TODO: Here we may distinguish for read and write pointer mutexes! - bool ret = _tu_fifo_peek_at_n(f, offset, p_buffer, n, f->wr_idx, f->rd_idx); + bool ret = _tu_fifo_peek_at_n(f, offset, p_buffer, n, f->wr_idx, f->rd_idx, TU_FIFO_COPY_INC); tu_fifo_unlock(f); return ret; } @@ -693,12 +749,12 @@ uint16_t tu_fifo_peek_n_into_other_fifo (tu_fifo_t* f, tu_fifo_t* f_target, uint // Copy linear size uint16_t sz = f_target->depth - wr_rel_tgt; - _tu_fifo_peek_at_n(f, offset, &f_target->buffer[wr_rel_tgt], sz, f_wr_idx, f_rd_idx); + _tu_fifo_peek_at_n(f, offset, &f_target->buffer[wr_rel_tgt], sz, f_wr_idx, f_rd_idx, TU_FIFO_COPY_INC); if (n > sz) { // Copy remaining, now wrapped part, into target buffer - _tu_fifo_peek_at_n(f, offset + sz, f_target->buffer, n-sz, f_wr_idx, f_rd_idx); + _tu_fifo_peek_at_n(f, offset + sz, f_target->buffer, n-sz, f_wr_idx, f_rd_idx, TU_FIFO_COPY_INC); } tu_fifo_unlock(f_target); @@ -759,41 +815,27 @@ bool tu_fifo_write(tu_fifo_t* f, const void * data) /******************************************************************************/ uint16_t tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n) { - if ( n == 0 ) return 0; + return _tu_fifo_write_n(f, data, n, TU_FIFO_COPY_INC); +} - tu_fifo_lock(f); +/******************************************************************************/ +/*! + @brief This function will write n elements into the array index specified by + the write pointer and increment the write index. The source address will + not be incremented which is useful for reading from registers. - uint16_t w = f->wr_idx, r = f->rd_idx; - uint8_t const* buf8 = (uint8_t const*) data; - - if (!f->overwritable) - { - // Not overwritable limit up to full - n = tu_min16(n, _tu_fifo_remaining(f, w, r)); - } - else if (n >= f->depth) - { - // Only copy last part - buf8 = buf8 + (n - f->depth) * f->item_size; - n = f->depth; - - // We start writing at the read pointer's position since we fill the complete - // buffer and we do not want to modify the read pointer within a write function! - // This would end up in a race condition with read functions! - w = r; - } - - uint16_t wRel = get_relative_pointer(f, w, 0); - - // Write data - _ff_push_n(f, buf8, n, wRel); - - // Advance pointer - f->wr_idx = advance_pointer(f, w, n); - - tu_fifo_unlock(f); - - return n; + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] data + The pointer to data to add to the FIFO + @param[in] count + Number of element + @return Number of written elements + */ +/******************************************************************************/ +uint16_t tu_fifo_write_n_const_addr(tu_fifo_t* f, const void * data, uint16_t n) +{ + return _tu_fifo_write_n(f, data, n, TU_FIFO_COPY_CST); } /******************************************************************************/ diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h index 2cab2abf8..feacc7a12 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -56,15 +56,6 @@ extern "C" { #define tu_fifo_mutex_t osal_mutex_t #endif -/** \enum tu_fifo_copy_mode_t - * \brief Write modes intended to allow special read and write functions to be able to copy data to and from USB hardware FIFOs as needed for e.g. STM32s - */ -typedef enum -{ - TU_FIFO_COPY_INC, ///< Copy from/to an increasing source/destination address - default mode - TU_FIFO_COPY_CST, ///< Copy from/to a constant source/destination address - required for e.g. STM32 to write into USB hardware FIFO -} tu_fifo_copy_mode_t; - /** \struct tu_fifo_t * \brief Simple Circular FIFO */ @@ -81,9 +72,6 @@ typedef struct volatile uint16_t wr_idx ; ///< write pointer volatile uint16_t rd_idx ; ///< read pointer - tu_fifo_copy_mode_t wr_mode ; ///< write mode - default is TU_FIFO_COPY_INC - tu_fifo_copy_mode_t rd_mode ; ///< read mode - default is TU_FIFO_COPY_INC - #if CFG_FIFO_MUTEX tu_fifo_mutex_t mutex; #endif @@ -98,8 +86,6 @@ typedef struct .overwritable = _overwritable, \ .max_pointer_idx = 2*(_depth)-1, \ .non_used_index_space = UINT16_MAX - (2*(_depth)-1), \ - .wr_mode = TU_FIFO_COPY_INC, \ - .rd_mode = TU_FIFO_COPY_INC, \ } #define TU_FIFO_DEF(_name, _depth, _type, _overwritable) \ @@ -120,9 +106,11 @@ static inline void tu_fifo_config_mutex(tu_fifo_t *f, tu_fifo_mutex_t mutex_hdl) bool tu_fifo_write (tu_fifo_t* f, void const * p_data); uint16_t tu_fifo_write_n (tu_fifo_t* f, void const * p_data, uint16_t n); +uint16_t tu_fifo_write_n_const_addr (tu_fifo_t* f, const void * data, uint16_t n); bool tu_fifo_read (tu_fifo_t* f, void * p_buffer); uint16_t tu_fifo_read_n (tu_fifo_t* f, void * p_buffer, uint16_t n); +uint16_t tu_fifo_read_n_const_addr (tu_fifo_t* f, void * buffer, uint16_t n); uint16_t tu_fifo_read_n_into_other_fifo (tu_fifo_t* f, tu_fifo_t* f_target, uint16_t offset, uint16_t n); bool tu_fifo_peek_at (tu_fifo_t* f, uint16_t pos, void * p_buffer); @@ -160,18 +148,6 @@ static inline uint16_t tu_fifo_depth(tu_fifo_t* f) return f->depth; } -// When writing into the FIFO by fifo_write_n(), rd_mode determines how the pointer read from is modified -static inline void tu_fifo_set_copy_mode_read(tu_fifo_t* f, tu_fifo_copy_mode_t rd_mode) -{ - f->rd_mode = rd_mode; -} - -// When reading from the FIFO by fifo_read_n() or fifo_peek_n(), wr_mode determines how the pointer written to is modified -static inline void tu_fifo_set_copy_mode_write(tu_fifo_t* f, tu_fifo_copy_mode_t wr_mode) -{ - f->wr_mode = wr_mode; -} - #ifdef __cplusplus } #endif From 3cdb82c21c7425c8fb6ba88b2a85a6238edb777a Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Tue, 2 Mar 2021 21:42:24 +0100 Subject: [PATCH 056/121] Change for copy modes in dcd_synopsis.c --- src/portable/st/synopsys/dcd_synopsys.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/portable/st/synopsys/dcd_synopsys.c b/src/portable/st/synopsys/dcd_synopsys.c index 6dad05ba1..e2390fe57 100644 --- a/src/portable/st/synopsys/dcd_synopsys.c +++ b/src/portable/st/synopsys/dcd_synopsys.c @@ -688,16 +688,6 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 xfer->ff = ff; xfer->total_len = total_bytes; - // Set copy mode to constant address - required since data copied to or from the hardware USB FIFO needs to be written at a constant address - if (dir == TUSB_DIR_IN) - { - tu_fifo_set_copy_mode_write(ff, TU_FIFO_COPY_CST); - } - else - { - tu_fifo_set_copy_mode_read(ff, TU_FIFO_COPY_CST); - } - uint16_t num_packets = (total_bytes / xfer->max_size); uint8_t const short_packet_size = total_bytes % xfer->max_size; @@ -912,7 +902,7 @@ static void handle_rxflvl_ints(uint8_t rhport, USB_OTG_OUTEndpointTypeDef * out_ if (xfer->ff) { // Ring buffer - tu_fifo_write_n(xfer->ff, (const void *) rx_fifo, bcnt); + tu_fifo_write_n_const_addr(xfer->ff, (const void *) rx_fifo, bcnt); } else { @@ -1032,7 +1022,7 @@ static void handle_epin_ints(uint8_t rhport, USB_OTG_DeviceTypeDef * dev, USB_OT if (xfer->ff) { usb_fifo_t tx_fifo = FIFO_BASE(rhport, n); - tu_fifo_read_n(xfer->ff, (void *) tx_fifo, packet_size); + tu_fifo_read_n_const_addr(xfer->ff, (void *) tx_fifo, packet_size); } else { From a1b07ae14c7133a012c48346923304e5d4062ecd Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Tue, 2 Mar 2021 21:52:42 +0100 Subject: [PATCH 057/121] Change copy modes for new read/write functions in tusb_fifo.c --- src/portable/espressif/esp32s2/dcd_esp32s2.c | 14 ++------------ src/portable/microchip/samg/dcd_samg.c | 7 ++----- src/portable/nuvoton/nuc120/dcd_nuc120.c | 2 -- src/portable/nuvoton/nuc121/dcd_nuc121.c | 2 -- src/portable/nuvoton/nuc505/dcd_nuc505.c | 6 ++---- src/portable/template/dcd_template.c | 2 +- src/portable/ti/msp430x5xx/dcd_msp430x5xx.c | 2 -- 7 files changed, 7 insertions(+), 28 deletions(-) diff --git a/src/portable/espressif/esp32s2/dcd_esp32s2.c b/src/portable/espressif/esp32s2/dcd_esp32s2.c index ade79f107..eb2c05153 100644 --- a/src/portable/espressif/esp32s2/dcd_esp32s2.c +++ b/src/portable/espressif/esp32s2/dcd_esp32s2.c @@ -382,16 +382,6 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 num_packets++; } - // Set copy mode to constant address - required since data copied to or from the hardware USB FIFO needs to be written at a constant address - if (dir == TUSB_DIR_IN) - { - tu_fifo_set_copy_mode_write(ff, TU_FIFO_COPY_CST); - } - else - { - tu_fifo_set_copy_mode_read(ff, TU_FIFO_COPY_CST); - } - ESP_LOGV(TAG, "Transfer <-> EP%i, %s, pkgs: %i, bytes: %i", epnum, ((dir == TUSB_DIR_IN) ? "USB0.HOST (in)" : "HOST->DEV (out)"), num_packets, total_bytes); @@ -527,7 +517,7 @@ static void receive_packet(xfer_ctl_t *xfer, /* usb_out_endpoint_t * out_ep, */ if (xfer->ff) { // Ring buffer - tu_fifo_write_n(xfer->ff, (const void *) rx_fifo, to_recv_size); + tu_fifo_write_n_const_addr(xfer->ff, (const void *) rx_fifo, to_recv_size); } else { @@ -583,7 +573,7 @@ static void transmit_packet(xfer_ctl_t *xfer, volatile usb_in_endpoint_t *in_ep, if (xfer->ff) { - tu_fifo_read_n(xfer->ff, (void *) tx_fifo, to_xfer_size); + tu_fifo_read_n_const_addr(xfer->ff, (void *) tx_fifo, to_xfer_size); } else { diff --git a/src/portable/microchip/samg/dcd_samg.c b/src/portable/microchip/samg/dcd_samg.c index 5866e1ce8..07ab9e83f 100644 --- a/src/portable/microchip/samg/dcd_samg.c +++ b/src/portable/microchip/samg/dcd_samg.c @@ -312,14 +312,11 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 if (dir == TUSB_DIR_OUT) { - tu_fifo_set_copy_mode_read(ff, TU_FIFO_COPY_CST); - // Enable interrupt when starting OUT transfer if (epnum != 0) UDP->UDP_IER |= (1 << epnum); } else { - tu_fifo_set_copy_mode_write(ff, TU_FIFO_COPY_CST); tu_fifo_read_n(ff, (void *) &UDP->UDP_FDR[epnum], xfer_packet_len(xfer)); // TX ready for transfer @@ -440,7 +437,7 @@ void dcd_int_handler(uint8_t rhport) // write to EP fifo if (xfer->ff) { - tu_fifo_read_n(xfer->ff, (void *) &UDP->UDP_FDR[epnum], xact_len); + tu_fifo_read_n_const_addr(xfer->ff, (void *) &UDP->UDP_FDR[epnum], xact_len); } else { @@ -473,7 +470,7 @@ void dcd_int_handler(uint8_t rhport) // Read from EP fifo if (xfer->ff) { - tu_fifo_write_n(xfer->ff, (const void *) &UDP->UDP_FDR[epnum], xact_len); + tu_fifo_write_n_const_addr(xfer->ff, (const void *) &UDP->UDP_FDR[epnum], xact_len); } else { diff --git a/src/portable/nuvoton/nuc120/dcd_nuc120.c b/src/portable/nuvoton/nuc120/dcd_nuc120.c index 0e7157d4c..06ffa2965 100644 --- a/src/portable/nuvoton/nuc120/dcd_nuc120.c +++ b/src/portable/nuvoton/nuc120/dcd_nuc120.c @@ -314,12 +314,10 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 if (TUSB_DIR_IN == dir) { - tu_fifo_set_copy_mode_write(ff, TU_FIFO_COPY_INC); // For the PHY in nuc120 the source and destination pointer have to be incremented! dcd_in_xfer(xfer, ep); } else { - tu_fifo_set_copy_mode_read(ff, TU_FIFO_COPY_INC); // For the PHY in nuc120 the source and destination pointer have to be incremented! xfer->out_bytes_so_far = 0; ep->MXPLD = xfer->max_packet_size; } diff --git a/src/portable/nuvoton/nuc121/dcd_nuc121.c b/src/portable/nuvoton/nuc121/dcd_nuc121.c index 65a41463c..6d98ba08a 100644 --- a/src/portable/nuvoton/nuc121/dcd_nuc121.c +++ b/src/portable/nuvoton/nuc121/dcd_nuc121.c @@ -320,12 +320,10 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 if (TUSB_DIR_IN == dir) { - tu_fifo_set_copy_mode_write(ff, TU_FIFO_COPY_INC); // For the PHY in nuc120 the source and destination pointer have to be incremented! dcd_in_xfer(xfer, ep); } else { - tu_fifo_set_copy_mode_read(ff, TU_FIFO_COPY_INC); // For the PHY in nuc120 the source and destination pointer have to be incremented! xfer->out_bytes_so_far = 0; ep->MXPLD = xfer->max_packet_size; } diff --git a/src/portable/nuvoton/nuc505/dcd_nuc505.c b/src/portable/nuvoton/nuc505/dcd_nuc505.c index 0d82a28c0..5d15ca962 100644 --- a/src/portable/nuvoton/nuc505/dcd_nuc505.c +++ b/src/portable/nuvoton/nuc505/dcd_nuc505.c @@ -183,7 +183,7 @@ static void dcd_userEP_in_xfer(struct xfer_ctl_t *xfer, USBD_EP_T *ep) /* provided buffers are thankfully 32-bit aligned, allowing most data to be transfered as 32-bit */ if (xfer->ff) { - tu_fifo_read_n(xfer->ff, (void *) (&ep->EPDAT_BYTE), bytes_now); + tu_fifo_read_n_const_addr(xfer->ff, (void *) (&ep->EPDAT_BYTE), bytes_now); } else { @@ -431,12 +431,10 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 if (TUSB_DIR_IN == dir) { - tu_fifo_set_copy_mode_write(ff, TU_FIFO_COPY_CST); // For the PHY in nuc505 the source and destination pointer have to be constant! ep->EPINTEN = USBD_EPINTEN_BUFEMPTYIEN_Msk; } else { - tu_fifo_set_copy_mode_read(ff, TU_FIFO_COPY_CST); // For the PHY in nuc505 the source and destination pointer have to be constant! xfer->out_bytes_so_far = 0; ep->EPINTEN = USBD_EPINTEN_RXPKIEN_Msk; } @@ -659,7 +657,7 @@ void dcd_int_handler(uint8_t rhport) /* copy the data from the PC to the previously provided buffer */ if (xfer->ff) { - tu_fifo_write_n(xfer->ff, (const void *) &ep->EPDAT_BYTE, tu_min16(available_bytes, xfer->total_bytes - xfer->out_bytes_so_far)); + tu_fifo_write_n_const_addr(xfer->ff, (const void *) &ep->EPDAT_BYTE, tu_min16(available_bytes, xfer->total_bytes - xfer->out_bytes_so_far)); } else { diff --git a/src/portable/template/dcd_template.c b/src/portable/template/dcd_template.c index ba656385b..d8c8753d3 100644 --- a/src/portable/template/dcd_template.c +++ b/src/portable/template/dcd_template.c @@ -105,7 +105,7 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t return false; } -// Submit a transfer where is managed by FIFO, When complete dcd_event_xfer_complete() is invoked to notify the stack +// Submit a transfer where is managed by FIFO, When complete dcd_event_xfer_complete() is invoked to notify the stack - optional, however, must be listed in usbd.c bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) { (void) rhport; diff --git a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c index a8da1ae49..40b12eb04 100644 --- a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c +++ b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c @@ -365,12 +365,10 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 if(dir == TUSB_DIR_OUT) { - tu_fifo_set_copy_mode_read(ff, TU_FIFO_COPY_INC); // For the PHY in msp430 the source and destination pointer have to be incremented! ep_regs[BCTX] &= ~NAK; } else { - tu_fifo_set_copy_mode_write(ff, TU_FIFO_COPY_INC); // For the PHY in msp430 the source and destination pointer have to be incremented! USBIEPIFG |= (1 << epnum); } From 848e403e3744eda8091330db1e6f23f86871ffaa Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Wed, 3 Mar 2021 08:18:57 +0100 Subject: [PATCH 058/121] Fix unused parameter in _ff_push_copy_fct() and _ff_pull_copy_fct --- src/common/tusb_fifo.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 94e9d90ec..d4251abea 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -167,7 +167,7 @@ static inline void _ff_push(tu_fifo_t* f, void const * data, uint16_t wRel) memcpy(f->buffer + (wRel * f->item_size), data, f->item_size); } -static inline void _ff_push_copy_fct(tu_fifo_t* f, void * dst, const void * src, uint16_t len, tu_fifo_copy_mode_t copy_mode) +static inline void _ff_push_copy_fct(void * dst, const void * src, uint16_t len, tu_fifo_copy_mode_t copy_mode) { switch (copy_mode) { @@ -181,7 +181,7 @@ static inline void _ff_push_copy_fct(tu_fifo_t* f, void * dst, const void * src, } } -static inline void _ff_pull_copy_fct(tu_fifo_t* f, void * dst, const void * src, uint16_t len, tu_fifo_copy_mode_t copy_mode) +static inline void _ff_pull_copy_fct(void * dst, const void * src, uint16_t len, tu_fifo_copy_mode_t copy_mode) { switch (copy_mode) { @@ -200,17 +200,17 @@ static void _ff_push_n(tu_fifo_t* f, void const * data, uint16_t n, uint16_t wRe { if(wRel + n <= f->depth) // Linear mode only { - _ff_push_copy_fct(f, f->buffer + (wRel * f->item_size), data, n*f->item_size, copy_mode); + _ff_push_copy_fct(f->buffer + (wRel * f->item_size), data, n*f->item_size, copy_mode); } else // Wrap around { uint16_t nLin = f->depth - wRel; // Write data to linear part of buffer - _ff_push_copy_fct(f, f->buffer + (wRel * f->item_size), data, nLin*f->item_size, copy_mode); + _ff_push_copy_fct(f->buffer + (wRel * f->item_size), data, nLin*f->item_size, copy_mode); // Write data wrapped around - _ff_push_copy_fct(f, f->buffer, ((uint8_t const*) data) + nLin*f->item_size, (n - nLin) * f->item_size, copy_mode); + _ff_push_copy_fct(f->buffer, ((uint8_t const*) data) + nLin*f->item_size, (n - nLin) * f->item_size, copy_mode); } } @@ -225,17 +225,17 @@ static void _ff_pull_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint16_t rRel, { if(rRel + n <= f->depth) // Linear mode only { - _ff_pull_copy_fct(f, p_buffer, f->buffer + (rRel * f->item_size), n*f->item_size, copy_mode); + _ff_pull_copy_fct(p_buffer, f->buffer + (rRel * f->item_size), n*f->item_size, copy_mode); } else // Wrap around { uint16_t nLin = f->depth - rRel; // Read data from linear part of buffer - _ff_pull_copy_fct(f, p_buffer, f->buffer + (rRel * f->item_size), nLin*f->item_size, copy_mode); + _ff_pull_copy_fct(p_buffer, f->buffer + (rRel * f->item_size), nLin*f->item_size, copy_mode); // Read data wrapped part - _ff_pull_copy_fct(f, (uint8_t*)p_buffer + nLin*f->item_size, f->buffer, (n - nLin) * f->item_size, copy_mode); + _ff_pull_copy_fct((uint8_t*)p_buffer + nLin*f->item_size, f->buffer, (n - nLin) * f->item_size, copy_mode); } } From 7e56f46957452c21a5f6228d0aff2d5544c04b9f Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Thu, 4 Mar 2021 13:52:14 +0100 Subject: [PATCH 059/121] Extend FIFO mutex to use separate write and read mutexes. Adjust all USB drivers using FIFO and mutexes. --- src/class/audio/audio_device.c | 16 +++--- src/class/cdc/cdc_device.c | 4 +- src/class/midi/midi_device.c | 4 +- src/class/vendor/vendor_device.c | 4 +- src/common/tusb_fifo.c | 97 ++++++++++++++++++++------------ src/common/tusb_fifo.h | 8 ++- 6 files changed, 80 insertions(+), 53 deletions(-) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 37d6a36a7..c0d3e123c 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -133,7 +133,7 @@ typedef struct tu_fifo_t ep_out_ff; #if CFG_FIFO_MUTEX - osal_mutex_def_t ep_out_ff_mutex; + osal_mutex_def_t ep_out_ff_mutex_rd; // No need for write mutex as only USB driver writes into FIFO #endif #endif @@ -149,7 +149,7 @@ typedef struct tu_fifo_t ep_in_ff; #if CFG_FIFO_MUTEX - osal_mutex_def_t ep_in_ff_mutex; + osal_mutex_def_t ep_in_ff_mutex_wr; // No need for read mutex as only USB driver reads from FIFO #endif #endif @@ -164,7 +164,7 @@ typedef struct tu_fifo_t tx_supp_ff[CFG_TUD_AUDIO_N_CHANNELS_TX]; CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf[CFG_TUD_AUDIO_N_CHANNELS_TX][CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE]; #if CFG_FIFO_MUTEX - osal_mutex_def_t tx_supp_ff_mutex[CFG_TUD_AUDIO_N_CHANNELS_TX]; + osal_mutex_def_t tx_supp_ff_mutex_wr[CFG_TUD_AUDIO_N_CHANNELS_TX]; // No need for read mutex as only USB driver reads from FIFO #endif #endif @@ -172,7 +172,7 @@ typedef struct tu_fifo_t rx_supp_ff[CFG_TUD_AUDIO_N_CHANNELS_RX]; CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf[CFG_TUD_AUDIO_N_CHANNELS_RX][CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE]; #if CFG_FIFO_MUTEX - osal_mutex_def_t rx_supp_ff_mutex[CFG_TUD_AUDIO_N_CHANNELS_RX]; + osal_mutex_def_t rx_supp_ff_mutex_rd[CFG_TUD_AUDIO_N_CHANNELS_RX]; // No need for write mutex as only USB driver writes into FIFO #endif #endif @@ -671,7 +671,7 @@ void audiod_init(void) #if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE && !CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE tu_fifo_config(&audio->ep_in_ff, &audio->ep_in_buf, CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&audio->ep_in_ff_mutex)); + tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&audio->ep_in_ff_mutex_wr), NULL); #endif #endif @@ -679,7 +679,7 @@ void audiod_init(void) #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && !CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE tu_fifo_config(&audio->ep_out_ff, &audio->ep_out_buf, CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->ep_out_ff, osal_mutex_create(&audio->ep_out_ff_mutex)); + tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&audio->ep_out_ff_mutex_rd)); #endif #endif @@ -689,7 +689,7 @@ void audiod_init(void) { tu_fifo_config(&audio->tx_supp_ff[cnt], &audio->tx_supp_ff_buf[cnt], CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->tx_supp_ff[cnt], osal_mutex_create(&audio->tx_supp_ff_mutex[cnt])); + tu_fifo_config_mutex(&audio->tx_supp_ff[cnt], osal_mutex_create(&audio->tx_supp_ff_mutex_wr[cnt]), NULL); #endif } #endif @@ -700,7 +700,7 @@ void audiod_init(void) { tu_fifo_config(&audio->rx_supp_ff[cnt], &audio->rx_supp_ff_buf[cnt], CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->rx_supp_ff[cnt], osal_mutex_create(&audio->rx_supp_ff_mutex[cnt])); + tu_fifo_config_mutex(&audio->rx_supp_ff[cnt], NULL, osal_mutex_create(&audio->rx_supp_ff_mutex_rd[cnt])); #endif } #endif diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index 58f485a5d..c679dc71e 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -243,8 +243,8 @@ void cdcd_init(void) tu_fifo_config(&p_cdc->tx_ff, p_cdc->tx_ff_buf, TU_ARRAY_SIZE(p_cdc->tx_ff_buf), 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&p_cdc->rx_ff, osal_mutex_create(&p_cdc->rx_ff_mutex)); - tu_fifo_config_mutex(&p_cdc->tx_ff, osal_mutex_create(&p_cdc->tx_ff_mutex)); + tu_fifo_config_mutex(&p_cdc->rx_ff, NULL, osal_mutex_create(&p_cdc->rx_ff_mutex)); + tu_fifo_config_mutex(&p_cdc->tx_ff, osal_mutex_create(&p_cdc->tx_ff_mutex), NULL); #endif } } diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c index 325fc4669..c61bad17c 100644 --- a/src/class/midi/midi_device.c +++ b/src/class/midi/midi_device.c @@ -310,8 +310,8 @@ void midid_init(void) tu_fifo_config(&midi->tx_ff, midi->tx_ff_buf, CFG_TUD_MIDI_TX_BUFSIZE, 1, false); // OBVS. #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&midi->rx_ff, osal_mutex_create(&midi->rx_ff_mutex)); - tu_fifo_config_mutex(&midi->tx_ff, osal_mutex_create(&midi->tx_ff_mutex)); + tu_fifo_config_mutex(&midi->rx_ff, NULL, osal_mutex_create(&midi->rx_ff_mutex)); + tu_fifo_config_mutex(&midi->tx_ff, osal_mutex_create(&midi->tx_ff_mutex), NULL); #endif } } diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c index 3fcea89c4..9b0a3c25f 100644 --- a/src/class/vendor/vendor_device.c +++ b/src/class/vendor/vendor_device.c @@ -146,8 +146,8 @@ void vendord_init(void) tu_fifo_config(&p_itf->tx_ff, p_itf->tx_ff_buf, CFG_TUD_VENDOR_TX_BUFSIZE, 1, false); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&p_itf->rx_ff, osal_mutex_create(&p_itf->rx_ff_mutex)); - tu_fifo_config_mutex(&p_itf->tx_ff, osal_mutex_create(&p_itf->tx_ff_mutex)); + tu_fifo_config_mutex(&p_itf->rx_ff, NULL, osal_mutex_create(&p_itf->rx_ff_mutex)); + tu_fifo_config_mutex(&p_itf->tx_ff, osal_mutex_create(&p_itf->tx_ff_mutex), NULL); #endif } } diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index d4251abea..44b4a11c0 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -39,31 +39,49 @@ // implement mutex lock and unlock #if CFG_FIFO_MUTEX -static void tu_fifo_lock(tu_fifo_t *f) +static void tu_fifo_lock_wr(tu_fifo_t *f) { - if (f->mutex) + if (f->mutex_wr) { - osal_mutex_lock(f->mutex, OSAL_TIMEOUT_WAIT_FOREVER); + osal_mutex_lock(f->mutex_wr, OSAL_TIMEOUT_WAIT_FOREVER); } } -static void tu_fifo_unlock(tu_fifo_t *f) +static void tu_fifo_unlock_wr(tu_fifo_t *f) { - if (f->mutex) + if (f->mutex_wr) { - osal_mutex_unlock(f->mutex); + osal_mutex_unlock(f->mutex_wr); + } +} + +static void tu_fifo_lock_rd(tu_fifo_t *f) +{ + if (f->mutex_rd) + { + osal_mutex_lock(f->mutex_rd, OSAL_TIMEOUT_WAIT_FOREVER); + } +} + +static void tu_fifo_unlock_rd(tu_fifo_t *f) +{ + if (f->mutex_rd) + { + osal_mutex_unlock(f->mutex_rd); } } #else -#define tu_fifo_lock(_ff) -#define tu_fifo_unlock(_ff) +#define tu_fifo_lock_wr(_ff) +#define tu_fifo_unlock_wr(_ff) +#define tu_fifo_lock_rd(_ff) +#define tu_fifo_unlock_rd(_ff) #endif /** \enum tu_fifo_copy_mode_t - * \brief Write modes intended to allow special read and write functions to be able to copy data to and from USB hardware FIFOs as needed for e.g. STM32s + * \brief Write modes intended to allow special read and write functions to be able to copy data to and from USB hardware FIFOs as needed for e.g. STM32s and others */ typedef enum { @@ -75,7 +93,8 @@ bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_si { if (depth > 0x8000) return false; // Maximum depth is 2^15 items - tu_fifo_lock(f); + tu_fifo_lock_wr(f); + tu_fifo_lock_rd(f); f->buffer = (uint8_t*) buffer; f->depth = depth; @@ -87,7 +106,8 @@ bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_si f->rd_idx = f->wr_idx = 0; - tu_fifo_unlock(f); + tu_fifo_unlock_wr(f); + tu_fifo_lock_rd(f); return true; } @@ -381,7 +401,7 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu { if ( n == 0 ) return 0; - tu_fifo_lock(f); + tu_fifo_lock_wr(f); uint16_t w = f->wr_idx, r = f->rd_idx; uint8_t const* buf8 = (uint8_t const*) data; @@ -411,14 +431,14 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu // Advance pointer f->wr_idx = advance_pointer(f, w, n); - tu_fifo_unlock(f); + tu_fifo_unlock_wr(f); return n; } static uint16_t _tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n, tu_fifo_copy_mode_t copy_mode) { - tu_fifo_lock(f); // TODO: Here we may distinguish for read and write pointer mutexes! + tu_fifo_lock_rd(f); // TODO: Here we may distinguish for read and write pointer mutexes! // Peek the data n = _tu_fifo_peek_at_n(f, 0, buffer, n, f->wr_idx, f->rd_idx, copy_mode); // f->rd_idx might get modified in case of an overflow so we can not use a local variable @@ -426,7 +446,7 @@ static uint16_t _tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n, tu_fifo // Advance read pointer f->rd_idx = advance_pointer(f, f->rd_idx, n); - tu_fifo_unlock(f); + tu_fifo_unlock_rd(f); return n; } @@ -533,9 +553,9 @@ bool tu_fifo_overflowed(tu_fifo_t* f) // Only use in case tu_fifo_overflow() returned true! void tu_fifo_correct_read_pointer(tu_fifo_t* f) { - tu_fifo_lock(f); + tu_fifo_lock_rd(f); _tu_fifo_correct_read_pointer(f, f->wr_idx); - tu_fifo_unlock(f); + tu_fifo_unlock_rd(f); } /******************************************************************************/ @@ -556,7 +576,7 @@ void tu_fifo_correct_read_pointer(tu_fifo_t* f) /******************************************************************************/ bool tu_fifo_read(tu_fifo_t* f, void * buffer) { - tu_fifo_lock(f); // TODO: Here we may distinguish for read and write pointer mutexes! + tu_fifo_lock_rd(f); // TODO: Here we may distinguish for read and write pointer mutexes! // Peek the data bool ret = _tu_fifo_peek_at(f, 0, buffer, f->wr_idx, f->rd_idx); // f->rd_idx might get modified in case of an overflow so we can not use a local variable @@ -564,7 +584,7 @@ bool tu_fifo_read(tu_fifo_t* f, void * buffer) // Advance pointer f->rd_idx = advance_pointer(f, f->rd_idx, ret); - tu_fifo_unlock(f); + tu_fifo_unlock_rd(f); return ret; } @@ -615,7 +635,8 @@ uint16_t tu_fifo_read_n_const_addr(tu_fifo_t* f, void * buffer, uint16_t n) /******************************************************************************/ uint16_t tu_fifo_read_n_into_other_fifo(tu_fifo_t* f, tu_fifo_t* f_target, uint16_t offset, uint16_t n) { - tu_fifo_lock(f); // TODO: Here we may distinguish for read and write pointer mutexes! + tu_fifo_lock_rd(f); + tu_fifo_lock_wr(f_target); // Conduct copy n = tu_fifo_peek_n_into_other_fifo(f, f_target, offset, n); @@ -623,7 +644,8 @@ uint16_t tu_fifo_read_n_into_other_fifo(tu_fifo_t* f, tu_fifo_t* f_target, uint1 // Advance read pointer f->rd_idx = advance_pointer(f, f->rd_idx, n); - tu_fifo_unlock(f); + tu_fifo_unlock_rd(f); + tu_fifo_unlock_wr(f_target); return n; } @@ -645,9 +667,9 @@ uint16_t tu_fifo_read_n_into_other_fifo(tu_fifo_t* f, tu_fifo_t* f_target, uint1 /******************************************************************************/ bool tu_fifo_peek_at(tu_fifo_t* f, uint16_t offset, void * p_buffer) { - tu_fifo_lock(f); // TODO: Here we may distinguish for read and write pointer mutexes! + tu_fifo_lock_rd(f); bool ret = _tu_fifo_peek_at(f, offset, p_buffer, f->wr_idx, f->rd_idx); - tu_fifo_unlock(f); + tu_fifo_unlock_rd(f); return ret; } @@ -670,9 +692,9 @@ bool tu_fifo_peek_at(tu_fifo_t* f, uint16_t offset, void * p_buffer) /******************************************************************************/ uint16_t tu_fifo_peek_at_n(tu_fifo_t* f, uint16_t offset, void * p_buffer, uint16_t n) { - tu_fifo_lock(f); // TODO: Here we may distinguish for read and write pointer mutexes! + tu_fifo_lock_rd(f); bool ret = _tu_fifo_peek_at_n(f, offset, p_buffer, n, f->wr_idx, f->rd_idx, TU_FIFO_COPY_INC); - tu_fifo_unlock(f); + tu_fifo_unlock_rd(f); return ret; } @@ -719,7 +741,7 @@ uint16_t tu_fifo_peek_n_into_other_fifo (tu_fifo_t* f, tu_fifo_t* f_target, uint cnt -= offset; if (cnt < n) n = cnt; - tu_fifo_lock(f_target); // Lock both read and write pointers - in case of an overwritable FIFO both may be modified + tu_fifo_lock_wr(f_target); // Lock both read and write pointers - in case of an overwritable FIFO both may be modified uint16_t wr_rel_tgt = get_relative_pointer(f_target, f_target->wr_idx, 0); @@ -757,7 +779,7 @@ uint16_t tu_fifo_peek_n_into_other_fifo (tu_fifo_t* f, tu_fifo_t* f_target, uint _tu_fifo_peek_at_n(f, offset + sz, f_target->buffer, n-sz, f_wr_idx, f_rd_idx, TU_FIFO_COPY_INC); } - tu_fifo_unlock(f_target); + tu_fifo_unlock_wr(f_target); return n; } @@ -780,7 +802,7 @@ uint16_t tu_fifo_peek_n_into_other_fifo (tu_fifo_t* f, tu_fifo_t* f_target, uint /******************************************************************************/ bool tu_fifo_write(tu_fifo_t* f, const void * data) { - tu_fifo_lock(f); + tu_fifo_lock_wr(f); uint16_t w = f->wr_idx; @@ -794,7 +816,7 @@ bool tu_fifo_write(tu_fifo_t* f, const void * data) // Advance pointer f->wr_idx = advance_pointer(f, w, 1); - tu_fifo_unlock(f); + tu_fifo_unlock_wr(f); return true; } @@ -848,12 +870,13 @@ uint16_t tu_fifo_write_n_const_addr(tu_fifo_t* f, const void * data, uint16_t n) /******************************************************************************/ bool tu_fifo_clear(tu_fifo_t *f) { - tu_fifo_lock(f); + tu_fifo_lock_wr(f); + tu_fifo_lock_rd(f); f->rd_idx = f->wr_idx = 0; f->max_pointer_idx = 2*f->depth-1; f->non_used_index_space = UINT16_MAX - f->max_pointer_idx; - tu_fifo_unlock(f); - + tu_fifo_unlock_wr(f); + tu_fifo_unlock_rd(f); return true; } @@ -869,11 +892,13 @@ bool tu_fifo_clear(tu_fifo_t *f) /******************************************************************************/ bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) { - tu_fifo_lock(f); + tu_fifo_lock_wr(f); + tu_fifo_lock_rd(f); f->overwritable = overwritable; - tu_fifo_unlock(f); + tu_fifo_unlock_wr(f); + tu_fifo_unlock_rd(f); return true; } @@ -996,9 +1021,9 @@ uint16_t tu_fifo_get_linear_read_info(tu_fifo_t *f, uint16_t offset, void **ptr, // Check overflow and correct if required if (cnt > f->depth) { - tu_fifo_lock(f); + tu_fifo_lock_rd(f); _tu_fifo_correct_read_pointer(f, w); - tu_fifo_unlock(f); + tu_fifo_unlock_rd(f); r = f->rd_idx; cnt = f->depth; } diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h index feacc7a12..6e0ecdc82 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -73,7 +73,8 @@ typedef struct volatile uint16_t rd_idx ; ///< read pointer #if CFG_FIFO_MUTEX - tu_fifo_mutex_t mutex; + tu_fifo_mutex_t mutex_wr; + tu_fifo_mutex_t mutex_rd; #endif } tu_fifo_t; @@ -98,9 +99,10 @@ bool tu_fifo_clear(tu_fifo_t *f); bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable); #if CFG_FIFO_MUTEX -static inline void tu_fifo_config_mutex(tu_fifo_t *f, tu_fifo_mutex_t mutex_hdl) +static inline void tu_fifo_config_mutex(tu_fifo_t *f, tu_fifo_mutex_t write_mutex_hdl, tu_fifo_mutex_t read_mutex_hdl) { - f->mutex = mutex_hdl; + f->mutex_wr = write_mutex_hdl; + f->mutex_rd = read_mutex_hdl; } #endif From 2e28861cf83dd735485b1f27552716da5d4043e8 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Thu, 4 Mar 2021 18:20:22 +0100 Subject: [PATCH 060/121] Remove TODOs done. --- src/common/tusb_fifo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 44b4a11c0..1b1e9ca3b 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -438,7 +438,7 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu static uint16_t _tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n, tu_fifo_copy_mode_t copy_mode) { - tu_fifo_lock_rd(f); // TODO: Here we may distinguish for read and write pointer mutexes! + tu_fifo_lock_rd(f); // Peek the data n = _tu_fifo_peek_at_n(f, 0, buffer, n, f->wr_idx, f->rd_idx, copy_mode); // f->rd_idx might get modified in case of an overflow so we can not use a local variable @@ -576,7 +576,7 @@ void tu_fifo_correct_read_pointer(tu_fifo_t* f) /******************************************************************************/ bool tu_fifo_read(tu_fifo_t* f, void * buffer) { - tu_fifo_lock_rd(f); // TODO: Here we may distinguish for read and write pointer mutexes! + tu_fifo_lock_rd(f); // Peek the data bool ret = _tu_fifo_peek_at(f, 0, buffer, f->wr_idx, f->rd_idx); // f->rd_idx might get modified in case of an overflow so we can not use a local variable From de1f36f2b02b00d8012748be304186e1eb78c728 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Thu, 4 Mar 2021 19:52:48 +0100 Subject: [PATCH 061/121] Adapt mutexes in fifo.c --- src/common/tusb_fifo.c | 102 +++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 60 deletions(-) diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 1b1e9ca3b..6a31b6373 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -39,44 +39,26 @@ // implement mutex lock and unlock #if CFG_FIFO_MUTEX -static void tu_fifo_lock_wr(tu_fifo_t *f) +static void tu_fifo_lock(tu_fifo_mutex_t mutex) { - if (f->mutex_wr) + if (mutex) { - osal_mutex_lock(f->mutex_wr, OSAL_TIMEOUT_WAIT_FOREVER); + osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER); } } -static void tu_fifo_unlock_wr(tu_fifo_t *f) +static void tu_fifo_unlock(tu_fifo_mutex_t mutex) { - if (f->mutex_wr) + if (mutex) { - osal_mutex_unlock(f->mutex_wr); - } -} - -static void tu_fifo_lock_rd(tu_fifo_t *f) -{ - if (f->mutex_rd) - { - osal_mutex_lock(f->mutex_rd, OSAL_TIMEOUT_WAIT_FOREVER); - } -} - -static void tu_fifo_unlock_rd(tu_fifo_t *f) -{ - if (f->mutex_rd) - { - osal_mutex_unlock(f->mutex_rd); + osal_mutex_unlock(mutex); } } #else -#define tu_fifo_lock_wr(_ff) -#define tu_fifo_unlock_wr(_ff) -#define tu_fifo_lock_rd(_ff) -#define tu_fifo_unlock_rd(_ff) +#define tu_fifo_lock(_mutex) +#define tu_fifo_unlock(_mutex) #endif @@ -93,8 +75,8 @@ bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_si { if (depth > 0x8000) return false; // Maximum depth is 2^15 items - tu_fifo_lock_wr(f); - tu_fifo_lock_rd(f); + tu_fifo_lock(f->mutex_wr); + tu_fifo_lock(f->mutex_rd); f->buffer = (uint8_t*) buffer; f->depth = depth; @@ -106,8 +88,8 @@ bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_si f->rd_idx = f->wr_idx = 0; - tu_fifo_unlock_wr(f); - tu_fifo_lock_rd(f); + tu_fifo_unlock(f->mutex_wr); + tu_fifo_lock(f->mutex_rd); return true; } @@ -401,7 +383,7 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu { if ( n == 0 ) return 0; - tu_fifo_lock_wr(f); + tu_fifo_lock(f->mutex_wr); uint16_t w = f->wr_idx, r = f->rd_idx; uint8_t const* buf8 = (uint8_t const*) data; @@ -431,14 +413,14 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu // Advance pointer f->wr_idx = advance_pointer(f, w, n); - tu_fifo_unlock_wr(f); + tu_fifo_unlock(f->mutex_wr); return n; } static uint16_t _tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n, tu_fifo_copy_mode_t copy_mode) { - tu_fifo_lock_rd(f); + tu_fifo_lock(f->mutex_rd); // Peek the data n = _tu_fifo_peek_at_n(f, 0, buffer, n, f->wr_idx, f->rd_idx, copy_mode); // f->rd_idx might get modified in case of an overflow so we can not use a local variable @@ -446,7 +428,7 @@ static uint16_t _tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n, tu_fifo // Advance read pointer f->rd_idx = advance_pointer(f, f->rd_idx, n); - tu_fifo_unlock_rd(f); + tu_fifo_unlock(f->mutex_rd); return n; } @@ -553,9 +535,9 @@ bool tu_fifo_overflowed(tu_fifo_t* f) // Only use in case tu_fifo_overflow() returned true! void tu_fifo_correct_read_pointer(tu_fifo_t* f) { - tu_fifo_lock_rd(f); + tu_fifo_lock(f->mutex_rd); _tu_fifo_correct_read_pointer(f, f->wr_idx); - tu_fifo_unlock_rd(f); + tu_fifo_unlock(f->mutex_rd); } /******************************************************************************/ @@ -576,7 +558,7 @@ void tu_fifo_correct_read_pointer(tu_fifo_t* f) /******************************************************************************/ bool tu_fifo_read(tu_fifo_t* f, void * buffer) { - tu_fifo_lock_rd(f); + tu_fifo_lock(f->mutex_rd); // Peek the data bool ret = _tu_fifo_peek_at(f, 0, buffer, f->wr_idx, f->rd_idx); // f->rd_idx might get modified in case of an overflow so we can not use a local variable @@ -584,7 +566,7 @@ bool tu_fifo_read(tu_fifo_t* f, void * buffer) // Advance pointer f->rd_idx = advance_pointer(f, f->rd_idx, ret); - tu_fifo_unlock_rd(f); + tu_fifo_unlock(f->mutex_rd); return ret; } @@ -635,8 +617,8 @@ uint16_t tu_fifo_read_n_const_addr(tu_fifo_t* f, void * buffer, uint16_t n) /******************************************************************************/ uint16_t tu_fifo_read_n_into_other_fifo(tu_fifo_t* f, tu_fifo_t* f_target, uint16_t offset, uint16_t n) { - tu_fifo_lock_rd(f); - tu_fifo_lock_wr(f_target); + tu_fifo_lock(f->mutex_rd); + tu_fifo_lock(f_target->mutex_wr); // Conduct copy n = tu_fifo_peek_n_into_other_fifo(f, f_target, offset, n); @@ -644,8 +626,8 @@ uint16_t tu_fifo_read_n_into_other_fifo(tu_fifo_t* f, tu_fifo_t* f_target, uint1 // Advance read pointer f->rd_idx = advance_pointer(f, f->rd_idx, n); - tu_fifo_unlock_rd(f); - tu_fifo_unlock_wr(f_target); + tu_fifo_unlock(f->mutex_rd); + tu_fifo_unlock(f_target->mutex_wr); return n; } @@ -667,9 +649,9 @@ uint16_t tu_fifo_read_n_into_other_fifo(tu_fifo_t* f, tu_fifo_t* f_target, uint1 /******************************************************************************/ bool tu_fifo_peek_at(tu_fifo_t* f, uint16_t offset, void * p_buffer) { - tu_fifo_lock_rd(f); + tu_fifo_lock(f->mutex_rd); bool ret = _tu_fifo_peek_at(f, offset, p_buffer, f->wr_idx, f->rd_idx); - tu_fifo_unlock_rd(f); + tu_fifo_unlock(f->mutex_rd); return ret; } @@ -692,9 +674,9 @@ bool tu_fifo_peek_at(tu_fifo_t* f, uint16_t offset, void * p_buffer) /******************************************************************************/ uint16_t tu_fifo_peek_at_n(tu_fifo_t* f, uint16_t offset, void * p_buffer, uint16_t n) { - tu_fifo_lock_rd(f); + tu_fifo_lock(f->mutex_rd); bool ret = _tu_fifo_peek_at_n(f, offset, p_buffer, n, f->wr_idx, f->rd_idx, TU_FIFO_COPY_INC); - tu_fifo_unlock_rd(f); + tu_fifo_unlock(f->mutex_rd); return ret; } @@ -741,7 +723,7 @@ uint16_t tu_fifo_peek_n_into_other_fifo (tu_fifo_t* f, tu_fifo_t* f_target, uint cnt -= offset; if (cnt < n) n = cnt; - tu_fifo_lock_wr(f_target); // Lock both read and write pointers - in case of an overwritable FIFO both may be modified + tu_fifo_lock(f_target->mutex_wr); // Lock both read and write pointers - in case of an overwritable FIFO both may be modified uint16_t wr_rel_tgt = get_relative_pointer(f_target, f_target->wr_idx, 0); @@ -779,7 +761,7 @@ uint16_t tu_fifo_peek_n_into_other_fifo (tu_fifo_t* f, tu_fifo_t* f_target, uint _tu_fifo_peek_at_n(f, offset + sz, f_target->buffer, n-sz, f_wr_idx, f_rd_idx, TU_FIFO_COPY_INC); } - tu_fifo_unlock_wr(f_target); + tu_fifo_unlock(f_target->mutex_wr); return n; } @@ -802,7 +784,7 @@ uint16_t tu_fifo_peek_n_into_other_fifo (tu_fifo_t* f, tu_fifo_t* f_target, uint /******************************************************************************/ bool tu_fifo_write(tu_fifo_t* f, const void * data) { - tu_fifo_lock_wr(f); + tu_fifo_lock(f->mutex_wr); uint16_t w = f->wr_idx; @@ -816,7 +798,7 @@ bool tu_fifo_write(tu_fifo_t* f, const void * data) // Advance pointer f->wr_idx = advance_pointer(f, w, 1); - tu_fifo_unlock_wr(f); + tu_fifo_unlock(f->mutex_wr); return true; } @@ -870,13 +852,13 @@ uint16_t tu_fifo_write_n_const_addr(tu_fifo_t* f, const void * data, uint16_t n) /******************************************************************************/ bool tu_fifo_clear(tu_fifo_t *f) { - tu_fifo_lock_wr(f); - tu_fifo_lock_rd(f); + tu_fifo_lock(f->mutex_wr); + tu_fifo_lock(f->mutex_rd); f->rd_idx = f->wr_idx = 0; f->max_pointer_idx = 2*f->depth-1; f->non_used_index_space = UINT16_MAX - f->max_pointer_idx; - tu_fifo_unlock_wr(f); - tu_fifo_unlock_rd(f); + tu_fifo_unlock(f->mutex_wr); + tu_fifo_unlock(f->mutex_rd); return true; } @@ -892,13 +874,13 @@ bool tu_fifo_clear(tu_fifo_t *f) /******************************************************************************/ bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) { - tu_fifo_lock_wr(f); - tu_fifo_lock_rd(f); + tu_fifo_lock(f->mutex_wr); + tu_fifo_lock(f->mutex_rd); f->overwritable = overwritable; - tu_fifo_unlock_wr(f); - tu_fifo_unlock_rd(f); + tu_fifo_unlock(f->mutex_wr); + tu_fifo_unlock(f->mutex_rd); return true; } @@ -1021,9 +1003,9 @@ uint16_t tu_fifo_get_linear_read_info(tu_fifo_t *f, uint16_t offset, void **ptr, // Check overflow and correct if required if (cnt > f->depth) { - tu_fifo_lock_rd(f); + tu_fifo_lock(f->mutex_rd); _tu_fifo_correct_read_pointer(f, w); - tu_fifo_unlock_rd(f); + tu_fifo_unlock(f->mutex_rd); r = f->rd_idx; cnt = f->depth; } From e864bda6272485a33398ebf0f139607bf244f237 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 10 Mar 2021 17:21:59 +0700 Subject: [PATCH 062/121] fix build with freertos --- src/common/tusb_fifo.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h index 6e0ecdc82..0276c8044 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -53,6 +53,7 @@ extern "C" { #endif #if CFG_FIFO_MUTEX +#include "osal/osal.h" #define tu_fifo_mutex_t osal_mutex_t #endif From a397353916db36d925f5aec654fc66d5ca09f427 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 10 Mar 2021 17:58:39 +0700 Subject: [PATCH 063/121] fix ci build with rp2040 --- src/common/tusb_fifo.h | 2 +- src/device/dcd.h | 5 +++-- src/osal/osal_pico.h | 4 ++-- src/portable/raspberrypi/rp2040/dcd_rp2040.c | 3 ++- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h index 0276c8044..62ee942d2 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -109,7 +109,7 @@ static inline void tu_fifo_config_mutex(tu_fifo_t *f, tu_fifo_mutex_t write_mute bool tu_fifo_write (tu_fifo_t* f, void const * p_data); uint16_t tu_fifo_write_n (tu_fifo_t* f, void const * p_data, uint16_t n); -uint16_t tu_fifo_write_n_const_addr (tu_fifo_t* f, const void * data, uint16_t n); +uint16_t tu_fifo_write_n_const_addr (tu_fifo_t* f, const void * data, uint16_t n); bool tu_fifo_read (tu_fifo_t* f, void * p_buffer); uint16_t tu_fifo_read_n (tu_fifo_t* f, void * p_buffer, uint16_t n); diff --git a/src/device/dcd.h b/src/device/dcd.h index 89f8760d0..1e5b3ff1e 100644 --- a/src/device/dcd.h +++ b/src/device/dcd.h @@ -134,8 +134,9 @@ void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) TU_ATTR_WEAK; // Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes); -// Submit an ISO transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack -bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes); +// Submit an transfer using fifo, When complete dcd_event_xfer_complete() is invoked to notify the stack +// This API is optional, may be useful for register-based for transferring data. +bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) TU_ATTR_WEAK; // Stall endpoint void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr); diff --git a/src/osal/osal_pico.h b/src/osal/osal_pico.h index c277af271..bae1217eb 100644 --- a/src/osal/osal_pico.h +++ b/src/osal/osal_pico.h @@ -143,7 +143,7 @@ static inline bool osal_queue_receive(osal_queue_t qhdl, void* data) // TODO: revisit... docs say that mutexes are never used from IRQ context, // however osal_queue_recieve may be. therefore my assumption is that // the fifo mutex is not populated for queues used from an IRQ context - assert(!qhdl->ff.mutex); + //assert(!qhdl->ff.mutex); _osal_q_lock(qhdl); bool success = tu_fifo_read(&qhdl->ff, data); @@ -157,7 +157,7 @@ static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in // TODO: revisit... docs say that mutexes are never used from IRQ context, // however osal_queue_recieve may be. therefore my assumption is that // the fifo mutex is not populated for queues used from an IRQ context - assert(!qhdl->ff.mutex); + //assert(!qhdl->ff.mutex); _osal_q_lock(qhdl); bool success = tu_fifo_write(&qhdl->ff, data); diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c index f844a0c65..7731078b5 100644 --- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c @@ -35,7 +35,8 @@ #include "pico/fix/rp2040_usb_device_enumeration.h" #endif - +#include "osal/osal.h" +#include "common/tusb_fifo.h" #include "device/dcd.h" /*------------------------------------------------------------------*/ From d5a5a1cab63e8e43b22f13db95df35afdfa6befb Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Wed, 10 Mar 2021 19:32:13 +0100 Subject: [PATCH 064/121] Implement audio PCM type I enc./decoding acc. to 2.3.1.5 Audio Streams Extending capabilities of support FIFOs Removing copy from to FIFO Adjusting audio examples Remove peek/read into other FIFO --- examples/device/audio_test/src/main.c | 6 +- examples/device/audio_test/src/tusb_config.h | 9 +- .../device/uac2_headset/src/tusb_config.h | 1 - src/class/audio/audio_device.c | 185 +++++++++++------- src/class/audio/audio_device.h | 70 +++---- src/common/tusb_fifo.c | 155 ++------------- src/common/tusb_fifo.h | 2 - 7 files changed, 167 insertions(+), 261 deletions(-) diff --git a/examples/device/audio_test/src/main.c b/examples/device/audio_test/src/main.c index c63e64934..c2406bd23 100644 --- a/examples/device/audio_test/src/main.c +++ b/examples/device/audio_test/src/main.c @@ -73,12 +73,12 @@ int main(void) tusb_init(); // Init values - sampFreq = 48000; + sampFreq = AUDIO_SAMPLE_RATE; clkValid = 1; sampleFreqRng.wNumSubRanges = 1; - sampleFreqRng.subrange[0].bMin = 48000; - sampleFreqRng.subrange[0].bMax = 48000; + sampleFreqRng.subrange[0].bMin = AUDIO_SAMPLE_RATE; + sampleFreqRng.subrange[0].bMax = AUDIO_SAMPLE_RATE; sampleFreqRng.subrange[0].bRes = 0; while (1) diff --git a/examples/device/audio_test/src/tusb_config.h b/examples/device/audio_test/src/tusb_config.h index c6d786398..6ee5d937c 100644 --- a/examples/device/audio_test/src/tusb_config.h +++ b/examples/device/audio_test/src/tusb_config.h @@ -91,9 +91,12 @@ extern "C" { // AUDIO CLASS DRIVER CONFIGURATION //-------------------------------------------------------------------- +#ifndef AUDIO_SAMPLE_RATE +#define AUDIO_SAMPLE_RATE 48000 +#endif + // Audio format type #define CFG_TUD_AUDIO_FORMAT_TYPE_TX AUDIO_FORMAT_TYPE_I -#define CFG_TUD_AUDIO_FORMAT_TYPE_RX AUDIO_FORMAT_TYPE_UNDEFINED // Audio format type I specifications #define CFG_TUD_AUDIO_FORMAT_TYPE_I_TX AUDIO_DATA_FORMAT_TYPE_I_PCM @@ -101,8 +104,8 @@ extern "C" { #define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX 2 // EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense) -#define CFG_TUD_AUDIO_EPSIZE_IN 48*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX*CFG_TUD_AUDIO_N_CHANNELS_TX // 48 Samples (48 kHz) x 2 Bytes/Sample x 1 Channels -#define CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE CFG_TUD_AUDIO_EPSIZE_IN + 1 // Just for safety one sample more space +#define CFG_TUD_AUDIO_EPSIZE_IN 48 * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_N_CHANNELS_TX // ceil(f_s/1000) * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_N_CHANNELS_TX +#define CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE CFG_TUD_AUDIO_EPSIZE_IN + CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_N_CHANNELS_TX // Just for safety one sample more space // Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes) #define CFG_TUD_AUDIO_N_AS_INT 1 diff --git a/examples/device/uac2_headset/src/tusb_config.h b/examples/device/uac2_headset/src/tusb_config.h index 2ad76b7dc..45acf0093 100644 --- a/examples/device/uac2_headset/src/tusb_config.h +++ b/examples/device/uac2_headset/src/tusb_config.h @@ -110,7 +110,6 @@ extern "C" { #define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX 2 #define CFG_TUD_AUDIO_N_CHANNELS_RX 2 #define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX 2 -#define CFG_TUD_AUDIO_RX_ITEMSIZE 2 #define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 0 // EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index c0d3e123c..00d95ede5 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -161,18 +161,18 @@ typedef struct // Support FIFOs #if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE - tu_fifo_t tx_supp_ff[CFG_TUD_AUDIO_N_CHANNELS_TX]; - CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf[CFG_TUD_AUDIO_N_CHANNELS_TX][CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE]; + tu_fifo_t tx_supp_ff[CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO]; + CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf[CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO][CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX]; #if CFG_FIFO_MUTEX - osal_mutex_def_t tx_supp_ff_mutex_wr[CFG_TUD_AUDIO_N_CHANNELS_TX]; // No need for read mutex as only USB driver reads from FIFO + osal_mutex_def_t tx_supp_ff_mutex_wr[CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO #endif #endif #if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE - tu_fifo_t rx_supp_ff[CFG_TUD_AUDIO_N_CHANNELS_RX]; - CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf[CFG_TUD_AUDIO_N_CHANNELS_RX][CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE]; + tu_fifo_t rx_supp_ff[CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO]; + CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf[CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO][CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX]; #if CFG_FIFO_MUTEX - osal_mutex_def_t rx_supp_ff_mutex_rd[CFG_TUD_AUDIO_N_CHANNELS_RX]; // No need for write mutex as only USB driver writes into FIFO + osal_mutex_def_t rx_supp_ff_mutex_rd[CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO #endif #endif @@ -284,19 +284,19 @@ bool tud_audio_n_clear_ep_out_ff(uint8_t itf) // Delete all content in the support RX FIFOs bool tud_audio_n_clear_rx_support_ff(uint8_t itf, uint8_t channelId) { - TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_RX); + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO); return tu_fifo_clear(&_audiod_itf[itf].rx_supp_ff[channelId]); } uint16_t tud_audio_n_available_support_ff(uint8_t itf, uint8_t channelId) { - TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_RX); + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO); return tu_fifo_count(&_audiod_itf[itf].rx_supp_ff[channelId]); } uint16_t tud_audio_n_read_support_ff(uint8_t itf, uint8_t channelId, void* buffer, uint16_t bufsize) { - TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_RX); + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO); return tu_fifo_read_n(&_audiod_itf[itf].rx_supp_ff[channelId], buffer, bufsize); } #endif @@ -382,35 +382,55 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint16_ // The following functions are used in case CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE != 0 #if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_OUT + +// Decoding according to 2.3.1.5 Audio Streams static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio, uint16_t n_bytes_received) { (void) rhport; - // We assume there is always the correct number of samples available for decoding - extra checks make no sense here + // Determine amount of samples + uint16_t const nChannelsPerFF = CFG_TUD_AUDIO_N_CHANNELS_RX / CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO; + uint16_t const nBytesToCopy = nChannelsPerFF*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX; + uint16_t const nSamplesPerFFToRead = n_bytes_received / CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX / CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO; + uint8_t cnt_ff; - uint16_t cnt = CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX; - uint16_t idxSample = 0; + // Decode + void * dst; + uint8_t * src; + uint8_t * dst_end; + uint16_t len; - while (cnt <= n_bytes_received) + for (cnt_ff = 0; cnt_ff < CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO; cnt_ff++) { - for (uint8_t cntChannel = 0; cntChannel < CFG_TUD_AUDIO_N_CHANNELS_RX; cntChannel++) - { - // If 8, 16, or 32 bit values are to be copied -#if CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX == CFG_TUD_AUDIO_RX_ITEMSIZE - // If this aborts then the target buffer is full - TU_VERIFY(tu_fifo_write_n(&audio->rx_supp_ff[cntChannel], &audio->lin_buf_out[idxSample], CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX)); -#else - uint32_t sample = audio->lin_buf_out[idxSample]; -#if CFG_TUD_AUDIO_JUSTIFICATION_RX == CFG_TUD_AUDIO_LEFT_JUSTIFIED - sample = sample << 8; -#endif + src = &audio->lin_buf_out[cnt_ff*nChannelsPerFF*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX]; - TU_VERIFY(tu_fifo_write_n(&audio->rx_supp_ff[cntChannel], &sample, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX)); -#endif - idxSample += CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX; + len = tu_fifo_get_linear_write_info(&audio->rx_supp_ff[cnt_ff], 0, &dst, nSamplesPerFFToRead); + tu_fifo_advance_write_pointer(&audio->rx_supp_ff[cnt_ff], len); + + dst_end = dst + len * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX; + + while((uint8_t *)dst < dst_end) + { + memcpy(dst, src, nBytesToCopy); + dst = (uint8_t *)dst + nBytesToCopy; + src += nBytesToCopy * CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO; } - cnt += CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX; + // Handle wrapped part of FIFO + if (len < nSamplesPerFFToRead) + { + len = tu_fifo_get_linear_write_info(&audio->rx_supp_ff[cnt_ff], 0, &dst, nSamplesPerFFToRead - len); + tu_fifo_advance_write_pointer(&audio->rx_supp_ff[cnt_ff], len); + + dst_end = dst + len * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX; + + while((uint8_t *)dst < dst_end) + { + memcpy(dst, src, nBytesToCopy); + dst = (uint8_t *)dst + nBytesToCopy; + src += nBytesToCopy * CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO; + } + } } // Number of bytes should be a multiple of CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX but checking makes no sense - no way to correct it @@ -469,13 +489,13 @@ uint16_t tud_audio_n_flush_tx_support_ff(uint8_t itf) // Force a bool tud_audio_n_clear_tx_support_ff(uint8_t itf, uint8_t channelId) { - TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_TX); + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO); return tu_fifo_clear(&_audiod_itf[itf].tx_supp_ff[channelId]); } uint16_t tud_audio_n_write_support_ff(uint8_t itf, uint8_t channelId, const void * data, uint16_t len) { - TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_TX); + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO); return tu_fifo_write_n(&_audiod_itf[itf].tx_supp_ff[channelId], data, len); } #endif @@ -590,60 +610,91 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t * audio) #if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_IN // Take samples from the support buffer and encode them into the IN EP software FIFO // Returns number of bytes written into linear buffer + +/* 2.3.1.7.1 PCM Format +The PCM (Pulse Coded Modulation) format is the most commonly used audio format to represent audio +data streams. The audio data is not compressed and uses a signed two’s-complement fixed point format. It +is left-justified (the sign bit is the Msb) and data is padded with trailing zeros to fill the remaining unused +bits of the subslot. The binary point is located to the right of the sign bit so that all values lie within the +range [-1, +1) +*/ + +/* + * This function encodes channels saved within the support FIFOs into one stream by interleaving the PCM samples + * in the support FIFOs according to 2.3.1.5 Audio Streams. It does not control justification (left or right) and + * does not change the number of bytes per sample. + * */ + static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio) { - // We encode directly into IN EP's FIFO - abort if previous transfer not complete + // We encode directly into IN EP's linear buffer - abort if previous transfer not complete TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_in)); // Determine amount of samples - uint16_t const nEndpointSampleCapacity = CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE / CFG_TUD_AUDIO_N_CHANNELS_TX / CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX; - uint16_t nSamplesPerChannelToSend = tu_fifo_count(&audio->tx_supp_ff[0]); // We first look for the minimum number of bytes and afterwards convert it to sample size - uint8_t cntChannel; + uint16_t const nChannelsPerFF = CFG_TUD_AUDIO_N_CHANNELS_TX / CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO; + uint16_t const nBytesToCopy = nChannelsPerFF*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX; + uint16_t const capSamplesPerFF = CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE / CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX / CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO; + uint16_t nSamplesPerFFToSend = tu_fifo_count(&audio->tx_supp_ff[0]); + uint8_t cnt_ff; - for (cntChannel = 1; cntChannel < CFG_TUD_AUDIO_N_CHANNELS_TX; cntChannel++) + for (cnt_ff = 1; cnt_ff < CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO; cnt_ff++) { - uint16_t const count = tu_fifo_count(&audio->tx_supp_ff[cntChannel]); - if (count < nSamplesPerChannelToSend) + uint16_t const count = tu_fifo_count(&audio->tx_supp_ff[cnt_ff]); + if (count < nSamplesPerFFToSend) { - nSamplesPerChannelToSend = count; + nSamplesPerFFToSend = count; } } - // Convert to sample size - nSamplesPerChannelToSend = nSamplesPerChannelToSend / CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX; - // Check if there is enough - if (nSamplesPerChannelToSend == 0) return 0; + if (nSamplesPerFFToSend == 0) return 0; // Limit to maximum sample number - THIS IS A POSSIBLE ERROR SOURCE IF TOO MANY SAMPLE WOULD NEED TO BE SENT BUT CAN NOT! - nSamplesPerChannelToSend = tu_min16(nSamplesPerChannelToSend, nEndpointSampleCapacity); + nSamplesPerFFToSend = tu_min16(nSamplesPerFFToSend, capSamplesPerFF); + + // Round to full number of samples (flooring) + nSamplesPerFFToSend = (nSamplesPerFFToSend / nChannelsPerFF) * nChannelsPerFF; // Encode - uint16_t cntSample; - uint16_t idxSample = 0; + void * src; + uint8_t * dst; + uint8_t * src_end; + uint16_t len; - for (cntSample = 0; cntSample < nSamplesPerChannelToSend; cntSample++) + for (cnt_ff = 0; cnt_ff < CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO; cnt_ff++) { - for (cntChannel = 0; cntChannel < CFG_TUD_AUDIO_N_CHANNELS_TX; cntChannel++) + dst = &audio->lin_buf_in[cnt_ff*nChannelsPerFF*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX]; + + len = tu_fifo_get_linear_read_info(&audio->tx_supp_ff[cnt_ff], 0, &src, nSamplesPerFFToSend); + tu_fifo_advance_read_pointer(&audio->tx_supp_ff[cnt_ff], len); + + src_end = src + len * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX; + + while((uint8_t *)src < src_end) { - // If 8, 16, or 32 bit values are to be copied -#if CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX == CFG_TUD_AUDIO_TX_ITEMSIZE - tu_fifo_read_n(&audio->tx_supp_ff[cntChannel], &audio->lin_buf_in[idxSample], CFG_TUD_AUDIO_TX_ITEMSIZE); -#else - uint32_t sample = 0; + memcpy(dst, src, nBytesToCopy); + src = (uint8_t *)src + nBytesToCopy; + dst += nBytesToCopy * CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO; + } - // Get sample from buffer - tu_fifo_read_n(&audio->tx_supp_ff[cntChannel], &sample, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX); + // Handle wrapped part of FIFO + if (len < nSamplesPerFFToSend) + { + len = tu_fifo_get_linear_read_info(&audio->tx_supp_ff[cnt_ff], 0, &src, nSamplesPerFFToSend - len); + tu_fifo_advance_read_pointer(&audio->tx_supp_ff[cnt_ff], len); -#if CFG_TUD_AUDIO_JUSTIFICATION_TX == CFG_TUD_AUDIO_LEFT_JUSTIFIED - sample = sample << 8; -#endif - audio->lin_buf_in[idxSample] = sample; -#endif - idxSample += CFG_TUD_AUDIO_TX_ITEMSIZE; + src_end = src + len * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX; + + while((uint8_t *)src < src_end) + { + memcpy(dst, src, nBytesToCopy); + src = (uint8_t *)src + nBytesToCopy; + dst += nBytesToCopy * CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO; + } } } - return nSamplesPerChannelToSend * CFG_TUD_AUDIO_N_CHANNELS_TX * CFG_TUD_AUDIO_TX_ITEMSIZE; + + return nSamplesPerFFToSend * CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO; } #endif //CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE @@ -685,9 +736,9 @@ void audiod_init(void) // Initialize TX support FIFOs if required #if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_TX; cnt++) + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO; cnt++) { - tu_fifo_config(&audio->tx_supp_ff[cnt], &audio->tx_supp_ff_buf[cnt], CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE, 1, true); + tu_fifo_config(&audio->tx_supp_ff[cnt], &audio->tx_supp_ff_buf[cnt], CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX, true); #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&audio->tx_supp_ff[cnt], osal_mutex_create(&audio->tx_supp_ff_mutex_wr[cnt]), NULL); #endif @@ -696,9 +747,9 @@ void audiod_init(void) // Initialize RX support FIFOs if required #if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_RX; cnt++) + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO; cnt++) { - tu_fifo_config(&audio->rx_supp_ff[cnt], &audio->rx_supp_ff_buf[cnt], CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE, 1, true); + tu_fifo_config(&audio->rx_supp_ff[cnt], &audio->rx_supp_ff_buf[cnt], CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX, true); #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&audio->rx_supp_ff[cnt], NULL, osal_mutex_create(&audio->rx_supp_ff_mutex_rd[cnt])); #endif @@ -725,14 +776,14 @@ void audiod_reset(uint8_t rhport) #endif #if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE && CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_TX; cnt++) + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO; cnt++) { tu_fifo_clear(&audio->tx_supp_ff[cnt]); } #endif #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_RX; cnt++) + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO; cnt++) { tu_fifo_clear(&audio->rx_supp_ff[cnt]); } diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index ca74d68f4..730d42c38 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -50,7 +50,7 @@ #error You must define an audio class control request buffer size! #endif -// End point sizes - Limits: Full Speed <= 1023, High Speed <= 1024 +// End point sizes IN BYTES - Limits: Full Speed <= 1023, High Speed <= 1024 #ifndef CFG_TUD_AUDIO_EPSIZE_IN #define CFG_TUD_AUDIO_EPSIZE_IN 0 // TX #endif @@ -76,13 +76,13 @@ #define CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE 0 #endif -// General information of number of TX and/or RX channels - is used in case support FIFOs (see below) are used and can be used for descriptor definitions +// General information of number of TX and/or RX channels - is used in combination with support FIFOs (see below) and can be used for descriptor definitions #ifndef CFG_TUD_AUDIO_N_CHANNELS_TX -#define CFG_TUD_AUDIO_N_CHANNELS_TX 0 +#define CFG_TUD_AUDIO_N_CHANNELS_TX 1 #endif #ifndef CFG_TUD_AUDIO_N_CHANNELS_RX -#define CFG_TUD_AUDIO_N_CHANNELS_RX 0 +#define CFG_TUD_AUDIO_N_CHANNELS_RX 1 #endif // Use of TX/RX support FIFOs @@ -104,7 +104,7 @@ // The encoding/decoding starts when the private callback functions // - audio_tx_done_cb() // - audio_rx_done_cb() -// are invoked. If support FIFOs are used the corresponding encoding/decoding functions are called from there. +// are invoked. If support FIFOs are used, the corresponding encoding/decoding functions are called from there. // Once encoding/decoding is done the result is put directly into the EP_X_SW_BUFFER_FIFOs. You can use the public callback functions // - tud_audio_tx_done_pre_load_cb() or tud_audio_tx_done_post_load_cb() // - tud_audio_rx_done_pre_read_cb() or tud_audio_rx_done_post_read_cb() @@ -120,13 +120,31 @@ // - audio_rx_done_cb() // functions. -// Size of support FIFOs - if size > 0 there are as many FIFOs set up as TX/RX channels defined +// The number of support FIFOs and number of channels is decoupled. The PCM encoding/decoding works depending on the ratio CFG_TUD_AUDIO_N_CHANNELS_XX / CFG_TUD_AUDIO_N_XX_SUPPORT_SW_FIFO, where currently 1:1 and 2:1 is implemented. The version 2:1 is useful in case of I2S for which usually 2 are channels already interleaved available. + +// Size of support FIFOs IN SAMPLES - if size > 0 there are as many FIFOs set up as CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO and CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO #ifndef CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE -#define CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE 0 // Buffer size per channel - minimum size: ceil(f_s/1000)*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX +#define CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE 0 // FIFO size - minimum size: // ceil(f_s/1000) * CFG_TUD_AUDIO_N_CHANNELS_TX / CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO #endif #ifndef CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE -#define CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE 0 // Buffer size per channel - minimum size: ceil(f_s/1000)*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX +#define CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE 0 // FIFO size - minimum size: ceil(f_s/1000) * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX / CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO +#endif + +#ifndef CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO +#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE +#define CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO CFG_TUD_AUDIO_N_CHANNELS_TX // default size is equal to number of channels +#else +#define CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO 0 +#endif +#endif + +#ifndef CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO +#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE +#define CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO CFG_TUD_AUDIO_N_CHANNELS_RX // default size is equal to number of channels +#else +#define CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO 0 +#endif #endif // Enable/disable feedback EP (required for asynchronous RX applications) @@ -167,20 +185,6 @@ #define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX 1 #endif -#ifndef CFG_TUD_AUDIO_TX_ITEMSIZE -#if CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX == 1 -#define CFG_TUD_AUDIO_TX_ITEMSIZE 1 -#elif CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX == 2 -#define CFG_TUD_AUDIO_TX_ITEMSIZE 2 -#else -#define CFG_TUD_AUDIO_TX_ITEMSIZE 4 -#endif -#endif - -#if CFG_TUD_AUDIO_TX_ITEMSIZE < CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX -#error FIFO element size (ITEMSIZE) must not be smaller then sample size -#endif - #endif #if CFG_TUD_AUDIO_FORMAT_TYPE_RX == AUDIO_FORMAT_TYPE_I @@ -193,26 +197,6 @@ #define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX 1 #endif -#if CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX == 1 -#define CFG_TUD_AUDIO_RX_ITEMSIZE 1 -#elif CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX == 2 -#define CFG_TUD_AUDIO_RX_ITEMSIZE 2 -#else -#define CFG_TUD_AUDIO_RX_ITEMSIZE 4 -#endif - -#endif - -// In case PCM encoding/decoding of 24 into 32 bits, the adjustment needs to be defined -#define CFG_TUD_AUDIO_LEFT_JUSTIFIED -#define CFG_TUD_AUDIO_RIGHT_JUSTIFIED - -#ifndef CFG_TUD_AUDIO_JUSTIFICATION_RX -#define CFG_TUD_AUDIO_JUSTIFICATION_RX CFG_TUD_AUDIO_LEFT_JUSTIFIED -#endif - -#ifndef CFG_TUD_AUDIO_JUSTIFICATION_TX -#define CFG_TUD_AUDIO_JUSTIFICATION_TX CFG_TUD_AUDIO_LEFT_JUSTIFIED #endif //static_assert(sizeof(tud_audio_desc_lengths) != CFG_TUD_AUDIO, "Supply audio function descriptor pack length!"); @@ -256,7 +240,7 @@ bool tud_audio_n_clear_ep_in_ff (uint8_t itf); #if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_IN uint16_t tud_audio_n_flush_tx_support_ff (uint8_t itf); // Force all content in the support TX FIFOs to be written into EP SW FIFO -bool tud_audio_n_clear_tx_support_ff (uint8_t itf, uint8_t channelId); +bool tud_audio_n_clear_tx_support_ff (uint8_t itf, uint8_t channelId); uint16_t tud_audio_n_write_support_ff (uint8_t itf, uint8_t channelId, const void * data, uint16_t len); #endif diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 6a31b6373..4936d5e7d 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -596,42 +596,6 @@ uint16_t tu_fifo_read_n_const_addr(tu_fifo_t* f, void * buffer, uint16_t n) return _tu_fifo_read_n(f, buffer, n, TU_FIFO_COPY_CST); } -/******************************************************************************/ -/*! - @brief This function will read n elements from the array index specified by - the read pointer and increment the read index. It copies the elements - into another FIFO and as such takes care of wraps etc. - This function checks for an overflow and corrects read pointer if required. - - @param[in] f - Pointer to the FIFO buffer to manipulate - @param[in] f_target - Pointer to target FIFO i.e. to copy into - @param[in] offset - Position to read from in the FIFO buffer with respect to read pointer - @param[in] n - Number of items to peek - - @returns number of items read from the FIFO - */ -/******************************************************************************/ -uint16_t tu_fifo_read_n_into_other_fifo(tu_fifo_t* f, tu_fifo_t* f_target, uint16_t offset, uint16_t n) -{ - tu_fifo_lock(f->mutex_rd); - tu_fifo_lock(f_target->mutex_wr); - - // Conduct copy - n = tu_fifo_peek_n_into_other_fifo(f, f_target, offset, n); - - // Advance read pointer - f->rd_idx = advance_pointer(f, f->rd_idx, n); - - tu_fifo_unlock(f->mutex_rd); - tu_fifo_unlock(f_target->mutex_wr); - - return n; -} - /******************************************************************************/ /*! @brief Read one item without removing it from the FIFO. @@ -680,92 +644,6 @@ uint16_t tu_fifo_peek_at_n(tu_fifo_t* f, uint16_t offset, void * p_buffer, uint1 return ret; } -/******************************************************************************/ -/*! - @brief Read n items without removing it from the FIFO and copy them into another FIFO. - This function checks for an overflow and corrects read pointer if required. - - @param[in] f - Pointer to the FIFO buffer to manipulate - @param[in] f_target - Pointer to target FIFO i.e. to copy into - @param[in] offset - Position to read from in the FIFO buffer with respect to read pointer - @param[in] n - Number of items to peek - - @returns Number of bytes written to p_buffer - */ -/******************************************************************************/ -uint16_t tu_fifo_peek_n_into_other_fifo (tu_fifo_t* f, tu_fifo_t* f_target, uint16_t offset, uint16_t n) -{ - // Copy is only possible if both FIFOs have common element size - TU_VERIFY(f->item_size == f_target->item_size); - - // Work on local copies on case any pointer changes in between (only necessary if something is written into FIFO f in the meantime) - uint16_t f_wr_idx = f->wr_idx; - uint16_t f_rd_idx = f->rd_idx; - - uint16_t cnt = _tu_fifo_count(f, f_wr_idx, f_rd_idx); - - // Check overflow and correct if required - if (cnt > f->depth) - { - _tu_fifo_correct_read_pointer(f, f->wr_idx); - f_rd_idx = f->rd_idx; - cnt = f->depth; - } - - // Skip beginning of buffer - if (cnt == 0 || offset >= cnt) return 0; - - // Check if we can read something at and after offset - if too less is available we read what remains - cnt -= offset; - if (cnt < n) n = cnt; - - tu_fifo_lock(f_target->mutex_wr); // Lock both read and write pointers - in case of an overwritable FIFO both may be modified - - uint16_t wr_rel_tgt = get_relative_pointer(f_target, f_target->wr_idx, 0); - - if (!f_target->overwritable) - { - // Not overwritable limit up to full - n = tu_min16(n, tu_fifo_remaining(f_target)); - } - - // Advance write pointer - not required for later - f_target->wr_idx = advance_pointer(f_target, f_target->wr_idx, n); - - if (n >= f_target->depth) - { - offset += n - f_target->depth; - - // We start writing at the read pointer's position since we fill the complete - // buffer and we do not want to modify the read pointer within a write function! - // This would end up in a race condition with read functions! - wr_rel_tgt = get_relative_pointer(f_target, f_target->rd_idx, 0); - - n = f_target->depth; - - // Update write pointer - f_target->wr_idx = advance_pointer(f_target, f_target->rd_idx, n); - } - - // Copy linear size - uint16_t sz = f_target->depth - wr_rel_tgt; - _tu_fifo_peek_at_n(f, offset, &f_target->buffer[wr_rel_tgt], sz, f_wr_idx, f_rd_idx, TU_FIFO_COPY_INC); - - if (n > sz) - { - // Copy remaining, now wrapped part, into target buffer - _tu_fifo_peek_at_n(f, offset + sz, f_target->buffer, n-sz, f_wr_idx, f_rd_idx, TU_FIFO_COPY_INC); - } - - tu_fifo_unlock(f_target->mutex_wr); - - return n; -} - /******************************************************************************/ /*! @brief Write one element into the buffer. @@ -976,7 +854,7 @@ void tu_fifo_backward_read_pointer(tu_fifo_t *f, uint16_t n) Returns the length and pointer from which bytes can be read in a linear manner. This is of major interest for DMA transmissions. If returned length is zero the corresponding pointer is invalid. The returned length is limited to the number - of BYTES n which the user wants to write into the buffer. + of ITEMS n which the user wants to write into the buffer. The write pointer does NOT get advanced, use tu_fifo_advance_read_pointer() to do so! If the length returned is less than n i.e. lendepth; } - // Convert to bytes - cnt = cnt * f->item_size; - // Skip beginning of buffer if (cnt == 0 || offset >= cnt) return 0; @@ -1027,16 +902,14 @@ uint16_t tu_fifo_get_linear_read_info(tu_fifo_t *f, uint16_t offset, void **ptr, // Check if there is a wrap around necessary uint16_t len; - if (w >= r) { + if (w > r) { len = w - r; } else { - len = f->depth - r; + len = f->depth - r; // Also the case if FIFO was full } - len = len * f->item_size; - // Limit to required length len = tu_min16(n, len); @@ -1060,31 +933,31 @@ uint16_t tu_fifo_get_linear_read_info(tu_fifo_t *f, uint16_t offset, void **ptr, @param[in] f Pointer to FIFO @param[in] offset - Number of bytes to ignore before start writing + Number of ITEMS to ignore before start writing @param[out] **ptr Pointer to start writing to @param[in] n - Number of BYTES to write into buffer + Number of ITEMS to write into buffer @return len - Length of linear part IN BYTES, if zero corresponding pointer ptr is invalid + Length of linear part IN ITEMS, if zero corresponding pointer ptr is invalid */ /******************************************************************************/ uint16_t tu_fifo_get_linear_write_info(tu_fifo_t *f, uint16_t offset, void **ptr, uint16_t n) { uint16_t w = f->wr_idx, r = f->rd_idx; - uint16_t free = _tu_fifo_remaining(f, w, r) * f->item_size; + uint16_t free = _tu_fifo_remaining(f, w, r); if (!f->overwritable) { // Not overwritable limit up to full n = tu_min16(n, free); } - else if (n >= f->depth * f->item_size) + else if (n >= f->depth) { // If overwrite is allowed it must be less than or equal to 2 x buffer length, otherwise the overflow can not be resolved by the read functions - TU_VERIFY(n <= 2*f->depth * f->item_size); + TU_VERIFY(n <= 2*f->depth); - n = f->depth * f->item_size; + n = f->depth; // We start writing at the read pointer's position since we fill the complete // buffer and we do not want to modify the read pointer within a write function! // This would end up in a race condition with read functions! @@ -1108,8 +981,6 @@ uint16_t tu_fifo_get_linear_write_info(tu_fifo_t *f, uint16_t offset, void **ptr len = f->depth - w; } - len = len * f->item_size; - // Limit to required length len = tu_min16(n, len); diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h index 6e0ecdc82..d31e52f1c 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -113,11 +113,9 @@ uint16_t tu_fifo_write_n_const_addr (tu_fifo_t* f, const void * dat bool tu_fifo_read (tu_fifo_t* f, void * p_buffer); uint16_t tu_fifo_read_n (tu_fifo_t* f, void * p_buffer, uint16_t n); uint16_t tu_fifo_read_n_const_addr (tu_fifo_t* f, void * buffer, uint16_t n); -uint16_t tu_fifo_read_n_into_other_fifo (tu_fifo_t* f, tu_fifo_t* f_target, uint16_t offset, uint16_t n); bool tu_fifo_peek_at (tu_fifo_t* f, uint16_t pos, void * p_buffer); uint16_t tu_fifo_peek_at_n (tu_fifo_t* f, uint16_t pos, void * p_buffer, uint16_t n); -uint16_t tu_fifo_peek_n_into_other_fifo (tu_fifo_t* f, tu_fifo_t* f_target, uint16_t offset, uint16_t n); uint16_t tu_fifo_count (tu_fifo_t* f); bool tu_fifo_empty (tu_fifo_t* f); From 4ee1216aaf8c0ea6cefb6f690e4a391fe06f1356 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 13 Mar 2021 00:22:04 +0700 Subject: [PATCH 065/121] fix fifo unlock typo, also clean up a bit --- src/common/tusb_fifo.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 4936d5e7d..dc74489f5 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -89,7 +89,7 @@ bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_si f->rd_idx = f->wr_idx = 0; tu_fifo_unlock(f->mutex_wr); - tu_fifo_lock(f->mutex_rd); + tu_fifo_unlock(f->mutex_rd); return true; } @@ -104,9 +104,10 @@ static inline uint16_t _ff_mod(uint16_t idx, uint16_t depth) // Intended to be used to read from hardware USB FIFO in e.g. STM32 where all data is read from a constant address // Code adapted from dcd_synopsis.c -static void _tu_fifo_read_from_const_src_ptr(void * __restrict dst, const void * __restrict src, uint16_t len) +// TODO generalize with configurable 1 byte or 4 byte each read +static void _tu_fifo_read_from_const_src_ptr(void * dst, const void * src, uint16_t len) { - uint8_t CFG_TUSB_MEM_ALIGN * dst_u8 = (uint8_t *)dst; + uint8_t * dst_u8 = (uint8_t *)dst; volatile uint32_t * rx_fifo = (volatile uint32_t *) src; // Reading full available 32 bit words from FIFO @@ -136,15 +137,18 @@ static void _tu_fifo_read_from_const_src_ptr(void * __restrict dst, const void * // Intended to be used to write to hardware USB FIFO in e.g. STM32 where all data is written to a constant address // Code adapted from dcd_synopsis.c -static void _tu_fifo_write_to_const_dst_ptr(void * __restrict dst, const void * __restrict src, uint16_t len) +// TODO generalize with configurable 1 byte or 4 byte each write +static void _tu_fifo_write_to_const_dst_ptr(void * dst, const void * src, uint16_t len) { volatile uint32_t * tx_fifo = (volatile uint32_t *) dst; - uint8_t CFG_TUSB_MEM_ALIGN * src_u8 = (uint8_t *)src; + uint8_t * src_u8 = (uint8_t *)src; // Pushing full available 32 bit words to FIFO - uint16_t full_words = len >> 2; + uint16_t const full_words = len >> 2; for(uint16_t i = 0; i < full_words; i++){ - *tx_fifo = ((uint32_t)(src_u8[3]) << 24) | ((uint32_t)(src_u8[2]) << 16) | ((uint32_t)(src_u8[1]) << 8) | (uint32_t)src_u8[0]; + uint32_t temp32; + memcpy(&temp32, src_u8, 4); + *tx_fifo = temp32; src_u8 += 4; } @@ -200,12 +204,14 @@ static inline void _ff_pull_copy_fct(void * dst, const void * src, uint16_t len, // send n items to FIFO WITHOUT updating write pointer static void _ff_push_n(tu_fifo_t* f, void const * data, uint16_t n, uint16_t wRel, tu_fifo_copy_mode_t copy_mode) { - if(wRel + n <= f->depth) // Linear mode only + if(wRel + n <= f->depth) { + // Linear mode only _ff_push_copy_fct(f->buffer + (wRel * f->item_size), data, n*f->item_size, copy_mode); } - else // Wrap around + else { + // Wrap around uint16_t nLin = f->depth - wRel; // Write data to linear part of buffer @@ -225,12 +231,14 @@ static inline void _ff_pull(tu_fifo_t* f, void * p_buffer, uint16_t rRel) // get n items from FIFO WITHOUT updating read pointer static void _ff_pull_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint16_t rRel, tu_fifo_copy_mode_t copy_mode) { - if(rRel + n <= f->depth) // Linear mode only + if(rRel + n <= f->depth) { + // Linear mode only _ff_pull_copy_fct(p_buffer, f->buffer + (rRel * f->item_size), n*f->item_size, copy_mode); } - else // Wrap around + else { + // Wrap around uint16_t nLin = f->depth - rRel; // Read data from linear part of buffer From db6242f07615f85d8bd1bcf9b6e86c4e031ecc19 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 13 Mar 2021 00:23:13 +0700 Subject: [PATCH 066/121] move AUDIO_SAMPLE_RATE to example main.c --- examples/device/audio_test/src/main.c | 4 ++++ examples/device/audio_test/src/tusb_config.h | 4 ---- examples/device/uac2_headset/src/main.c | 4 ++++ examples/device/uac2_headset/src/tusb_config.h | 5 ----- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/examples/device/audio_test/src/main.c b/examples/device/audio_test/src/main.c index c2406bd23..a631f37b6 100644 --- a/examples/device/audio_test/src/main.c +++ b/examples/device/audio_test/src/main.c @@ -34,6 +34,10 @@ // MACRO CONSTANT TYPEDEF PROTYPES //--------------------------------------------------------------------+ +#ifndef AUDIO_SAMPLE_RATE +#define AUDIO_SAMPLE_RATE 48000 +#endif + /* Blink pattern * - 250 ms : device not mounted * - 1000 ms : device mounted diff --git a/examples/device/audio_test/src/tusb_config.h b/examples/device/audio_test/src/tusb_config.h index 6ee5d937c..557a8b15e 100644 --- a/examples/device/audio_test/src/tusb_config.h +++ b/examples/device/audio_test/src/tusb_config.h @@ -91,10 +91,6 @@ extern "C" { // AUDIO CLASS DRIVER CONFIGURATION //-------------------------------------------------------------------- -#ifndef AUDIO_SAMPLE_RATE -#define AUDIO_SAMPLE_RATE 48000 -#endif - // Audio format type #define CFG_TUD_AUDIO_FORMAT_TYPE_TX AUDIO_FORMAT_TYPE_I diff --git a/examples/device/uac2_headset/src/main.c b/examples/device/uac2_headset/src/main.c index cdb29f3f4..f5360a0b6 100644 --- a/examples/device/uac2_headset/src/main.c +++ b/examples/device/uac2_headset/src/main.c @@ -34,6 +34,10 @@ // MACRO CONSTANT TYPEDEF PROTOTYPES //--------------------------------------------------------------------+ +#ifndef AUDIO_SAMPLE_RATE +#define AUDIO_SAMPLE_RATE 48000 +#endif + /* Blink pattern * - 25 ms : streaming data * - 250 ms : device not mounted diff --git a/examples/device/uac2_headset/src/tusb_config.h b/examples/device/uac2_headset/src/tusb_config.h index 45acf0093..7795d8405 100644 --- a/examples/device/uac2_headset/src/tusb_config.h +++ b/examples/device/uac2_headset/src/tusb_config.h @@ -91,11 +91,6 @@ extern "C" { //-------------------------------------------------------------------- // AUDIO CLASS DRIVER CONFIGURATION //-------------------------------------------------------------------- - -#ifndef AUDIO_SAMPLE_RATE -#define AUDIO_SAMPLE_RATE 48000 -#endif - #define CFG_TUD_AUDIO_IN_PATH (CFG_TUD_AUDIO) #define CFG_TUD_AUDIO_OUT_PATH (CFG_TUD_AUDIO) From de3c03af76ebb4f092f798a390a463fe78cc27f0 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sat, 13 Mar 2021 11:37:38 +0100 Subject: [PATCH 067/121] Add python script to plot audio sample data. --- .../audio_test/src/plot_audio_samples.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 examples/device/audio_test/src/plot_audio_samples.py diff --git a/examples/device/audio_test/src/plot_audio_samples.py b/examples/device/audio_test/src/plot_audio_samples.py new file mode 100644 index 000000000..e6a9e2eec --- /dev/null +++ b/examples/device/audio_test/src/plot_audio_samples.py @@ -0,0 +1,24 @@ +import sounddevice as sd +import matplotlib.pyplot as plt +import numpy as np + +if __name__ == '__main__': + + # devList = sd.query_devices() + # print(devList) + + fs = 48000 # Sample rate + duration = 100e-3 # Duration of recording + device = 'Microphone (MicNode) MME' # MME is needed since there are more than one MicNode device APIs (at least in Windows) + + myrecording = sd.rec(int(duration * fs), samplerate=fs, channels=1, dtype='int16', device=device) + print('Waiting...') + sd.wait() # Wait until recording is finished + print('Done!') + + time = np.arange(0, duration, 1 / fs) # time vector + plt.plot(time, myrecording) + plt.xlabel('Time [s]') + plt.ylabel('Amplitude') + plt.title('MicNode') + plt.show() \ No newline at end of file From d566444d584f644afc580ff9d3cf8e1adc7ccb30 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sat, 13 Mar 2021 11:41:46 +0100 Subject: [PATCH 068/121] Add new line at end of python script --- examples/device/audio_test/src/plot_audio_samples.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/device/audio_test/src/plot_audio_samples.py b/examples/device/audio_test/src/plot_audio_samples.py index e6a9e2eec..0b0c3394f 100644 --- a/examples/device/audio_test/src/plot_audio_samples.py +++ b/examples/device/audio_test/src/plot_audio_samples.py @@ -21,4 +21,5 @@ if __name__ == '__main__': plt.xlabel('Time [s]') plt.ylabel('Amplitude') plt.title('MicNode') - plt.show() \ No newline at end of file + plt.show() + \ No newline at end of file From cd491e296e0c8bce113d5474955d08f4c99b3099 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sun, 14 Mar 2021 18:55:16 +0100 Subject: [PATCH 069/121] Intermediate commit --- src/class/audio/audio_device.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 00d95ede5..73f265a8f 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -206,6 +206,15 @@ CFG_TUSB_MEM_SECTION audiod_interface_t _audiod_itf[CFG_TUD_AUDIO]; extern const uint16_t tud_audio_desc_lengths[]; +// bSubslotSize for PCM encoding/decoding using support FIFOs +#if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE +extern const tud_audio_n_bytes_per_sample_tx[CFG_TUD_AUDIO][CFG_TUD_AUDIO_N_AS_INT]; +#endif + +#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE +extern const tud_audio_n_bytes_per_sample_rx[CFG_TUD_AUDIO][CFG_TUD_AUDIO_N_AS_INT]; +#endif + #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE static bool audiod_rx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint16_t n_bytes_received); #endif From a60bd0c8ac374e9d96fd7248503cf822306547d8 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Tue, 23 Mar 2021 19:33:04 +0100 Subject: [PATCH 070/121] Fix bug in writing to constant src/dst address. Copying has to be conduct in full words (at least for STM32). Renamed copy function to tu_fifo_write_n_const_addr_full_words() --- src/common/tusb_fifo.c | 201 +++++++++++++------ src/common/tusb_fifo.h | 4 +- src/portable/espressif/esp32s2/dcd_esp32s2.c | 4 +- src/portable/microchip/samg/dcd_samg.c | 4 +- src/portable/nuvoton/nuc505/dcd_nuc505.c | 4 +- src/portable/st/synopsys/dcd_synopsys.c | 6 +- 6 files changed, 149 insertions(+), 74 deletions(-) diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index dc74489f5..7d5453850 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -68,7 +68,7 @@ static void tu_fifo_unlock(tu_fifo_mutex_t mutex) typedef enum { TU_FIFO_COPY_INC, ///< Copy from/to an increasing source/destination address - default mode - TU_FIFO_COPY_CST, ///< Copy from/to a constant source/destination address - required for e.g. STM32 to write into USB hardware FIFO + TU_FIFO_COPY_CST_FULL_WORDS, ///< Copy from/to a constant source/destination address - required for e.g. STM32 to write into USB hardware FIFO } tu_fifo_copy_mode_t; bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable) @@ -105,7 +105,7 @@ static inline uint16_t _ff_mod(uint16_t idx, uint16_t depth) // Intended to be used to read from hardware USB FIFO in e.g. STM32 where all data is read from a constant address // Code adapted from dcd_synopsis.c // TODO generalize with configurable 1 byte or 4 byte each read -static void _tu_fifo_read_from_const_src_ptr(void * dst, const void * src, uint16_t len) +static void _tu_fifo_read_from_const_src_ptr_in_full_words(void * dst, const void * src, uint16_t len) { uint8_t * dst_u8 = (uint8_t *)dst; volatile uint32_t * rx_fifo = (volatile uint32_t *) src; @@ -138,7 +138,7 @@ static void _tu_fifo_read_from_const_src_ptr(void * dst, const void * src, uint1 // Intended to be used to write to hardware USB FIFO in e.g. STM32 where all data is written to a constant address // Code adapted from dcd_synopsis.c // TODO generalize with configurable 1 byte or 4 byte each write -static void _tu_fifo_write_to_const_dst_ptr(void * dst, const void * src, uint16_t len) +static void _tu_fifo_write_to_const_dst_ptr_in_full_words(void * dst, const void * src, uint16_t len) { volatile uint32_t * tx_fifo = (volatile uint32_t *) dst; uint8_t * src_u8 = (uint8_t *)src; @@ -173,52 +173,77 @@ static inline void _ff_push(tu_fifo_t* f, void const * data, uint16_t wRel) memcpy(f->buffer + (wRel * f->item_size), data, f->item_size); } -static inline void _ff_push_copy_fct(void * dst, const void * src, uint16_t len, tu_fifo_copy_mode_t copy_mode) -{ - switch (copy_mode) - { - case TU_FIFO_COPY_INC: - memcpy(dst, src, len); - break; - - case TU_FIFO_COPY_CST: - _tu_fifo_read_from_const_src_ptr(dst, src, len); - break; - } -} - -static inline void _ff_pull_copy_fct(void * dst, const void * src, uint16_t len, tu_fifo_copy_mode_t copy_mode) -{ - switch (copy_mode) - { - case TU_FIFO_COPY_INC: - memcpy(dst, src, len); - break; - - case TU_FIFO_COPY_CST: - _tu_fifo_write_to_const_dst_ptr(dst, src, len); - break; - } -} - // send n items to FIFO WITHOUT updating write pointer static void _ff_push_n(tu_fifo_t* f, void const * data, uint16_t n, uint16_t wRel, tu_fifo_copy_mode_t copy_mode) { - if(wRel + n <= f->depth) + switch (copy_mode) { - // Linear mode only - _ff_push_copy_fct(f->buffer + (wRel * f->item_size), data, n*f->item_size, copy_mode); - } - else - { - // Wrap around - uint16_t nLin = f->depth - wRel; + case TU_FIFO_COPY_INC: + if(n <= f->depth-wRel) + { + // Linear mode only + memcpy(f->buffer + (wRel * f->item_size), data, n*f->item_size); + } + else + { + // Wrap around + uint16_t nLin = f->depth - wRel; - // Write data to linear part of buffer - _ff_push_copy_fct(f->buffer + (wRel * f->item_size), data, nLin*f->item_size, copy_mode); + // Write data to linear part of buffer + memcpy(f->buffer + (wRel * f->item_size), data, nLin*f->item_size); - // Write data wrapped around - _ff_push_copy_fct(f->buffer, ((uint8_t const*) data) + nLin*f->item_size, (n - nLin) * f->item_size, copy_mode); + // Write data wrapped around + memcpy(f->buffer, ((uint8_t const*) data) + nLin*f->item_size, (n - nLin) * f->item_size); + } + break; + + case TU_FIFO_COPY_CST_FULL_WORDS: // Intended for hardware buffers from which it can be read word by word only + if(n <= f->depth-wRel) + { + // Linear mode only + _tu_fifo_read_from_const_src_ptr_in_full_words(f->buffer + (wRel * f->item_size), data, n*f->item_size); + } + else + { + // Wrap around case + uint16_t nLin = (f->depth - wRel) * f->item_size; + uint16_t nWrap = (n - nLin) * f->item_size; + + uint8_t * dst_u8 = (uint8_t *)(f->buffer + (wRel * f->item_size)); + volatile uint32_t * rx_fifo = (volatile uint32_t *) data; + CFG_TUSB_MEM_ALIGN uint32_t tmp; + + // Write full words of linear part to buffer + uint16_t full_words = nLin >> 2; + for(uint16_t i = 0; i < full_words; i++) { + tmp = *rx_fifo; + memcpy(dst_u8, &tmp, 4); + // dst_u8[0] = tmp & 0x000000FF; + // dst_u8[1] = (tmp & 0x0000FF00) >> 8; + // dst_u8[2] = (tmp & 0x00FF0000) >> 16; + // dst_u8[3] = (tmp & 0xFF000000) >> 24; + dst_u8 += 4; + } + + // Handle wrap around + uint8_t rem = nLin - (full_words << 2); + uint8_t remrem = 0; + if (rem > 0) + { + tmp = *rx_fifo; + memcpy(dst_u8, &tmp, rem); + remrem = tu_min16(nWrap, 4-rem); + memcpy(f->buffer, ((uint8_t *) &tmp) + rem, remrem); + nWrap -= remrem; + } + + // Final part + if (nWrap > 0) + { + _tu_fifo_read_from_const_src_ptr_in_full_words(f->buffer + remrem, data, nWrap); + } + } + break; } } @@ -231,24 +256,74 @@ static inline void _ff_pull(tu_fifo_t* f, void * p_buffer, uint16_t rRel) // get n items from FIFO WITHOUT updating read pointer static void _ff_pull_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint16_t rRel, tu_fifo_copy_mode_t copy_mode) { - if(rRel + n <= f->depth) + switch (copy_mode) { - // Linear mode only - _ff_pull_copy_fct(p_buffer, f->buffer + (rRel * f->item_size), n*f->item_size, copy_mode); - } - else - { - // Wrap around - uint16_t nLin = f->depth - rRel; + case TU_FIFO_COPY_INC: + if(n <= f->depth-rRel) + { + // Linear mode only + memcpy(p_buffer, f->buffer + (rRel * f->item_size), n*f->item_size); + } + else + { + // Wrap around + uint16_t nLin = f->depth - rRel; - // Read data from linear part of buffer - _ff_pull_copy_fct(p_buffer, f->buffer + (rRel * f->item_size), nLin*f->item_size, copy_mode); + // Read data from linear part of buffer + memcpy(p_buffer, f->buffer + (rRel * f->item_size), nLin*f->item_size); - // Read data wrapped part - _ff_pull_copy_fct((uint8_t*)p_buffer + nLin*f->item_size, f->buffer, (n - nLin) * f->item_size, copy_mode); + // Read data wrapped part + memcpy((uint8_t*)p_buffer + nLin*f->item_size, f->buffer, (n - nLin) * f->item_size); + } + break; + + case TU_FIFO_COPY_CST_FULL_WORDS: + + if(n <= f->depth-rRel) + { + // Linear mode only + _tu_fifo_write_to_const_dst_ptr_in_full_words(p_buffer, f->buffer + (rRel * f->item_size), n*f->item_size); + } + else + { + // Wrap around case + uint16_t nLin = (f->depth - rRel) * f->item_size; + uint16_t nWrap = (n - nLin) * f->item_size; + + volatile uint32_t * tx_fifo = (volatile uint32_t *) p_buffer; + uint8_t * src_u8 = f->buffer + (rRel * f->item_size); + CFG_TUSB_MEM_ALIGN uint32_t tmp; + + // Pushing full available 32 bit words to FIFO + uint16_t const full_words = nLin >> 2; + for(uint16_t i = 0; i < full_words; i++){ + memcpy(&tmp, src_u8, 4); + *tx_fifo = tmp; + src_u8 += 4; + } + + // Handle wrap around + uint8_t rem = nLin - (full_words << 2); + uint8_t remrem = 0; + if (rem > 0) + { + tmp = 0; + memcpy(&tmp, src_u8, rem); + remrem = tu_min16(nWrap, 4-rem); + memcpy(((uint8_t *) &tmp) + rem, f->buffer, remrem); + nWrap -= remrem; + *tx_fifo = tmp; + } + + // Final part + if (nWrap > 0) + { + _tu_fifo_write_to_const_dst_ptr_in_full_words(p_buffer, f->buffer + remrem, nWrap); + } + } + break; } } - // Advance an absolute pointer static uint16_t advance_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset) { @@ -599,9 +674,9 @@ uint16_t tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n) return _tu_fifo_read_n(f, buffer, n, TU_FIFO_COPY_INC); } -uint16_t tu_fifo_read_n_const_addr(tu_fifo_t* f, void * buffer, uint16_t n) +uint16_t tu_fifo_read_n_const_addr_full_words(tu_fifo_t* f, void * buffer, uint16_t n) { - return _tu_fifo_read_n(f, buffer, n, TU_FIFO_COPY_CST); + return _tu_fifo_read_n(f, buffer, n, TU_FIFO_COPY_CST_FULL_WORDS); } /******************************************************************************/ @@ -723,9 +798,9 @@ uint16_t tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n) @return Number of written elements */ /******************************************************************************/ -uint16_t tu_fifo_write_n_const_addr(tu_fifo_t* f, const void * data, uint16_t n) +uint16_t tu_fifo_write_n_const_addr_full_words(tu_fifo_t* f, const void * data, uint16_t n) { - return _tu_fifo_write_n(f, data, n, TU_FIFO_COPY_CST); + return _tu_fifo_write_n(f, data, n, TU_FIFO_COPY_CST_FULL_WORDS); } /******************************************************************************/ @@ -756,7 +831,7 @@ bool tu_fifo_clear(tu_fifo_t *f) Pointer to the FIFO buffer to manipulate @param[in] overwritable Overwritable mode the fifo is set to -*/ + */ /******************************************************************************/ bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) { @@ -877,7 +952,7 @@ void tu_fifo_backward_read_pointer(tu_fifo_t *f, uint16_t n) Number of ITEMS to read from buffer @return len Length of linear part IN ITEMS, if zero corresponding pointer ptr is invalid -*/ + */ /******************************************************************************/ uint16_t tu_fifo_get_linear_read_info(tu_fifo_t *f, uint16_t offset, void **ptr, uint16_t n) { @@ -948,7 +1023,7 @@ uint16_t tu_fifo_get_linear_read_info(tu_fifo_t *f, uint16_t offset, void **ptr, Number of ITEMS to write into buffer @return len Length of linear part IN ITEMS, if zero corresponding pointer ptr is invalid -*/ + */ /******************************************************************************/ uint16_t tu_fifo_get_linear_write_info(tu_fifo_t *f, uint16_t offset, void **ptr, uint16_t n) { diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h index 4b4fe92ba..93ed6095d 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -109,11 +109,11 @@ static inline void tu_fifo_config_mutex(tu_fifo_t *f, tu_fifo_mutex_t write_mute bool tu_fifo_write (tu_fifo_t* f, void const * p_data); uint16_t tu_fifo_write_n (tu_fifo_t* f, void const * p_data, uint16_t n); -uint16_t tu_fifo_write_n_const_addr (tu_fifo_t* f, const void * data, uint16_t n); +uint16_t tu_fifo_write_n_const_addr_full_words (tu_fifo_t* f, const void * data, uint16_t n); bool tu_fifo_read (tu_fifo_t* f, void * p_buffer); uint16_t tu_fifo_read_n (tu_fifo_t* f, void * p_buffer, uint16_t n); -uint16_t tu_fifo_read_n_const_addr (tu_fifo_t* f, void * buffer, uint16_t n); +uint16_t tu_fifo_read_n_const_addr_full_words (tu_fifo_t* f, void * buffer, uint16_t n); bool tu_fifo_peek_at (tu_fifo_t* f, uint16_t pos, void * p_buffer); uint16_t tu_fifo_peek_at_n (tu_fifo_t* f, uint16_t pos, void * p_buffer, uint16_t n); diff --git a/src/portable/espressif/esp32s2/dcd_esp32s2.c b/src/portable/espressif/esp32s2/dcd_esp32s2.c index eb2c05153..28a3bcd07 100644 --- a/src/portable/espressif/esp32s2/dcd_esp32s2.c +++ b/src/portable/espressif/esp32s2/dcd_esp32s2.c @@ -517,7 +517,7 @@ static void receive_packet(xfer_ctl_t *xfer, /* usb_out_endpoint_t * out_ep, */ if (xfer->ff) { // Ring buffer - tu_fifo_write_n_const_addr(xfer->ff, (const void *) rx_fifo, to_recv_size); + tu_fifo_write_n_const_addr_full_words(xfer->ff, (const void *) rx_fifo, to_recv_size); } else { @@ -573,7 +573,7 @@ static void transmit_packet(xfer_ctl_t *xfer, volatile usb_in_endpoint_t *in_ep, if (xfer->ff) { - tu_fifo_read_n_const_addr(xfer->ff, (void *) tx_fifo, to_xfer_size); + tu_fifo_read_n_const_addr_full_words(xfer->ff, (void *) tx_fifo, to_xfer_size); } else { diff --git a/src/portable/microchip/samg/dcd_samg.c b/src/portable/microchip/samg/dcd_samg.c index 07ab9e83f..8b5bebf85 100644 --- a/src/portable/microchip/samg/dcd_samg.c +++ b/src/portable/microchip/samg/dcd_samg.c @@ -437,7 +437,7 @@ void dcd_int_handler(uint8_t rhport) // write to EP fifo if (xfer->ff) { - tu_fifo_read_n_const_addr(xfer->ff, (void *) &UDP->UDP_FDR[epnum], xact_len); + tu_fifo_read_n_const_addr_full_words(xfer->ff, (void *) &UDP->UDP_FDR[epnum], xact_len); } else { @@ -470,7 +470,7 @@ void dcd_int_handler(uint8_t rhport) // Read from EP fifo if (xfer->ff) { - tu_fifo_write_n_const_addr(xfer->ff, (const void *) &UDP->UDP_FDR[epnum], xact_len); + tu_fifo_write_n_const_addr_full_words(xfer->ff, (const void *) &UDP->UDP_FDR[epnum], xact_len); } else { diff --git a/src/portable/nuvoton/nuc505/dcd_nuc505.c b/src/portable/nuvoton/nuc505/dcd_nuc505.c index 5d15ca962..67693e335 100644 --- a/src/portable/nuvoton/nuc505/dcd_nuc505.c +++ b/src/portable/nuvoton/nuc505/dcd_nuc505.c @@ -183,7 +183,7 @@ static void dcd_userEP_in_xfer(struct xfer_ctl_t *xfer, USBD_EP_T *ep) /* provided buffers are thankfully 32-bit aligned, allowing most data to be transfered as 32-bit */ if (xfer->ff) { - tu_fifo_read_n_const_addr(xfer->ff, (void *) (&ep->EPDAT_BYTE), bytes_now); + tu_fifo_read_n_const_addr_full_words(xfer->ff, (void *) (&ep->EPDAT_BYTE), bytes_now); } else { @@ -657,7 +657,7 @@ void dcd_int_handler(uint8_t rhport) /* copy the data from the PC to the previously provided buffer */ if (xfer->ff) { - tu_fifo_write_n_const_addr(xfer->ff, (const void *) &ep->EPDAT_BYTE, tu_min16(available_bytes, xfer->total_bytes - xfer->out_bytes_so_far)); + tu_fifo_write_n_const_addr_full_words(xfer->ff, (const void *) &ep->EPDAT_BYTE, tu_min16(available_bytes, xfer->total_bytes - xfer->out_bytes_so_far)); } else { diff --git a/src/portable/st/synopsys/dcd_synopsys.c b/src/portable/st/synopsys/dcd_synopsys.c index e2390fe57..aa927d5a4 100644 --- a/src/portable/st/synopsys/dcd_synopsys.c +++ b/src/portable/st/synopsys/dcd_synopsys.c @@ -902,7 +902,7 @@ static void handle_rxflvl_ints(uint8_t rhport, USB_OTG_OUTEndpointTypeDef * out_ if (xfer->ff) { // Ring buffer - tu_fifo_write_n_const_addr(xfer->ff, (const void *) rx_fifo, bcnt); + tu_fifo_write_n_const_addr_full_words(xfer->ff, (const void *) rx_fifo, bcnt); } else { @@ -1008,7 +1008,7 @@ static void handle_epin_ints(uint8_t rhport, USB_OTG_DeviceTypeDef * dev, USB_OT // Process every single packet (only whole packets can be written to fifo) for(uint16_t i = 0; i < remaining_packets; i++){ - uint16_t remaining_bytes = (in_ep[n].DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ_Msk) >> USB_OTG_DIEPTSIZ_XFRSIZ_Pos; + volatile uint16_t remaining_bytes = (in_ep[n].DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ_Msk) >> USB_OTG_DIEPTSIZ_XFRSIZ_Pos; // Packet can not be larger than ep max size uint16_t packet_size = tu_min16(remaining_bytes, xfer->max_size); @@ -1022,7 +1022,7 @@ static void handle_epin_ints(uint8_t rhport, USB_OTG_DeviceTypeDef * dev, USB_OT if (xfer->ff) { usb_fifo_t tx_fifo = FIFO_BASE(rhport, n); - tu_fifo_read_n_const_addr(xfer->ff, (void *) tx_fifo, packet_size); + tu_fifo_read_n_const_addr_full_words(xfer->ff, (void *) tx_fifo, packet_size); } else { From 1e4e87de51e67bc6439b463bf30c1f1b7302d510 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Thu, 25 Mar 2021 13:53:26 +0100 Subject: [PATCH 071/121] Rework to copy wrapped word bytes by byte in copy_to_cont_dst etc. --- src/common/tusb_fifo.c | 65 ++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 7d5453850..e3613e45f 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -215,7 +215,9 @@ static void _ff_push_n(tu_fifo_t* f, void const * data, uint16_t n, uint16_t wRe // Write full words of linear part to buffer uint16_t full_words = nLin >> 2; - for(uint16_t i = 0; i < full_words; i++) { + uint8_t rem = nLin - (full_words << 2); + while(full_words--) + { tmp = *rx_fifo; memcpy(dst_u8, &tmp, 4); // dst_u8[0] = tmp & 0x000000FF; @@ -226,22 +228,29 @@ static void _ff_push_n(tu_fifo_t* f, void const * data, uint16_t n, uint16_t wRe } // Handle wrap around - uint8_t rem = nLin - (full_words << 2); - uint8_t remrem = 0; if (rem > 0) { - tmp = *rx_fifo; - memcpy(dst_u8, &tmp, rem); - remrem = tu_min16(nWrap, 4-rem); - memcpy(f->buffer, ((uint8_t *) &tmp) + rem, remrem); + uint8_t remrem = tu_min16(nWrap, 4-rem); nWrap -= remrem; + tmp = *rx_fifo; + uint8_t * src_u8 = ((uint8_t *) &tmp); + while(rem--) + { + *dst_u8++ = *src_u8++; + } + dst_u8 = f->buffer; + while(remrem--) + { + *dst_u8++ = *src_u8++; + } + } + else + { + dst_u8 = f->buffer; } // Final part - if (nWrap > 0) - { - _tu_fifo_read_from_const_src_ptr_in_full_words(f->buffer + remrem, data, nWrap); - } + if (nWrap > 0) _tu_fifo_read_from_const_src_ptr_in_full_words(dst_u8, data, nWrap); } break; } @@ -295,31 +304,39 @@ static void _ff_pull_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint16_t rRel, CFG_TUSB_MEM_ALIGN uint32_t tmp; // Pushing full available 32 bit words to FIFO - uint16_t const full_words = nLin >> 2; - for(uint16_t i = 0; i < full_words; i++){ + uint16_t full_words = nLin >> 2; + uint8_t rem = nLin - (full_words << 2); + while(full_words--) + { memcpy(&tmp, src_u8, 4); *tx_fifo = tmp; src_u8 += 4; } - // Handle wrap around - uint8_t rem = nLin - (full_words << 2); - uint8_t remrem = 0; + // Handle wrap around - do it manually as these are only 4 bytes and its faster without memcpy if (rem > 0) { - tmp = 0; - memcpy(&tmp, src_u8, rem); - remrem = tu_min16(nWrap, 4-rem); - memcpy(((uint8_t *) &tmp) + rem, f->buffer, remrem); + uint8_t remrem = tu_min16(nWrap, 4-rem); nWrap -= remrem; + uint8_t * dst_u8 = (uint8_t *)&tmp; + while(rem--) + { + *dst_u8++ = *src_u8++; + } + src_u8 = f->buffer; + while(remrem--) + { + *dst_u8++ = *src_u8++; + } *tx_fifo = tmp; } - - // Final part - if (nWrap > 0) + else { - _tu_fifo_write_to_const_dst_ptr_in_full_words(p_buffer, f->buffer + remrem, nWrap); + src_u8 = f->buffer; } + + // Final linear part + if (nWrap > 0) _tu_fifo_write_to_const_dst_ptr_in_full_words(p_buffer, src_u8, nWrap); } break; } From bfddfbadc72eb389f88e045f68a4219149397a46 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Thu, 25 Mar 2021 14:28:59 +0100 Subject: [PATCH 072/121] Implement unaligned word copy. --- src/common/tusb_fifo.c | 108 +++++++++++++++++++++++------------------ 1 file changed, 62 insertions(+), 46 deletions(-) diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index e3613e45f..c131a1910 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -107,30 +107,33 @@ static inline uint16_t _ff_mod(uint16_t idx, uint16_t depth) // TODO generalize with configurable 1 byte or 4 byte each read static void _tu_fifo_read_from_const_src_ptr_in_full_words(void * dst, const void * src, uint16_t len) { - uint8_t * dst_u8 = (uint8_t *)dst; volatile uint32_t * rx_fifo = (volatile uint32_t *) src; + // Optimize for fast word copies + typedef struct{ + uint32_t val; + } __attribute((__packed__)) unaligned_uint32_t; + + unaligned_uint32_t* dst_una = (unaligned_uint32_t*)dst; + // Reading full available 32 bit words from FIFO uint16_t full_words = len >> 2; - for(uint16_t i = 0; i < full_words; i++) { - uint32_t tmp = *rx_fifo; - dst_u8[0] = tmp & 0x000000FF; - dst_u8[1] = (tmp & 0x0000FF00) >> 8; - dst_u8[2] = (tmp & 0x00FF0000) >> 16; - dst_u8[3] = (tmp & 0xFF000000) >> 24; - dst_u8 += 4; + while(full_words--) + { + dst_una->val = *rx_fifo; + dst_una++; } // Read the remaining 1-3 bytes from FIFO uint8_t bytes_rem = len & 0x03; if(bytes_rem != 0) { + uint8_t * dst_u8 = (uint8_t *)dst_una; uint32_t tmp = *rx_fifo; - dst_u8[0] = tmp & 0x000000FF; - if(bytes_rem > 1) { - dst_u8[1] = (tmp & 0x0000FF00) >> 8; - } - if(bytes_rem > 2) { - dst_u8[2] = (tmp & 0x00FF0000) >> 16; + uint8_t * src = (uint8_t *) &tmp; + + while(bytes_rem--) + { + *dst_u8++ = *src++; } } } @@ -141,29 +144,34 @@ static void _tu_fifo_read_from_const_src_ptr_in_full_words(void * dst, const voi static void _tu_fifo_write_to_const_dst_ptr_in_full_words(void * dst, const void * src, uint16_t len) { volatile uint32_t * tx_fifo = (volatile uint32_t *) dst; - uint8_t * src_u8 = (uint8_t *)src; + + // Optimize for fast word copies + typedef struct{ + uint32_t val; + } __attribute((__packed__)) unaligned_uint32_t; + + unaligned_uint32_t* src_una = (unaligned_uint32_t *) src; // Pushing full available 32 bit words to FIFO - uint16_t const full_words = len >> 2; - for(uint16_t i = 0; i < full_words; i++){ - uint32_t temp32; - memcpy(&temp32, src_u8, 4); - *tx_fifo = temp32; - src_u8 += 4; + uint16_t full_words = len >> 2; + while(full_words--) + { + *tx_fifo = src_una->val; + src_una++; } // Write the remaining 1-3 bytes into FIFO uint8_t bytes_rem = len & 0x03; if(bytes_rem){ - uint32_t tmp_word = 0; - tmp_word |= src_u8[0]; - if(bytes_rem > 1){ - tmp_word |= (uint32_t)(src_u8[1]) << 8; + uint8_t * src_u8 = (uint8_t *) src_una; + uint32_t tmp = 0; + uint8_t * dst_u8 = (uint8_t *)&tmp; + + while(bytes_rem--) + { + *dst_u8++ = *src_u8++; } - if(bytes_rem > 2){ - tmp_word |= (uint32_t)(src_u8[2]) << 16; - } - *tx_fifo = tmp_word; + *tx_fifo = tmp; } } @@ -209,30 +217,31 @@ static void _ff_push_n(tu_fifo_t* f, void const * data, uint16_t n, uint16_t wRe uint16_t nLin = (f->depth - wRel) * f->item_size; uint16_t nWrap = (n - nLin) * f->item_size; - uint8_t * dst_u8 = (uint8_t *)(f->buffer + (wRel * f->item_size)); + // Optimize for fast word copies + typedef struct{ + uint32_t val; + } __attribute((__packed__)) unaligned_uint32_t; + + unaligned_uint32_t* dst = (unaligned_uint32_t*)(f->buffer + (wRel * f->item_size)); volatile uint32_t * rx_fifo = (volatile uint32_t *) data; - CFG_TUSB_MEM_ALIGN uint32_t tmp; // Write full words of linear part to buffer uint16_t full_words = nLin >> 2; - uint8_t rem = nLin - (full_words << 2); while(full_words--) { - tmp = *rx_fifo; - memcpy(dst_u8, &tmp, 4); - // dst_u8[0] = tmp & 0x000000FF; - // dst_u8[1] = (tmp & 0x0000FF00) >> 8; - // dst_u8[2] = (tmp & 0x00FF0000) >> 16; - // dst_u8[3] = (tmp & 0xFF000000) >> 24; - dst_u8 += 4; + dst->val = *rx_fifo; + dst++; } + uint8_t * dst_u8; + uint8_t rem = nLin & 0x03; // Handle wrap around if (rem > 0) { + dst_u8 = (uint8_t *)dst; uint8_t remrem = tu_min16(nWrap, 4-rem); nWrap -= remrem; - tmp = *rx_fifo; + uint32_t tmp = *rx_fifo; uint8_t * src_u8 = ((uint8_t *) &tmp); while(rem--) { @@ -299,25 +308,32 @@ static void _ff_pull_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint16_t rRel, uint16_t nLin = (f->depth - rRel) * f->item_size; uint16_t nWrap = (n - nLin) * f->item_size; + // Optimize for fast word copies + typedef struct{ + uint32_t val; + } __attribute((__packed__)) unaligned_uint32_t; + + unaligned_uint32_t* src = (unaligned_uint32_t*)(f->buffer + (rRel * f->item_size)); + volatile uint32_t * tx_fifo = (volatile uint32_t *) p_buffer; - uint8_t * src_u8 = f->buffer + (rRel * f->item_size); - CFG_TUSB_MEM_ALIGN uint32_t tmp; // Pushing full available 32 bit words to FIFO uint16_t full_words = nLin >> 2; - uint8_t rem = nLin - (full_words << 2); while(full_words--) { - memcpy(&tmp, src_u8, 4); - *tx_fifo = tmp; - src_u8 += 4; + *tx_fifo = src->val; + src++; } + uint8_t * src_u8; + uint8_t rem = nLin & 0x03; // Handle wrap around - do it manually as these are only 4 bytes and its faster without memcpy if (rem > 0) { + src_u8 = (uint8_t *) src; uint8_t remrem = tu_min16(nWrap, 4-rem); nWrap -= remrem; + uint32_t tmp; uint8_t * dst_u8 = (uint8_t *)&tmp; while(rem--) { From 994dddc231c3b7d52e16e5b42d8c42a84e664622 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Thu, 25 Mar 2021 14:38:55 +0100 Subject: [PATCH 073/121] Fix shadowing parameter in fifo.c --- src/common/tusb_fifo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index c131a1910..d05549e3e 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -129,11 +129,11 @@ static void _tu_fifo_read_from_const_src_ptr_in_full_words(void * dst, const voi if(bytes_rem != 0) { uint8_t * dst_u8 = (uint8_t *)dst_una; uint32_t tmp = *rx_fifo; - uint8_t * src = (uint8_t *) &tmp; + uint8_t * src_u8 = (uint8_t *) &tmp; while(bytes_rem--) { - *dst_u8++ = *src++; + *dst_u8++ = *src_u8++; } } } From 9b2ddd9cc6401b80350179d26e842557f9b60aaf Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sat, 3 Apr 2021 09:49:27 +0200 Subject: [PATCH 074/121] Generalize audio driver for 3 audio functions plus a lot more. - Audio format and parameters are parsed from descriptors thus user no longer needs to give them explicitely - Tested for 4 channel software type I PCM encoding with 16 bit with 1 channel per FIFO and 2 channels per FIFO (this is I2S specific) --- examples/device/audio_test/src/main.c | 8 +- examples/device/audio_test/src/tusb_config.h | 22 +- .../device/audio_test/src/usb_descriptors.c | 11 +- .../device/uac2_headset/src/tusb_config.h | 34 +- .../device/uac2_headset/src/usb_descriptors.c | 2 +- src/class/audio/audio.h | 70 +- src/class/audio/audio_device.c | 1092 +++++++++++++---- src/class/audio/audio_device.h | 329 +++-- src/common/tusb_fifo.c | 4 +- src/device/usbd.h | 59 +- 10 files changed, 1221 insertions(+), 410 deletions(-) diff --git a/examples/device/audio_test/src/main.c b/examples/device/audio_test/src/main.c index a631f37b6..7cbf57946 100644 --- a/examples/device/audio_test/src/main.c +++ b/examples/device/audio_test/src/main.c @@ -53,17 +53,17 @@ static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; // Audio controls // Current states -bool mute[CFG_TUD_AUDIO_N_CHANNELS_TX + 1]; // +1 for master channel 0 -uint16_t volume[CFG_TUD_AUDIO_N_CHANNELS_TX + 1]; // +1 for master channel 0 +bool mute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master channel 0 +uint16_t volume[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master channel 0 uint32_t sampFreq; uint8_t clkValid; // Range states -audio_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_N_CHANNELS_TX+1]; // Volume range state +audio_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX+1]; // Volume range state audio_control_range_4_n_t(1) sampleFreqRng; // Sample frequency range state // Audio test data -uint16_t test_buffer_audio[CFG_TUD_AUDIO_EPSIZE_IN/2]; +uint16_t test_buffer_audio[CFG_TUD_AUDIO_EP_SZ_IN/2]; uint16_t startVal = 0; void led_blinking_task(void); diff --git a/examples/device/audio_test/src/tusb_config.h b/examples/device/audio_test/src/tusb_config.h index 557a8b15e..d3b617319 100644 --- a/examples/device/audio_test/src/tusb_config.h +++ b/examples/device/audio_test/src/tusb_config.h @@ -91,6 +91,21 @@ extern "C" { // AUDIO CLASS DRIVER CONFIGURATION //-------------------------------------------------------------------- +// Have a look into audio_device.h for all configurations + +#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_MIC_ONE_CH_DESC_LEN +#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1 // Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes) +#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 // Size of control request buffer + +#define CFG_TUD_AUDIO_ENABLE_EP_IN 1 +#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX 2 // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below +#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 1 // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below - be aware: for different number of channels you need another descriptor! +#define CFG_TUD_AUDIO_EP_SZ_IN 48 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX // 48 Samples (48 kHz) x 2 Bytes/Sample x 1 Channel +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX CFG_TUD_AUDIO_EP_SZ_IN +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ CFG_TUD_AUDIO_EP_SZ_IN + 1 + + + // Audio format type #define CFG_TUD_AUDIO_FORMAT_TYPE_TX AUDIO_FORMAT_TYPE_I @@ -100,14 +115,11 @@ extern "C" { #define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX 2 // EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense) +#define CFG_TUD_AUDIO_ENABLE_EP_IN 1 #define CFG_TUD_AUDIO_EPSIZE_IN 48 * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_N_CHANNELS_TX // ceil(f_s/1000) * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_N_CHANNELS_TX -#define CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE CFG_TUD_AUDIO_EPSIZE_IN + CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_N_CHANNELS_TX // Just for safety one sample more space +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ CFG_TUD_AUDIO_EPSIZE_IN + CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_N_CHANNELS_TX // Just for safety one sample more space -// Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes) -#define CFG_TUD_AUDIO_N_AS_INT 1 -// Size of control request buffer -#define CFG_TUD_AUDIO_CTRL_BUF_SIZE 64 #ifdef __cplusplus } diff --git a/examples/device/audio_test/src/usb_descriptors.c b/examples/device/audio_test/src/usb_descriptors.c index d4869a940..67dd34d2a 100644 --- a/examples/device/audio_test/src/usb_descriptors.c +++ b/examples/device/audio_test/src/usb_descriptors.c @@ -79,7 +79,7 @@ enum ITF_NUM_TOTAL }; -#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_AUDIO * TUD_AUDIO_MIC_DESC_LEN) +#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_AUDIO * TUD_AUDIO_MIC_ONE_CH_DESC_LEN) #if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number @@ -89,20 +89,13 @@ enum #define EPNUM_AUDIO 0x01 #endif -// These variables are required by the audio driver in audio_device.c - -// List of audio descriptor lengths which is required by audio driver - you need as many entries as CFG_TUD_AUDIO - unfortunately this is not possible to determine otherwise -const uint16_t tud_audio_desc_lengths[] = {TUD_AUDIO_MIC_DESC_LEN}; - -// TAKE CARE - THE NUMBER OF AUDIO STREAMING INTERFACES PER AUDIO FUNCTION MUST NOT EXCEED CFG_TUD_AUDIO_N_AS_INT - IF IT DOES INCREASE CFG_TUD_AUDIO_N_AS_INT IN tusb_config.h! - uint8_t const desc_configuration[] = { // Interface count, string index, total length, attribute, power in mA TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), // Interface number, string index, EP Out & EP In address, EP size - TUD_AUDIO_MIC_DESCRIPTOR(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_stridx*/ 0, /*_nBytesPerSample*/ CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX, /*_nBitsUsedPerSample*/ 16, /*_epin*/ 0x80 | EPNUM_AUDIO, /*_epsize*/ CFG_TUD_AUDIO_EPSIZE_IN) + TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_stridx*/ 0, /*_nBytesPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, /*_nBitsUsedPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX*8, /*_epin*/ 0x80 | EPNUM_AUDIO, /*_epsize*/ CFG_TUD_AUDIO_EP_SZ_IN) }; // Invoked when received GET CONFIGURATION DESCRIPTOR diff --git a/examples/device/uac2_headset/src/tusb_config.h b/examples/device/uac2_headset/src/tusb_config.h index 7795d8405..511e4e558 100644 --- a/examples/device/uac2_headset/src/tusb_config.h +++ b/examples/device/uac2_headset/src/tusb_config.h @@ -91,35 +91,31 @@ extern "C" { //-------------------------------------------------------------------- // AUDIO CLASS DRIVER CONFIGURATION //-------------------------------------------------------------------- -#define CFG_TUD_AUDIO_IN_PATH (CFG_TUD_AUDIO) -#define CFG_TUD_AUDIO_OUT_PATH (CFG_TUD_AUDIO) - -// Audio format type -#define CFG_TUD_AUDIO_FORMAT_TYPE_TX AUDIO_FORMAT_TYPE_I -#define CFG_TUD_AUDIO_FORMAT_TYPE_RX AUDIO_FORMAT_TYPE_I +#define CFG_TUD_AUDIO_IN_PATH (CFG_TUD_AUDIO) +#define CFG_TUD_AUDIO_OUT_PATH (CFG_TUD_AUDIO) // Audio format type I specifications -#define CFG_TUD_AUDIO_FORMAT_TYPE_I_TX AUDIO_DATA_FORMAT_TYPE_I_PCM -#define CFG_TUD_AUDIO_FORMAT_TYPE_I_RX AUDIO_DATA_FORMAT_TYPE_I_PCM -#define CFG_TUD_AUDIO_N_CHANNELS_TX 1 -#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX 2 -#define CFG_TUD_AUDIO_N_CHANNELS_RX 2 -#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX 2 -#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 0 +#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 1 +#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX 2 +#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX 2 +#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX 2 +#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 0 // EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense) -#define CFG_TUD_AUDIO_EPSIZE_IN (CFG_TUD_AUDIO_IN_PATH * (48 + 1) * (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX) * (CFG_TUD_AUDIO_N_CHANNELS_TX)) // 48 Samples (48 kHz) x 2 Bytes/Sample x n Channels -#define CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE CFG_TUD_AUDIO_EPSIZE_IN +#define CFG_TUD_AUDIO_ENABLE_EP_IN 1 +#define CFG_TUD_AUDIO_EP_SZ_IN (CFG_TUD_AUDIO_IN_PATH * (48 + 1) * (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX) * (CFG_TUD_AUDIO_N_CHANNELS_TX)) // 48 Samples (48 kHz) x 2 Bytes/Sample x n Channels +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ CFG_TUD_AUDIO_EPSIZE_IN // EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense) -#define CFG_TUD_AUDIO_EPSIZE_OUT (CFG_TUD_AUDIO_OUT_PATH * ((48 + CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP) * (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX) * (CFG_TUD_AUDIO_N_CHANNELS_RX))) // N Samples (N kHz) x 2 Bytes/Sample x n Channels -#define CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE CFG_TUD_AUDIO_EPSIZE_OUT*3 +#define CFG_TUD_AUDIO_ENABLE_EP_OUT 1 +#define CFG_TUD_AUDIO_EP_OUT_SZ (CFG_TUD_AUDIO_OUT_PATH * ((48 + CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP) * (CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX) * (CFG_TUD_AUDIO_N_CHANNELS_RX))) // N Samples (N kHz) x 2 Bytes/Sample x n Channels +#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ CFG_TUD_AUDIO_EP_OUT_SZ*3 // Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes) -#define CFG_TUD_AUDIO_N_AS_INT 1 +#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1 // Size of control request buffer -#define CFG_TUD_AUDIO_CTRL_BUF_SIZE 64 +#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 #ifdef __cplusplus } diff --git a/examples/device/uac2_headset/src/usb_descriptors.c b/examples/device/uac2_headset/src/usb_descriptors.c index 940f0fe2b..b69e5a5e0 100644 --- a/examples/device/uac2_headset/src/usb_descriptors.c +++ b/examples/device/uac2_headset/src/usb_descriptors.c @@ -98,7 +98,7 @@ uint8_t const desc_configuration[] = TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), // Interface number, string index, EP Out & EP In address, EP size - TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR(2, 2, 16, EPNUM_AUDIO, CFG_TUD_AUDIO_EPSIZE_OUT, EPNUM_AUDIO | 0x80, CFG_TUD_AUDIO_EPSIZE_IN) + TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR(2, 2, 16, EPNUM_AUDIO, CFG_TUD_AUDIO_EP_OUT_SZ, EPNUM_AUDIO | 0x80, CFG_TUD_AUDIO_EP_SZ_IN) }; // Invoked when received GET CONFIGURATION DESCRIPTOR diff --git a/src/class/audio/audio.h b/src/class/audio/audio.h index af0e86e21..2c6cd260a 100644 --- a/src/class/audio/audio.h +++ b/src/class/audio/audio.h @@ -469,44 +469,44 @@ typedef enum /// Additional Audio Device Class Codes - Source: Audio Data Formats /// A.1 - Audio Class-Format Type Codes UAC2 -//typedef enum -//{ -// AUDIO_FORMAT_TYPE_UNDEFINED = 0x00, -// AUDIO_FORMAT_TYPE_I = 0x01, -// AUDIO_FORMAT_TYPE_II = 0x02, -// AUDIO_FORMAT_TYPE_III = 0x03, -// AUDIO_FORMAT_TYPE_IV = 0x04, -// AUDIO_EXT_FORMAT_TYPE_I = 0x81, -// AUDIO_EXT_FORMAT_TYPE_II = 0x82, -// AUDIO_EXT_FORMAT_TYPE_III = 0x83, -//} audio_format_type_t; +typedef enum +{ + AUDIO_FORMAT_TYPE_UNDEFINED = 0x00, + AUDIO_FORMAT_TYPE_I = 0x01, + AUDIO_FORMAT_TYPE_II = 0x02, + AUDIO_FORMAT_TYPE_III = 0x03, + AUDIO_FORMAT_TYPE_IV = 0x04, + AUDIO_EXT_FORMAT_TYPE_I = 0x81, + AUDIO_EXT_FORMAT_TYPE_II = 0x82, + AUDIO_EXT_FORMAT_TYPE_III = 0x83, +} audio_format_type_t; -#define AUDIO_FORMAT_TYPE_UNDEFINED 0x00 -#define AUDIO_FORMAT_TYPE_I 0x01 -#define AUDIO_FORMAT_TYPE_II 0x02 -#define AUDIO_FORMAT_TYPE_III 0x03 -#define AUDIO_FORMAT_TYPE_IV 0x04 -#define AUDIO_EXT_FORMAT_TYPE_I 0x81 -#define AUDIO_EXT_FORMAT_TYPE_II 0x82 -#define AUDIO_EXT_FORMAT_TYPE_III 0x83 +//#define AUDIO_FORMAT_TYPE_UNDEFINED 0x00 +//#define AUDIO_FORMAT_TYPE_I 0x01 +//#define AUDIO_FORMAT_TYPE_II 0x02 +//#define AUDIO_FORMAT_TYPE_III 0x03 +//#define AUDIO_FORMAT_TYPE_IV 0x04 +//#define AUDIO_EXT_FORMAT_TYPE_I 0x81 +//#define AUDIO_EXT_FORMAT_TYPE_II 0x82 +//#define AUDIO_EXT_FORMAT_TYPE_III 0x83 -/// A.2.1 - Audio Class-Audio Data Format Type I UAC2 -//typedef enum -//{ -// AUDIO_DATA_FORMAT_TYPE_I_PCM = (uint32_t) (1 << 0), -// AUDIO_DATA_FORMAT_TYPE_I_PCM8 = (uint32_t) (1 << 1), -// AUDIO_DATA_FORMAT_TYPE_I_IEEE_FLOAT = (uint32_t) (1 << 2), -// AUDIO_DATA_FORMAT_TYPE_I_ALAW = (uint32_t) (1 << 3), -// AUDIO_DATA_FORMAT_TYPE_I_MULAW = (uint32_t) (1 << 4), -// AUDIO_DATA_FORMAT_TYPE_I_RAW_DATA = 0x100000000, -//} audio_data_format_type_I_t; +// A.2.1 - Audio Class-Audio Data Format Type I UAC2 +typedef enum +{ + AUDIO_DATA_FORMAT_TYPE_I_PCM = (uint32_t) (1 << 0), + AUDIO_DATA_FORMAT_TYPE_I_PCM8 = (uint32_t) (1 << 1), + AUDIO_DATA_FORMAT_TYPE_I_IEEE_FLOAT = (uint32_t) (1 << 2), + AUDIO_DATA_FORMAT_TYPE_I_ALAW = (uint32_t) (1 << 3), + AUDIO_DATA_FORMAT_TYPE_I_MULAW = (uint32_t) (1 << 4), + AUDIO_DATA_FORMAT_TYPE_I_RAW_DATA = 0x100000000, +} audio_data_format_type_I_t; -#define AUDIO_DATA_FORMAT_TYPE_I_PCM ((uint32_t) (1 << 0)) -#define AUDIO_DATA_FORMAT_TYPE_I_PCM8 ((uint32_t) (1 << 1)) -#define AUDIO_DATA_FORMAT_TYPE_I_IEEE_FLOAT ((uint32_t) (1 << 2)) -#define AUDIO_DATA_FORMAT_TYPE_I_ALAW ((uint32_t) (1 << 3)) -#define AUDIO_DATA_FORMAT_TYPE_I_MULAW ((uint32_t) (1 << 4)) -#define AUDIO_DATA_FORMAT_TYPE_I_RAW_DATA 0x100000000 +//#define AUDIO_DATA_FORMAT_TYPE_I_PCM ((uint32_t) (1 << 0)) +//#define AUDIO_DATA_FORMAT_TYPE_I_PCM8 ((uint32_t) (1 << 1)) +//#define AUDIO_DATA_FORMAT_TYPE_I_IEEE_FLOAT ((uint32_t) (1 << 2)) +//#define AUDIO_DATA_FORMAT_TYPE_I_ALAW ((uint32_t) (1 << 3)) +//#define AUDIO_DATA_FORMAT_TYPE_I_MULAW ((uint32_t) (1 << 4)) +//#define AUDIO_DATA_FORMAT_TYPE_I_RAW_DATA 0x100000000 /// All remaining definitions are taken from the descriptor descriptions in the UAC2 main specification diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 73f265a8f..5df32c30f 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -63,7 +63,7 @@ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ - // Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically +// Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically #if ( CFG_TUSB_MCU == OPT_MCU_MKL25ZXX || /* Intermediate software buffer required */ \ CFG_TUSB_MCU == OPT_MCU_DA1469X || /* Intermediate software buffer required */ \ CFG_TUSB_MCU == OPT_MCU_LPC18XX || /* No clue how driver works */ \ @@ -92,18 +92,170 @@ #define USE_LINEAR_BUFFER 0 #endif +// Declaration of buffers + +// Check for maximum supported numbers +#if CFG_TUD_AUDIO > 3 +#error Maximum number of audio functions restricted to three! +#endif + +// EP IN software buffers and mutexes +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING +#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 +CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t ep_in_ff_mutex_wr_1; // No need for read mutex as only USB driver reads from FIFO +#endif +#endif // CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 +CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t ep_in_ff_mutex_wr_2; // No need for read mutex as only USB driver reads from FIFO +#endif +#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 +CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t ep_in_ff_mutex_wr_3; // No need for read mutex as only USB driver reads from FIFO +#endif +#endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 +#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING + +// Linear buffer TX in case: +// - target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR +// - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into +#if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING) +#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0 +CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX]; +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0 +CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX]; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0 +CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX]; +#endif +#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) + +// EP OUT software buffers and mutexes +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING +#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 +CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t ep_out_ff_mutex_rd_1; // No need for write mutex as only USB driver writes into FIFO +#endif +#endif // CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 +CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t ep_out_ff_mutex_rd_2; // No need for write mutex as only USB driver writes into FIFO +#endif +#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 +CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t ep_out_ff_mutex_rd_3; // No need for write mutex as only USB driver writes into FIFO +#endif +#endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 +#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING + +// Linear buffer RX in case: +// - target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR +// - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) +#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0 +CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX]; +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0 +CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX]; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0 +CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX]; +#endif +#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) + +// Control buffers +CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ]; +#if CFG_TUD_AUDIO > 1 +CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ]; +#endif +#if CFG_TUD_AUDIO > 2 +CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ]; +#endif + +// Active alternate setting of interfaces +#if CFG_TUD_AUDIO_FUNC_1_N_AS_INT > 0 +CFG_TUSB_MEM_ALIGN uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT]; +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0 +CFG_TUSB_MEM_ALIGN uint8_t alt_setting_2[CFG_TUD_AUDIO_FUNC_2_N_AS_INT]; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0 +CFG_TUSB_MEM_ALIGN uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT]; +#endif + +// Software encoding/decoding support FIFOs +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING +#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 +CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ]; +tu_fifo_t tx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t tx_supp_ff_mutex_wr_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO +#endif +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 +CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ]; +tu_fifo_t tx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t tx_supp_ff_mutex_wr_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO +#endif +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0 +CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ]; +tu_fifo_t tx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t tx_supp_ff_mutex_wr_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO +#endif +#endif +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING +#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 +CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ]; +tu_fifo_t rx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t rx_supp_ff_mutex_rd_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO +#endif +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 +CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ]; +tu_fifo_t rx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t rx_supp_ff_mutex_rd_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO +#endif +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0 +CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ]; +tu_fifo_t rx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t rx_supp_ff_mutex_rd_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO +#endif +#endif +#endif + typedef struct { uint8_t rhport; uint8_t const * p_desc; // Pointer pointing to Standard AC Interface Descriptor(4.7.1) - Audio Control descriptor defining audio function -#if CFG_TUD_AUDIO_EPSIZE_IN +#if CFG_TUD_AUDIO_ENABLE_EP_IN uint8_t ep_in; // TX audio data EP. + uint16_t ep_in_sz; // Current size of TX EP uint8_t ep_in_as_intf_num; // Corresponding Standard AS Interface Descriptor (4.9.1) belonging to output terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero) #endif -#if CFG_TUD_AUDIO_EPSIZE_OUT +#if CFG_TUD_AUDIO_ENABLE_EP_OUT uint8_t ep_out; // Incoming (into uC) audio data EP. + uint16_t ep_out_sz; // Current size of RX EP uint8_t ep_out_as_intf_num; // Corresponding Standard AS Interface Descriptor (4.9.1) belonging to input terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero) #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP @@ -116,74 +268,83 @@ typedef struct uint8_t ep_int_ctr; // Audio control interrupt EP. #endif -#if CFG_TUD_AUDIO_N_AS_INT - uint8_t altSetting[CFG_TUD_AUDIO_N_AS_INT]; // We need to save the current alternate setting this way, because it is possible that there are AS interfaces which do not have an EP! +#if CFG_TUD_AUDIO_FUNC_1_N_AS_INT > 0 || CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0 || CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0 + uint8_t * alt_setting_ptr; // We need to save the current alternate setting this way, because it is possible that there are AS interfaces which do not have an EP! #endif /*------------- From this point, data is not cleared by bus reset -------------*/ + // + uint16_t desc_length; // Length of audio function descriptor + // Buffer for control requests - CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf[CFG_TUD_AUDIO_CTRL_BUF_SIZE]; + uint8_t * ctrl_buf; + uint8_t ctrl_buf_sz; // EP Transfer buffers and FIFOs -#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE - -#if !CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE - CFG_TUSB_MEM_ALIGN uint8_t ep_out_buf[CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE]; +#if CFG_TUD_AUDIO_ENABLE_EP_OUT +#if !CFG_TUD_AUDIO_ENABLE_DECODING tu_fifo_t ep_out_ff; - -#if CFG_FIFO_MUTEX - osal_mutex_def_t ep_out_ff_mutex_rd; // No need for write mutex as only USB driver writes into FIFO -#endif - #endif #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP uint32_t fb_val; // Feedback value for asynchronous mode (in 16.16 format). #endif - #endif -#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE && !CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE - CFG_TUSB_MEM_ALIGN uint8_t ep_in_buf[CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE]; +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING tu_fifo_t ep_in_ff; - -#if CFG_FIFO_MUTEX - osal_mutex_def_t ep_in_ff_mutex_wr; // No need for read mutex as only USB driver reads from FIFO #endif -#endif - - // Audio control interrupt buffer - no FIFO + // Audio control interrupt buffer - no FIFO - 6 Bytes according to UAC 2 specification (p. 74) #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE]; #endif - // Support FIFOs -#if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE - tu_fifo_t tx_supp_ff[CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO]; - CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf[CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO][CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX]; -#if CFG_FIFO_MUTEX - osal_mutex_def_t tx_supp_ff_mutex_wr[CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO + // Decoding parameters - parameters are set when alternate AS interface is set by host + // Coding is currently only supported for EP. Software coding corresponding to AS interfaces without EPs are not supported currently. +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING + audio_format_type_t format_type_rx; + uint8_t n_channels_rx; + +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING + audio_data_format_type_I_t format_type_I_rx; + uint8_t n_bytes_per_sampe_rx; #endif #endif -#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE - tu_fifo_t rx_supp_ff[CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO]; - CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf[CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO][CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX]; -#if CFG_FIFO_MUTEX - osal_mutex_def_t rx_supp_ff_mutex_rd[CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO + // Encoding parameters - parameters are set when alternate AS interface is set by host +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING + audio_format_type_t format_type_tx; + uint8_t n_channels_tx; + +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING + audio_data_format_type_I_t format_type_I_tx; + uint8_t n_bytes_per_sampe_tx; + uint8_t n_channels_per_ff_tx; #endif #endif + // Support FIFOs for software encoding and decoding +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING + tu_fifo_t * rx_supp_ff; + uint8_t n_rx_supp_ff; + uint8_t n_channels_per_ff_rx; +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING + tu_fifo_t * tx_supp_ff; + uint8_t n_tx_supp_ff; +#endif + // Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR the support FIFOs are used -#if CFG_TUD_AUDIO_EPSIZE_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE) - CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out[CFG_TUD_AUDIO_EPSIZE_OUT]; +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) + uint8_t * lin_buf_out; #define USE_LINEAR_BUFFER_RX 1 #endif -#if CFG_TUD_AUDIO_EPSIZE_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE) - CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in[CFG_TUD_AUDIO_EPSIZE_IN]; +#if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING) + uint8_t * lin_buf_in; #define USE_LINEAR_BUFFER_TX 1 #endif @@ -204,30 +365,19 @@ typedef struct //--------------------------------------------------------------------+ CFG_TUSB_MEM_SECTION audiod_interface_t _audiod_itf[CFG_TUD_AUDIO]; -extern const uint16_t tud_audio_desc_lengths[]; - -// bSubslotSize for PCM encoding/decoding using support FIFOs -#if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE -extern const tud_audio_n_bytes_per_sample_tx[CFG_TUD_AUDIO][CFG_TUD_AUDIO_N_AS_INT]; -#endif - -#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE -extern const tud_audio_n_bytes_per_sample_rx[CFG_TUD_AUDIO][CFG_TUD_AUDIO_N_AS_INT]; -#endif - -#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE +#if CFG_TUD_AUDIO_ENABLE_EP_OUT static bool audiod_rx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint16_t n_bytes_received); #endif -#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_OUT +#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio, uint16_t n_bytes_received); #endif -#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE +#if CFG_TUD_AUDIO_ENABLE_EP_IN static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t* audio); #endif -#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_IN +#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio); #endif @@ -238,17 +388,23 @@ static bool audiod_get_AS_interface_index(uint8_t itf, uint8_t *idxDriver, uint8 static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *idxDriver); static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *idxDriver); static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *idxDriver); +static void audiod_parse_for_AS_params(audiod_interface_t* audio, uint8_t const * p_desc, uint8_t const * p_desc_end, uint8_t const itf); + +static inline uint8_t tu_desc_subtype(void const* desc) +{ + return ((uint8_t const*) desc)[2]; +} bool tud_audio_n_mounted(uint8_t itf) { TU_VERIFY(itf < CFG_TUD_AUDIO); audiod_interface_t* audio = &_audiod_itf[itf]; -#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE +#if CFG_TUD_AUDIO_ENABLE_EP_OUT if (audio->ep_out == 0) return false; #endif -#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE +#if CFG_TUD_AUDIO_ENABLE_EP_IN if (audio->ep_in == 0) return false; #endif @@ -267,7 +423,7 @@ bool tud_audio_n_mounted(uint8_t itf) // READ API //--------------------------------------------------------------------+ -#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && !CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING uint16_t tud_audio_n_available(uint8_t itf) { @@ -289,50 +445,46 @@ bool tud_audio_n_clear_ep_out_ff(uint8_t itf) #endif -#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_OUT +#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT // Delete all content in the support RX FIFOs bool tud_audio_n_clear_rx_support_ff(uint8_t itf, uint8_t channelId) { - TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO); + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < _audiod_itf[itf].n_rx_supp_ff); return tu_fifo_clear(&_audiod_itf[itf].rx_supp_ff[channelId]); } uint16_t tud_audio_n_available_support_ff(uint8_t itf, uint8_t channelId) { - TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO); + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < _audiod_itf[itf].n_rx_supp_ff); return tu_fifo_count(&_audiod_itf[itf].rx_supp_ff[channelId]); } uint16_t tud_audio_n_read_support_ff(uint8_t itf, uint8_t channelId, void* buffer, uint16_t bufsize) { - TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO); + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < _audiod_itf[itf].n_rx_supp_ff); return tu_fifo_read_n(&_audiod_itf[itf].rx_supp_ff[channelId], buffer, bufsize); } #endif // This function is called once an audio packet is received by the USB and is responsible for putting data from USB memory into EP_OUT_FIFO (or support FIFOs + decoding of received stream into audio channels). -// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE = 0. +// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_ENABLE_DECODING = 0. -#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE +#if CFG_TUD_AUDIO_ENABLE_EP_OUT static bool audiod_rx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint16_t n_bytes_received) { uint8_t idxDriver, idxItf; uint8_t const *dummy2; - // If a callback is used determine current alternate setting of - if (tud_audio_rx_done_pre_read_cb || tud_audio_rx_done_post_read_cb) - { - // Find index of audio streaming interface and index of interface - TU_VERIFY(audiod_get_AS_interface_index(audio->ep_out_as_intf_num, &idxDriver, &idxItf, &dummy2)); - } + // Find index of audio streaming interface and index of interface + TU_VERIFY(audiod_get_AS_interface_index(audio->ep_out_as_intf_num, &idxDriver, &idxItf, &dummy2)); // Call a weak callback here - a possibility for user to get informed an audio packet was received and data gets now loaded into EP FIFO (or decoded into support RX software FIFO) - if (tud_audio_rx_done_pre_read_cb) TU_VERIFY(tud_audio_rx_done_pre_read_cb(rhport, n_bytes_received, idxDriver, audio->ep_out, audio->altSetting[idxItf])); + if (tud_audio_rx_done_pre_read_cb) TU_VERIFY(tud_audio_rx_done_pre_read_cb(rhport, n_bytes_received, idxDriver, audio->ep_out, audio->alt_setting_ptr[idxItf])); -#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_OUT +#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT - switch (CFG_TUD_AUDIO_FORMAT_TYPE_RX) + switch (audio->format_type_rx) { case AUDIO_FORMAT_TYPE_UNDEFINED: // INDIVIDUAL DECODING PROCEDURE REQUIRED HERE! @@ -342,7 +494,7 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint16_ case AUDIO_FORMAT_TYPE_I: - switch (CFG_TUD_AUDIO_FORMAT_TYPE_I_RX) + switch (audio->format_type_I_tx) { case AUDIO_DATA_FORMAT_TYPE_I_PCM: TU_VERIFY(audiod_decode_type_I_pcm(rhport, audio, n_bytes_received)); @@ -364,7 +516,7 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint16_ } // Prepare for next transmission - TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, CFG_TUD_AUDIO_EPSIZE_OUT), false); + TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false); #else @@ -373,34 +525,108 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint16_ TU_VERIFY(tu_fifo_write_n(&audio->ep_out_ff, audio->lin_buf_out, n_bytes_received)); // Schedule for next receive - TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, CFG_TUD_AUDIO_EPSIZE_OUT), false); + TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false); #else // Data is already placed in EP FIFO, schedule for next receive - TU_VERIFY(usbd_edpt_iso_xfer(rhport, audio->ep_out, &audio->ep_out_ff, CFG_TUD_AUDIO_EPSIZE_OUT), false); + TU_VERIFY(usbd_edpt_iso_xfer(rhport, audio->ep_out, &audio->ep_out_ff, audio->ep_out_sz), false); #endif #endif // Call a weak callback here - a possibility for user to get informed decoding was completed - if (tud_audio_rx_done_post_read_cb) TU_VERIFY(tud_audio_rx_done_post_read_cb(rhport, n_bytes_received, idxDriver, audio->ep_out, audio->altSetting[idxItf])); + if (tud_audio_rx_done_post_read_cb) TU_VERIFY(tud_audio_rx_done_post_read_cb(rhport, n_bytes_received, idxDriver, audio->ep_out, audio->alt_setting_ptr[idxItf])); return true; } -#endif //CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE +#endif //CFG_TUD_AUDIO_ENABLE_EP_OUT -// The following functions are used in case CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE != 0 -#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_OUT +// The following functions are used in case CFG_TUD_AUDIO_ENABLE_DECODING != 0 +#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT // Decoding according to 2.3.1.5 Audio Streams + +// Helper function +static inline uint8_t * audiod_interleaved_copy_bytes_fast_decode(uint16_t const nBytesToCopy, void * dst, uint8_t * dst_end, uint8_t * src, uint8_t const n_ff_used) +{ + + // This function is an optimized version of +// while((uint8_t *)dst < dst_end) +// { +// memcpy(dst, src, nBytesToCopy); +// dst = (uint8_t *)dst + nBytesToCopy; +// src += nBytesToCopy * n_ff_used; +// } + + // Optimize for fast half word copies + typedef struct{ + uint16_t val; + } __attribute((__packed__)) unaligned_uint16_t; + + // Optimize for fast word copies + typedef struct{ + uint32_t val; + } __attribute((__packed__)) unaligned_uint32_t; + + switch (nBytesToCopy) + { + case 1: + while((uint8_t *)dst < dst_end) + { + *(uint8_t *)dst++ = *src; + src += n_ff_used; + } + break; + + case 2: + while((uint8_t *)dst < dst_end) + { + *(unaligned_uint16_t*)dst = *(unaligned_uint16_t*)src; + dst += 2; + src += 2 * n_ff_used; + } + break; + + case 3: + while((uint8_t *)dst < dst_end) + { +// memcpy(dst, src, 3); +// dst = (uint8_t *)dst + 3; +// src += 3 * n_ff_used; + + // TODO: Is there a faster way to copy 3 bytes? + *(uint8_t *)dst++ = *src++; + *(uint8_t *)dst++ = *src++; + *(uint8_t *)dst++ = *src++; + + src += 3 * (n_ff_used - 1); + } + break; + + case 4: + while((uint8_t *)dst < dst_end) + { + *(unaligned_uint32_t*)dst = *(unaligned_uint32_t*)src; + dst += 4; + src += 4 * n_ff_used; + } + break; + } + + return src; +} + static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio, uint16_t n_bytes_received) { (void) rhport; // Determine amount of samples - uint16_t const nChannelsPerFF = CFG_TUD_AUDIO_N_CHANNELS_RX / CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO; - uint16_t const nBytesToCopy = nChannelsPerFF*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX; - uint16_t const nSamplesPerFFToRead = n_bytes_received / CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX / CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO; + uint8_t const n_ff_used = audio->n_channels_rx / audio->n_channels_per_ff_rx; + + TU_ASSERT( n_ff_used <= audio->n_rx_supp_ff ); + + uint16_t const nBytesToCopy = audio->n_channels_per_ff_rx * audio->n_bytes_per_sampe_rx; + uint16_t const nBytesPerFFToRead = n_bytes_received / n_ff_used; uint8_t cnt_ff; // Decode @@ -409,36 +635,26 @@ static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio, uint8_t * dst_end; uint16_t len; - for (cnt_ff = 0; cnt_ff < CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO; cnt_ff++) + for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++) { - src = &audio->lin_buf_out[cnt_ff*nChannelsPerFF*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX]; + src = &audio->lin_buf_out[cnt_ff*audio->n_channels_per_ff_rx * audio->n_bytes_per_sampe_rx]; - len = tu_fifo_get_linear_write_info(&audio->rx_supp_ff[cnt_ff], 0, &dst, nSamplesPerFFToRead); + len = tu_fifo_get_linear_write_info(&audio->rx_supp_ff[cnt_ff], 0, &dst, nBytesPerFFToRead); tu_fifo_advance_write_pointer(&audio->rx_supp_ff[cnt_ff], len); - dst_end = dst + len * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX; + dst_end = dst + len; - while((uint8_t *)dst < dst_end) - { - memcpy(dst, src, nBytesToCopy); - dst = (uint8_t *)dst + nBytesToCopy; - src += nBytesToCopy * CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO; - } + src = audiod_interleaved_copy_bytes_fast_decode(nBytesToCopy, dst, dst_end, src, n_ff_used); // Handle wrapped part of FIFO - if (len < nSamplesPerFFToRead) + if (len < nBytesPerFFToRead) { - len = tu_fifo_get_linear_write_info(&audio->rx_supp_ff[cnt_ff], 0, &dst, nSamplesPerFFToRead - len); + len = tu_fifo_get_linear_write_info(&audio->rx_supp_ff[cnt_ff], 0, &dst, nBytesPerFFToRead - len); tu_fifo_advance_write_pointer(&audio->rx_supp_ff[cnt_ff], len); - dst_end = dst + len * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX; + dst_end = dst + len; - while((uint8_t *)dst < dst_end) - { - memcpy(dst, src, nBytesToCopy); - dst = (uint8_t *)dst + nBytesToCopy; - src += nBytesToCopy * CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO; - } + audiod_interleaved_copy_bytes_fast_decode(nBytesToCopy, dst, dst_end, src, n_ff_used); } } @@ -447,13 +663,13 @@ static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio, return true; } -#endif //CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE +#endif //CFG_TUD_AUDIO_ENABLE_DECODING //--------------------------------------------------------------------+ // WRITE API //--------------------------------------------------------------------+ -#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE && !CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING /** * \brief Write data to EP in buffer @@ -480,7 +696,7 @@ bool tud_audio_n_clear_ep_in_ff(uint8_t itf) // Delete #endif -#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_IN +#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN uint16_t tud_audio_n_flush_tx_support_ff(uint8_t itf) // Force all content in the support TX FIFOs to be written into linear buffer and schedule a transmit { TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL); @@ -498,13 +714,13 @@ uint16_t tud_audio_n_flush_tx_support_ff(uint8_t itf) // Force a bool tud_audio_n_clear_tx_support_ff(uint8_t itf, uint8_t channelId) { - TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO); + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < _audiod_itf[itf].n_tx_supp_ff); return tu_fifo_clear(&_audiod_itf[itf].tx_supp_ff[channelId]); } uint16_t tud_audio_n_write_support_ff(uint8_t itf, uint8_t channelId, const void * data, uint16_t len) { - TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO); + TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < _audiod_itf[itf].n_tx_supp_ff); return tu_fifo_write_n(&_audiod_itf[itf].tx_supp_ff[channelId], data, len); } #endif @@ -534,42 +750,44 @@ uint16_t tud_audio_int_ctr_n_write(uint8_t itf, uint8_t const* buffer, uint16_t // This function is called once a transmit of an audio packet was successfully completed. Here, we encode samples and place it in IN EP's buffer for next transmission. -// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE = 0 and use tud_audio_n_write. +// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_ENABLE_ENCODING = 0 and use tud_audio_n_write. // n_bytes_copied - Informs caller how many bytes were loaded. In case n_bytes_copied = 0, a ZLP is scheduled to inform host no data is available for current frame. -#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE +#if CFG_TUD_AUDIO_ENABLE_EP_IN static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t * audio) { uint8_t idxDriver, idxItf; uint8_t const *dummy2; - // If a callback is used determine current alternate setting of - if (tud_audio_tx_done_pre_load_cb || tud_audio_tx_done_post_load_cb) - { - // Find index of audio streaming interface and index of interface - TU_VERIFY(audiod_get_AS_interface_index(audio->ep_in_as_intf_num, &idxDriver, &idxItf, &dummy2)); - } +#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_FORMAT_TYPE_TX == AUDIO_FORMAT_TYPE_I + // Required in any case regardless if call backs are used - find index of audio streaming interface and index of interface + TU_VERIFY(audiod_get_AS_interface_index(audio->ep_in_as_intf_num, &idxDriver, &idxItf, &dummy2)); +#else + // If a callback is used determine current alternate setting of - find index of audio streaming interface and index of interface + if (tud_audio_tx_done_pre_load_cb || tud_audio_tx_done_post_load_cb) TU_VERIFY(audiod_get_AS_interface_index(audio->ep_in_as_intf_num, &idxDriver, &idxItf, &dummy2)); +#endif // Call a weak callback here - a possibility for user to get informed former TX was completed and data gets now loaded into EP in buffer (in case FIFOs are used) or // if no FIFOs are used the user may use this call back to load its data into the EP IN buffer by use of tud_audio_n_write_ep_in_buffer(). - if (tud_audio_tx_done_pre_load_cb) TU_VERIFY(tud_audio_tx_done_pre_load_cb(rhport, idxDriver, audio->ep_in, audio->altSetting[idxItf])); + if (tud_audio_tx_done_pre_load_cb) TU_VERIFY(tud_audio_tx_done_pre_load_cb(rhport, idxDriver, audio->ep_in, audio->alt_setting_ptr[idxItf])); // Send everything in ISO EP FIFO uint16_t n_bytes_tx; // If support FIFOs are used, encode and schedule transmit -#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_IN - switch (CFG_TUD_AUDIO_FORMAT_TYPE_TX) +#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN + switch (audio->format_type_tx) { case AUDIO_FORMAT_TYPE_UNDEFINED: // INDIVIDUAL ENCODING PROCEDURE REQUIRED HERE! TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT encoding not implemented!\r\n"); TU_BREAKPOINT(); + n_bytes_tx = 0; break; case AUDIO_FORMAT_TYPE_I: - switch (CFG_TUD_AUDIO_FORMAT_TYPE_I_TX) + switch (audio->format_type_I_tx) { case AUDIO_DATA_FORMAT_TYPE_I_PCM: @@ -580,6 +798,7 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t * audio) // YOUR ENCODING IS REQUIRED HERE! TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_I_TX encoding not implemented!\r\n"); TU_BREAKPOINT(); + n_bytes_tx = 0; break; } break; @@ -588,6 +807,7 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t * audio) // Desired CFG_TUD_AUDIO_FORMAT_TYPE_TX not implemented! TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_TX not implemented!\r\n"); TU_BREAKPOINT(); + n_bytes_tx = 0; break; } @@ -596,27 +816,27 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t * audio) #else // No support FIFOs, if no linear buffer required schedule transmit, else put data into linear buffer and schedule - n_bytes_tx = tu_fifo_count(&audio->ep_in_ff); + n_bytes_tx = tu_min16(tu_fifo_count(&audio->ep_in_ff), audio->ep_in_sz); // Limit up to max packet size, more can not be done for ISO - #if USE_LINEAR_BUFFER_TX - tu_fifo_write_n(&audio->ep_in_ff, audio->lin_buf_in, n_bytes_tx); - TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->lin_buf_in, n_bytes_tx)); - #else - // Send everything in ISO EP FIFO - TU_VERIFY(usbd_edpt_iso_xfer(rhport, audio->ep_in, &audio->ep_in_ff, n_bytes_tx)); - #endif +#if USE_LINEAR_BUFFER_TX + tu_fifo_read_n(&audio->ep_in_ff, audio->lin_buf_in, n_bytes_tx); + TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->lin_buf_in, n_bytes_tx)); +#else + // Send everything in ISO EP FIFO + TU_VERIFY(usbd_edpt_iso_xfer(rhport, audio->ep_in, &audio->ep_in_ff, n_bytes_tx)); +#endif #endif // Call a weak callback here - a possibility for user to get informed former TX was completed and how many bytes were loaded for the next frame - if (tud_audio_tx_done_post_load_cb) TU_VERIFY(tud_audio_tx_done_post_load_cb(rhport, n_bytes_tx, idxDriver, audio->ep_in, audio->altSetting[idxItf])); + if (tud_audio_tx_done_post_load_cb) TU_VERIFY(tud_audio_tx_done_post_load_cb(rhport, n_bytes_tx, idxDriver, audio->ep_in, audio->alt_setting_ptr[idxItf])); return true; } -#endif //CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE +#endif //CFG_TUD_AUDIO_ENABLE_EP_IN -#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_IN +#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN // Take samples from the support buffer and encode them into the IN EP software FIFO // Returns number of bytes written into linear buffer @@ -626,7 +846,7 @@ data streams. The audio data is not compressed and uses a signed two’s-complem is left-justified (the sign bit is the Msb) and data is padded with trailing zeros to fill the remaining unused bits of the subslot. The binary point is located to the right of the sign bit so that all values lie within the range [-1, +1) -*/ + */ /* * This function encodes channels saved within the support FIFOs into one stream by interleaving the PCM samples @@ -634,35 +854,99 @@ range [-1, +1) * does not change the number of bytes per sample. * */ +// Helper function +static inline uint8_t * audiod_interleaved_copy_bytes_fast_encode(uint16_t const nBytesToCopy, void * src, uint8_t * src_end, uint8_t * dst, uint8_t const n_ff_used) +{ + // Optimize for fast half word copies + typedef struct{ + uint16_t val; + } __attribute((__packed__)) unaligned_uint16_t; + + // Optimize for fast word copies + typedef struct{ + uint32_t val; + } __attribute((__packed__)) unaligned_uint32_t; + + switch (nBytesToCopy) + { + case 1: + while((uint8_t *)src < src_end) + { + *dst = *(uint8_t *)src++; + dst += n_ff_used; + } + break; + + case 2: + while((uint8_t *)src < src_end) + { + *(unaligned_uint16_t*)dst = *(unaligned_uint16_t*)src; + src += 2; + dst += 2 * n_ff_used; + } + break; + + case 3: + while((uint8_t *)src < src_end) + { +// memcpy(dst, src, 3); +// src = (uint8_t *)src + 3; +// dst += 3 * n_ff_used; + + // TODO: Is there a faster way to copy 3 bytes? + *dst++ = *(uint8_t *)src++; + *dst++ = *(uint8_t *)src++; + *dst++ = *(uint8_t *)src++; + + dst += 3 * (n_ff_used - 1); + } + break; + + case 4: + while((uint8_t *)src < src_end) + { + *(unaligned_uint32_t*)dst = *(unaligned_uint32_t*)src; + src += 4; + dst += 4 * n_ff_used; + } + break; + } + + return dst; +} + static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio) { // We encode directly into IN EP's linear buffer - abort if previous transfer not complete TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_in)); // Determine amount of samples - uint16_t const nChannelsPerFF = CFG_TUD_AUDIO_N_CHANNELS_TX / CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO; - uint16_t const nBytesToCopy = nChannelsPerFF*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX; - uint16_t const capSamplesPerFF = CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE / CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX / CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO; - uint16_t nSamplesPerFFToSend = tu_fifo_count(&audio->tx_supp_ff[0]); + uint8_t const n_ff_used = audio->n_channels_tx / audio->n_channels_per_ff_tx; + + TU_ASSERT( n_ff_used <= audio->n_tx_supp_ff ); + + uint16_t const nBytesToCopy = audio->n_channels_per_ff_tx * audio->n_bytes_per_sampe_tx; + uint16_t const capPerFF = audio->ep_in_sz / n_ff_used; // Sample capacity per FIFO in bytes + uint16_t nBytesPerFFToSend = tu_fifo_count(&audio->tx_supp_ff[0]); uint8_t cnt_ff; - for (cnt_ff = 1; cnt_ff < CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO; cnt_ff++) + for (cnt_ff = 1; cnt_ff < n_ff_used; cnt_ff++) { uint16_t const count = tu_fifo_count(&audio->tx_supp_ff[cnt_ff]); - if (count < nSamplesPerFFToSend) + if (count < nBytesPerFFToSend) { - nSamplesPerFFToSend = count; + nBytesPerFFToSend = count; } } // Check if there is enough - if (nSamplesPerFFToSend == 0) return 0; + if (nBytesPerFFToSend == 0) return 0; // Limit to maximum sample number - THIS IS A POSSIBLE ERROR SOURCE IF TOO MANY SAMPLE WOULD NEED TO BE SENT BUT CAN NOT! - nSamplesPerFFToSend = tu_min16(nSamplesPerFFToSend, capSamplesPerFF); + nBytesPerFFToSend = tu_min16(nBytesPerFFToSend, capPerFF); // Round to full number of samples (flooring) - nSamplesPerFFToSend = (nSamplesPerFFToSend / nChannelsPerFF) * nChannelsPerFF; + nBytesPerFFToSend = (nBytesPerFFToSend / audio->n_channels_per_ff_tx) * audio->n_channels_per_ff_tx; // Encode void * src; @@ -670,46 +954,36 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_interface_t* aud uint8_t * src_end; uint16_t len; - for (cnt_ff = 0; cnt_ff < CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO; cnt_ff++) + for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++) { - dst = &audio->lin_buf_in[cnt_ff*nChannelsPerFF*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX]; + dst = &audio->lin_buf_in[cnt_ff*audio->n_channels_per_ff_tx*audio->n_bytes_per_sampe_tx]; - len = tu_fifo_get_linear_read_info(&audio->tx_supp_ff[cnt_ff], 0, &src, nSamplesPerFFToSend); + len = tu_fifo_get_linear_read_info(&audio->tx_supp_ff[cnt_ff], 0, &src, nBytesPerFFToSend); tu_fifo_advance_read_pointer(&audio->tx_supp_ff[cnt_ff], len); - src_end = src + len * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX; + src_end = src + len; - while((uint8_t *)src < src_end) - { - memcpy(dst, src, nBytesToCopy); - src = (uint8_t *)src + nBytesToCopy; - dst += nBytesToCopy * CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO; - } + dst = audiod_interleaved_copy_bytes_fast_encode(nBytesToCopy, src, src_end, dst, n_ff_used); // Handle wrapped part of FIFO - if (len < nSamplesPerFFToSend) + if (len < nBytesPerFFToSend) { - len = tu_fifo_get_linear_read_info(&audio->tx_supp_ff[cnt_ff], 0, &src, nSamplesPerFFToSend - len); + len = tu_fifo_get_linear_read_info(&audio->tx_supp_ff[cnt_ff], 0, &src, nBytesPerFFToSend - len); tu_fifo_advance_read_pointer(&audio->tx_supp_ff[cnt_ff], len); - src_end = src + len * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX; + src_end = src + len; - while((uint8_t *)src < src_end) - { - memcpy(dst, src, nBytesToCopy); - src = (uint8_t *)src + nBytesToCopy; - dst += nBytesToCopy * CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO; - } + audiod_interleaved_copy_bytes_fast_encode(nBytesToCopy, src, src_end, dst, n_ff_used); } } - return nSamplesPerFFToSend * CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO; + return nBytesPerFFToSend * n_ff_used; } -#endif //CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE +#endif //CFG_TUD_AUDIO_ENABLE_ENCODING // This function is called once a transmit of a feedback packet was successfully completed. Here, we get the next feedback value to be sent -#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP static inline bool audiod_fb_send(uint8_t rhport, audiod_interface_t *audio) { return usbd_edpt_xfer(rhport, audio->ep_fb, (uint8_t *) &audio->fb_val, 4); @@ -727,43 +1001,304 @@ void audiod_init(void) { audiod_interface_t* audio = &_audiod_itf[i]; + // Initialize control buffers + switch (i) + { + case 0: + audio->ctrl_buf = ctrl_buf_1; + audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ; + break; +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ > 0 + case 1: + audio->ctrl_buf = ctrl_buf_2; + audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ; + break; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ > 0 + case 2: + audio->ctrl_buf = ctrl_buf_3; + audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ; + break; +#endif + } + + // Initialize active alternate interface buffers +#if CFG_TUD_AUDIO_FUNC_1_N_AS_INT > 0 || CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0 || CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0 + switch (i) + { +#if CFG_TUD_AUDIO_FUNC_1_N_AS_INT > 0 + case 0: + audio->alt_setting_ptr = alt_setting_1; + break; +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0 + case 1: + audio->alt_setting_ptr = alt_setting_2; + break; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0 + case 2: + audio->alt_setting_ptr = alt_setting_3; + break; +#endif + } +#endif + // Initialize IN EP FIFO if required -#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE && !CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE - tu_fifo_config(&audio->ep_in_ff, &audio->ep_in_buf, CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE, 1, true); +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING + + switch (i) + { +#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 + case 0: + tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&audio->ep_in_ff_mutex_wr), NULL); + tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(ep_in_ff_mutex_wr_1), NULL); #endif + break; #endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 + case 1: + tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_2, CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(ep_in_ff_mutex_wr_2), NULL); +#endif + break; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 + case 2: + tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(ep_in_ff_mutex_wr_3), NULL); +#endif + break; +#endif + } +#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING + + // Initialize linear buffers +#if USE_LINEAR_BUFFER_TX + switch (i) + { +#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0 + case 0: + audio->lin_buf_in = lin_buf_in_1; + break; +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0 + case 1: + audio->lin_buf_in = lin_buf_in_2; + break; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0 + case 2: + audio->lin_buf_in = lin_buf_in_3; + break; +#endif + } +#endif // USE_LINEAR_BUFFER_TX // Initialize OUT EP FIFO if required -#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && !CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE - tu_fifo_config(&audio->ep_out_ff, &audio->ep_out_buf, CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE, 1, true); +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING + + switch (i) + { +#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 + case 0: + tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&audio->ep_out_ff_mutex_rd)); + tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(rx_supp_ff_mutex_rd_1)); #endif + break; #endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 + case 1: + tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_2, CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(rx_supp_ff_mutex_rd_2)); +#endif + break; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 + case 2: + tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(rx_supp_ff_mutex_rd_3)); +#endif + break; +#endif + } +#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING + + // Initialize linear buffers +#if USE_LINEAR_BUFFER_RX + switch (i) + { +#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0 + case 0: + audio->lin_buf_out = lin_buf_out_1; + break; +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0 + case 1: + audio->lin_buf_out = lin_buf_out_2; + break; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0 + case 2: + audio->lin_buf_out = lin_buf_out_3; + break; +#endif + } +#endif // USE_LINEAR_BUFFER_TX // Initialize TX support FIFOs if required -#if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO; cnt++) +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING + + switch (i) { - tu_fifo_config(&audio->tx_supp_ff[cnt], &audio->tx_supp_ff_buf[cnt], CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX, true); +#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 + case 0: + audio->tx_supp_ff = tx_supp_ff_1; + audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; cnt++) + { + tu_fifo_config(&tx_supp_ff_1[cnt], tx_supp_ff_buf_1[cnt], CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->tx_supp_ff[cnt], osal_mutex_create(&audio->tx_supp_ff_mutex_wr[cnt]), NULL); + tu_fifo_config_mutex(&tx_supp_ff_1[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_1[cnt]), NULL); +#endif + } + + break; +#endif // CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 + +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 + case 1: + audio->tx_supp_ff = tx_supp_ff_2; + audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO; + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO; cnt++) + { + tu_fifo_config(&tx_supp_ff_2[cnt], tx_supp_ff_buf_2[cnt], CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&tx_supp_ff_2[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_2[cnt]), NULL); +#endif + } + + break; +#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 + +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0 + case 2: + audio->tx_supp_ff = tx_supp_ff_3; + audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO; + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO; cnt++) + { + tu_fifo_config(&tx_supp_ff_3[cnt], tx_supp_ff_buf_3[cnt], CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&tx_supp_ff_3[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_3[cnt]), NULL); +#endif + } + + break; +#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 + } +#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING + + // Set encoding parameters for Type_I formats +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING + switch (i) + { +#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 + case 0: + audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX; + break; +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 + case 1: + audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_TX; + break; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0 + case 2: + audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_TX; + break; #endif } -#endif +#endif // CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING // Initialize RX support FIFOs if required -#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO; cnt++) +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING + + switch (i) { - tu_fifo_config(&audio->rx_supp_ff[cnt], &audio->rx_supp_ff_buf[cnt], CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX, true); +#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 + case 0: + audio->rx_supp_ff = rx_supp_ff_1; + audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO; + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO; cnt++) + { + tu_fifo_config(&rx_supp_ff_1[cnt], rx_supp_ff_buf_1[cnt], CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->rx_supp_ff[cnt], NULL, osal_mutex_create(&audio->rx_supp_ff_mutex_rd[cnt])); + tu_fifo_config_mutex(&rx_supp_ff_1[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_1[cnt]), NULL); +#endif + } + + break; +#endif // CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 + +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 + case 1: + audio->rx_supp_ff = rx_supp_ff_2; + audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO; + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO; cnt++) + { + tu_fifo_config(&rx_supp_ff_2[cnt], rx_supp_ff_buf_2[cnt], CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&rx_supp_ff_2[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_2[cnt]), NULL); +#endif + } + + break; +#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 + +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0 + case 2: + audio->rx_supp_ff = rx_supp_ff_3; + audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO; + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO; cnt++) + { + tu_fifo_config(&rx_supp_ff_3[cnt], rx_supp_ff_buf_3[cnt], CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&rx_supp_ff_3[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_3[cnt]), NULL); +#endif + } + + break; +#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 + } +#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING + + // Set encoding parameters for Type_I formats +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING + switch (i) + { +#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 + case 0: + audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_RX; + break; +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 + case 1: + audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_RX; + break; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0 + case 2: + audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_RX; + break; #endif } -#endif +#endif // CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING } } @@ -776,23 +1311,23 @@ void audiod_reset(uint8_t rhport) audiod_interface_t* audio = &_audiod_itf[i]; tu_memclr(audio, ITF_MEM_RESET_SIZE); -#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE && !CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING tu_fifo_clear(&audio->ep_in_ff); #endif -#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && !CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING tu_fifo_clear(&audio->ep_out_ff); #endif -#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE && CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO; cnt++) +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING + for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) { tu_fifo_clear(&audio->tx_supp_ff[cnt]); } #endif -#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO; cnt++) +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING + for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) { tu_fifo_clear(&audio->rx_supp_ff[cnt]); } @@ -827,6 +1362,25 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin { _audiod_itf[i].p_desc = (uint8_t const *)itf_desc; // Save pointer to AC descriptor which is by specification always the first one _audiod_itf[i].rhport = rhport; + + // Setup descriptor lengths + switch (i) + { + case 0: + _audiod_itf[i].desc_length = CFG_TUD_AUDIO_FUNC_1_DESC_LEN; + break; +#if CFG_TUD_AUDIO > 1 + case 1: + _audiod_itf[i].desc_length = CFG_TUD_AUDIO_FUNC_2_DESC_LEN; + break; +#endif +#if CFG_TUD_AUDIO > 2 + case 2: + _audiod_itf[i].desc_length = CFG_TUD_AUDIO_FUNC_3_DESC_LEN; + break; +#endif + } + break; } } @@ -835,14 +1389,14 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin TU_ASSERT( i < CFG_TUD_AUDIO ); // This is all we need so far - the EPs are setup by a later set_interface request (as per UAC2 specification) - uint16_t drv_len = tud_audio_desc_lengths[i] - TUD_AUDIO_DESC_IAD_LEN; // - TUD_AUDIO_DESC_IAD_LEN since tinyUSB already handles the IAD descriptor + uint16_t drv_len = _audiod_itf[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; // - TUD_AUDIO_DESC_IAD_LEN since tinyUSB already handles the IAD descriptor return drv_len; } static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const * p_request) { -#if CFG_TUD_AUDIO_N_AS_INT > 0 +#if CFG_TUD_AUDIO_FUNC_1_N_AS_INT > 0 || CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0 || CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0 uint8_t const itf = tu_u16_low(p_request->wIndex); // Find index of audio streaming interface @@ -850,9 +1404,9 @@ static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const * uint8_t const *dummy; TU_VERIFY(audiod_get_AS_interface_index(itf, &idxDriver, &idxItf, &dummy)); - TU_VERIFY(tud_control_xfer(rhport, p_request, &_audiod_itf[idxDriver].altSetting[idxItf], 1)); + TU_VERIFY(tud_control_xfer(rhport, p_request, &_audiod_itf[idxDriver].alt_setting_ptr[idxItf], 1)); - TU_LOG2(" Get itf: %u - current alt: %u\r\n", itf, _audiod_itf[idxDriver].altSetting[idxItf]); + TU_LOG2(" Get itf: %u - current alt: %u\r\n", itf, _audiod_itf[idxDriver].alt_setting_ptr[idxItf]); return true; @@ -888,41 +1442,60 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * uint8_t const *p_desc; TU_VERIFY(audiod_get_AS_interface_index(itf, &idxDriver, &idxItf, &p_desc)); + audiod_interface_t* audio = &_audiod_itf[idxDriver]; + // Look if there is an EP to be closed - for this driver, there are only 3 possible EPs which may be closed (only AS related EPs can be closed, AC EP (if present) is always open) -#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE - if (_audiod_itf[idxDriver].ep_in_as_intf_num == itf) +#if CFG_TUD_AUDIO_ENABLE_EP_IN + if (audio->ep_in_as_intf_num == itf) { - _audiod_itf[idxDriver].ep_in_as_intf_num = 0; - usbd_edpt_close(rhport, _audiod_itf[idxDriver].ep_in); + audio->ep_in_as_intf_num = 0; + usbd_edpt_close(rhport, audio->ep_in); // Invoke callback - can be used to stop data sampling if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request)); - _audiod_itf[idxDriver].ep_in = 0; // Necessary? + audio->ep_in = 0; // Necessary? + + // Clear support FIFOs if used +#if CFG_TUD_AUDIO_ENABLE_ENCODING + for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) + { + tu_fifo_clear(&audio->tx_supp_ff[cnt]); + } +#endif + } #endif -#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE - if (_audiod_itf[idxDriver].ep_out_as_intf_num == itf) +#if CFG_TUD_AUDIO_ENABLE_EP_OUT + if (audio->ep_out_as_intf_num == itf) { - _audiod_itf[idxDriver].ep_out_as_intf_num = 0; - usbd_edpt_close(rhport, _audiod_itf[idxDriver].ep_out); - _audiod_itf[idxDriver].ep_out = 0; // Necessary? + audio->ep_out_as_intf_num = 0; + usbd_edpt_close(rhport, audio->ep_out); + audio->ep_out = 0; // Necessary? + + // Clear support FIFOs if used +#if CFG_TUD_AUDIO_ENABLE_DECODING + for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) + { + tu_fifo_clear(&audio->rx_supp_ff[cnt]); + } +#endif // Close corresponding feedback EP #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - usbd_edpt_close(rhport, _audiod_itf[idxDriver].ep_fb); - _audiod_itf[idxDriver].ep_fb = 0; // Necessary? + usbd_edpt_close(rhport, audio->ep_fb); + audio->ep_fb = 0; // Necessary? #endif } #endif // Save current alternative interface setting - _audiod_itf[idxDriver].altSetting[idxItf] = alt; + audio->alt_setting_ptr[idxItf] = alt; // Open new EP if necessary - EPs are only to be closed or opened for AS interfaces - Look for AS interface with correct alternate interface // Get pointer at end - uint8_t const *p_desc_end = _audiod_itf[idxDriver].p_desc + tud_audio_desc_lengths[idxDriver] - TUD_AUDIO_DESC_IAD_LEN; + uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN; // p_desc starts at required interface with alternate setting zero while (p_desc < p_desc_end) @@ -930,6 +1503,9 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * // Find correct interface if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == alt) { +#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING + uint8_t const * p_desc_parse_for_params = p_desc; +#endif // From this point forward follow the EP descriptors associated to the current alternate setting interface - Open EPs if necessary uint8_t foundEPs = 0, nEps = ((tusb_desc_interface_t const * )p_desc)->bNumEndpoints; while (foundEPs < nEps && p_desc < p_desc_end) @@ -943,52 +1519,61 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * //TODO: We need to set EP non busy since this is not taken care of right now in ep_close() - THIS IS A WORKAROUND! usbd_edpt_clear_stall(rhport, ep_addr); -#if CFG_TUD_AUDIO_EPSIZE_IN +#if CFG_TUD_AUDIO_ENABLE_EP_IN if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && ((tusb_desc_endpoint_t const *) p_desc)->bmAttributes.usage == 0x00) // Check if usage is data EP { // Save address - _audiod_itf[idxDriver].ep_in = ep_addr; - _audiod_itf[idxDriver].ep_in_as_intf_num = itf; + audio->ep_in = ep_addr; + audio->ep_in_as_intf_num = itf; + audio->ep_in_sz = ((tusb_desc_endpoint_t const *) p_desc)->wMaxPacketSize.size; + // If software encoding is enabled, parse for the corresponding parameters - doing this here means only AS interfaces with EPs get scanned for parameters +#if CFG_TUD_AUDIO_ENABLE_ENCODING + audiod_parse_for_AS_params(audio, p_desc_parse_for_params, p_desc_end, itf); +#endif // Invoke callback - can be used to trigger data sampling if not already running if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request)); // Schedule first transmit - in case no sample data is available a ZLP is loaded - // It is necessary to trigger this here since the refill is done with an TX FIFO empty interrupt which can only trigger if something was in there + // It is necessary to trigger this here since the refill is done with an RX FIFO empty interrupt which can only trigger if something was in there TU_VERIFY(audiod_tx_done_cb(rhport, &_audiod_itf[idxDriver])); } -#endif +#endif // CFG_TUD_AUDIO_ENABLE_EP_IN -#if CFG_TUD_AUDIO_EPSIZE_OUT +#if CFG_TUD_AUDIO_ENABLE_EP_OUT if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) // Checking usage not necessary { // Save address - _audiod_itf[idxDriver].ep_out = ep_addr; - _audiod_itf[idxDriver].ep_out_as_intf_num = itf; + audio->ep_out = ep_addr; + audio->ep_out_as_intf_num = itf; + audio->ep_out_sz = ((tusb_desc_endpoint_t const *) p_desc)->wMaxPacketSize.size; +#if CFG_TUD_AUDIO_ENABLE_DECODING + audiod_parse_for_AS_params(audio, p_desc_parse_for_params, p_desc_end, itf); +#endif // Invoke callback if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request)); // Prepare for incoming data #if USE_LINEAR_BUFFER_RX - TU_VERIFY(usbd_edpt_xfer(rhport, _audiod_itf[idxDriver].ep_out, _audiod_itf[idxDriver].lin_buf_out, CFG_TUD_AUDIO_EPSIZE_OUT), false); + TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false); #else - TU_VERIFY(usbd_edpt_iso_xfer(rhport, _audiod_itf[idxDriver].ep_out, &_audiod_itf[idxDriver].ep_out_ff, CFG_TUD_AUDIO_EPSIZE_OUT), false); + TU_VERIFY(usbd_edpt_iso_xfer(rhport, audio->ep_out, &audio->ep_out_ff, audio->ep_out_sz), false); #endif } #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && ((tusb_desc_endpoint_t const *) p_desc)->bmAttributes.usage == 1) // Check if usage is explicit data feedback { - _audiod_itf[idxDriver].ep_fb = ep_addr; + audio->ep_fb = ep_addr; // Invoke callback if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request)); } #endif +#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT -#endif foundEPs += 1; } p_desc = tu_desc_next(p_desc); @@ -1188,7 +1773,7 @@ static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const } // If we end here, the received request is a set request - we schedule a receive for the data stage and return true here. We handle the rest later in audiod_control_complete() once the data stage was finished - TU_VERIFY(tud_control_xfer(rhport, p_request, _audiod_itf[idxDriver].ctrl_buf, CFG_TUD_AUDIO_CTRL_BUF_SIZE)); + TU_VERIFY(tud_control_xfer(rhport, p_request, _audiod_itf[idxDriver].ctrl_buf, _audiod_itf[idxDriver].ctrl_buf_sz)); return true; } @@ -1238,7 +1823,7 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 #endif -#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE +#if CFG_TUD_AUDIO_ENABLE_EP_IN // Data transmission of audio packet finished if (_audiod_itf[idxDriver].ep_in == ep_addr) @@ -1259,7 +1844,7 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 } #endif -#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE +#if CFG_TUD_AUDIO_ENABLE_EP_OUT // New audio packet received if (_audiod_itf[idxDriver].ep_out == ep_addr) @@ -1327,7 +1912,7 @@ bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_req } // Crop length - if (len > CFG_TUD_AUDIO_CTRL_BUF_SIZE) len = CFG_TUD_AUDIO_CTRL_BUF_SIZE; + if (len > _audiod_itf[idxDriver].ctrl_buf_sz) len = _audiod_itf[idxDriver].ctrl_buf_sz; // Copy into buffer memcpy((void *)_audiod_itf[idxDriver].ctrl_buf, data, (size_t)len); @@ -1348,7 +1933,7 @@ static bool audiod_get_AS_interface_index(uint8_t itf, uint8_t *idxDriver, uint8 if (_audiod_itf[i].p_desc) { // Get pointer at end - uint8_t const *p_desc_end = _audiod_itf[i].p_desc + tud_audio_desc_lengths[i] - TUD_AUDIO_DESC_IAD_LEN; + uint8_t const *p_desc_end = _audiod_itf[i].p_desc + _audiod_itf[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; // Advance past AC descriptors uint8_t const *p_desc = tu_desc_next(_audiod_itf[i].p_desc); @@ -1413,7 +1998,7 @@ static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *idxDriver) { // Get pointer at beginning and end uint8_t const *p_desc = _audiod_itf[i].p_desc; - uint8_t const *p_desc_end = _audiod_itf[i].p_desc + tud_audio_desc_lengths[i] - TUD_AUDIO_DESC_IAD_LEN; + uint8_t const *p_desc_end = _audiod_itf[i].p_desc + _audiod_itf[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; while (p_desc < p_desc_end) { @@ -1437,7 +2022,7 @@ static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *idxDriver) if (_audiod_itf[i].p_desc) { // Get pointer at end - uint8_t const *p_desc_end = _audiod_itf[i].p_desc + tud_audio_desc_lengths[i]; + uint8_t const *p_desc_end = _audiod_itf[i].p_desc + _audiod_itf[i].desc_length; // Advance past AC descriptors - EP we look for are streaming EPs uint8_t const *p_desc = tu_desc_next(_audiod_itf[i].p_desc); @@ -1457,6 +2042,69 @@ static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *idxDriver) return false; } +#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING +// p_desc points to the AS interface of alternate setting zero +// itf is the interface number of the corresponding interface - we check if the interface belongs to EP in or EP out to see if it is a TX or RX parameter +// Currently, only AS interfaces with an EP (in or out) are supposed to be parsed for! +static void audiod_parse_for_AS_params(audiod_interface_t* audio, uint8_t const * p_desc, uint8_t const * p_desc_end, uint8_t const itf) +{ + p_desc = tu_desc_next(p_desc); // Exclude standard AS interface descriptor of current alternate interface descriptor + + while (p_desc < p_desc_end) + { + // Abort if follow up descriptor is a new standard interface descriptor - indicates the last AS descriptor was already finished + if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) break; + + // Look for a Class-Specific AS Interface Descriptor(4.9.2) to verify format type and format and also to get number of physical channels + if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_AS_GENERAL) + { + if (itf != audio->ep_in_as_intf_num && itf != audio->ep_out_as_intf_num) break; // Abort loop, this interface has no EP, this driver does not support this currently + + if (itf == audio->ep_in_as_intf_num) + { + audio->n_channels_tx = ((audio_desc_cs_as_interface_t const * )p_desc)->bNrChannels; + audio->format_type_tx = ((audio_desc_cs_as_interface_t const * )p_desc)->bFormatType; + +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING || CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING + audio->format_type_I_tx = ((audio_desc_cs_as_interface_t const * )p_desc)->bmFormats; +#endif + } + + if (itf == audio->ep_out_as_intf_num) + { + audio->n_channels_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bNrChannels; + audio->format_type_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bFormatType; +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING || CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING + audio->format_type_I_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bmFormats; +#endif + } + } + + // Look for a Type I Format Type Descriptor(2.3.1.6 - Audio Formats) +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING || CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING + if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_FORMAT_TYPE && ((audio_desc_type_I_format_t const * )p_desc)->bFormatType == AUDIO_FORMAT_TYPE_I) + { + if (itf != audio->ep_in_as_intf_num && itf != audio->ep_out_as_intf_num) break; // Abort loop, this interface has no EP, this driver does not support this currently + + if (itf == audio->ep_in_as_intf_num) + { + audio->n_bytes_per_sampe_tx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize; + } + + if (itf == audio->ep_out_as_intf_num) + { + audio->n_bytes_per_sampe_rx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize; + } + } +#endif + + // Other format types are not supported yet + + p_desc = tu_desc_next(p_desc); + } +} +#endif + #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP // Input value feedback has to be in 16.16 format - the format will be converted according to speed settings automatically diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index 730d42c38..e68c437ad 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -40,49 +40,151 @@ // All sizes are in bytes! -// Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just waste a few bytes) -#ifndef CFG_TUD_AUDIO_N_AS_INT -#error You must tell the driver the number of Standard AS Interface Descriptors you have defined in the descriptors! +#ifndef CFG_TUD_AUDIO_FUNC_1_DESC_LEN +#error You must tell the driver the length of the audio function descriptor including IAD descriptor +#endif +#if CFG_TUD_AUDIO > 1 +#ifndef CFG_TUD_AUDIO_FUNC_2_DESC_LEN +#error You must tell the driver the length of the audio function descriptor including IAD descriptor +#endif +#endif +#if CFG_TUD_AUDIO > 2 +#ifndef CFG_TUD_AUDIO_FUNC_3_DESC_LEN +#error You must tell the driver the length of the audio function descriptor including IAD descriptor +#endif +#endif + +// Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces +#ifndef CFG_TUD_AUDIO_FUNC_1_N_AS_INT +#error You must tell the driver the number of Standard AS Interface Descriptors you have defined in the audio function descriptor! +#endif +#if CFG_TUD_AUDIO > 1 +#ifndef CFG_TUD_AUDIO_FUNC_2_N_AS_INT +#error You must tell the driver the number of Standard AS Interface Descriptors you have defined in the audio function descriptor! +#endif +#endif +#if CFG_TUD_AUDIO > 2 +#ifndef CFG_TUD_AUDIO_FUNC_3_N_AS_INT +#error You must tell the driver the number of Standard AS Interface Descriptors you have defined in the audio function descriptor! +#endif #endif // Size of control buffer used to receive and send control messages via EP0 - has to be big enough to hold your biggest request structure e.g. range requests with multiple intervals defined or cluster descriptors -#ifndef CFG_TUD_AUDIO_CTRL_BUF_SIZE +#ifndef CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ #error You must define an audio class control request buffer size! #endif +#if CFG_TUD_AUDIO > 1 +#ifndef CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ +#error You must define an audio class control request buffer size! +#endif +#endif + +#if CFG_TUD_AUDIO > 2 +#ifndef CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ +#error You must define an audio class control request buffer size! +#endif +#endif + // End point sizes IN BYTES - Limits: Full Speed <= 1023, High Speed <= 1024 -#ifndef CFG_TUD_AUDIO_EPSIZE_IN -#define CFG_TUD_AUDIO_EPSIZE_IN 0 // TX +#ifndef CFG_TUD_AUDIO_ENABLE_EP_IN +#define CFG_TUD_AUDIO_ENABLE_EP_IN 0 // TX #endif -#ifndef CFG_TUD_AUDIO_EPSIZE_OUT -#define CFG_TUD_AUDIO_EPSIZE_OUT 0 // RX +#ifndef CFG_TUD_AUDIO_ENABLE_EP_OUT +#define CFG_TUD_AUDIO_ENABLE_EP_OUT 0 // RX #endif -// Software EP FIFO buffer sizes - must be >= EP SIZEs! -#if CFG_TUD_AUDIO_EPSIZE_IN -#ifndef CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE -#define CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE CFG_TUD_AUDIO_EPSIZE_IN // TX +// Maximum EP sizes for all alternate AS interface settings - used for checks and buffer allocation +#if CFG_TUD_AUDIO_ENABLE_EP_IN +#ifndef CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX +#error You must tell the driver the biggest EP IN size! #endif -#else -#define CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE 0 +#if CFG_TUD_AUDIO > 1 +#ifndef CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX +#error You must tell the driver the biggest EP IN size! +#endif +#endif +#if CFG_TUD_AUDIO > 2 +#ifndef CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX +#error You must tell the driver the biggest EP IN size! +#endif +#endif +#endif // CFG_TUD_AUDIO_ENABLE_EP_IN + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT +#ifndef CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX +#error You must tell the driver the biggest EP OUT size! +#endif +#if CFG_TUD_AUDIO > 1 +#ifndef CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX +#error You must tell the driver the biggest EP OUT size! +#endif +#endif +#if CFG_TUD_AUDIO > 2 +#ifndef CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX +#error You must tell the driver the biggest EP OUT size! +#endif +#endif +#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT + +// Software EP FIFO buffer sizes - must be >= max EP SIZEs! +#ifndef CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ 0 +#endif +#ifndef CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ +#define CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ 0 +#endif +#ifndef CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ +#define CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ 0 #endif -#if CFG_TUD_AUDIO_EPSIZE_OUT -#ifndef CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE -#define CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE CFG_TUD_AUDIO_EPSIZE_OUT // RX +#ifndef CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ +#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ 0 #endif -#else -#define CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE 0 +#ifndef CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ +#define CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ 0 +#endif +#ifndef CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ +#define CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ 0 #endif -// General information of number of TX and/or RX channels - is used in combination with support FIFOs (see below) and can be used for descriptor definitions -#ifndef CFG_TUD_AUDIO_N_CHANNELS_TX -#define CFG_TUD_AUDIO_N_CHANNELS_TX 1 +#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX +#error EP software buffer size MUST BE at least as big as maximum EP size #endif -#ifndef CFG_TUD_AUDIO_N_CHANNELS_RX -#define CFG_TUD_AUDIO_N_CHANNELS_RX 1 +#if CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX +#error EP software buffer size MUST BE at least as big as maximum EP size +#endif + +#if CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX +#error EP software buffer size MUST BE at least as big as maximum EP size +#endif + +#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX +#error EP software buffer size MUST BE at least as big as maximum EP size +#endif + +#if CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX +#error EP software buffer size MUST BE at least as big as maximum EP size +#endif + +#if CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX +#error EP software buffer size MUST BE at least as big as maximum EP size +#endif + +// Enable/disable feedback EP (required for asynchronous RX applications) +#ifndef CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 0 // Feedback - 0 or 1 +#endif + +// Audio interrupt control EP size - disabled if 0 +#ifndef CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN +#define CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN 0 // Audio interrupt control - if required - 6 Bytes according to UAC 2 specification (p. 74) +#endif + +#ifndef CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE +#define CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE 6 // Buffer size of audio control interrupt EP - 6 Bytes according to UAC 2 specification (p. 74) #endif // Use of TX/RX support FIFOs @@ -120,83 +222,100 @@ // - audio_rx_done_cb() // functions. -// The number of support FIFOs and number of channels is decoupled. The PCM encoding/decoding works depending on the ratio CFG_TUD_AUDIO_N_CHANNELS_XX / CFG_TUD_AUDIO_N_XX_SUPPORT_SW_FIFO, where currently 1:1 and 2:1 is implemented. The version 2:1 is useful in case of I2S for which usually 2 are channels already interleaved available. +// Enable encoding/decodings - for these to work, support FIFOs need to be setup in appropriate numbers and size +// The actual parameters of active encoding is parsed from the descriptors -// Size of support FIFOs IN SAMPLES - if size > 0 there are as many FIFOs set up as CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO and CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO -#ifndef CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE -#define CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE 0 // FIFO size - minimum size: // ceil(f_s/1000) * CFG_TUD_AUDIO_N_CHANNELS_TX / CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO +// For PCM encoding/decoding + +#ifndef CFG_TUD_AUDIO_ENABLE_ENCODING +#define CFG_TUD_AUDIO_ENABLE_ENCODING 0 #endif -#ifndef CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE -#define CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE 0 // FIFO size - minimum size: ceil(f_s/1000) * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX / CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO +#ifndef CFG_TUD_AUDIO_ENABLE_DECODING +#define CFG_TUD_AUDIO_ENABLE_DECODING 0 #endif -#ifndef CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO -#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE -#define CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO CFG_TUD_AUDIO_N_CHANNELS_TX // default size is equal to number of channels -#else -#define CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO 0 +// This enabling allows to save the current coding parameters e.g. # of bytes per sample etc. - TYPE_I includes common PCM encoding +#ifndef CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING +#define CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING 0 +#endif + +#ifndef CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING +#define CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING 0 +#endif + +// Type I Coding parameters not given within UAC2 descriptors +// It would be possible to allow for a more flexible setting and not fix this parameter as done below. However, this is most often not needed and kept for later if really necessary. The more flexible setting could be implemented within set_interface(), however, how the values are saved per alternate setting is to be determined! +#ifndef CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX +#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO +#endif +#if CFG_TUD_AUDIO > 1 +#ifndef CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_TX +#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO +#endif +#endif +#if CFG_TUD_AUDIO > 2 +#ifndef CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_TX +#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO #endif #endif -#ifndef CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO -#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE -#define CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO CFG_TUD_AUDIO_N_CHANNELS_RX // default size is equal to number of channels -#else -#define CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO 0 +#ifndef CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_RX +#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO +#endif +#if CFG_TUD_AUDIO > 1 +#ifndef CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_RX +#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO +#endif +#endif +#if CFG_TUD_AUDIO > 2 +#ifndef CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_RX +#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO #endif #endif -// Enable/disable feedback EP (required for asynchronous RX applications) -#ifndef CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 0 // Feedback - 0 or 1 +// Remaining types not support so far + +// Number of support FIFOs to set up - multiple channels can be handled by one FIFO - very common is two channels per FIFO stemming from one I2S interface +#ifndef CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO +#define CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO 0 +#endif +#ifndef CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO +#define CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO 0 +#endif +#ifndef CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO +#define CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO 0 #endif -// Audio interrupt control EP size - disabled if 0 -#ifndef CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN -#define CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN 0 // Audio interrupt control - if required - 6 Bytes according to UAC 2 specification (p. 74) +#ifndef CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO +#define CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO 0 +#endif +#ifndef CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO +#define CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO 0 +#endif +#ifndef CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO +#define CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO 0 #endif -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN -#ifndef CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE -#define CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE 6 // Buffer size of audio control interrupt EP - 6 Bytes according to UAC 2 specification (p. 74) +// Size of support FIFOs IN BYTES - if size > 0 there are as many FIFOs set up as CFG_TUD_AUDIO_FUNC_X_N_TX_SUPP_SW_FIFO and CFG_TUD_AUDIO_FUNC_X_N_RX_SUPP_SW_FIFO +#ifndef CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ +#define CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ 0 // FIFO size - minimum size: ceil(f_s/1000) * max(# of TX channels) / (# of TX support FIFOs) * max(# of bytes per sample) #endif +#ifndef CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ +#define CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ 0 +#endif +#ifndef CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ +#define CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ 0 #endif -// Audio data format types - look in audio.h for existing types -// Used in case support FIFOs are used -#ifndef CFG_TUD_AUDIO_FORMAT_TYPE_TX -#define CFG_TUD_AUDIO_FORMAT_TYPE_TX AUDIO_FORMAT_TYPE_UNDEFINED // If this option is used, an encoding function has to be implemented in audio_device.c +#ifndef CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ +#define CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ 0 // FIFO size - minimum size: ceil(f_s/1000) * max(# of RX channels) / (# of RX support FIFOs) * max(# of bytes per sample) #endif - -#ifndef CFG_TUD_AUDIO_FORMAT_TYPE_RX -#define CFG_TUD_AUDIO_FORMAT_TYPE_RX AUDIO_FORMAT_TYPE_UNDEFINED // If this option is used, a decoding function has to be implemented in audio_device.c +#ifndef CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ +#define CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ 0 #endif - -// Audio data format type I specifications -#if CFG_TUD_AUDIO_FORMAT_TYPE_TX == AUDIO_FORMAT_TYPE_I - -// Type definitions - for possible formats see: audio_data_format_type_I_t and further in UAC2 specifications. -#ifndef CFG_TUD_AUDIO_FORMAT_TYPE_I_TX -#define CFG_TUD_AUDIO_FORMAT_TYPE_I_TX AUDIO_DATA_FORMAT_TYPE_I_PCM -#endif - -#ifndef CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX // bSubslotSize -#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX 1 -#endif - -#endif - -#if CFG_TUD_AUDIO_FORMAT_TYPE_RX == AUDIO_FORMAT_TYPE_I - -#ifndef CFG_TUD_AUDIO_FORMAT_TYPE_I_RX -#define CFG_TUD_AUDIO_FORMAT_TYPE_I_RX AUDIO_DATA_FORMAT_TYPE_I_PCM -#endif - -#ifndef CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX // bSubslotSize -#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX 1 -#endif - +#ifndef CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ +#define CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ 0 #endif //static_assert(sizeof(tud_audio_desc_lengths) != CFG_TUD_AUDIO, "Supply audio function descriptor pack length!"); @@ -219,31 +338,27 @@ extern "C" { //--------------------------------------------------------------------+ bool tud_audio_n_mounted (uint8_t itf); -#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && !CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE - +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING uint16_t tud_audio_n_available (uint8_t itf); uint16_t tud_audio_n_read (uint8_t itf, void* buffer, uint16_t bufsize); bool tud_audio_n_clear_ep_out_ff (uint8_t itf); // Delete all content in the EP OUT FIFO - #endif -#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_OUT +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING bool tud_audio_n_clear_rx_support_ff (uint8_t itf, uint8_t channelId); // Delete all content in the support RX FIFOs uint16_t tud_audio_n_available_support_ff (uint8_t itf, uint8_t channelId); uint16_t tud_audio_n_read_support_ff (uint8_t itf, uint8_t channelId, void* buffer, uint16_t bufsize); #endif -#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE - +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING uint16_t tud_audio_n_write (uint8_t itf, const void * data, uint16_t len); bool tud_audio_n_clear_ep_in_ff (uint8_t itf); // Delete all content in the EP IN FIFO - -#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_IN -uint16_t tud_audio_n_flush_tx_support_ff (uint8_t itf); // Force all content in the support TX FIFOs to be written into EP SW FIFO -bool tud_audio_n_clear_tx_support_ff (uint8_t itf, uint8_t channelId); -uint16_t tud_audio_n_write_support_ff (uint8_t itf, uint8_t channelId, const void * data, uint16_t len); #endif +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING +uint16_t tud_audio_n_flush_tx_support_ff (uint8_t itf); // Force all content in the support TX FIFOs to be written into EP SW FIFO +bool tud_audio_n_clear_tx_support_ff (uint8_t itf, uint8_t channelId); +uint16_t tud_audio_n_write_support_ff (uint8_t itf, uint8_t channelId, const void * data, uint16_t len); #endif #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN @@ -258,15 +373,13 @@ static inline bool tud_audio_mounted (void); // RX API -#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && !CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE - +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING static inline uint16_t tud_audio_available (void); static inline bool tud_audio_clear_ep_out_ff (void); // Delete all content in the EP OUT FIFO static inline uint16_t tud_audio_read (void* buffer, uint16_t bufsize); - #endif -#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_OUT +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING static inline bool tud_audio_clear_rx_support_ff (uint8_t channelId); static inline uint16_t tud_audio_available_support_ff (uint8_t channelId); static inline uint16_t tud_audio_read_support_ff (uint8_t channelId, void* buffer, uint16_t bufsize); @@ -274,14 +387,12 @@ static inline uint16_t tud_audio_read_support_ff (uint8_t channelId, // TX API -#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE && !CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE - +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING static inline uint16_t tud_audio_write (const void * data, uint16_t len); static inline bool tud_audio_clear_ep_in_ff (void); - #endif -#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_IN +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING static inline uint16_t tud_audio_flush_tx_support_ff (void); static inline uint16_t tud_audio_clear_tx_support_ff (uint8_t channelId); static inline uint16_t tud_audio_write_support_ff (uint8_t channelId, const void * data, uint16_t len); @@ -290,7 +401,7 @@ static inline uint16_t tud_audio_write_support_ff (uint8_t channelId, // INT CTR API #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN -static inline uint16_t tud_audio_int_ctr_write (uint8_t const* buffer, uint16_t len); +static inline uint16_t tud_audio_int_ctr_write (uint8_t const* buffer, uint16_t len); #endif // Buffer control EP data and schedule a transmit @@ -305,17 +416,17 @@ bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_req // Application Callback API (weak is optional) //--------------------------------------------------------------------+ -#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE +#if CFG_TUD_AUDIO_ENABLE_EP_IN TU_ATTR_WEAK bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t itf, uint8_t ep_in, uint8_t cur_alt_setting); TU_ATTR_WEAK bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uint8_t itf, uint8_t ep_in, uint8_t cur_alt_setting); #endif -#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE +#if CFG_TUD_AUDIO_ENABLE_EP_OUT TU_ATTR_WEAK bool tud_audio_rx_done_pre_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t itf, uint8_t ep_out, uint8_t cur_alt_setting); TU_ATTR_WEAK bool tud_audio_rx_done_post_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t itf, uint8_t ep_out, uint8_t cur_alt_setting); #endif -#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP TU_ATTR_WEAK bool tud_audio_fb_done_cb(uint8_t rhport); // User code should call this function with feedback value in 16.16 format for FS and HS. // Value will be corrected for FS to 10.14 format automatically. @@ -364,7 +475,7 @@ static inline bool tud_audio_mounted(void) // RX API -#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && !CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING static inline uint16_t tud_audio_available (void) { @@ -383,7 +494,7 @@ static inline bool tud_audio_clear_ep_out_ff (void) #endif -#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_OUT +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING static inline bool tud_audio_clear_rx_support_ff (uint8_t channelId) { @@ -404,7 +515,7 @@ static inline uint16_t tud_audio_read_support_ff (uint8_t channelId, // TX API -#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE && !CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING static inline uint16_t tud_audio_write (const void * data, uint16_t len) { @@ -418,7 +529,7 @@ static inline bool tud_audio_clear_ep_in_ff (void) #endif -#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_IN +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING static inline uint16_t tud_audio_flush_tx_support_ff (void) { @@ -444,7 +555,7 @@ static inline uint16_t tud_audio_int_ctr_write(uint8_t const* buffer, uint16_t l } #endif -#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP static inline bool tud_audio_fb_set(uint32_t feedback) { return tud_audio_n_fb_set(0, feedback); diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index d05549e3e..1b7f64447 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -138,9 +138,7 @@ static void _tu_fifo_read_from_const_src_ptr_in_full_words(void * dst, const voi } } -// Intended to be used to write to hardware USB FIFO in e.g. STM32 where all data is written to a constant address -// Code adapted from dcd_synopsis.c -// TODO generalize with configurable 1 byte or 4 byte each write +// Intended to be used to write to hardware USB FIFO in e.g. STM32 where all data is written to a constant address in full word copies static void _tu_fifo_write_to_const_dst_ptr_in_full_words(void * dst, const void * src, uint16_t len) { volatile uint32_t * tx_fifo = (volatile uint32_t *) dst; diff --git a/src/device/usbd.h b/src/device/usbd.h index 56615b081..7c50a6db0 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -353,6 +353,10 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb #define TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN (6+(2+1)*4) #define TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL(_unitid, _srcid, _ctrlch0master, _ctrlch1, _ctrlch2, _stridx) \ TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_FEATURE_UNIT, _unitid, _srcid, U32_TO_U8S_LE(_ctrlch0master), U32_TO_U8S_LE(_ctrlch1), U32_TO_U8S_LE(_ctrlch2), _stridx +// 4 - Channels +#define TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL_LEN (6+(4+1)*4) +#define TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL(_unitid, _srcid, _ctrlch0master, _ctrlch1, _ctrlch2, _ctrlch3, _ctrlch4, _stridx) \ + TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_FEATURE_UNIT, _unitid, _srcid, U32_TO_U8S_LE(_ctrlch0master), U32_TO_U8S_LE(_ctrlch1), U32_TO_U8S_LE(_ctrlch2), U32_TO_U8S_LE(_ctrlch3), U32_TO_U8S_LE(_ctrlch4), _stridx // For more channels, add definitions here @@ -389,7 +393,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb // AUDIO simple descriptor (UAC2) for 1 microphone input // - 1 Input Terminal, 1 Feature Unit (Mute and Volume Control), 1 Output Terminal, 1 Clock Source -#define TUD_AUDIO_MIC_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN\ +#define TUD_AUDIO_MIC_ONE_CH_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN\ + TUD_AUDIO_DESC_STD_AC_LEN\ + TUD_AUDIO_DESC_CS_AC_LEN\ + TUD_AUDIO_DESC_CLK_SRC_LEN\ @@ -403,9 +407,9 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\ + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) -#define TUD_AUDIO_MIC_DESC_N_AS_INT 1 // Number of AS interfaces +#define TUD_AUDIO_MIC_ONE_CH_DESC_N_AS_INT 1 // Number of AS interfaces -#define TUD_AUDIO_MIC_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \ +#define TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \ /* Standard Interface Association Descriptor (IAD) */\ TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ /* Standard AC Interface Descriptor(4.7.1) */\ @@ -435,6 +439,55 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) +// AUDIO simple descriptor (UAC2) for 4 microphone input +// - 1 Input Terminal, 1 Feature Unit (Mute and Volume Control), 1 Output Terminal, 1 Clock Source + +#define TUD_AUDIO_MIC_FOUR_CH_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN\ + + TUD_AUDIO_DESC_STD_AC_LEN\ + + TUD_AUDIO_DESC_CS_AC_LEN\ + + TUD_AUDIO_DESC_CLK_SRC_LEN\ + + TUD_AUDIO_DESC_INPUT_TERM_LEN\ + + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\ + + TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL_LEN\ + + TUD_AUDIO_DESC_STD_AS_INT_LEN\ + + TUD_AUDIO_DESC_STD_AS_INT_LEN\ + + TUD_AUDIO_DESC_CS_AS_INT_LEN\ + + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\ + + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\ + + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) + +#define TUD_AUDIO_MIC_FOUR_CH_DESC_N_AS_INT 1 // Number of AS interfaces + +#define TUD_AUDIO_MIC_FOUR_CH_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \ + /* Standard Interface Association Descriptor (IAD) */\ + TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ + /* Standard AC Interface Descriptor(4.7.1) */\ + TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ + /* Class-Specific AC Interface Header Descriptor(4.7.2) */\ + TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_MICROPHONE, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS),\ + /* Clock Source Descriptor(4.7.2.1) */\ + TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x01, /*_stridx*/ 0x00),\ + /* Input Terminal Descriptor(4.7.2.4) */\ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x03, /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x04, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00),\ + /* Output Terminal Descriptor(4.7.2.5) */\ + TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x01, /*_srcid*/ 0x02, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ + /* Feature Unit Descriptor(4.7.2.8) */\ + TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch2*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch3*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch4*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00),\ + /* Standard AS Interface Descriptor(4.9.1) */\ + /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\ + /* Standard AS Interface Descriptor(4.9.1) */\ + /* Interface 1, Alternate 1 - alternate interface for data streaming */\ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00),\ + /* Class-Specific AS Interface Descriptor(4.9.2) */\ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x03, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x04, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ + TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 0x01),\ + /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ + TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) + // AUDIO simple descriptor (UAC2) for mono speaker // - 1 Input Terminal, 2 Feature Unit (Mute and Volume Control), 3 Output Terminal, 4 Clock Source From 40b2ffcb523c16f297cd605cb90f5dc816786549 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sat, 3 Apr 2021 10:09:40 +0200 Subject: [PATCH 075/121] Delete old settings --- examples/device/audio_test/src/tusb_config.h | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/examples/device/audio_test/src/tusb_config.h b/examples/device/audio_test/src/tusb_config.h index d3b617319..683a1a567 100644 --- a/examples/device/audio_test/src/tusb_config.h +++ b/examples/device/audio_test/src/tusb_config.h @@ -101,26 +101,9 @@ extern "C" { #define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX 2 // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below #define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 1 // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below - be aware: for different number of channels you need another descriptor! #define CFG_TUD_AUDIO_EP_SZ_IN 48 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX // 48 Samples (48 kHz) x 2 Bytes/Sample x 1 Channel -#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX CFG_TUD_AUDIO_EP_SZ_IN +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX CFG_TUD_AUDIO_EP_SZ_IN // Maximum EP IN size for all AS alternate settings used #define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ CFG_TUD_AUDIO_EP_SZ_IN + 1 - - -// Audio format type -#define CFG_TUD_AUDIO_FORMAT_TYPE_TX AUDIO_FORMAT_TYPE_I - -// Audio format type I specifications -#define CFG_TUD_AUDIO_FORMAT_TYPE_I_TX AUDIO_DATA_FORMAT_TYPE_I_PCM -#define CFG_TUD_AUDIO_N_CHANNELS_TX 1 -#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX 2 - -// EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense) -#define CFG_TUD_AUDIO_ENABLE_EP_IN 1 -#define CFG_TUD_AUDIO_EPSIZE_IN 48 * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_N_CHANNELS_TX // ceil(f_s/1000) * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_N_CHANNELS_TX -#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ CFG_TUD_AUDIO_EPSIZE_IN + CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_N_CHANNELS_TX // Just for safety one sample more space - - - #ifdef __cplusplus } #endif From 8b90c08b357ce04aebe093856b954e02624ff0fe Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sat, 3 Apr 2021 15:24:38 +0200 Subject: [PATCH 076/121] Fix #define errors in audio_device.h --- src/class/audio/audio_device.h | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index e68c437ad..9ff74d6c7 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -153,25 +153,33 @@ #error EP software buffer size MUST BE at least as big as maximum EP size #endif +#if CFG_TUD_AUDIO > 1 #if CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX #error EP software buffer size MUST BE at least as big as maximum EP size #endif +#endif +#if CFG_TUD_AUDIO > 2 #if CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX #error EP software buffer size MUST BE at least as big as maximum EP size #endif +#endif #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX #error EP software buffer size MUST BE at least as big as maximum EP size #endif +#if CFG_TUD_AUDIO > 1 #if CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX #error EP software buffer size MUST BE at least as big as maximum EP size #endif +#endif +#if CFG_TUD_AUDIO > 2 #if CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX #error EP software buffer size MUST BE at least as big as maximum EP size #endif +#endif // Enable/disable feedback EP (required for asynchronous RX applications) #ifndef CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP @@ -187,13 +195,16 @@ #define CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE 6 // Buffer size of audio control interrupt EP - 6 Bytes according to UAC 2 specification (p. 74) #endif -// Use of TX/RX support FIFOs +// Use software encoding/decoding -// Support FIFOs are not mandatory for the audio driver, rather they are intended to be of use in -// - TX case: CFG_TUD_AUDIO_N_CHANNELS_TX channels need to be encoded into one USB output stream (currently PCM type I is implemented) -// - RX case: CFG_TUD_AUDIO_N_CHANNELS_RX channels need to be decoded from a single USB input stream (currently PCM type I is implemented) +// The software coding feature of the driver is not mandatory. It is useful if, for instance, you have two I2S streams which need to be interleaved +// into a single PCM stream as SAMPLE_1 | SAMPLE_2 | SAMPLE_3 | SAMPLE_4. // -// This encoding/decoding is done in software and thus time consuming. If you can encode/decode your stream more efficiently do not use the +// Currently, only PCM type I encoding/decoding is supported! +// +// If the coding feature is to be used, support FIFOs need to be configured. Their sizes and numbers are defined below. + +// Encoding/decoding is done in software and thus time consuming. If you can encode/decode your stream more efficiently do not use the // support FIFOs but write/read directly into/from the EP_X_SW_BUFFER_FIFOs using // - tud_audio_n_write() or // - tud_audio_n_read(). @@ -223,7 +234,7 @@ // functions. // Enable encoding/decodings - for these to work, support FIFOs need to be setup in appropriate numbers and size -// The actual parameters of active encoding is parsed from the descriptors +// The actual coding parameters of active AS alternate interface is parsed from the descriptors // For PCM encoding/decoding From 6236effb1415ea509e6283d33f2779eeae7d425e Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sat, 3 Apr 2021 15:29:39 +0200 Subject: [PATCH 077/121] Fix #define error in audio_device.h --- src/class/audio/audio_device.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index 9ff74d6c7..e2208629f 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -149,6 +149,7 @@ #define CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ 0 #endif +#if CFG_TUD_AUDIO_ENABLE_EP_IN #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX #error EP software buffer size MUST BE at least as big as maximum EP size #endif @@ -164,7 +165,9 @@ #error EP software buffer size MUST BE at least as big as maximum EP size #endif #endif +#endif +#if CFG_TUD_AUDIO_ENABLE_EP_OUT #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX #error EP software buffer size MUST BE at least as big as maximum EP size #endif @@ -180,6 +183,7 @@ #error EP software buffer size MUST BE at least as big as maximum EP size #endif #endif +#endif // Enable/disable feedback EP (required for asynchronous RX applications) #ifndef CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP From ec6b240de299e24a7fabb54aa2f2d9c72d0eaad4 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sat, 3 Apr 2021 15:44:44 +0200 Subject: [PATCH 078/121] Fix #define error in audio_device.h --- src/class/audio/audio_device.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index e2208629f..d4793c9d8 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -261,6 +261,7 @@ // Type I Coding parameters not given within UAC2 descriptors // It would be possible to allow for a more flexible setting and not fix this parameter as done below. However, this is most often not needed and kept for later if really necessary. The more flexible setting could be implemented within set_interface(), however, how the values are saved per alternate setting is to be determined! +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING #ifndef CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX #error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO #endif @@ -274,7 +275,9 @@ #error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO #endif #endif +#endif +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING #ifndef CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_RX #error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO #endif @@ -288,6 +291,7 @@ #error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO #endif #endif +#endif // Remaining types not support so far From fcb97bd4e90346d0bfb21f4eda4fc0426b6b74c3 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sat, 3 Apr 2021 15:48:09 +0200 Subject: [PATCH 079/121] Fix #define in audio_test --- examples/device/audio_test/src/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/device/audio_test/src/main.c b/examples/device/audio_test/src/main.c index 7cbf57946..f01a5a183 100644 --- a/examples/device/audio_test/src/main.c +++ b/examples/device/audio_test/src/main.c @@ -53,7 +53,7 @@ static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; // Audio controls // Current states -bool mute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master channel 0 +bool mute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master channel 0 uint16_t volume[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master channel 0 uint32_t sampFreq; uint8_t clkValid; @@ -379,7 +379,7 @@ bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t itf, uint8_t ep_in, u (void) ep_in; (void) cur_alt_setting; - tud_audio_write ((uint8_t *)test_buffer_audio, CFG_TUD_AUDIO_EPSIZE_IN); + tud_audio_write ((uint8_t *)test_buffer_audio, CFG_TUD_AUDIO_EP_SZ_IN); return true; } @@ -392,7 +392,7 @@ bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uin (void) ep_in; (void) cur_alt_setting; - for (size_t cnt = 0; cnt < CFG_TUD_AUDIO_EPSIZE_IN/2; cnt++) + for (size_t cnt = 0; cnt < CFG_TUD_AUDIO_EP_SZ_IN/2; cnt++) { test_buffer_audio[cnt] = startVal++; } From fc65f39ff224cdfe3c486c95e0c04f1f979fa1b2 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sat, 3 Apr 2021 15:58:41 +0200 Subject: [PATCH 080/121] Fix error in #defines in uac2_headset --- examples/device/uac2_headset/src/tusb_config.h | 2 ++ examples/device/uac2_headset/src/usb_descriptors.c | 5 ----- src/class/audio/audio_device.c | 3 +++ 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/device/uac2_headset/src/tusb_config.h b/examples/device/uac2_headset/src/tusb_config.h index 511e4e558..cbdd7b3df 100644 --- a/examples/device/uac2_headset/src/tusb_config.h +++ b/examples/device/uac2_headset/src/tusb_config.h @@ -94,6 +94,8 @@ extern "C" { #define CFG_TUD_AUDIO_IN_PATH (CFG_TUD_AUDIO) #define CFG_TUD_AUDIO_OUT_PATH (CFG_TUD_AUDIO) +#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_HEADSET_STEREO_DESC_LEN + // Audio format type I specifications #define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 1 #define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX 2 diff --git a/examples/device/uac2_headset/src/usb_descriptors.c b/examples/device/uac2_headset/src/usb_descriptors.c index b69e5a5e0..cd749eb65 100644 --- a/examples/device/uac2_headset/src/usb_descriptors.c +++ b/examples/device/uac2_headset/src/usb_descriptors.c @@ -87,11 +87,6 @@ uint8_t const * tud_descriptor_device_cb(void) #define EPNUM_AUDIO 0x01 #endif -// These variables are required by the audio driver in audio_device.c - -// List of audio descriptor lengths which is required by audio driver - you need as many entries as CFG_TUD_AUDIO -const uint16_t tud_audio_desc_lengths[] = {TUD_AUDIO_HEADSET_STEREO_DESC_LEN}; - uint8_t const desc_configuration[] = { // Interface count, string index, total length, attribute, power in mA diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 5df32c30f..a39a030e6 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -388,7 +388,10 @@ static bool audiod_get_AS_interface_index(uint8_t itf, uint8_t *idxDriver, uint8 static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *idxDriver); static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *idxDriver); static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *idxDriver); + +#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING static void audiod_parse_for_AS_params(audiod_interface_t* audio, uint8_t const * p_desc, uint8_t const * p_desc_end, uint8_t const itf); +#endif static inline uint8_t tu_desc_subtype(void const* desc) { From 5eb893011c78d2f1e91301de2db6df48e1cb2fdc Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sat, 3 Apr 2021 15:59:42 +0200 Subject: [PATCH 081/121] Fix #define error in uac2_headset --- examples/device/uac2_headset/src/tusb_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/device/uac2_headset/src/tusb_config.h b/examples/device/uac2_headset/src/tusb_config.h index cbdd7b3df..ee6bdd519 100644 --- a/examples/device/uac2_headset/src/tusb_config.h +++ b/examples/device/uac2_headset/src/tusb_config.h @@ -106,7 +106,7 @@ extern "C" { // EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense) #define CFG_TUD_AUDIO_ENABLE_EP_IN 1 #define CFG_TUD_AUDIO_EP_SZ_IN (CFG_TUD_AUDIO_IN_PATH * (48 + 1) * (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX) * (CFG_TUD_AUDIO_N_CHANNELS_TX)) // 48 Samples (48 kHz) x 2 Bytes/Sample x n Channels -#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ CFG_TUD_AUDIO_EPSIZE_IN +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ CFG_TUD_AUDIO_EP_SZ_IN // EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense) #define CFG_TUD_AUDIO_ENABLE_EP_OUT 1 From 475badd0873dda58b507d3dfe5ab74957fcaa3c0 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sat, 3 Apr 2021 16:10:46 +0200 Subject: [PATCH 082/121] Add missing #defines in uac2_headset example --- examples/device/uac2_headset/src/tusb_config.h | 2 ++ src/class/audio/audio_device.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/device/uac2_headset/src/tusb_config.h b/examples/device/uac2_headset/src/tusb_config.h index ee6bdd519..5f86ee1a8 100644 --- a/examples/device/uac2_headset/src/tusb_config.h +++ b/examples/device/uac2_headset/src/tusb_config.h @@ -107,11 +107,13 @@ extern "C" { #define CFG_TUD_AUDIO_ENABLE_EP_IN 1 #define CFG_TUD_AUDIO_EP_SZ_IN (CFG_TUD_AUDIO_IN_PATH * (48 + 1) * (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX) * (CFG_TUD_AUDIO_N_CHANNELS_TX)) // 48 Samples (48 kHz) x 2 Bytes/Sample x n Channels #define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ CFG_TUD_AUDIO_EP_SZ_IN +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX CFG_TUD_AUDIO_EP_SZ_IN // Maximum EP IN size for all AS alternate settings used // EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense) #define CFG_TUD_AUDIO_ENABLE_EP_OUT 1 #define CFG_TUD_AUDIO_EP_OUT_SZ (CFG_TUD_AUDIO_OUT_PATH * ((48 + CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP) * (CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX) * (CFG_TUD_AUDIO_N_CHANNELS_RX))) // N Samples (N kHz) x 2 Bytes/Sample x n Channels #define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ CFG_TUD_AUDIO_EP_OUT_SZ*3 +#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX CFG_TUD_AUDIO_EP_SZ_OUT // Maximum EP IN size for all AS alternate settings used // Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes) #define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1 diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index a39a030e6..8e4f9d218 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -949,7 +949,7 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_interface_t* aud nBytesPerFFToSend = tu_min16(nBytesPerFFToSend, capPerFF); // Round to full number of samples (flooring) - nBytesPerFFToSend = (nBytesPerFFToSend / audio->n_channels_per_ff_tx) * audio->n_channels_per_ff_tx; + nBytesPerFFToSend = (nBytesPerFFToSend / nBytesToCopy) * nBytesToCopy; // Encode void * src; From c57369ee8349ec0a11d769a704568e4f7c51a3b2 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sat, 3 Apr 2021 16:22:35 +0200 Subject: [PATCH 083/121] Fix old defines in uac2_headset --- examples/device/uac2_headset/src/main.c | 4 ++-- examples/device/uac2_headset/src/tusb_config.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/device/uac2_headset/src/main.c b/examples/device/uac2_headset/src/main.c index f5360a0b6..d29deb588 100644 --- a/examples/device/uac2_headset/src/main.c +++ b/examples/device/uac2_headset/src/main.c @@ -72,8 +72,8 @@ static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; // Audio controls // Current states -int8_t mute[CFG_TUD_AUDIO_N_CHANNELS_TX + 1]; // +1 for master channel 0 -int16_t volume[CFG_TUD_AUDIO_N_CHANNELS_TX + 1]; // +1 for master channel 0 +int8_t mute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master channel 0 +int16_t volume[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master channel 0 // Buffer for microphone data int16_t mic_buf[1000]; diff --git a/examples/device/uac2_headset/src/tusb_config.h b/examples/device/uac2_headset/src/tusb_config.h index 5f86ee1a8..c338ddda5 100644 --- a/examples/device/uac2_headset/src/tusb_config.h +++ b/examples/device/uac2_headset/src/tusb_config.h @@ -105,13 +105,13 @@ extern "C" { // EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense) #define CFG_TUD_AUDIO_ENABLE_EP_IN 1 -#define CFG_TUD_AUDIO_EP_SZ_IN (CFG_TUD_AUDIO_IN_PATH * (48 + 1) * (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX) * (CFG_TUD_AUDIO_N_CHANNELS_TX)) // 48 Samples (48 kHz) x 2 Bytes/Sample x n Channels +#define CFG_TUD_AUDIO_EP_SZ_IN (CFG_TUD_AUDIO_IN_PATH * (48 + 1) * (CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX) * (CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX)) // 48 Samples (48 kHz) x 2 Bytes/Sample x n Channels #define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ CFG_TUD_AUDIO_EP_SZ_IN #define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX CFG_TUD_AUDIO_EP_SZ_IN // Maximum EP IN size for all AS alternate settings used // EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense) #define CFG_TUD_AUDIO_ENABLE_EP_OUT 1 -#define CFG_TUD_AUDIO_EP_OUT_SZ (CFG_TUD_AUDIO_OUT_PATH * ((48 + CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP) * (CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX) * (CFG_TUD_AUDIO_N_CHANNELS_RX))) // N Samples (N kHz) x 2 Bytes/Sample x n Channels +#define CFG_TUD_AUDIO_EP_OUT_SZ (CFG_TUD_AUDIO_OUT_PATH * ((48 + CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP) * (CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX) * (CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX))) // N Samples (N kHz) x 2 Bytes/Sample x n Channels #define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ CFG_TUD_AUDIO_EP_OUT_SZ*3 #define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX CFG_TUD_AUDIO_EP_SZ_OUT // Maximum EP IN size for all AS alternate settings used From 955979633774b5421f73c70fc524ef058af676b7 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sat, 3 Apr 2021 16:29:44 +0200 Subject: [PATCH 084/121] Fix typo in uac2_headset --- examples/device/uac2_headset/src/tusb_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/device/uac2_headset/src/tusb_config.h b/examples/device/uac2_headset/src/tusb_config.h index c338ddda5..514728ac4 100644 --- a/examples/device/uac2_headset/src/tusb_config.h +++ b/examples/device/uac2_headset/src/tusb_config.h @@ -113,7 +113,7 @@ extern "C" { #define CFG_TUD_AUDIO_ENABLE_EP_OUT 1 #define CFG_TUD_AUDIO_EP_OUT_SZ (CFG_TUD_AUDIO_OUT_PATH * ((48 + CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP) * (CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX) * (CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX))) // N Samples (N kHz) x 2 Bytes/Sample x n Channels #define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ CFG_TUD_AUDIO_EP_OUT_SZ*3 -#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX CFG_TUD_AUDIO_EP_SZ_OUT // Maximum EP IN size for all AS alternate settings used +#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX CFG_TUD_AUDIO_EP_OUT_SZ // Maximum EP IN size for all AS alternate settings used // Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes) #define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1 From 4af5189492f850615581d3310e20c98f69cf6138 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sat, 3 Apr 2021 16:53:29 +0200 Subject: [PATCH 085/121] Fix potential bug in support FIFO sizes --- .../device/uac2_headset/src/tusb_config.h | 2 -- .../device/uac2_headset/src/usb_descriptors.c | 2 ++ src/class/audio/audio_device.c | 32 ++++++++++++++++++- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/examples/device/uac2_headset/src/tusb_config.h b/examples/device/uac2_headset/src/tusb_config.h index 514728ac4..00620d9ed 100644 --- a/examples/device/uac2_headset/src/tusb_config.h +++ b/examples/device/uac2_headset/src/tusb_config.h @@ -94,8 +94,6 @@ extern "C" { #define CFG_TUD_AUDIO_IN_PATH (CFG_TUD_AUDIO) #define CFG_TUD_AUDIO_OUT_PATH (CFG_TUD_AUDIO) -#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_HEADSET_STEREO_DESC_LEN - // Audio format type I specifications #define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 1 #define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX 2 diff --git a/examples/device/uac2_headset/src/usb_descriptors.c b/examples/device/uac2_headset/src/usb_descriptors.c index cd749eb65..404863dba 100644 --- a/examples/device/uac2_headset/src/usb_descriptors.c +++ b/examples/device/uac2_headset/src/usb_descriptors.c @@ -87,6 +87,8 @@ uint8_t const * tud_descriptor_device_cb(void) #define EPNUM_AUDIO 0x01 #endif +#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_HEADSET_STEREO_DESC_LEN + uint8_t const desc_configuration[] = { // Interface count, string index, total length, attribute, power in mA diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 8e4f9d218..8bd15a8c1 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -310,6 +310,7 @@ typedef struct #if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING audio_data_format_type_I_t format_type_I_rx; uint8_t n_bytes_per_sampe_rx; + uint8_t n_channels_per_ff_rx; #endif #endif @@ -329,12 +330,13 @@ typedef struct #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING tu_fifo_t * rx_supp_ff; uint8_t n_rx_supp_ff; - uint8_t n_channels_per_ff_rx; + uint16_t rx_supp_ff_sz_max; #endif #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING tu_fifo_t * tx_supp_ff; uint8_t n_tx_supp_ff; + uint16_t tx_supp_ff_sz_max; #endif // Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR the support FIFOs are used @@ -920,6 +922,9 @@ static inline uint8_t * audiod_interleaved_copy_bytes_fast_encode(uint16_t const static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio) { + // This function relies on the fact that the length of the support FIFOs was configured to be a multiple of the active sample size in bytes s.t. no sample is split within a wrap + // This is ensured within set_interface, where the FIFOs are reconfigured according to this size + // We encode directly into IN EP's linear buffer - abort if previous transfer not complete TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_in)); @@ -1164,6 +1169,7 @@ void audiod_init(void) case 0: audio->tx_supp_ff = tx_supp_ff_1; audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; + audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ; for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; cnt++) { tu_fifo_config(&tx_supp_ff_1[cnt], tx_supp_ff_buf_1[cnt], CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ, 1, true); @@ -1179,6 +1185,7 @@ void audiod_init(void) case 1: audio->tx_supp_ff = tx_supp_ff_2; audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO; + audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ; for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO; cnt++) { tu_fifo_config(&tx_supp_ff_2[cnt], tx_supp_ff_buf_2[cnt], CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ, 1, true); @@ -1194,6 +1201,7 @@ void audiod_init(void) case 2: audio->tx_supp_ff = tx_supp_ff_3; audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO; + audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ; for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO; cnt++) { tu_fifo_config(&tx_supp_ff_3[cnt], tx_supp_ff_buf_3[cnt], CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ, 1, true); @@ -1238,6 +1246,7 @@ void audiod_init(void) case 0: audio->rx_supp_ff = rx_supp_ff_1; audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO; + audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ; for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO; cnt++) { tu_fifo_config(&rx_supp_ff_1[cnt], rx_supp_ff_buf_1[cnt], CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ, 1, true); @@ -1253,6 +1262,7 @@ void audiod_init(void) case 1: audio->rx_supp_ff = rx_supp_ff_2; audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO; + audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ; for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO; cnt++) { tu_fifo_config(&rx_supp_ff_2[cnt], rx_supp_ff_buf_2[cnt], CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ, 1, true); @@ -1268,6 +1278,7 @@ void audiod_init(void) case 2: audio->rx_supp_ff = rx_supp_ff_3; audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO; + audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ; for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO; cnt++) { tu_fifo_config(&rx_supp_ff_3[cnt], rx_supp_ff_buf_3[cnt], CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ, 1, true); @@ -1533,6 +1544,16 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * // If software encoding is enabled, parse for the corresponding parameters - doing this here means only AS interfaces with EPs get scanned for parameters #if CFG_TUD_AUDIO_ENABLE_ENCODING audiod_parse_for_AS_params(audio, p_desc_parse_for_params, p_desc_end, itf); + + // Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING + const uint16_t active_fifo_depth = (audio->tx_supp_ff_sz_max / audio->n_bytes_per_sampe_tx) * audio->n_bytes_per_sampe_tx; + for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) + { + tu_fifo_config(&audio->tx_supp_ff[cnt], audio->tx_supp_ff[cnt].buffer, active_fifo_depth, 1, true); + } +#endif + #endif // Invoke callback - can be used to trigger data sampling if not already running if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request)); @@ -1554,6 +1575,15 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * #if CFG_TUD_AUDIO_ENABLE_DECODING audiod_parse_for_AS_params(audio, p_desc_parse_for_params, p_desc_end, itf); + + // Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING + const uint16_t active_fifo_depth = (audio->rx_supp_ff_sz_max / audio->n_bytes_per_sampe_rx) * audio->n_bytes_per_sampe_rx; + for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) + { + tu_fifo_config(&audio->rx_supp_ff[cnt], audio->rx_supp_ff[cnt].buffer, active_fifo_depth, 1, true); + } +#endif #endif // Invoke callback if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request)); From 6f2f5320f26f131e56fba21c079d007d22cafa37 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sat, 3 Apr 2021 16:58:05 +0200 Subject: [PATCH 086/121] Fix uac2_headset example --- examples/device/uac2_headset/src/tusb_config.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/device/uac2_headset/src/tusb_config.h b/examples/device/uac2_headset/src/tusb_config.h index 00620d9ed..8285c6b66 100644 --- a/examples/device/uac2_headset/src/tusb_config.h +++ b/examples/device/uac2_headset/src/tusb_config.h @@ -31,6 +31,8 @@ extern "C" { #endif +#include "usb_descriptors.h" + //-------------------------------------------------------------------- // COMMON CONFIGURATION //-------------------------------------------------------------------- @@ -94,6 +96,8 @@ extern "C" { #define CFG_TUD_AUDIO_IN_PATH (CFG_TUD_AUDIO) #define CFG_TUD_AUDIO_OUT_PATH (CFG_TUD_AUDIO) +#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_HEADSET_STEREO_DESC_LEN + // Audio format type I specifications #define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 1 #define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX 2 From f6ba58e370cd67b78dcd1758aa9fe010035f13bc Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sat, 3 Apr 2021 17:50:30 +0200 Subject: [PATCH 087/121] Fix wrong pointer type in audio_device.c --- examples/device/uac2_headset/src/usb_descriptors.c | 2 -- src/class/audio/audio_device.c | 12 ++++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/examples/device/uac2_headset/src/usb_descriptors.c b/examples/device/uac2_headset/src/usb_descriptors.c index 404863dba..cd749eb65 100644 --- a/examples/device/uac2_headset/src/usb_descriptors.c +++ b/examples/device/uac2_headset/src/usb_descriptors.c @@ -87,8 +87,6 @@ uint8_t const * tud_descriptor_device_cb(void) #define EPNUM_AUDIO 0x01 #endif -#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_HEADSET_STEREO_DESC_LEN - uint8_t const desc_configuration[] = { // Interface count, string index, total length, attribute, power in mA diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 8bd15a8c1..642688876 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -1174,7 +1174,7 @@ void audiod_init(void) { tu_fifo_config(&tx_supp_ff_1[cnt], tx_supp_ff_buf_1[cnt], CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&tx_supp_ff_1[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_1[cnt]), NULL); + tu_fifo_config_mutex(&tx_supp_ff_1[cnt], osal_mutex_create(tx_supp_ff_mutex_wr_1[cnt]), NULL); #endif } @@ -1190,7 +1190,7 @@ void audiod_init(void) { tu_fifo_config(&tx_supp_ff_2[cnt], tx_supp_ff_buf_2[cnt], CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&tx_supp_ff_2[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_2[cnt]), NULL); + tu_fifo_config_mutex(&tx_supp_ff_2[cnt], osal_mutex_create(tx_supp_ff_mutex_wr_2[cnt]), NULL); #endif } @@ -1206,7 +1206,7 @@ void audiod_init(void) { tu_fifo_config(&tx_supp_ff_3[cnt], tx_supp_ff_buf_3[cnt], CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&tx_supp_ff_3[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_3[cnt]), NULL); + tu_fifo_config_mutex(&tx_supp_ff_3[cnt], osal_mutex_create(tx_supp_ff_mutex_wr_3[cnt]), NULL); #endif } @@ -1251,7 +1251,7 @@ void audiod_init(void) { tu_fifo_config(&rx_supp_ff_1[cnt], rx_supp_ff_buf_1[cnt], CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&rx_supp_ff_1[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_1[cnt]), NULL); + tu_fifo_config_mutex(&rx_supp_ff_1[cnt], osal_mutex_create(rx_supp_ff_mutex_rd_1[cnt]), NULL); #endif } @@ -1267,7 +1267,7 @@ void audiod_init(void) { tu_fifo_config(&rx_supp_ff_2[cnt], rx_supp_ff_buf_2[cnt], CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&rx_supp_ff_2[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_2[cnt]), NULL); + tu_fifo_config_mutex(&rx_supp_ff_2[cnt], osal_mutex_create(rx_supp_ff_mutex_rd_2[cnt]), NULL); #endif } @@ -1283,7 +1283,7 @@ void audiod_init(void) { tu_fifo_config(&rx_supp_ff_3[cnt], rx_supp_ff_buf_3[cnt], CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&rx_supp_ff_3[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_3[cnt]), NULL); + tu_fifo_config_mutex(&rx_supp_ff_3[cnt], osal_mutex_create(rx_supp_ff_mutex_rd_3[cnt]), NULL); #endif } From b3e548d2d640673ab2921878e8cabe56e31740c2 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sat, 3 Apr 2021 17:57:23 +0200 Subject: [PATCH 088/121] Fix uac2_headset --- examples/device/uac2_headset/src/tusb_config.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/device/uac2_headset/src/tusb_config.h b/examples/device/uac2_headset/src/tusb_config.h index 8285c6b66..514728ac4 100644 --- a/examples/device/uac2_headset/src/tusb_config.h +++ b/examples/device/uac2_headset/src/tusb_config.h @@ -31,8 +31,6 @@ extern "C" { #endif -#include "usb_descriptors.h" - //-------------------------------------------------------------------- // COMMON CONFIGURATION //-------------------------------------------------------------------- From e0cb4159542cf41c5ca502106dec66cbbf88f268 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sat, 3 Apr 2021 18:07:18 +0200 Subject: [PATCH 089/121] Fix uac2_headset include hassle be declaring value by hand --- examples/device/uac2_headset/src/tusb_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/device/uac2_headset/src/tusb_config.h b/examples/device/uac2_headset/src/tusb_config.h index 514728ac4..4b4570b77 100644 --- a/examples/device/uac2_headset/src/tusb_config.h +++ b/examples/device/uac2_headset/src/tusb_config.h @@ -94,7 +94,7 @@ extern "C" { #define CFG_TUD_AUDIO_IN_PATH (CFG_TUD_AUDIO) #define CFG_TUD_AUDIO_OUT_PATH (CFG_TUD_AUDIO) -#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_HEADSET_STEREO_DESC_LEN +#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN 220 // This equals TUD_AUDIO_HEADSET_STEREO_DESC_LEN, however, including it from usb_descriptors.h is not possible due to some strange include hassle // Audio format type I specifications #define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 1 From 1ac9e7e3a70b48e73f150d1e7494eaecd2d34822 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Sat, 3 Apr 2021 18:22:19 +0200 Subject: [PATCH 090/121] Fix wrong read mutexes in audio_device.c --- src/class/audio/audio_device.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 642688876..dadb66caa 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -1061,7 +1061,7 @@ void audiod_init(void) case 0: tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(ep_in_ff_mutex_wr_1), NULL); + tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_1), NULL); #endif break; #endif @@ -1069,7 +1069,7 @@ void audiod_init(void) case 1: tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_2, CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(ep_in_ff_mutex_wr_2), NULL); + tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_2), NULL); #endif break; #endif @@ -1077,7 +1077,7 @@ void audiod_init(void) case 2: tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(ep_in_ff_mutex_wr_3), NULL); + tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_3), NULL); #endif break; #endif @@ -1115,7 +1115,7 @@ void audiod_init(void) case 0: tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(rx_supp_ff_mutex_rd_1)); + tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_1)); #endif break; #endif @@ -1123,7 +1123,7 @@ void audiod_init(void) case 1: tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_2, CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(rx_supp_ff_mutex_rd_2)); + tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_2)); #endif break; #endif @@ -1131,7 +1131,7 @@ void audiod_init(void) case 2: tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(rx_supp_ff_mutex_rd_3)); + tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_3)); #endif break; #endif @@ -1174,7 +1174,7 @@ void audiod_init(void) { tu_fifo_config(&tx_supp_ff_1[cnt], tx_supp_ff_buf_1[cnt], CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&tx_supp_ff_1[cnt], osal_mutex_create(tx_supp_ff_mutex_wr_1[cnt]), NULL); + tu_fifo_config_mutex(&tx_supp_ff_1[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_1[cnt]), NULL); #endif } @@ -1190,7 +1190,7 @@ void audiod_init(void) { tu_fifo_config(&tx_supp_ff_2[cnt], tx_supp_ff_buf_2[cnt], CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&tx_supp_ff_2[cnt], osal_mutex_create(tx_supp_ff_mutex_wr_2[cnt]), NULL); + tu_fifo_config_mutex(&tx_supp_ff_2[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_2[cnt]), NULL); #endif } @@ -1206,7 +1206,7 @@ void audiod_init(void) { tu_fifo_config(&tx_supp_ff_3[cnt], tx_supp_ff_buf_3[cnt], CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&tx_supp_ff_3[cnt], osal_mutex_create(tx_supp_ff_mutex_wr_3[cnt]), NULL); + tu_fifo_config_mutex(&tx_supp_ff_3[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_3[cnt]), NULL); #endif } @@ -1251,7 +1251,7 @@ void audiod_init(void) { tu_fifo_config(&rx_supp_ff_1[cnt], rx_supp_ff_buf_1[cnt], CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&rx_supp_ff_1[cnt], osal_mutex_create(rx_supp_ff_mutex_rd_1[cnt]), NULL); + tu_fifo_config_mutex(&rx_supp_ff_1[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_1[cnt]), NULL); #endif } @@ -1267,7 +1267,7 @@ void audiod_init(void) { tu_fifo_config(&rx_supp_ff_2[cnt], rx_supp_ff_buf_2[cnt], CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&rx_supp_ff_2[cnt], osal_mutex_create(rx_supp_ff_mutex_rd_2[cnt]), NULL); + tu_fifo_config_mutex(&rx_supp_ff_2[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_2[cnt]), NULL); #endif } @@ -1283,7 +1283,7 @@ void audiod_init(void) { tu_fifo_config(&rx_supp_ff_3[cnt], rx_supp_ff_buf_3[cnt], CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ, 1, true); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&rx_supp_ff_3[cnt], osal_mutex_create(rx_supp_ff_mutex_rd_3[cnt]), NULL); + tu_fifo_config_mutex(&rx_supp_ff_3[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_3[cnt]), NULL); #endif } From 586a46c7d3991b28f9a0a8769c90c4992fcc1539 Mon Sep 17 00:00:00 2001 From: hathach Date: Sun, 4 Apr 2021 21:33:19 +0700 Subject: [PATCH 091/121] revert dcd_edpt_xfer_fifo() implementation for samg samg fifo is accessed byte by byte (although the register is 32 bit). --- src/portable/microchip/samg/dcd_samg.c | 29 ++++++-------------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/src/portable/microchip/samg/dcd_samg.c b/src/portable/microchip/samg/dcd_samg.c index 8b5bebf85..f8b204508 100644 --- a/src/portable/microchip/samg/dcd_samg.c +++ b/src/portable/microchip/samg/dcd_samg.c @@ -297,34 +297,13 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t return true; } +#if 0 // TODO support dcd_edpt_xfer_fifo API bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) { (void) rhport; - - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); - - xfer_desc_t* xfer = &_dcd_xfer[epnum]; - xfer->total_len = total_bytes; - xfer->actual_len = 0; - xfer->buffer = NULL; // Indicates a FIFO shall be used - xfer->ff = ff; - - if (dir == TUSB_DIR_OUT) - { - // Enable interrupt when starting OUT transfer - if (epnum != 0) UDP->UDP_IER |= (1 << epnum); - } - else - { - tu_fifo_read_n(ff, (void *) &UDP->UDP_FDR[epnum], xfer_packet_len(xfer)); - - // TX ready for transfer - csr_set(epnum, UDP_CSR_TXPKTRDY_Msk); - } - return true; } +#endif // Stall endpoint void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr) @@ -435,11 +414,13 @@ void dcd_int_handler(uint8_t rhport) if (xact_len) { // write to EP fifo +#if 0 // TODO support dcd_edpt_xfer_fifo if (xfer->ff) { tu_fifo_read_n_const_addr_full_words(xfer->ff, (void *) &UDP->UDP_FDR[epnum], xact_len); } else +#endif { xact_ep_write(epnum, xfer->buffer, xact_len); } @@ -468,11 +449,13 @@ void dcd_int_handler(uint8_t rhport) uint16_t const xact_len = (uint16_t) ((UDP->UDP_CSR[epnum] & UDP_CSR_RXBYTECNT_Msk) >> UDP_CSR_RXBYTECNT_Pos); // Read from EP fifo +#if 0 // TODO support dcd_edpt_xfer_fifo API if (xfer->ff) { tu_fifo_write_n_const_addr_full_words(xfer->ff, (const void *) &UDP->UDP_FDR[epnum], xact_len); } else +#endif { xact_ep_read(epnum, xfer->buffer, xact_len); } From bebe2f0bbf68561727a68037bae25f223d284578 Mon Sep 17 00:00:00 2001 From: hathach Date: Sun, 4 Apr 2021 22:50:26 +0700 Subject: [PATCH 092/121] revert dcd_edpt_xfer_fifo() implementation for nuc505 --- src/portable/microchip/samg/dcd_samg.c | 6 +++--- src/portable/nuvoton/nuc505/dcd_nuc505.c | 24 ++++++++++++++++-------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/portable/microchip/samg/dcd_samg.c b/src/portable/microchip/samg/dcd_samg.c index f8b204508..62fab8d17 100644 --- a/src/portable/microchip/samg/dcd_samg.c +++ b/src/portable/microchip/samg/dcd_samg.c @@ -44,7 +44,7 @@ typedef struct { uint8_t* buffer; - tu_fifo_t* ff; + // tu_fifo_t* ff; // TODO support dcd_edpt_xfer_fifo API uint16_t total_len; volatile uint16_t actual_len; uint16_t epsize; @@ -61,7 +61,7 @@ void xfer_epsize_set(xfer_desc_t* xfer, uint16_t epsize) void xfer_begin(xfer_desc_t* xfer, uint8_t * buffer, uint16_t total_bytes) { xfer->buffer = buffer; - xfer->ff = NULL; + // xfer->ff = NULL; // TODO support dcd_edpt_xfer_fifo API xfer->total_len = total_bytes; xfer->actual_len = 0; } @@ -69,7 +69,7 @@ void xfer_begin(xfer_desc_t* xfer, uint8_t * buffer, uint16_t total_bytes) void xfer_end(xfer_desc_t* xfer) { xfer->buffer = NULL; - xfer->ff = NULL; + // xfer->ff = NULL; // TODO support dcd_edpt_xfer_fifo API xfer->total_len = 0; xfer->actual_len = 0; } diff --git a/src/portable/nuvoton/nuc505/dcd_nuc505.c b/src/portable/nuvoton/nuc505/dcd_nuc505.c index 67693e335..b7bbb020b 100644 --- a/src/portable/nuvoton/nuc505/dcd_nuc505.c +++ b/src/portable/nuvoton/nuc505/dcd_nuc505.c @@ -95,7 +95,7 @@ static uint32_t bufseg_addr; static struct xfer_ctl_t { uint8_t *data_ptr; /* data_ptr tracks where to next copy data to (for OUT) or from (for IN) */ - tu_fifo_t * ff; /* pointer to FIFO required for dcd_edpt_xfer_fifo() */ + // tu_fifo_t* ff; // TODO support dcd_edpt_xfer_fifo API union { uint16_t in_remaining_bytes; /* for IN endpoints, we track how many bytes are left to transfer */ uint16_t out_bytes_so_far; /* but for OUT endpoints, we track how many bytes we've transferred so far */ @@ -165,7 +165,7 @@ static USBD_EP_T *ep_entry(uint8_t ep_addr, bool add) /* perform a non-control IN endpoint transfer; this is called by the ISR */ static void dcd_userEP_in_xfer(struct xfer_ctl_t *xfer, USBD_EP_T *ep) { - uint16_t bytes_now = tu_min16(xfer->in_remaining_bytes, xfer->max_packet_size); + uint16_t const bytes_now = tu_min16(xfer->in_remaining_bytes, xfer->max_packet_size); /* precompute what amount of data will be left */ xfer->in_remaining_bytes -= bytes_now; @@ -181,11 +181,13 @@ static void dcd_userEP_in_xfer(struct xfer_ctl_t *xfer, USBD_EP_T *ep) } /* provided buffers are thankfully 32-bit aligned, allowing most data to be transfered as 32-bit */ +#if 0 // TODO support dcd_edpt_xfer_fifo API if (xfer->ff) { tu_fifo_read_n_const_addr_full_words(xfer->ff, (void *) (&ep->EPDAT_BYTE), bytes_now); } else +#endif { uint16_t countdown = bytes_now; while (countdown > 3) @@ -196,13 +198,12 @@ static void dcd_userEP_in_xfer(struct xfer_ctl_t *xfer, USBD_EP_T *ep) ep->EPDAT = u32; xfer->data_ptr += 4; countdown -= 4; } - while (countdown--) - ep->EPDAT_BYTE = *xfer->data_ptr++; + + while (countdown--) ep->EPDAT_BYTE = *xfer->data_ptr++; } /* for short packets, we must nudge the peripheral to say 'that's all folks' */ - if (bytes_now != xfer->max_packet_size) - ep->EPRSPCTL = USBD_EPRSPCTL_SHORTTXEN_Msk; + if (bytes_now != xfer->max_packet_size) ep->EPRSPCTL = USBD_EPRSPCTL_SHORTTXEN_Msk; } /* called by dcd_init() as well as by the ISR during a USB bus reset */ @@ -394,7 +395,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to /* store away the information we'll needing now and later */ xfer->data_ptr = buffer; - xfer->ff = NULL; + // xfer->ff = NULL; // TODO support dcd_edpt_xfer_fifo API xfer->in_remaining_bytes = total_bytes; xfer->total_bytes = total_bytes; @@ -412,6 +413,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to return true; } +#if 0 // TODO support dcd_edpt_xfer_fifo API bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) { (void) rhport; @@ -441,6 +443,7 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 return true; } +#endif void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { @@ -655,20 +658,25 @@ void dcd_int_handler(uint8_t rhport) #else uint16_t const available_bytes = ep->EPDATCNT & USBD_EPDATCNT_DATCNT_Msk; /* copy the data from the PC to the previously provided buffer */ +#if 0 // TODO support dcd_edpt_xfer_fifo API if (xfer->ff) { tu_fifo_write_n_const_addr_full_words(xfer->ff, (const void *) &ep->EPDAT_BYTE, tu_min16(available_bytes, xfer->total_bytes - xfer->out_bytes_so_far)); } else +#endif { for (int count = 0; (count < available_bytes) && (xfer->out_bytes_so_far < xfer->total_bytes); count++, xfer->out_bytes_so_far++) + { *xfer->data_ptr++ = ep->EPDAT_BYTE; - + } } /* when the transfer is finished, alert TinyUSB; otherwise, continue accepting more data */ if ( (xfer->total_bytes == xfer->out_bytes_so_far) || (available_bytes < xfer->max_packet_size) ) + { dcd_event_xfer_complete(0, ep_addr, xfer->out_bytes_so_far, XFER_RESULT_SUCCESS, true); + } #endif } From 8d2dfe872ca5e1cdbde629b4bfd072bbca0c0216 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 5 Apr 2021 19:19:49 +0700 Subject: [PATCH 093/121] revert dcd_edpt_xfer_fifo() implementation for stm32_fsdev --- src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index dbd514f86..b8b0fc104 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -166,7 +166,7 @@ TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) % 8) == 0, "BTABLE base must be aligne typedef struct { uint8_t * buffer; - tu_fifo_t * ff; + // tu_fifo_t * ff; // TODO support dcd_edpt_xfer_fifo API uint16_t total_len; uint16_t queued_len; uint16_t pma_ptr; @@ -197,9 +197,10 @@ static void dcd_pma_alloc_reset(void); static uint16_t dcd_pma_alloc(uint8_t ep_addr, size_t length); static void dcd_pma_free(uint8_t ep_addr); static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, size_t wNBytes); -static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wNBytes); static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wNBytes); -static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNBytes); + +//static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wNBytes); +//static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNBytes); // Using a function due to better type checks // This seems better than having to do type casts everywhere else @@ -480,14 +481,15 @@ static void dcd_ep_ctr_rx_handler(uint32_t wIstr) if (count != 0U) { +#if 0 // TODO support dcd_edpt_xfer_fifo API if (xfer->ff) { dcd_read_packet_memory_ff(xfer->ff, *pcd_ep_rx_address_ptr(USB,EPindex), count); } else +#endif { - dcd_read_packet_memory(&(xfer->buffer[xfer->queued_len]), - *pcd_ep_rx_address_ptr(USB,EPindex), count); + dcd_read_packet_memory(&(xfer->buffer[xfer->queued_len]), *pcd_ep_rx_address_ptr(USB,EPindex), count); } xfer->queued_len = (uint16_t)(xfer->queued_len + count); @@ -816,11 +818,14 @@ static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix) len = xfer->max_packet_size; } uint16_t oldAddr = *pcd_ep_tx_address_ptr(USB,ep_ix); + +#if 0 // TODO support dcd_edpt_xfer_fifo API if (xfer->ff) { dcd_write_packet_memory_ff(xfer->ff, oldAddr, len); } else +#endif { dcd_write_packet_memory(oldAddr, &(xfer->buffer[xfer->queued_len]), len); } @@ -840,7 +845,7 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t xfer_ctl_t * xfer = xfer_ctl_ptr(epnum,dir); xfer->buffer = buffer; - xfer->ff = NULL; + // xfer->ff = NULL; // TODO support dcd_edpt_xfer_fifo API xfer->total_len = total_bytes; xfer->queued_len = 0; @@ -867,6 +872,7 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t return true; } +#if 0 // TODO support dcd_edpt_xfer_fifo API bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) { (void) rhport; @@ -877,7 +883,7 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 xfer_ctl_t * xfer = xfer_ctl_ptr(epnum,dir); xfer->buffer = NULL; - xfer->ff = ff; + // xfer->ff = ff; // TODO support dcd_edpt_xfer_fifo API xfer->total_len = total_bytes; xfer->queued_len = 0; @@ -897,6 +903,7 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 } return true; } +#endif void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr) { @@ -971,6 +978,7 @@ static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, si return true; } +#if 0 // TODO support dcd_edpt_xfer_fifo API /** * @brief Copy from FIFO to packet memory area (PMA). * Uses byte-access of system memory and 16-bit access of packet memory @@ -1015,6 +1023,7 @@ static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wN return true; } +#endif /** * @brief Copy a buffer from packet memory area (PMA) to user memory area. @@ -1051,6 +1060,7 @@ static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wN return true; } +#if 0 // TODO support dcd_edpt_xfer_fifo API /** * @brief Copy a buffer from user packet memory area (PMA) to FIFO. * Uses byte-access of system memory and 16-bit access of packet memory @@ -1097,3 +1107,5 @@ static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNB #endif +#endif + From 49b2d8f26cdf0dd832c7f3f752d5fe3cdeb45a77 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 6 Apr 2021 00:07:17 +0700 Subject: [PATCH 094/121] revert dcd_edpt_xfer_fifo() implementation for msp430 --- src/portable/ti/msp430x5xx/dcd_msp430x5xx.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c index 40b12eb04..48e9dd592 100644 --- a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c +++ b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c @@ -49,7 +49,7 @@ uint8_t _setup_packet[8]; typedef struct { uint8_t * buffer; - tu_fifo_t * ff; + // tu_fifo_t * ff; // TODO support dcd_edpt_xfer_fifo API uint16_t total_len; uint16_t queued_len; uint16_t max_size; @@ -308,7 +308,7 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); xfer->buffer = buffer; - xfer->ff = NULL; + // xfer->ff = NULL; // TODO support dcd_edpt_xfer_fifo API xfer->total_len = total_bytes; xfer->queued_len = 0; xfer->short_packet = false; @@ -347,6 +347,7 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t return true; } +#if 0 // TODO support dcd_edpt_xfer_fifo API bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) { (void) rhport; @@ -374,6 +375,7 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 return true; } +#endif void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr) { @@ -474,12 +476,14 @@ static void receive_packet(uint8_t ep_num) to_recv_size = (xfer_size > xfer->max_size) ? xfer->max_size : xfer_size; } +#if 0 // TODO support dcd_edpt_xfer_fifo API if (xfer->ff) { - volatile uint8_t * ep_buf = &USBSTABUFF + (ep_regs[BBAX] << 3); + volatile uint8_t * ep_buf = (ep_num == 0) ? &USBOEP0BUF : (&USBSTABUFF + (ep_regs[BBAX] << 3)); tu_fifo_write_n(xfer->ff, (const void *) ep_buf, to_recv_size); } else +#endif { uint8_t * base = (xfer->buffer + xfer->queued_len); @@ -565,11 +569,13 @@ static void transmit_packet(uint8_t ep_num) ep_regs_t ep_regs = EP_REGS(ep_num, TUSB_DIR_IN); volatile uint8_t * ep_buf = &USBSTABUFF + (ep_regs[BBAX] << 3); +#if 0 // TODO support dcd_edpt_xfer_fifo API if (xfer->ff) { tu_fifo_read_n(xfer->ff, (void *) ep_buf, xfer_size); } else +#endif { uint8_t * base = (xfer->buffer + xfer->queued_len); for(int i = 0; i < xfer_size; i++) From 69ad092fceb635062c20bef5bd03e325a1a5d59a Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 6 Apr 2021 00:13:12 +0700 Subject: [PATCH 095/121] revert dcd_edpt_xfer_fifo() implementation for nuc120 121 --- src/portable/nuvoton/nuc120/dcd_nuc120.c | 10 ++++++++-- src/portable/nuvoton/nuc121/dcd_nuc121.c | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/portable/nuvoton/nuc120/dcd_nuc120.c b/src/portable/nuvoton/nuc120/dcd_nuc120.c index 06ffa2965..5dc3bca21 100644 --- a/src/portable/nuvoton/nuc120/dcd_nuc120.c +++ b/src/portable/nuvoton/nuc120/dcd_nuc120.c @@ -77,7 +77,7 @@ static bool active_ep0_xfer; static struct xfer_ctl_t { uint8_t *data_ptr; /* data_ptr tracks where to next copy data to (for OUT) or from (for IN) */ - tu_fifo_t * ff; /* pointer to FIFO required for dcd_edpt_xfer_fifo() */ + // tu_fifo_t * ff; /* pointer to FIFO required for dcd_edpt_xfer_fifo() */ // TODO support dcd_edpt_xfer_fifo API union { uint16_t in_remaining_bytes; /* for IN endpoints, we track how many bytes are left to transfer */ uint16_t out_bytes_so_far; /* but for OUT endpoints, we track how many bytes we've transferred so far */ @@ -144,11 +144,13 @@ static void dcd_in_xfer(struct xfer_ctl_t *xfer, USBD_EP_T *ep) { uint16_t bytes_now = tu_min16(xfer->in_remaining_bytes, xfer->max_packet_size); +#if 0 // TODO support dcd_edpt_xfer_fifo API if (xfer->ff) { tu_fifo_read_n(xfer->ff, (void *) (USBD_BUF_BASE + ep->BUFSEG), bytes_now); } else +#endif { memcpy((uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), xfer->data_ptr, bytes_now); } @@ -277,7 +279,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to /* store away the information we'll needing now and later */ xfer->data_ptr = buffer; - xfer->ff = NULL; + // xfer->ff = NULL; // TODO support dcd_edpt_xfer_fifo API xfer->in_remaining_bytes = total_bytes; xfer->total_bytes = total_bytes; @@ -297,6 +299,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to return true; } +#if 0 // TODO support dcd_edpt_xfer_fifo API bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) { (void) rhport; @@ -324,6 +327,7 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 return true; } +#endif void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { @@ -428,11 +432,13 @@ void dcd_int_handler(uint8_t rhport) if (out_ep) { /* copy the data from the PC to the previously provided buffer */ +#if 0 // // TODO support dcd_edpt_xfer_fifo API if (xfer->ff) { tu_fifo_write_n(xfer->ff, (const void *) (USBD_BUF_BASE + ep->BUFSEG), available_bytes); } else +#endif { memcpy(xfer->data_ptr, (uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), available_bytes); xfer->data_ptr += available_bytes; diff --git a/src/portable/nuvoton/nuc121/dcd_nuc121.c b/src/portable/nuvoton/nuc121/dcd_nuc121.c index 6d98ba08a..d50e82846 100644 --- a/src/portable/nuvoton/nuc121/dcd_nuc121.c +++ b/src/portable/nuvoton/nuc121/dcd_nuc121.c @@ -79,7 +79,7 @@ static bool active_ep0_xfer; static struct xfer_ctl_t { uint8_t *data_ptr; /* data_ptr tracks where to next copy data to (for OUT) or from (for IN) */ - tu_fifo_t * ff; + // tu_fifo_t * ff; // TODO support dcd_edpt_xfer_fifo API union { uint16_t in_remaining_bytes; /* for IN endpoints, we track how many bytes are left to transfer */ uint16_t out_bytes_so_far; /* but for OUT endpoints, we track how many bytes we've transferred so far */ @@ -146,11 +146,13 @@ static void dcd_in_xfer(struct xfer_ctl_t *xfer, USBD_EP_T *ep) { uint16_t bytes_now = tu_min16(xfer->in_remaining_bytes, xfer->max_packet_size); +#if 0 // TODO support dcd_edpt_xfer_fifo API if (xfer->ff) { tu_fifo_read_n(xfer->ff, (void *) (USBD_BUF_BASE + ep->BUFSEG), bytes_now); } else +#endif { memcpy((uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), xfer->data_ptr, bytes_now); } @@ -283,7 +285,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to /* store away the information we'll needing now and later */ xfer->data_ptr = buffer; - xfer->ff = NULL; + // xfer->ff = NULL; // TODO support dcd_edpt_xfer_fifo API xfer->in_remaining_bytes = total_bytes; xfer->total_bytes = total_bytes; @@ -303,6 +305,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to return true; } +#if 0 // TODO support dcd_edpt_xfer_fifo API bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) { (void) rhport; @@ -330,6 +333,7 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 return true; } +#endif void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { @@ -439,11 +443,13 @@ void dcd_int_handler(uint8_t rhport) if (out_ep) { /* copy the data from the PC to the previously provided buffer */ +#if 0 // TODO support dcd_edpt_xfer_fifo API if (xfer->ff) { tu_fifo_write_n(xfer->ff, (const void *) (USBD_BUF_BASE + ep->BUFSEG), available_bytes); } else +#endif { memcpy(xfer->data_ptr, (uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), available_bytes); xfer->data_ptr += available_bytes; From 3acf0c2d73defdc92de02db2456591b8a441a2e0 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 6 Apr 2021 01:00:00 +0700 Subject: [PATCH 096/121] revert dcd_edpt_xfer_fifo() implementation for esp32s2 --- src/portable/espressif/esp32s2/dcd_esp32s2.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/portable/espressif/esp32s2/dcd_esp32s2.c b/src/portable/espressif/esp32s2/dcd_esp32s2.c index 28a3bcd07..edbc872fe 100644 --- a/src/portable/espressif/esp32s2/dcd_esp32s2.c +++ b/src/portable/espressif/esp32s2/dcd_esp32s2.c @@ -60,7 +60,7 @@ typedef struct { uint8_t *buffer; - tu_fifo_t * ff; + // tu_fifo_t * ff; // TODO support dcd_edpt_xfer_fifo API uint16_t total_len; uint16_t queued_len; uint16_t max_size; @@ -321,7 +321,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); xfer->buffer = buffer; - xfer->ff = NULL; + // xfer->ff = NULL; // TODO support dcd_edpt_xfer_fifo API xfer->total_len = total_bytes; xfer->queued_len = 0; xfer->short_packet = false; @@ -357,6 +357,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to return true; } +#if 0 // TODO support dcd_edpt_xfer_fifo API bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) { (void)rhport; @@ -404,6 +405,7 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 } return true; } +#endif void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { @@ -514,12 +516,14 @@ static void receive_packet(xfer_ctl_t *xfer, /* usb_out_endpoint_t * out_ep, */ } // Common buffer read +#if 0 // TODO support dcd_edpt_xfer_fifo API if (xfer->ff) { // Ring buffer tu_fifo_write_n_const_addr_full_words(xfer->ff, (const void *) rx_fifo, to_recv_size); } else +#endif { uint8_t to_recv_rem = to_recv_size % 4; uint16_t to_recv_size_aligned = to_recv_size - to_recv_rem; @@ -571,11 +575,13 @@ static void transmit_packet(xfer_ctl_t *xfer, volatile usb_in_endpoint_t *in_ep, uint16_t to_xfer_size = (remaining > xfer->max_size) ? xfer->max_size : remaining; +#if 0 // TODO support dcd_edpt_xfer_fifo API if (xfer->ff) { tu_fifo_read_n_const_addr_full_words(xfer->ff, (void *) tx_fifo, to_xfer_size); } else +#endif { uint8_t to_xfer_rem = to_xfer_size % 4; uint16_t to_xfer_size_aligned = to_xfer_size - to_xfer_rem; From 7ab8da949e6622f59e49d7435a22f52a18940350 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 6 Apr 2021 01:07:32 +0700 Subject: [PATCH 097/121] audio driver only use USE_LINEAR_BUFFER = 0 for stm32 synopsys driver --- src/class/audio/audio_device.c | 47 +++++++++++++++++----------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index dadb66caa..634e9e4d2 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -63,33 +63,32 @@ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ -// Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically -#if ( CFG_TUSB_MCU == OPT_MCU_MKL25ZXX || /* Intermediate software buffer required */ \ - CFG_TUSB_MCU == OPT_MCU_DA1469X || /* Intermediate software buffer required */ \ - CFG_TUSB_MCU == OPT_MCU_LPC18XX || /* No clue how driver works */ \ - CFG_TUSB_MCU == OPT_MCU_LPC43XX || \ - CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \ - CFG_TUSB_MCU == OPT_MCU_RP2040 || /* Don't want to change driver */ \ - CFG_TUSB_MCU == OPT_MCU_VALENTYUSB_EPTRI || /* Intermediate software buffer required */ \ - CFG_TUSB_MCU == OPT_MCU_CXD56 || /* No clue how driver works */ \ - CFG_TUSB_MCU == OPT_MCU_NRF5X || /* Uses DMA - Ok for FIFO, had no time for implementation */ \ - CFG_TUSB_MCU == OPT_MCU_LPC11UXX || /* Uses DMA - Ok for FIFO, had no time for implementation */ \ - CFG_TUSB_MCU == OPT_MCU_LPC13XX || \ - CFG_TUSB_MCU == OPT_MCU_LPC15XX || \ - CFG_TUSB_MCU == OPT_MCU_LPC51UXX || \ - CFG_TUSB_MCU == OPT_MCU_LPC54XXX || \ - CFG_TUSB_MCU == OPT_MCU_LPC55XX || \ - CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || \ - CFG_TUSB_MCU == OPT_MCU_LPC40XX || \ - CFG_TUSB_MCU == OPT_MCU_SAMD11 || /* Uses DMA - Ok for FIFO, had no time for implementation */ \ - CFG_TUSB_MCU == OPT_MCU_SAMD21 || \ - CFG_TUSB_MCU == OPT_MCU_SAMD51 || \ - CFG_TUSB_MCU == OPT_MCU_SAME5X ) +// Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer +// is available or driver is would need to be changed dramatically -#define USE_LINEAR_BUFFER 1 +// Only STM32 synopsys use non-linear buffer for now +// Synopsys detection copied from dcd_synopsys.c (refactor later on) +#if defined (STM32F105x8) || defined (STM32F105xB) || defined (STM32F105xC) || \ + defined (STM32F107xB) || defined (STM32F107xC) +#define STM32F1_SYNOPSYS +#endif +#if defined (STM32L475xx) || defined (STM32L476xx) || \ + defined (STM32L485xx) || defined (STM32L486xx) || defined (STM32L496xx) || \ + defined (STM32L4R5xx) || defined (STM32L4R7xx) || defined (STM32L4R9xx) || \ + defined (STM32L4S5xx) || defined (STM32L4S7xx) || defined (STM32L4S9xx) +#define STM32L4_SYNOPSYS +#endif + +#if (CFG_TUSB_MCU == OPT_MCU_STM32F1 && defined(STM32F1_SYNOPSYS)) || \ + CFG_TUSB_MCU == OPT_MCU_STM32F2 || \ + CFG_TUSB_MCU == OPT_MCU_STM32F4 || \ + CFG_TUSB_MCU == OPT_MCU_STM32F7 || \ + CFG_TUSB_MCU == OPT_MCU_STM32H7 || \ + (CFG_TUSB_MCU == OPT_MCU_STM32L4 && defined(STM32L4_SYNOPSYS)) \ + #define USE_LINEAR_BUFFER 0 #else -#define USE_LINEAR_BUFFER 0 + #define USE_LINEAR_BUFFER 1 #endif // Declaration of buffers From 68687ed0f400adc456cd8e4dbda4eb7d8e32d5cd Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 6 Apr 2021 01:16:51 +0700 Subject: [PATCH 098/121] fix build --- src/class/audio/audio_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 634e9e4d2..a85dfddb8 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -85,7 +85,7 @@ CFG_TUSB_MCU == OPT_MCU_STM32F4 || \ CFG_TUSB_MCU == OPT_MCU_STM32F7 || \ CFG_TUSB_MCU == OPT_MCU_STM32H7 || \ - (CFG_TUSB_MCU == OPT_MCU_STM32L4 && defined(STM32L4_SYNOPSYS)) \ + (CFG_TUSB_MCU == OPT_MCU_STM32L4 && defined(STM32L4_SYNOPSYS)) #define USE_LINEAR_BUFFER 0 #else #define USE_LINEAR_BUFFER 1 From 8b79040c3864f9d76bba90b8660464f1821209a5 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 6 Apr 2021 15:34:50 +0700 Subject: [PATCH 099/121] code format --- examples/device/audio_test/src/main.c | 134 ++++++++++++++------------ src/class/audio/audio.h | 16 --- 2 files changed, 73 insertions(+), 77 deletions(-) diff --git a/examples/device/audio_test/src/main.c b/examples/device/audio_test/src/main.c index f01a5a183..4de515b3b 100644 --- a/examples/device/audio_test/src/main.c +++ b/examples/device/audio_test/src/main.c @@ -207,7 +207,6 @@ bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * mute[channelNum] = ((audio_control_cur_1_t*) pBuff)->bCur; TU_LOG2(" Set Mute: %d of channel: %u\r\n", mute[channelNum], channelNum); - return true; case AUDIO_FU_CTRL_VOLUME: @@ -217,8 +216,7 @@ bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * volume[channelNum] = ((audio_control_cur_2_t*) pBuff)->bCur; TU_LOG2(" Set Volume: %d dB of channel: %u\r\n", volume[channelNum], channelNum); - - return true; + return true; // Unknown/Unsupported control default: @@ -275,96 +273,110 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * // Input terminal (Microphone input) if (entityID == 1) { - switch (ctrlSel) + switch ( ctrlSel ) { - case AUDIO_TE_CTRL_CONNECTOR:; - // The terminal connector control only has a get request with only the CUR attribute. + case AUDIO_TE_CTRL_CONNECTOR: + { + // The terminal connector control only has a get request with only the CUR attribute. + audio_desc_channel_cluster_t ret; - audio_desc_channel_cluster_t ret; + // Those are dummy values for now + ret.bNrChannels = 1; + ret.bmChannelConfig = 0; + ret.iChannelNames = 0; - // Those are dummy values for now - ret.bNrChannels = 1; - ret.bmChannelConfig = 0; - ret.iChannelNames = 0; + TU_LOG2(" Get terminal connector\r\n"); - TU_LOG2(" Get terminal connector\r\n"); + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void*) &ret, sizeof(ret)); + } + break; - return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void*)&ret, sizeof(ret)); - - // Unknown/Unsupported control selector - default: TU_BREAKPOINT(); return false; + // Unknown/Unsupported control selector + default: + TU_BREAKPOINT(); + return false; } } // Feature unit if (entityID == 2) { - switch (ctrlSel) + switch ( ctrlSel ) { case AUDIO_FU_CTRL_MUTE: - // Audio control mute cur parameter block consists of only one byte - we thus can send it right away - // There does not exist a range parameter block for mute - TU_LOG2(" Get Mute of channel: %u\r\n", channelNum); - return tud_control_xfer(rhport, p_request, &mute[channelNum], 1); + // Audio control mute cur parameter block consists of only one byte - we thus can send it right away + // There does not exist a range parameter block for mute + TU_LOG2(" Get Mute of channel: %u\r\n", channelNum); + return tud_control_xfer(rhport, p_request, &mute[channelNum], 1); case AUDIO_FU_CTRL_VOLUME: + switch ( p_request->bRequest ) + { + case AUDIO_CS_REQ_CUR: + TU_LOG2(" Get Volume of channel: %u\r\n", channelNum); + return tud_control_xfer(rhport, p_request, &volume[channelNum], sizeof(volume[channelNum])); - switch (p_request->bRequest) - { - case AUDIO_CS_REQ_CUR: - TU_LOG2(" Get Volume of channel: %u\r\n", channelNum); - return tud_control_xfer(rhport, p_request, &volume[channelNum], sizeof(volume[channelNum])); - case AUDIO_CS_REQ_RANGE: - TU_LOG2(" Get Volume range of channel: %u\r\n", channelNum); + case AUDIO_CS_REQ_RANGE: + TU_LOG2(" Get Volume range of channel: %u\r\n", channelNum); - // Copy values - only for testing - better is version below - audio_control_range_2_n_t(1) ret; + // Copy values - only for testing - better is version below + audio_control_range_2_n_t(1) + ret; - ret.wNumSubRanges = 1; - ret.subrange[0].bMin = -90; // -90 dB - ret.subrange[0].bMax = 90; // +90 dB - ret.subrange[0].bRes = 1; // 1 dB steps + ret.wNumSubRanges = 1; + ret.subrange[0].bMin = -90; // -90 dB + ret.subrange[0].bMax = 90; // +90 dB + ret.subrange[0].bRes = 1; // 1 dB steps - return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void*)&ret, sizeof(ret)); + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void*) &ret, sizeof(ret)); - // Unknown/Unsupported control - default: TU_BREAKPOINT(); return false; - } + // Unknown/Unsupported control + default: + TU_BREAKPOINT(); + return false; + } + break; - // Unknown/Unsupported control - default: TU_BREAKPOINT(); return false; + // Unknown/Unsupported control + default: + TU_BREAKPOINT(); + return false; } } // Clock Source unit - if (entityID == 4) + if ( entityID == 4 ) { - switch (ctrlSel) + switch ( ctrlSel ) { case AUDIO_CS_CTRL_SAM_FREQ: + // channelNum is always zero in this case + switch ( p_request->bRequest ) + { + case AUDIO_CS_REQ_CUR: + TU_LOG2(" Get Sample Freq.\r\n"); + return tud_control_xfer(rhport, p_request, &sampFreq, sizeof(sampFreq)); - // channelNum is always zero in this case + case AUDIO_CS_REQ_RANGE: + TU_LOG2(" Get Sample Freq. range\r\n"); + return tud_control_xfer(rhport, p_request, &sampleFreqRng, sizeof(sampleFreqRng)); - switch (p_request->bRequest) - { - case AUDIO_CS_REQ_CUR: - TU_LOG2(" Get Sample Freq.\r\n"); - return tud_control_xfer(rhport, p_request, &sampFreq, sizeof(sampFreq)); - case AUDIO_CS_REQ_RANGE: - TU_LOG2(" Get Sample Freq. range\r\n"); - return tud_control_xfer(rhport, p_request, &sampleFreqRng, sizeof(sampleFreqRng)); + // Unknown/Unsupported control + default: + TU_BREAKPOINT(); + return false; + } + break; - // Unknown/Unsupported control - default: TU_BREAKPOINT(); return false; - } + case AUDIO_CS_CTRL_CLK_VALID: + // Only cur attribute exists for this request + TU_LOG2(" Get Sample Freq. valid\r\n"); + return tud_control_xfer(rhport, p_request, &clkValid, sizeof(clkValid)); - case AUDIO_CS_CTRL_CLK_VALID: - // Only cur attribute exists for this request - TU_LOG2(" Get Sample Freq. valid\r\n"); - return tud_control_xfer(rhport, p_request, &clkValid, sizeof(clkValid)); - - // Unknown/Unsupported control - default: TU_BREAKPOINT(); return false; + // Unknown/Unsupported control + default: + TU_BREAKPOINT(); + return false; } } diff --git a/src/class/audio/audio.h b/src/class/audio/audio.h index 2c6cd260a..936f09104 100644 --- a/src/class/audio/audio.h +++ b/src/class/audio/audio.h @@ -481,15 +481,6 @@ typedef enum AUDIO_EXT_FORMAT_TYPE_III = 0x83, } audio_format_type_t; -//#define AUDIO_FORMAT_TYPE_UNDEFINED 0x00 -//#define AUDIO_FORMAT_TYPE_I 0x01 -//#define AUDIO_FORMAT_TYPE_II 0x02 -//#define AUDIO_FORMAT_TYPE_III 0x03 -//#define AUDIO_FORMAT_TYPE_IV 0x04 -//#define AUDIO_EXT_FORMAT_TYPE_I 0x81 -//#define AUDIO_EXT_FORMAT_TYPE_II 0x82 -//#define AUDIO_EXT_FORMAT_TYPE_III 0x83 - // A.2.1 - Audio Class-Audio Data Format Type I UAC2 typedef enum { @@ -501,13 +492,6 @@ typedef enum AUDIO_DATA_FORMAT_TYPE_I_RAW_DATA = 0x100000000, } audio_data_format_type_I_t; -//#define AUDIO_DATA_FORMAT_TYPE_I_PCM ((uint32_t) (1 << 0)) -//#define AUDIO_DATA_FORMAT_TYPE_I_PCM8 ((uint32_t) (1 << 1)) -//#define AUDIO_DATA_FORMAT_TYPE_I_IEEE_FLOAT ((uint32_t) (1 << 2)) -//#define AUDIO_DATA_FORMAT_TYPE_I_ALAW ((uint32_t) (1 << 3)) -//#define AUDIO_DATA_FORMAT_TYPE_I_MULAW ((uint32_t) (1 << 4)) -//#define AUDIO_DATA_FORMAT_TYPE_I_RAW_DATA 0x100000000 - /// All remaining definitions are taken from the descriptor descriptions in the UAC2 main specification /// Isochronous End Point Attributes From 58bab86d794aad8979bd2557bdc81f44d0731a97 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 6 Apr 2021 21:09:23 +0700 Subject: [PATCH 100/121] minor clean up --- src/class/audio/audio_device.h | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index d4793c9d8..81e0024d7 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -496,17 +496,17 @@ static inline bool tud_audio_mounted(void) #if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING -static inline uint16_t tud_audio_available (void) +static inline uint16_t tud_audio_available(void) { return tud_audio_n_available(0); } -static inline uint16_t tud_audio_read (void* buffer, uint16_t bufsize) +static inline uint16_t tud_audio_read(void* buffer, uint16_t bufsize) { return tud_audio_n_read(0, buffer, bufsize); } -static inline bool tud_audio_clear_ep_out_ff (void) +static inline bool tud_audio_clear_ep_out_ff(void) { return tud_audio_n_clear_ep_out_ff(0); } @@ -515,17 +515,17 @@ static inline bool tud_audio_clear_ep_out_ff (void) #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING -static inline bool tud_audio_clear_rx_support_ff (uint8_t channelId) +static inline bool tud_audio_clear_rx_support_ff(uint8_t channelId) { return tud_audio_n_clear_rx_support_ff(0, channelId); } -static inline uint16_t tud_audio_available_support_ff (uint8_t channelId) +static inline uint16_t tud_audio_available_support_ff(uint8_t channelId) { return tud_audio_n_available_support_ff(0, channelId); } -static inline uint16_t tud_audio_read_support_ff (uint8_t channelId, void* buffer, uint16_t bufsize) +static inline uint16_t tud_audio_read_support_ff(uint8_t channelId, void* buffer, uint16_t bufsize) { return tud_audio_n_read_support_ff(0, channelId, buffer, bufsize); } @@ -536,12 +536,12 @@ static inline uint16_t tud_audio_read_support_ff (uint8_t channelId, #if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING -static inline uint16_t tud_audio_write (const void * data, uint16_t len) +static inline uint16_t tud_audio_write(const void * data, uint16_t len) { return tud_audio_n_write(0, data, len); } -static inline bool tud_audio_clear_ep_in_ff (void) +static inline bool tud_audio_clear_ep_in_ff(void) { return tud_audio_n_clear_ep_in_ff(0); } @@ -550,17 +550,17 @@ static inline bool tud_audio_clear_ep_in_ff (void) #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING -static inline uint16_t tud_audio_flush_tx_support_ff (void) +static inline uint16_t tud_audio_flush_tx_support_ff(void) { return tud_audio_n_flush_tx_support_ff(0); } -static inline uint16_t tud_audio_clear_tx_support_ff (uint8_t channelId) +static inline uint16_t tud_audio_clear_tx_support_ff(uint8_t channelId) { return tud_audio_n_clear_tx_support_ff(0, channelId); } -static inline uint16_t tud_audio_write_support_ff (uint8_t channelId, const void * data, uint16_t len) +static inline uint16_t tud_audio_write_support_ff(uint8_t channelId, const void * data, uint16_t len) { return tud_audio_n_write_support_ff(0, channelId, data, len); } @@ -584,11 +584,11 @@ static inline bool tud_audio_fb_set(uint32_t feedback) //--------------------------------------------------------------------+ // Internal Class Driver API //--------------------------------------------------------------------+ -void audiod_init (void); -void audiod_reset (uint8_t rhport); -uint16_t audiod_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -bool audiod_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); -bool audiod_xfer_cb (uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes); +void audiod_init (void); +void audiod_reset (uint8_t rhport); +uint16_t audiod_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +bool audiod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); +bool audiod_xfer_cb (uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes); #ifdef __cplusplus } From d82ee2f8c04342390d2c754f14ad13673a7f6c11 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 6 Apr 2021 23:12:04 +0700 Subject: [PATCH 101/121] refactor _ff_pull_n() with const addr --- src/common/tusb_fifo.c | 77 +++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 46 deletions(-) diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 1b7f64447..184807bef 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -139,37 +139,30 @@ static void _tu_fifo_read_from_const_src_ptr_in_full_words(void * dst, const voi } // Intended to be used to write to hardware USB FIFO in e.g. STM32 where all data is written to a constant address in full word copies -static void _tu_fifo_write_to_const_dst_ptr_in_full_words(void * dst, const void * src, uint16_t len) +static void _ff_pull_const_addr_in_full_words(void * dst, const uint8_t * src, uint16_t len) { volatile uint32_t * tx_fifo = (volatile uint32_t *) dst; - // Optimize for fast word copies - typedef struct{ - uint32_t val; - } __attribute((__packed__)) unaligned_uint32_t; - - unaligned_uint32_t* src_una = (unaligned_uint32_t *) src; - // Pushing full available 32 bit words to FIFO uint16_t full_words = len >> 2; while(full_words--) { - *tx_fifo = src_una->val; - src_una++; + *tx_fifo = tu_unaligned_read32(src); + src += 4; } // Write the remaining 1-3 bytes into FIFO uint8_t bytes_rem = len & 0x03; - if(bytes_rem){ - uint8_t * src_u8 = (uint8_t *) src_una; - uint32_t tmp = 0; - uint8_t * dst_u8 = (uint8_t *)&tmp; + if(bytes_rem) + { + uint32_t tmp32 = 0; + uint8_t* dst8 = (uint8_t*) &tmp32; while(bytes_rem--) { - *dst_u8++ = *src_u8++; + *dst8++ = *src++; } - *tx_fifo = tmp; + *tx_fifo = tmp32; } } @@ -270,12 +263,12 @@ static inline void _ff_pull(tu_fifo_t* f, void * p_buffer, uint16_t rRel) } // get n items from FIFO WITHOUT updating read pointer -static void _ff_pull_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint16_t rRel, tu_fifo_copy_mode_t copy_mode) +static void _ff_pull_n(tu_fifo_t* f, uint8_t* p_buffer, uint16_t n, uint16_t rRel, tu_fifo_copy_mode_t copy_mode) { switch (copy_mode) { case TU_FIFO_COPY_INC: - if(n <= f->depth-rRel) + if ( n <= f->depth - rRel ) { // Linear mode only memcpy(p_buffer, f->buffer + (rRel * f->item_size), n*f->item_size); @@ -289,68 +282,60 @@ static void _ff_pull_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint16_t rRel, memcpy(p_buffer, f->buffer + (rRel * f->item_size), nLin*f->item_size); // Read data wrapped part - memcpy((uint8_t*)p_buffer + nLin*f->item_size, f->buffer, (n - nLin) * f->item_size); + memcpy(p_buffer + nLin*f->item_size, f->buffer, (n - nLin) * f->item_size); } break; case TU_FIFO_COPY_CST_FULL_WORDS: - - if(n <= f->depth-rRel) + if ( n <= f->depth - rRel ) { // Linear mode only - _tu_fifo_write_to_const_dst_ptr_in_full_words(p_buffer, f->buffer + (rRel * f->item_size), n*f->item_size); + _ff_pull_const_addr_in_full_words(p_buffer, f->buffer + (rRel * f->item_size), n*f->item_size); } else { + // since it is const address, we don't increase p_buffer + volatile uint32_t * tx_fifo = (volatile uint32_t *) p_buffer; + uint8_t* src = f->buffer + (rRel * f->item_size); + // Wrap around case uint16_t nLin = (f->depth - rRel) * f->item_size; + uint16_t nLin_4n = nLin & 0xFFFC; + uint16_t nWrap = (n - nLin) * f->item_size; - // Optimize for fast word copies - typedef struct{ - uint32_t val; - } __attribute((__packed__)) unaligned_uint32_t; + // Read data from linear part of buffer + _ff_pull_const_addr_in_full_words(p_buffer, src, nLin_4n); - unaligned_uint32_t* src = (unaligned_uint32_t*)(f->buffer + (rRel * f->item_size)); + src += nLin_4n; - volatile uint32_t * tx_fifo = (volatile uint32_t *) p_buffer; - - // Pushing full available 32 bit words to FIFO - uint16_t full_words = nLin >> 2; - while(full_words--) - { - *tx_fifo = src->val; - src++; - } - - uint8_t * src_u8; - uint8_t rem = nLin & 0x03; + // There could be odd 1-3 bytes before the wrap-around boundary // Handle wrap around - do it manually as these are only 4 bytes and its faster without memcpy + uint8_t rem = nLin & 0x03; if (rem > 0) { - src_u8 = (uint8_t *) src; uint8_t remrem = tu_min16(nWrap, 4-rem); nWrap -= remrem; uint32_t tmp; uint8_t * dst_u8 = (uint8_t *)&tmp; while(rem--) { - *dst_u8++ = *src_u8++; + *dst_u8++ = *src++; } - src_u8 = f->buffer; + src = f->buffer; while(remrem--) { - *dst_u8++ = *src_u8++; + *dst_u8++ = *src++; } *tx_fifo = tmp; } else { - src_u8 = f->buffer; + src = f->buffer; // wrap around to beginning } // Final linear part - if (nWrap > 0) _tu_fifo_write_to_const_dst_ptr_in_full_words(p_buffer, src_u8, nWrap); + if (nWrap > 0) _ff_pull_const_addr_in_full_words(p_buffer, src, nWrap); } break; } @@ -482,7 +467,7 @@ static uint16_t _tu_fifo_peek_at_n(tu_fifo_t* f, uint16_t offset, void * p_buffe uint16_t rRel = get_relative_pointer(f, rAbs, offset); // Peek data - _ff_pull_n(f, p_buffer, n, rRel, copy_mode); + _ff_pull_n(f, (uint8_t*) p_buffer, n, rRel, copy_mode); return n; } From a3c06aa7bc66c33c2a4801426934ced1ed72ce6e Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 6 Apr 2021 23:39:39 +0700 Subject: [PATCH 102/121] more clean up for _ff_pull_const_addr_in_full_words() --- src/common/tusb_fifo.c | 64 ++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 184807bef..0b5b6854f 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -265,68 +265,68 @@ static inline void _ff_pull(tu_fifo_t* f, void * p_buffer, uint16_t rRel) // get n items from FIFO WITHOUT updating read pointer static void _ff_pull_n(tu_fifo_t* f, uint8_t* p_buffer, uint16_t n, uint16_t rRel, tu_fifo_copy_mode_t copy_mode) { + uint16_t const nLin = f->depth - rRel; + uint16_t const nWrap = n - nLin; // only used if wrapped + switch (copy_mode) { case TU_FIFO_COPY_INC: - if ( n <= f->depth - rRel ) + if ( n <= nLin ) { - // Linear mode only + // Linear only memcpy(p_buffer, f->buffer + (rRel * f->item_size), n*f->item_size); } else { // Wrap around - uint16_t nLin = f->depth - rRel; // Read data from linear part of buffer memcpy(p_buffer, f->buffer + (rRel * f->item_size), nLin*f->item_size); // Read data wrapped part - memcpy(p_buffer + nLin*f->item_size, f->buffer, (n - nLin) * f->item_size); + memcpy(p_buffer + nLin*f->item_size, f->buffer, nWrap*f->item_size); } - break; + break; case TU_FIFO_COPY_CST_FULL_WORDS: - if ( n <= f->depth - rRel ) + if ( n <= nLin ) { // Linear mode only _ff_pull_const_addr_in_full_words(p_buffer, f->buffer + (rRel * f->item_size), n*f->item_size); } else { - // since it is const address, we don't increase p_buffer - volatile uint32_t * tx_fifo = (volatile uint32_t *) p_buffer; + // Wrap around case + + uint16_t nLin_bytes = nLin * f->item_size; + uint16_t nWrap_bytes = nWrap * f->item_size; + uint8_t* src = f->buffer + (rRel * f->item_size); - // Wrap around case - uint16_t nLin = (f->depth - rRel) * f->item_size; - uint16_t nLin_4n = nLin & 0xFFFC; - - uint16_t nWrap = (n - nLin) * f->item_size; - // Read data from linear part of buffer - _ff_pull_const_addr_in_full_words(p_buffer, src, nLin_4n); - - src += nLin_4n; + uint16_t nLin_4n_bytes = nLin_bytes & 0xFFFC; + _ff_pull_const_addr_in_full_words(p_buffer, src, nLin_4n_bytes); + src += nLin_4n_bytes; // There could be odd 1-3 bytes before the wrap-around boundary // Handle wrap around - do it manually as these are only 4 bytes and its faster without memcpy - uint8_t rem = nLin & 0x03; + volatile uint32_t * tx_fifo = (volatile uint32_t *) p_buffer; + uint8_t rem = nLin_bytes & 0x03; if (rem > 0) { - uint8_t remrem = tu_min16(nWrap, 4-rem); - nWrap -= remrem; + uint8_t remrem = tu_min16(nWrap_bytes, 4-rem); + nWrap_bytes -= remrem; + uint32_t tmp; uint8_t * dst_u8 = (uint8_t *)&tmp; - while(rem--) - { - *dst_u8++ = *src++; - } + + // Get 1-3 bytes before wrapped boundary + while(rem--) *dst_u8++ = *src++; + + // Get more bytes from beginning to form a complete word src = f->buffer; - while(remrem--) - { - *dst_u8++ = *src++; - } + while(remrem--) *dst_u8++ = *src++; + *tx_fifo = tmp; } else @@ -334,10 +334,12 @@ static void _ff_pull_n(tu_fifo_t* f, uint8_t* p_buffer, uint16_t n, uint16_t rRe src = f->buffer; // wrap around to beginning } - // Final linear part - if (nWrap > 0) _ff_pull_const_addr_in_full_words(p_buffer, src, nWrap); + // Read data wrapped part + if (nWrap_bytes > 0) _ff_pull_const_addr_in_full_words(p_buffer, src, nWrap_bytes); } - break; + break; + + default: break; } } // Advance an absolute pointer From 8ac156622d6e1021cc96055da9036d50b55e936d Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 7 Apr 2021 00:38:12 +0700 Subject: [PATCH 103/121] fix cast-align warning --- src/common/tusb_fifo.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 0b5b6854f..4061514a0 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -263,7 +263,7 @@ static inline void _ff_pull(tu_fifo_t* f, void * p_buffer, uint16_t rRel) } // get n items from FIFO WITHOUT updating read pointer -static void _ff_pull_n(tu_fifo_t* f, uint8_t* p_buffer, uint16_t n, uint16_t rRel, tu_fifo_copy_mode_t copy_mode) +static void _ff_pull_n(tu_fifo_t* f, void* p_buffer, uint16_t n, uint16_t rRel, tu_fifo_copy_mode_t copy_mode) { uint16_t const nLin = f->depth - rRel; uint16_t const nWrap = n - nLin; // only used if wrapped @@ -284,7 +284,7 @@ static void _ff_pull_n(tu_fifo_t* f, uint8_t* p_buffer, uint16_t n, uint16_t rRe memcpy(p_buffer, f->buffer + (rRel * f->item_size), nLin*f->item_size); // Read data wrapped part - memcpy(p_buffer + nLin*f->item_size, f->buffer, nWrap*f->item_size); + memcpy((uint8_t*) p_buffer + nLin*f->item_size, f->buffer, nWrap*f->item_size); } break; @@ -469,7 +469,7 @@ static uint16_t _tu_fifo_peek_at_n(tu_fifo_t* f, uint16_t offset, void * p_buffe uint16_t rRel = get_relative_pointer(f, rAbs, offset); // Peek data - _ff_pull_n(f, (uint8_t*) p_buffer, n, rRel, copy_mode); + _ff_pull_n(f, p_buffer, n, rRel, copy_mode); return n; } From d0fa4d5189a6f75a3028897b04e9c30481689b59 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 7 Apr 2021 12:24:24 +0700 Subject: [PATCH 104/121] rename --- src/common/tusb_fifo.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 4061514a0..99f107581 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -105,7 +105,7 @@ static inline uint16_t _ff_mod(uint16_t idx, uint16_t depth) // Intended to be used to read from hardware USB FIFO in e.g. STM32 where all data is read from a constant address // Code adapted from dcd_synopsis.c // TODO generalize with configurable 1 byte or 4 byte each read -static void _tu_fifo_read_from_const_src_ptr_in_full_words(void * dst, const void * src, uint16_t len) +static void _ff_push_const_addr(void * dst, const void * src, uint16_t len) { volatile uint32_t * rx_fifo = (volatile uint32_t *) src; @@ -139,7 +139,7 @@ static void _tu_fifo_read_from_const_src_ptr_in_full_words(void * dst, const voi } // Intended to be used to write to hardware USB FIFO in e.g. STM32 where all data is written to a constant address in full word copies -static void _ff_pull_const_addr_in_full_words(void * dst, const uint8_t * src, uint16_t len) +static void _ff_pull_const_addr(void * dst, const uint8_t * src, uint16_t len) { volatile uint32_t * tx_fifo = (volatile uint32_t *) dst; @@ -200,7 +200,7 @@ static void _ff_push_n(tu_fifo_t* f, void const * data, uint16_t n, uint16_t wRe if(n <= f->depth-wRel) { // Linear mode only - _tu_fifo_read_from_const_src_ptr_in_full_words(f->buffer + (wRel * f->item_size), data, n*f->item_size); + _ff_push_const_addr(f->buffer + (wRel * f->item_size), data, n*f->item_size); } else { @@ -250,7 +250,7 @@ static void _ff_push_n(tu_fifo_t* f, void const * data, uint16_t n, uint16_t wRe } // Final part - if (nWrap > 0) _tu_fifo_read_from_const_src_ptr_in_full_words(dst_u8, data, nWrap); + if (nWrap > 0) _ff_push_const_addr(dst_u8, data, nWrap); } break; } @@ -292,7 +292,7 @@ static void _ff_pull_n(tu_fifo_t* f, void* p_buffer, uint16_t n, uint16_t rRel, if ( n <= nLin ) { // Linear mode only - _ff_pull_const_addr_in_full_words(p_buffer, f->buffer + (rRel * f->item_size), n*f->item_size); + _ff_pull_const_addr(p_buffer, f->buffer + (rRel * f->item_size), n*f->item_size); } else { @@ -305,7 +305,7 @@ static void _ff_pull_n(tu_fifo_t* f, void* p_buffer, uint16_t n, uint16_t rRel, // Read data from linear part of buffer uint16_t nLin_4n_bytes = nLin_bytes & 0xFFFC; - _ff_pull_const_addr_in_full_words(p_buffer, src, nLin_4n_bytes); + _ff_pull_const_addr(p_buffer, src, nLin_4n_bytes); src += nLin_4n_bytes; // There could be odd 1-3 bytes before the wrap-around boundary @@ -335,7 +335,7 @@ static void _ff_pull_n(tu_fifo_t* f, void* p_buffer, uint16_t n, uint16_t rRel, } // Read data wrapped part - if (nWrap_bytes > 0) _ff_pull_const_addr_in_full_words(p_buffer, src, nWrap_bytes); + if (nWrap_bytes > 0) _ff_pull_const_addr(p_buffer, src, nWrap_bytes); } break; From d6737fb5fe9b2f51767c62b6e8d4e9c526d579ae Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 7 Apr 2021 12:34:00 +0700 Subject: [PATCH 105/121] use tu_unaligned_write32() for _ff_push_const_addr --- src/common/tusb_fifo.c | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 99f107581..5f8623786 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -105,35 +105,28 @@ static inline uint16_t _ff_mod(uint16_t idx, uint16_t depth) // Intended to be used to read from hardware USB FIFO in e.g. STM32 where all data is read from a constant address // Code adapted from dcd_synopsis.c // TODO generalize with configurable 1 byte or 4 byte each read -static void _ff_push_const_addr(void * dst, const void * src, uint16_t len) +static void _ff_push_const_addr(uint8_t * dst, const void * src, uint16_t len) { volatile uint32_t * rx_fifo = (volatile uint32_t *) src; - // Optimize for fast word copies - typedef struct{ - uint32_t val; - } __attribute((__packed__)) unaligned_uint32_t; - - unaligned_uint32_t* dst_una = (unaligned_uint32_t*)dst; - // Reading full available 32 bit words from FIFO uint16_t full_words = len >> 2; while(full_words--) { - dst_una->val = *rx_fifo; - dst_una++; + tu_unaligned_write32(dst, *rx_fifo); + dst += 4; } // Read the remaining 1-3 bytes from FIFO uint8_t bytes_rem = len & 0x03; - if(bytes_rem != 0) { - uint8_t * dst_u8 = (uint8_t *)dst_una; - uint32_t tmp = *rx_fifo; - uint8_t * src_u8 = (uint8_t *) &tmp; + if ( bytes_rem ) + { + uint32_t tmp32 = *rx_fifo; + uint8_t *src_u8 = (uint8_t*) &tmp32; - while(bytes_rem--) + while ( bytes_rem-- ) { - *dst_u8++ = *src_u8++; + *dst++ = *src_u8++; } } } @@ -153,12 +146,12 @@ static void _ff_pull_const_addr(void * dst, const uint8_t * src, uint16_t len) // Write the remaining 1-3 bytes into FIFO uint8_t bytes_rem = len & 0x03; - if(bytes_rem) + if ( bytes_rem ) { uint32_t tmp32 = 0; - uint8_t* dst8 = (uint8_t*) &tmp32; + uint8_t *dst8 = (uint8_t*) &tmp32; - while(bytes_rem--) + while ( bytes_rem-- ) { *dst8++ = *src++; } From 9042e973d34fb3c1cf397489aa8953b795dbf930 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 7 Apr 2021 12:52:57 +0700 Subject: [PATCH 106/121] clean up _ff_push_n --- src/common/tusb_fifo.c | 91 +++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 50 deletions(-) diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 5f8623786..6e2ea51e6 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -168,18 +168,20 @@ static inline void _ff_push(tu_fifo_t* f, void const * data, uint16_t wRel) // send n items to FIFO WITHOUT updating write pointer static void _ff_push_n(tu_fifo_t* f, void const * data, uint16_t n, uint16_t wRel, tu_fifo_copy_mode_t copy_mode) { + uint16_t const nLin = f->depth - wRel; + uint16_t const nWrap = n - nLin; // only used if wrapped + switch (copy_mode) { case TU_FIFO_COPY_INC: - if(n <= f->depth-wRel) + if(n <= nLin) { - // Linear mode only + // Linear only memcpy(f->buffer + (wRel * f->item_size), data, n*f->item_size); } else { // Wrap around - uint16_t nLin = f->depth - wRel; // Write data to linear part of buffer memcpy(f->buffer + (wRel * f->item_size), data, nLin*f->item_size); @@ -189,61 +191,51 @@ static void _ff_push_n(tu_fifo_t* f, void const * data, uint16_t n, uint16_t wRe } break; - case TU_FIFO_COPY_CST_FULL_WORDS: // Intended for hardware buffers from which it can be read word by word only - if(n <= f->depth-wRel) + case TU_FIFO_COPY_CST_FULL_WORDS: + // Intended for hardware buffers from which it can be read word by word only + if(n <= nLin) { - // Linear mode only + // Linear only _ff_push_const_addr(f->buffer + (wRel * f->item_size), data, n*f->item_size); } else { // Wrap around case - uint16_t nLin = (f->depth - wRel) * f->item_size; - uint16_t nWrap = (n - nLin) * f->item_size; + uint16_t nLin_bytes = nLin * f->item_size; + uint16_t nWrap_bytes = nWrap * f->item_size; - // Optimize for fast word copies - typedef struct{ - uint32_t val; - } __attribute((__packed__)) unaligned_uint32_t; + uint8_t* dst = f->buffer + (wRel * f->item_size); - unaligned_uint32_t* dst = (unaligned_uint32_t*)(f->buffer + (wRel * f->item_size)); + // Write full words to linear part of buffer + uint16_t nLin_4n_bytes = nLin_bytes & 0xFFFC; + _ff_push_const_addr(dst, data, nLin_4n_bytes); + dst += nLin_4n_bytes; + + // There could be odd 1-3 bytes before the wrap-around boundary volatile uint32_t * rx_fifo = (volatile uint32_t *) data; - - // Write full words of linear part to buffer - uint16_t full_words = nLin >> 2; - while(full_words--) - { - dst->val = *rx_fifo; - dst++; - } - - uint8_t * dst_u8; - uint8_t rem = nLin & 0x03; - // Handle wrap around + uint8_t rem = nLin_bytes & 0x03; if (rem > 0) { - dst_u8 = (uint8_t *)dst; - uint8_t remrem = tu_min16(nWrap, 4-rem); - nWrap -= remrem; - uint32_t tmp = *rx_fifo; - uint8_t * src_u8 = ((uint8_t *) &tmp); - while(rem--) - { - *dst_u8++ = *src_u8++; - } - dst_u8 = f->buffer; - while(remrem--) - { - *dst_u8++ = *src_u8++; - } + uint8_t remrem = tu_min16(nWrap_bytes, 4-rem); + nWrap_bytes -= remrem; + + uint32_t tmp32 = *rx_fifo; + uint8_t * src_u8 = ((uint8_t *) &tmp32); + + // Write 1-3 bytes before wrapped boundary + while(rem--) *dst++ = *src_u8++; + + // Read more bytes to beginning to complete a word + dst = f->buffer; + while(remrem--) *dst++ = *src_u8++; } else { - dst_u8 = f->buffer; + dst = f->buffer; // wrap around to beginning } - // Final part - if (nWrap > 0) _ff_push_const_addr(dst_u8, data, nWrap); + // Write data wrapped part + if (nWrap_bytes > 0) _ff_push_const_addr(dst, data, nWrap_bytes); } break; } @@ -284,7 +276,7 @@ static void _ff_pull_n(tu_fifo_t* f, void* p_buffer, uint16_t n, uint16_t rRel, case TU_FIFO_COPY_CST_FULL_WORDS: if ( n <= nLin ) { - // Linear mode only + // Linear only _ff_pull_const_addr(p_buffer, f->buffer + (rRel * f->item_size), n*f->item_size); } else @@ -296,13 +288,12 @@ static void _ff_pull_n(tu_fifo_t* f, void* p_buffer, uint16_t n, uint16_t rRel, uint8_t* src = f->buffer + (rRel * f->item_size); - // Read data from linear part of buffer + // Read full words from linear part of buffer uint16_t nLin_4n_bytes = nLin_bytes & 0xFFFC; _ff_pull_const_addr(p_buffer, src, nLin_4n_bytes); src += nLin_4n_bytes; // There could be odd 1-3 bytes before the wrap-around boundary - // Handle wrap around - do it manually as these are only 4 bytes and its faster without memcpy volatile uint32_t * tx_fifo = (volatile uint32_t *) p_buffer; uint8_t rem = nLin_bytes & 0x03; if (rem > 0) @@ -310,17 +301,17 @@ static void _ff_pull_n(tu_fifo_t* f, void* p_buffer, uint16_t n, uint16_t rRel, uint8_t remrem = tu_min16(nWrap_bytes, 4-rem); nWrap_bytes -= remrem; - uint32_t tmp; - uint8_t * dst_u8 = (uint8_t *)&tmp; + uint32_t tmp32; + uint8_t * dst_u8 = (uint8_t *)&tmp32; - // Get 1-3 bytes before wrapped boundary + // Read 1-3 bytes before wrapped boundary while(rem--) *dst_u8++ = *src++; - // Get more bytes from beginning to form a complete word + // Read more bytes from beginning to complete a word src = f->buffer; while(remrem--) *dst_u8++ = *src++; - *tx_fifo = tmp; + *tx_fifo = tmp32; } else { From 2468f9e26d63313e74d2673437b605af3ea45c74 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 7 Apr 2021 13:15:25 +0700 Subject: [PATCH 107/121] more _ff_pull/push clean up --- src/common/tusb_fifo.c | 77 ++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 6e2ea51e6..32739f8b7 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -166,10 +166,16 @@ static inline void _ff_push(tu_fifo_t* f, void const * data, uint16_t wRel) } // send n items to FIFO WITHOUT updating write pointer -static void _ff_push_n(tu_fifo_t* f, void const * data, uint16_t n, uint16_t wRel, tu_fifo_copy_mode_t copy_mode) +static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t wRel, tu_fifo_copy_mode_t copy_mode) { uint16_t const nLin = f->depth - wRel; - uint16_t const nWrap = n - nLin; // only used if wrapped + uint16_t const nWrap = n - nLin; + + uint16_t nLin_bytes = nLin * f->item_size; + uint16_t nWrap_bytes = nWrap * f->item_size; + + // current buffer of fifo + uint8_t* ff_buf = f->buffer + (wRel * f->item_size); switch (copy_mode) { @@ -177,17 +183,17 @@ static void _ff_push_n(tu_fifo_t* f, void const * data, uint16_t n, uint16_t wRe if(n <= nLin) { // Linear only - memcpy(f->buffer + (wRel * f->item_size), data, n*f->item_size); + memcpy(ff_buf, app_buf, n*f->item_size); } else { // Wrap around // Write data to linear part of buffer - memcpy(f->buffer + (wRel * f->item_size), data, nLin*f->item_size); + memcpy(ff_buf, app_buf, nLin_bytes); // Write data wrapped around - memcpy(f->buffer, ((uint8_t const*) data) + nLin*f->item_size, (n - nLin) * f->item_size); + memcpy(f->buffer, ((uint8_t const*) app_buf) + nLin_bytes, nWrap_bytes); } break; @@ -196,23 +202,19 @@ static void _ff_push_n(tu_fifo_t* f, void const * data, uint16_t n, uint16_t wRe if(n <= nLin) { // Linear only - _ff_push_const_addr(f->buffer + (wRel * f->item_size), data, n*f->item_size); + _ff_push_const_addr(ff_buf, app_buf, n*f->item_size); } else { // Wrap around case - uint16_t nLin_bytes = nLin * f->item_size; - uint16_t nWrap_bytes = nWrap * f->item_size; - - uint8_t* dst = f->buffer + (wRel * f->item_size); // Write full words to linear part of buffer uint16_t nLin_4n_bytes = nLin_bytes & 0xFFFC; - _ff_push_const_addr(dst, data, nLin_4n_bytes); - dst += nLin_4n_bytes; + _ff_push_const_addr(ff_buf, app_buf, nLin_4n_bytes); + ff_buf += nLin_4n_bytes; // There could be odd 1-3 bytes before the wrap-around boundary - volatile uint32_t * rx_fifo = (volatile uint32_t *) data; + volatile uint32_t * rx_fifo = (volatile uint32_t *) app_buf; uint8_t rem = nLin_bytes & 0x03; if (rem > 0) { @@ -223,19 +225,19 @@ static void _ff_push_n(tu_fifo_t* f, void const * data, uint16_t n, uint16_t wRe uint8_t * src_u8 = ((uint8_t *) &tmp32); // Write 1-3 bytes before wrapped boundary - while(rem--) *dst++ = *src_u8++; + while(rem--) *ff_buf++ = *src_u8++; // Read more bytes to beginning to complete a word - dst = f->buffer; - while(remrem--) *dst++ = *src_u8++; + ff_buf = f->buffer; + while(remrem--) *ff_buf++ = *src_u8++; } else { - dst = f->buffer; // wrap around to beginning + ff_buf = f->buffer; // wrap around to beginning } // Write data wrapped part - if (nWrap_bytes > 0) _ff_push_const_addr(dst, data, nWrap_bytes); + if (nWrap_bytes > 0) _ff_push_const_addr(ff_buf, app_buf, nWrap_bytes); } break; } @@ -248,28 +250,34 @@ static inline void _ff_pull(tu_fifo_t* f, void * p_buffer, uint16_t rRel) } // get n items from FIFO WITHOUT updating read pointer -static void _ff_pull_n(tu_fifo_t* f, void* p_buffer, uint16_t n, uint16_t rRel, tu_fifo_copy_mode_t copy_mode) +static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t wRel, tu_fifo_copy_mode_t copy_mode) { - uint16_t const nLin = f->depth - rRel; + uint16_t const nLin = f->depth - wRel; uint16_t const nWrap = n - nLin; // only used if wrapped + uint16_t nLin_bytes = nLin * f->item_size; + uint16_t nWrap_bytes = nWrap * f->item_size; + + // current buffer of fifo + uint8_t* ff_buf = f->buffer + (wRel * f->item_size); + switch (copy_mode) { case TU_FIFO_COPY_INC: if ( n <= nLin ) { // Linear only - memcpy(p_buffer, f->buffer + (rRel * f->item_size), n*f->item_size); + memcpy(app_buf, ff_buf, n*f->item_size); } else { // Wrap around // Read data from linear part of buffer - memcpy(p_buffer, f->buffer + (rRel * f->item_size), nLin*f->item_size); + memcpy(app_buf, ff_buf, nLin_bytes); // Read data wrapped part - memcpy((uint8_t*) p_buffer + nLin*f->item_size, f->buffer, nWrap*f->item_size); + memcpy((uint8_t*) app_buf + nLin_bytes, f->buffer, nWrap_bytes); } break; @@ -277,24 +285,19 @@ static void _ff_pull_n(tu_fifo_t* f, void* p_buffer, uint16_t n, uint16_t rRel, if ( n <= nLin ) { // Linear only - _ff_pull_const_addr(p_buffer, f->buffer + (rRel * f->item_size), n*f->item_size); + _ff_pull_const_addr(app_buf, ff_buf, n*f->item_size); } else { // Wrap around case - uint16_t nLin_bytes = nLin * f->item_size; - uint16_t nWrap_bytes = nWrap * f->item_size; - - uint8_t* src = f->buffer + (rRel * f->item_size); - // Read full words from linear part of buffer uint16_t nLin_4n_bytes = nLin_bytes & 0xFFFC; - _ff_pull_const_addr(p_buffer, src, nLin_4n_bytes); - src += nLin_4n_bytes; + _ff_pull_const_addr(app_buf, ff_buf, nLin_4n_bytes); + ff_buf += nLin_4n_bytes; // There could be odd 1-3 bytes before the wrap-around boundary - volatile uint32_t * tx_fifo = (volatile uint32_t *) p_buffer; + volatile uint32_t * tx_fifo = (volatile uint32_t *) app_buf; uint8_t rem = nLin_bytes & 0x03; if (rem > 0) { @@ -305,21 +308,21 @@ static void _ff_pull_n(tu_fifo_t* f, void* p_buffer, uint16_t n, uint16_t rRel, uint8_t * dst_u8 = (uint8_t *)&tmp32; // Read 1-3 bytes before wrapped boundary - while(rem--) *dst_u8++ = *src++; + while(rem--) *dst_u8++ = *ff_buf++; // Read more bytes from beginning to complete a word - src = f->buffer; - while(remrem--) *dst_u8++ = *src++; + ff_buf = f->buffer; + while(remrem--) *dst_u8++ = *ff_buf++; *tx_fifo = tmp32; } else { - src = f->buffer; // wrap around to beginning + ff_buf = f->buffer; // wrap around to beginning } // Read data wrapped part - if (nWrap_bytes > 0) _ff_pull_const_addr(p_buffer, src, nWrap_bytes); + if (nWrap_bytes > 0) _ff_pull_const_addr(app_buf, ff_buf, nWrap_bytes); } break; From 893919a848926f453f85fc131d553935554af23b Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 7 Apr 2021 13:27:28 +0700 Subject: [PATCH 108/121] remove tu_fifo_backward_write/read_pointer API since it is illegal from fifo perspective --- src/common/tusb_fifo.c | 42 ------------------------------------------ src/common/tusb_fifo.h | 2 -- 2 files changed, 44 deletions(-) diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 32739f8b7..8de07c819 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -893,48 +893,6 @@ void tu_fifo_advance_read_pointer(tu_fifo_t *f, uint16_t n) f->rd_idx = advance_pointer(f, f->rd_idx, n); } -/******************************************************************************/ -/*! - @brief Move back write pointer - intended to be used in combination with DMA. - It is possible to fill the FIFO by use of a DMA in circular mode. Within - DMA ISRs you may update the write pointer to be able to read from the FIFO. - As long as the DMA is the only process writing into the FIFO this is safe - to use. - - USE WITH CARE - WE DO NOT CONDUCT SAFTY CHECKS HERE! - - @param[in] f - Pointer to the FIFO buffer to manipulate - @param[in] n - Number of items the write pointer moves backward - */ -/******************************************************************************/ -void tu_fifo_backward_write_pointer(tu_fifo_t *f, uint16_t n) -{ - f->wr_idx = backward_pointer(f, f->wr_idx, n); -} - -/******************************************************************************/ -/*! - @brief Move back read pointer - intended to be used in combination with DMA. - It is possible to read from the FIFO by use of a DMA in linear mode. Within - DMA ISRs you may update the read pointer to be able to again write into the - FIFO. As long as the DMA is the only process reading from the FIFO this is - safe to use. - - USE WITH CARE - WE DO NOT CONDUCT SAFTY CHECKS HERE! - - @param[in] f - Pointer to the FIFO buffer to manipulate - @param[in] n - Number of items the read pointer moves backward - */ -/******************************************************************************/ -void tu_fifo_backward_read_pointer(tu_fifo_t *f, uint16_t n) -{ - f->rd_idx = backward_pointer(f, f->rd_idx, n); -} - /******************************************************************************/ /*! @brief Get linear read info diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h index 93ed6095d..b2d0b5be9 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -128,9 +128,7 @@ void tu_fifo_correct_read_pointer (tu_fifo_t* f); // Pointer modifications intended to be used in combinations with DMAs. // USE WITH CARE - NO SAFTY CHECKS CONDUCTED HERE! NOT MUTEX PROTECTED! void tu_fifo_advance_write_pointer (tu_fifo_t *f, uint16_t n); -void tu_fifo_backward_write_pointer (tu_fifo_t *f, uint16_t n); void tu_fifo_advance_read_pointer (tu_fifo_t *f, uint16_t n); -void tu_fifo_backward_read_pointer (tu_fifo_t *f, uint16_t n); // If you want to read/write from/to the FIFO by use of a DMA, you may need to conduct two copies to handle a possible wrapping part // This functions deliver a pointer to start reading/writing from/to and a valid linear length along which no wrap occurs. From d9a0cc9e9f328db15df6cc31b2a04532d4e8ad35 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 7 Apr 2021 15:56:43 +0700 Subject: [PATCH 109/121] more cleanup --- src/common/tusb_fifo.c | 148 +++++++++++++++++++---------------------- 1 file changed, 68 insertions(+), 80 deletions(-) diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 8de07c819..098d54801 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -39,26 +39,20 @@ // implement mutex lock and unlock #if CFG_FIFO_MUTEX -static void tu_fifo_lock(tu_fifo_mutex_t mutex) +static inline void _ff_lock(tu_fifo_mutex_t mutex) { - if (mutex) - { - osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER); - } + if (mutex) osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER); } -static void tu_fifo_unlock(tu_fifo_mutex_t mutex) +static inline void _ff_unlock(tu_fifo_mutex_t mutex) { - if (mutex) - { - osal_mutex_unlock(mutex); - } + if (mutex) osal_mutex_unlock(mutex); } #else -#define tu_fifo_lock(_mutex) -#define tu_fifo_unlock(_mutex) +#define _ff_lock(_mutex) +#define _ff_unlock(_mutex) #endif @@ -67,16 +61,16 @@ static void tu_fifo_unlock(tu_fifo_mutex_t mutex) */ typedef enum { - TU_FIFO_COPY_INC, ///< Copy from/to an increasing source/destination address - default mode - TU_FIFO_COPY_CST_FULL_WORDS, ///< Copy from/to a constant source/destination address - required for e.g. STM32 to write into USB hardware FIFO + TU_FIFO_COPY_INC, ///< Copy from/to an increasing source/destination address - default mode + TU_FIFO_COPY_CST_FULL_WORDS, ///< Copy from/to a constant source/destination address - required for e.g. STM32 to write into USB hardware FIFO } tu_fifo_copy_mode_t; bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable) { if (depth > 0x8000) return false; // Maximum depth is 2^15 items - tu_fifo_lock(f->mutex_wr); - tu_fifo_lock(f->mutex_rd); + _ff_lock(f->mutex_wr); + _ff_lock(f->mutex_rd); f->buffer = (uint8_t*) buffer; f->depth = depth; @@ -88,14 +82,13 @@ bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_si f->rd_idx = f->wr_idx = 0; - tu_fifo_unlock(f->mutex_wr); - tu_fifo_unlock(f->mutex_rd); + _ff_unlock(f->mutex_wr); + _ff_unlock(f->mutex_rd); return true; } // Static functions are intended to work on local variables - static inline uint16_t _ff_mod(uint16_t idx, uint16_t depth) { while ( idx >= depth) idx -= depth; @@ -105,77 +98,69 @@ static inline uint16_t _ff_mod(uint16_t idx, uint16_t depth) // Intended to be used to read from hardware USB FIFO in e.g. STM32 where all data is read from a constant address // Code adapted from dcd_synopsis.c // TODO generalize with configurable 1 byte or 4 byte each read -static void _ff_push_const_addr(uint8_t * dst, const void * src, uint16_t len) +static void _ff_push_const_addr(uint8_t * ff_buf, const void * app_buf, uint16_t len) { - volatile uint32_t * rx_fifo = (volatile uint32_t *) src; + volatile uint32_t * rx_fifo = (volatile uint32_t *) app_buf; - // Reading full available 32 bit words from FIFO + // Reading full available 32 bit words from const app address uint16_t full_words = len >> 2; while(full_words--) { - tu_unaligned_write32(dst, *rx_fifo); - dst += 4; + tu_unaligned_write32(ff_buf, *rx_fifo); + ff_buf += 4; } - // Read the remaining 1-3 bytes from FIFO - uint8_t bytes_rem = len & 0x03; + // Read the remaining 1-3 bytes from const app address + uint8_t const bytes_rem = len & 0x03; if ( bytes_rem ) { uint32_t tmp32 = *rx_fifo; - uint8_t *src_u8 = (uint8_t*) &tmp32; - - while ( bytes_rem-- ) - { - *dst++ = *src_u8++; - } + memcpy(ff_buf, &tmp32, bytes_rem); } } -// Intended to be used to write to hardware USB FIFO in e.g. STM32 where all data is written to a constant address in full word copies -static void _ff_pull_const_addr(void * dst, const uint8_t * src, uint16_t len) +// Intended to be used to write to hardware USB FIFO in e.g. STM32 +// where all data is written to a constant address in full word copies +static void _ff_pull_const_addr(void * app_buf, const uint8_t * ff_buf, uint16_t len) { - volatile uint32_t * tx_fifo = (volatile uint32_t *) dst; + volatile uint32_t * tx_fifo = (volatile uint32_t *) app_buf; - // Pushing full available 32 bit words to FIFO + // Pushing full available 32 bit words to const app address uint16_t full_words = len >> 2; while(full_words--) { - *tx_fifo = tu_unaligned_read32(src); - src += 4; + *tx_fifo = tu_unaligned_read32(ff_buf); + ff_buf += 4; } - // Write the remaining 1-3 bytes into FIFO - uint8_t bytes_rem = len & 0x03; + // Write the remaining 1-3 bytes into const app address + uint8_t const bytes_rem = len & 0x03; if ( bytes_rem ) { uint32_t tmp32 = 0; - uint8_t *dst8 = (uint8_t*) &tmp32; + memcpy(&tmp32, ff_buf, bytes_rem); - while ( bytes_rem-- ) - { - *dst8++ = *src++; - } *tx_fifo = tmp32; } } // send one item to FIFO WITHOUT updating write pointer -static inline void _ff_push(tu_fifo_t* f, void const * data, uint16_t wRel) +static inline void _ff_push(tu_fifo_t* f, void const * app_buf, uint16_t rel) { - memcpy(f->buffer + (wRel * f->item_size), data, f->item_size); + memcpy(f->buffer + (rel * f->item_size), app_buf, f->item_size); } // send n items to FIFO WITHOUT updating write pointer -static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t wRel, tu_fifo_copy_mode_t copy_mode) +static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t rel, tu_fifo_copy_mode_t copy_mode) { - uint16_t const nLin = f->depth - wRel; + uint16_t const nLin = f->depth - rel; uint16_t const nWrap = n - nLin; uint16_t nLin_bytes = nLin * f->item_size; uint16_t nWrap_bytes = nWrap * f->item_size; // current buffer of fifo - uint8_t* ff_buf = f->buffer + (wRel * f->item_size); + uint8_t* ff_buf = f->buffer + (rel * f->item_size); switch (copy_mode) { @@ -244,22 +229,22 @@ static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t } // get one item from FIFO WITHOUT updating read pointer -static inline void _ff_pull(tu_fifo_t* f, void * p_buffer, uint16_t rRel) +static inline void _ff_pull(tu_fifo_t* f, void * app_buf, uint16_t rel) { - memcpy(p_buffer, f->buffer + (rRel * f->item_size), f->item_size); + memcpy(app_buf, f->buffer + (rel * f->item_size), f->item_size); } // get n items from FIFO WITHOUT updating read pointer -static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t wRel, tu_fifo_copy_mode_t copy_mode) +static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu_fifo_copy_mode_t copy_mode) { - uint16_t const nLin = f->depth - wRel; + uint16_t const nLin = f->depth - rel; uint16_t const nWrap = n - nLin; // only used if wrapped uint16_t nLin_bytes = nLin * f->item_size; uint16_t nWrap_bytes = nWrap * f->item_size; // current buffer of fifo - uint8_t* ff_buf = f->buffer + (wRel * f->item_size); + uint8_t* ff_buf = f->buffer + (rel * f->item_size); switch (copy_mode) { @@ -304,7 +289,7 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t wRel, t uint8_t remrem = tu_min16(nWrap_bytes, 4-rem); nWrap_bytes -= remrem; - uint32_t tmp32; + uint32_t tmp32=0; uint8_t * dst_u8 = (uint8_t *)&tmp32; // Read 1-3 bytes before wrapped boundary @@ -329,6 +314,7 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t wRel, t default: break; } } + // Advance an absolute pointer static uint16_t advance_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset) { @@ -471,7 +457,7 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu { if ( n == 0 ) return 0; - tu_fifo_lock(f->mutex_wr); + _ff_lock(f->mutex_wr); uint16_t w = f->wr_idx, r = f->rd_idx; uint8_t const* buf8 = (uint8_t const*) data; @@ -501,14 +487,14 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu // Advance pointer f->wr_idx = advance_pointer(f, w, n); - tu_fifo_unlock(f->mutex_wr); + _ff_unlock(f->mutex_wr); return n; } static uint16_t _tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n, tu_fifo_copy_mode_t copy_mode) { - tu_fifo_lock(f->mutex_rd); + _ff_lock(f->mutex_rd); // Peek the data n = _tu_fifo_peek_at_n(f, 0, buffer, n, f->wr_idx, f->rd_idx, copy_mode); // f->rd_idx might get modified in case of an overflow so we can not use a local variable @@ -516,7 +502,7 @@ static uint16_t _tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n, tu_fifo // Advance read pointer f->rd_idx = advance_pointer(f, f->rd_idx, n); - tu_fifo_unlock(f->mutex_rd); + _ff_unlock(f->mutex_rd); return n; } @@ -623,9 +609,9 @@ bool tu_fifo_overflowed(tu_fifo_t* f) // Only use in case tu_fifo_overflow() returned true! void tu_fifo_correct_read_pointer(tu_fifo_t* f) { - tu_fifo_lock(f->mutex_rd); + _ff_lock(f->mutex_rd); _tu_fifo_correct_read_pointer(f, f->wr_idx); - tu_fifo_unlock(f->mutex_rd); + _ff_unlock(f->mutex_rd); } /******************************************************************************/ @@ -646,7 +632,7 @@ void tu_fifo_correct_read_pointer(tu_fifo_t* f) /******************************************************************************/ bool tu_fifo_read(tu_fifo_t* f, void * buffer) { - tu_fifo_lock(f->mutex_rd); + _ff_lock(f->mutex_rd); // Peek the data bool ret = _tu_fifo_peek_at(f, 0, buffer, f->wr_idx, f->rd_idx); // f->rd_idx might get modified in case of an overflow so we can not use a local variable @@ -654,7 +640,7 @@ bool tu_fifo_read(tu_fifo_t* f, void * buffer) // Advance pointer f->rd_idx = advance_pointer(f, f->rd_idx, ret); - tu_fifo_unlock(f->mutex_rd); + _ff_unlock(f->mutex_rd); return ret; } @@ -701,9 +687,9 @@ uint16_t tu_fifo_read_n_const_addr_full_words(tu_fifo_t* f, void * buffer, uint1 /******************************************************************************/ bool tu_fifo_peek_at(tu_fifo_t* f, uint16_t offset, void * p_buffer) { - tu_fifo_lock(f->mutex_rd); + _ff_lock(f->mutex_rd); bool ret = _tu_fifo_peek_at(f, offset, p_buffer, f->wr_idx, f->rd_idx); - tu_fifo_unlock(f->mutex_rd); + _ff_unlock(f->mutex_rd); return ret; } @@ -726,9 +712,9 @@ bool tu_fifo_peek_at(tu_fifo_t* f, uint16_t offset, void * p_buffer) /******************************************************************************/ uint16_t tu_fifo_peek_at_n(tu_fifo_t* f, uint16_t offset, void * p_buffer, uint16_t n) { - tu_fifo_lock(f->mutex_rd); + _ff_lock(f->mutex_rd); bool ret = _tu_fifo_peek_at_n(f, offset, p_buffer, n, f->wr_idx, f->rd_idx, TU_FIFO_COPY_INC); - tu_fifo_unlock(f->mutex_rd); + _ff_unlock(f->mutex_rd); return ret; } @@ -750,7 +736,7 @@ uint16_t tu_fifo_peek_at_n(tu_fifo_t* f, uint16_t offset, void * p_buffer, uint1 /******************************************************************************/ bool tu_fifo_write(tu_fifo_t* f, const void * data) { - tu_fifo_lock(f->mutex_wr); + _ff_lock(f->mutex_wr); uint16_t w = f->wr_idx; @@ -764,7 +750,7 @@ bool tu_fifo_write(tu_fifo_t* f, const void * data) // Advance pointer f->wr_idx = advance_pointer(f, w, 1); - tu_fifo_unlock(f->mutex_wr); + _ff_unlock(f->mutex_wr); return true; } @@ -818,13 +804,15 @@ uint16_t tu_fifo_write_n_const_addr_full_words(tu_fifo_t* f, const void * data, /******************************************************************************/ bool tu_fifo_clear(tu_fifo_t *f) { - tu_fifo_lock(f->mutex_wr); - tu_fifo_lock(f->mutex_rd); + _ff_lock(f->mutex_wr); + _ff_lock(f->mutex_rd); + f->rd_idx = f->wr_idx = 0; f->max_pointer_idx = 2*f->depth-1; f->non_used_index_space = UINT16_MAX - f->max_pointer_idx; - tu_fifo_unlock(f->mutex_wr); - tu_fifo_unlock(f->mutex_rd); + + _ff_unlock(f->mutex_wr); + _ff_unlock(f->mutex_rd); return true; } @@ -840,13 +828,13 @@ bool tu_fifo_clear(tu_fifo_t *f) /******************************************************************************/ bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) { - tu_fifo_lock(f->mutex_wr); - tu_fifo_lock(f->mutex_rd); + _ff_lock(f->mutex_wr); + _ff_lock(f->mutex_rd); f->overwritable = overwritable; - tu_fifo_unlock(f->mutex_wr); - tu_fifo_unlock(f->mutex_rd); + _ff_unlock(f->mutex_wr); + _ff_unlock(f->mutex_rd); return true; } @@ -927,9 +915,9 @@ uint16_t tu_fifo_get_linear_read_info(tu_fifo_t *f, uint16_t offset, void **ptr, // Check overflow and correct if required if (cnt > f->depth) { - tu_fifo_lock(f->mutex_rd); + _ff_lock(f->mutex_rd); _tu_fifo_correct_read_pointer(f, w); - tu_fifo_unlock(f->mutex_rd); + _ff_unlock(f->mutex_rd); r = f->rd_idx; cnt = f->depth; } From 8eacdffebdcc10a6fffdc248ef6086b223f3edf3 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Wed, 7 Apr 2021 20:07:28 +0200 Subject: [PATCH 110/121] Optimize encode/decode - refactor unnecessary repetitive division --- src/class/audio/audio_device.c | 16 ++++++++-------- src/class/audio/audio_device.h | 3 +++ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index a85dfddb8..2e9684cb9 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -310,6 +310,7 @@ typedef struct audio_data_format_type_I_t format_type_I_rx; uint8_t n_bytes_per_sampe_rx; uint8_t n_channels_per_ff_rx; + uint8_t n_ff_used_rx; #endif #endif @@ -322,6 +323,7 @@ typedef struct audio_data_format_type_I_t format_type_I_tx; uint8_t n_bytes_per_sampe_tx; uint8_t n_channels_per_ff_tx; + uint8_t n_ff_used_tx; #endif #endif @@ -625,10 +627,7 @@ static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio, (void) rhport; // Determine amount of samples - uint8_t const n_ff_used = audio->n_channels_rx / audio->n_channels_per_ff_rx; - - TU_ASSERT( n_ff_used <= audio->n_rx_supp_ff ); - + uint8_t const n_ff_used = audio->n_ff_used_rx; uint16_t const nBytesToCopy = audio->n_channels_per_ff_rx * audio->n_bytes_per_sampe_rx; uint16_t const nBytesPerFFToRead = n_bytes_received / n_ff_used; uint8_t cnt_ff; @@ -928,10 +927,7 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_interface_t* aud TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_in)); // Determine amount of samples - uint8_t const n_ff_used = audio->n_channels_tx / audio->n_channels_per_ff_tx; - - TU_ASSERT( n_ff_used <= audio->n_tx_supp_ff ); - + uint8_t const n_ff_used = audio->n_ff_used_tx; uint16_t const nBytesToCopy = audio->n_channels_per_ff_tx * audio->n_bytes_per_sampe_tx; uint16_t const capPerFF = audio->ep_in_sz / n_ff_used; // Sample capacity per FIFO in bytes uint16_t nBytesPerFFToSend = tu_fifo_count(&audio->tx_supp_ff[0]); @@ -1551,6 +1547,8 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * { tu_fifo_config(&audio->tx_supp_ff[cnt], audio->tx_supp_ff[cnt].buffer, active_fifo_depth, 1, true); } + audio->n_ff_used_tx = audio->n_channels_tx / audio->n_channels_per_ff_tx; + TU_ASSERT( audio->n_ff_used_tx <= audio->n_tx_supp_ff ); #endif #endif @@ -1582,6 +1580,8 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * { tu_fifo_config(&audio->rx_supp_ff[cnt], audio->rx_supp_ff[cnt].buffer, active_fifo_depth, 1, true); } + audio->n_ff_used_rx = audio->n_channels_rx / audio->n_channels_per_ff_rx; + TU_ASSERT( audio->n_ff_used_rx <= audio->n_rx_supp_ff ); #endif #endif // Invoke callback diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index 81e0024d7..f91540b64 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -240,6 +240,9 @@ // Enable encoding/decodings - for these to work, support FIFOs need to be setup in appropriate numbers and size // The actual coding parameters of active AS alternate interface is parsed from the descriptors +// The item size of the FIFO is always fixed to one i.e. bytes! Furthermore, the actively used FIFO depth is reconfigured such that the depth is a multiple of the current sample size in order to avoid samples to get split up in case of a wrap in the FIFO ring buffer (depth = (max_depth / sampe_sz) * sampe_sz)! +// This is important to remind in case you use DMAs! If the sample sizes changes, the DMA MUST BE RECONFIGURED just like the FIFOs for a different depth!!! + // For PCM encoding/decoding #ifndef CFG_TUD_AUDIO_ENABLE_ENCODING From 930eca0748f047c0130bcf28039c34a1d489b89e Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Thu, 8 Apr 2021 19:56:26 +0200 Subject: [PATCH 111/121] Add 4 channel microphone audio example using software encoding --- .../audio_4_channel_mic/.skip.MCU_SAMD11 | 0 .../audio_4_channel_mic/.skip.MCU_SAME5X | 0 .../device/audio_4_channel_mic/.skip.MCU_SAMG | 0 .../device/audio_4_channel_mic/CMakeLists.txt | 39 ++ examples/device/audio_4_channel_mic/Makefile | 12 + .../device/audio_4_channel_mic/src/main.c | 451 ++++++++++++++++++ .../src/plot_audio_samples.py | 26 + .../audio_4_channel_mic/src/tusb_config.h | 118 +++++ .../audio_4_channel_mic/src/usb_descriptors.c | 160 +++++++ 9 files changed, 806 insertions(+) create mode 100644 examples/device/audio_4_channel_mic/.skip.MCU_SAMD11 create mode 100644 examples/device/audio_4_channel_mic/.skip.MCU_SAME5X create mode 100644 examples/device/audio_4_channel_mic/.skip.MCU_SAMG create mode 100644 examples/device/audio_4_channel_mic/CMakeLists.txt create mode 100644 examples/device/audio_4_channel_mic/Makefile create mode 100644 examples/device/audio_4_channel_mic/src/main.c create mode 100644 examples/device/audio_4_channel_mic/src/plot_audio_samples.py create mode 100644 examples/device/audio_4_channel_mic/src/tusb_config.h create mode 100644 examples/device/audio_4_channel_mic/src/usb_descriptors.c diff --git a/examples/device/audio_4_channel_mic/.skip.MCU_SAMD11 b/examples/device/audio_4_channel_mic/.skip.MCU_SAMD11 new file mode 100644 index 000000000..e69de29bb diff --git a/examples/device/audio_4_channel_mic/.skip.MCU_SAME5X b/examples/device/audio_4_channel_mic/.skip.MCU_SAME5X new file mode 100644 index 000000000..e69de29bb diff --git a/examples/device/audio_4_channel_mic/.skip.MCU_SAMG b/examples/device/audio_4_channel_mic/.skip.MCU_SAMG new file mode 100644 index 000000000..e69de29bb diff --git a/examples/device/audio_4_channel_mic/CMakeLists.txt b/examples/device/audio_4_channel_mic/CMakeLists.txt new file mode 100644 index 000000000..03f2439e2 --- /dev/null +++ b/examples/device/audio_4_channel_mic/CMakeLists.txt @@ -0,0 +1,39 @@ +# use BOARD-Directory name for project id +get_filename_component(PROJECT ${CMAKE_CURRENT_SOURCE_DIR} NAME) +set(PROJECT ${BOARD}-${PROJECT}) + +# TOP is absolute path to root directory of TinyUSB git repo +set(TOP "../../..") +get_filename_component(TOP "${TOP}" REALPATH) + +# Check for -DFAMILY= +if(FAMILY STREQUAL "rp2040") + cmake_minimum_required(VERSION 3.12) + + set(PICO_SDK_PATH ${TOP}/hw/mcu/raspberrypi/pico-sdk) + include(${PICO_SDK_PATH}/pico_sdk_init.cmake) + + project(${PROJECT}) + add_executable(${PROJECT}) + + include(${TOP}/hw/bsp/${FAMILY}/family.cmake) + + # Example source + target_sources(${PROJECT} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c + ) + + # Example include + target_include_directories(${PROJECT} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/src + ) + + # Example defines + target_compile_definitions(${PROJECT} PUBLIC + CFG_TUSB_OS=OPT_OS_PICO + ) + +else() + message(FATAL_ERROR "Invalid FAMILY specified") +endif() diff --git a/examples/device/audio_4_channel_mic/Makefile b/examples/device/audio_4_channel_mic/Makefile new file mode 100644 index 000000000..5a455078e --- /dev/null +++ b/examples/device/audio_4_channel_mic/Makefile @@ -0,0 +1,12 @@ +include ../../../tools/top.mk +include ../../make.mk + +INC += \ + src \ + $(TOP)/hw \ + +# Example source +EXAMPLE_SOURCE += $(wildcard src/*.c) +SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE)) + +include ../../rules.mk diff --git a/examples/device/audio_4_channel_mic/src/main.c b/examples/device/audio_4_channel_mic/src/main.c new file mode 100644 index 000000000..767ebecdc --- /dev/null +++ b/examples/device/audio_4_channel_mic/src/main.c @@ -0,0 +1,451 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Reinhard Panhuber + * + * 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. + * + */ + +#include +#include +#include + +#include "bsp/board.h" +#include "tusb.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF PROTYPES +//--------------------------------------------------------------------+ + +#ifndef AUDIO_SAMPLE_RATE +#define AUDIO_SAMPLE_RATE 48000 +#endif + +/* Blink pattern + * - 250 ms : device not mounted + * - 1000 ms : device mounted + * - 2500 ms : device is suspended + */ +enum { + BLINK_NOT_MOUNTED = 250, + BLINK_MOUNTED = 1000, + BLINK_SUSPENDED = 2500, +}; + +static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; + +// Audio controls +// Current states +bool mute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master channel 0 +uint16_t volume[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master channel 0 +uint32_t sampFreq; +uint8_t clkValid; + +// Range states +audio_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX+1]; // Volume range state +audio_control_range_4_n_t(1) sampleFreqRng; // Sample frequency range state + +// Audio test data +uint8_t i2s_dummy_buffer[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ]; + +void led_blinking_task(void); +void audio_task(void); + +/*------------- MAIN -------------*/ +int main(void) +{ + board_init(); + + tusb_init(); + + // Init values + sampFreq = AUDIO_SAMPLE_RATE; + clkValid = 1; + + sampleFreqRng.wNumSubRanges = 1; + sampleFreqRng.subrange[0].bMin = AUDIO_SAMPLE_RATE; + sampleFreqRng.subrange[0].bMax = AUDIO_SAMPLE_RATE; + sampleFreqRng.subrange[0].bRes = 0; + + while (1) + { + tud_task(); // tinyusb device task + led_blinking_task(); + audio_task(); + } + + + return 0; +} + +//--------------------------------------------------------------------+ +// Device callbacks +//--------------------------------------------------------------------+ + +// Invoked when device is mounted +void tud_mount_cb(void) +{ + blink_interval_ms = BLINK_MOUNTED; +} + +// Invoked when device is unmounted +void tud_umount_cb(void) +{ + blink_interval_ms = BLINK_NOT_MOUNTED; +} + +// Invoked when usb bus is suspended +// remote_wakeup_en : if host allow us to perform remote wakeup +// Within 7ms, device must draw an average of current less than 2.5 mA from bus +void tud_suspend_cb(bool remote_wakeup_en) +{ + (void) remote_wakeup_en; + blink_interval_ms = BLINK_SUSPENDED; +} + +// Invoked when usb bus is resumed +void tud_resume_cb(void) +{ + blink_interval_ms = BLINK_MOUNTED; +} + +//--------------------------------------------------------------------+ +// AUDIO Task +//--------------------------------------------------------------------+ + +void audio_task(void) +{ + // Yet to be filled - e.g. put meas data into TX FIFOs etc. + asm("nop"); +} + +//--------------------------------------------------------------------+ +// Application Callback API Implementations +//--------------------------------------------------------------------+ + +// Invoked when audio class specific set request received for an EP +bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff) +{ + (void) rhport; + (void) pBuff; + + // We do not support any set range requests here, only current value requests + TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR); + + // Page 91 in UAC2 specification + uint8_t channelNum = TU_U16_LOW(p_request->wValue); + uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); + uint8_t ep = TU_U16_LOW(p_request->wIndex); + + (void) channelNum; (void) ctrlSel; (void) ep; + + return false; // Yet not implemented +} + +// Invoked when audio class specific set request received for an interface +bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff) +{ + (void) rhport; + (void) pBuff; + + // We do not support any set range requests here, only current value requests + TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR); + + // Page 91 in UAC2 specification + uint8_t channelNum = TU_U16_LOW(p_request->wValue); + uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); + uint8_t itf = TU_U16_LOW(p_request->wIndex); + + (void) channelNum; (void) ctrlSel; (void) itf; + + return false; // Yet not implemented +} + +// Invoked when audio class specific set request received for an entity +bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff) +{ + (void) rhport; + + // Page 91 in UAC2 specification + uint8_t channelNum = TU_U16_LOW(p_request->wValue); + uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); + uint8_t itf = TU_U16_LOW(p_request->wIndex); + uint8_t entityID = TU_U16_HIGH(p_request->wIndex); + + (void) itf; + + // We do not support any set range requests here, only current value requests + TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR); + + // If request is for our feature unit + if ( entityID == 2 ) + { + switch ( ctrlSel ) + { + case AUDIO_FU_CTRL_MUTE: + // Request uses format layout 1 + TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_1_t)); + + mute[channelNum] = ((audio_control_cur_1_t*) pBuff)->bCur; + + TU_LOG2(" Set Mute: %d of channel: %u\r\n", mute[channelNum], channelNum); + return true; + + case AUDIO_FU_CTRL_VOLUME: + // Request uses format layout 2 + TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_2_t)); + + volume[channelNum] = ((audio_control_cur_2_t*) pBuff)->bCur; + + TU_LOG2(" Set Volume: %d dB of channel: %u\r\n", volume[channelNum], channelNum); + return true; + + // Unknown/Unsupported control + default: + TU_BREAKPOINT(); + return false; + } + } + return false; // Yet not implemented +} + +// Invoked when audio class specific get request received for an EP +bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request) +{ + (void) rhport; + + // Page 91 in UAC2 specification + uint8_t channelNum = TU_U16_LOW(p_request->wValue); + uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); + uint8_t ep = TU_U16_LOW(p_request->wIndex); + + (void) channelNum; (void) ctrlSel; (void) ep; + + // return tud_control_xfer(rhport, p_request, &tmp, 1); + + return false; // Yet not implemented +} + +// Invoked when audio class specific get request received for an interface +bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request) +{ + (void) rhport; + + // Page 91 in UAC2 specification + uint8_t channelNum = TU_U16_LOW(p_request->wValue); + uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); + uint8_t itf = TU_U16_LOW(p_request->wIndex); + + (void) channelNum; (void) ctrlSel; (void) itf; + + return false; // Yet not implemented +} + +// Invoked when audio class specific get request received for an entity +bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request) +{ + (void) rhport; + + // Page 91 in UAC2 specification + uint8_t channelNum = TU_U16_LOW(p_request->wValue); + uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); + // uint8_t itf = TU_U16_LOW(p_request->wIndex); // Since we have only one audio function implemented, we do not need the itf value + uint8_t entityID = TU_U16_HIGH(p_request->wIndex); + + // Input terminal (Microphone input) + if (entityID == 1) + { + switch ( ctrlSel ) + { + case AUDIO_TE_CTRL_CONNECTOR: + { + // The terminal connector control only has a get request with only the CUR attribute. + audio_desc_channel_cluster_t ret; + + // Those are dummy values for now + ret.bNrChannels = 1; + ret.bmChannelConfig = 0; + ret.iChannelNames = 0; + + TU_LOG2(" Get terminal connector\r\n"); + + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void*) &ret, sizeof(ret)); + } + break; + + // Unknown/Unsupported control selector + default: + TU_BREAKPOINT(); + return false; + } + } + + // Feature unit + if (entityID == 2) + { + switch ( ctrlSel ) + { + case AUDIO_FU_CTRL_MUTE: + // Audio control mute cur parameter block consists of only one byte - we thus can send it right away + // There does not exist a range parameter block for mute + TU_LOG2(" Get Mute of channel: %u\r\n", channelNum); + return tud_control_xfer(rhport, p_request, &mute[channelNum], 1); + + case AUDIO_FU_CTRL_VOLUME: + switch ( p_request->bRequest ) + { + case AUDIO_CS_REQ_CUR: + TU_LOG2(" Get Volume of channel: %u\r\n", channelNum); + return tud_control_xfer(rhport, p_request, &volume[channelNum], sizeof(volume[channelNum])); + + case AUDIO_CS_REQ_RANGE: + TU_LOG2(" Get Volume range of channel: %u\r\n", channelNum); + + // Copy values - only for testing - better is version below + audio_control_range_2_n_t(1) + ret; + + ret.wNumSubRanges = 1; + ret.subrange[0].bMin = -90; // -90 dB + ret.subrange[0].bMax = 90; // +90 dB + ret.subrange[0].bRes = 1; // 1 dB steps + + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void*) &ret, sizeof(ret)); + + // Unknown/Unsupported control + default: + TU_BREAKPOINT(); + return false; + } + break; + + // Unknown/Unsupported control + default: + TU_BREAKPOINT(); + return false; + } + } + + // Clock Source unit + if ( entityID == 4 ) + { + switch ( ctrlSel ) + { + case AUDIO_CS_CTRL_SAM_FREQ: + // channelNum is always zero in this case + switch ( p_request->bRequest ) + { + case AUDIO_CS_REQ_CUR: + TU_LOG2(" Get Sample Freq.\r\n"); + return tud_control_xfer(rhport, p_request, &sampFreq, sizeof(sampFreq)); + + case AUDIO_CS_REQ_RANGE: + TU_LOG2(" Get Sample Freq. range\r\n"); + return tud_control_xfer(rhport, p_request, &sampleFreqRng, sizeof(sampleFreqRng)); + + // Unknown/Unsupported control + default: + TU_BREAKPOINT(); + return false; + } + break; + + case AUDIO_CS_CTRL_CLK_VALID: + // Only cur attribute exists for this request + TU_LOG2(" Get Sample Freq. valid\r\n"); + return tud_control_xfer(rhport, p_request, &clkValid, sizeof(clkValid)); + + // Unknown/Unsupported control + default: + TU_BREAKPOINT(); + return false; + } + } + + TU_LOG2(" Unsupported entity: %d\r\n", entityID); + return false; // Yet not implemented +} + +bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t itf, uint8_t ep_in, uint8_t cur_alt_setting) +{ + (void) rhport; + (void) itf; + (void) ep_in; + (void) cur_alt_setting; + + for (uint8_t cnt=0; cnt < CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; cnt++) + { + tud_audio_write_support_ff(cnt, i2s_dummy_buffer[cnt], AUDIO_SAMPLE_RATE/1000 * CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX); + } + + return true; +} + +bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uint8_t itf, uint8_t ep_in, uint8_t cur_alt_setting) +{ + (void) rhport; + (void) n_bytes_copied; + (void) itf; + (void) ep_in; + (void) cur_alt_setting; + + uint16_t dataVal; + + // Generate dummy data + for (uint16_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; cnt++) + { + uint16_t * p_buff = (uint16_t *) i2s_dummy_buffer[cnt]; // 2 bytes per sample + dataVal = 1; + for (uint16_t cnt2 = 0; cnt2 < AUDIO_SAMPLE_RATE/1000; cnt2++) + { + for (uint8_t cnt3 = 0; cnt3 < CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX; cnt++) + { + *p_buff++ = dataVal; + } + dataVal++; + } + } + return true; +} + +bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const * p_request) +{ + (void) rhport; + (void) p_request; + startVal = 0; + + return true; +} + +//--------------------------------------------------------------------+ +// BLINKING TASK +//--------------------------------------------------------------------+ +void led_blinking_task(void) +{ + static uint32_t start_ms = 0; + static bool led_state = false; + + // Blink every interval ms + if ( board_millis() - start_ms < blink_interval_ms) return; // not enough time + start_ms += blink_interval_ms; + + board_led_write(led_state); + led_state = 1 - led_state; // toggle +} diff --git a/examples/device/audio_4_channel_mic/src/plot_audio_samples.py b/examples/device/audio_4_channel_mic/src/plot_audio_samples.py new file mode 100644 index 000000000..0bd6f3b5d --- /dev/null +++ b/examples/device/audio_4_channel_mic/src/plot_audio_samples.py @@ -0,0 +1,26 @@ +import sounddevice as sd +import matplotlib.pyplot as plt +import numpy as np + +if __name__ == '__main__': + + # Currently tested for Windows - on Linux try to find the device or use default device if not clearly listed + # devList = sd.query_devices() + # print(devList) + + fs = 48000 # Sample rate + duration = 100e-3 # Duration of recording + device = 'Microphone (MicNode_4_Ch), Windows WDM-KS' # WDM-KS is needed since there are more than one MicNode device APIs (at least in Windows) + + myrecording = sd.rec(int(duration * fs), samplerate=fs, channels=4, dtype='int16', device=device) + print('Waiting...') + sd.wait() # Wait until recording is finished + print('Done!') + + time = np.arange(0, duration, 1 / fs) # time vector + plt.plot(time, myrecording) + plt.xlabel('Time [s]') + plt.ylabel('Amplitude') + plt.title('MicNode 4 Channel') + plt.show() + \ No newline at end of file diff --git a/examples/device/audio_4_channel_mic/src/tusb_config.h b/examples/device/audio_4_channel_mic/src/tusb_config.h new file mode 100644 index 000000000..44be5a0d7 --- /dev/null +++ b/examples/device/audio_4_channel_mic/src/tusb_config.h @@ -0,0 +1,118 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (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. + * + */ + +#ifndef _TUSB_CONFIG_H_ +#define _TUSB_CONFIG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +//-------------------------------------------------------------------- +// COMMON CONFIGURATION +//-------------------------------------------------------------------- + +// defined by compiler flags for flexibility +#ifndef CFG_TUSB_MCU +#error CFG_TUSB_MCU must be defined +#endif + +#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX +#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED) +#else +#define CFG_TUSB_RHPORT0_MODE OPT_MODE_DEVICE +#endif + +#ifndef CFG_TUSB_OS +#define CFG_TUSB_OS OPT_OS_NONE +#endif + +#ifndef CFG_TUSB_DEBUG +#define CFG_TUSB_DEBUG 0 +#endif + +// CFG_TUSB_DEBUG is defined by compiler in DEBUG build +// #define CFG_TUSB_DEBUG 0 + +/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment. + * Tinyusb use follows macros to declare transferring memory so that they can be put + * into those specific section. + * e.g + * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) + * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4))) + */ +#ifndef CFG_TUSB_MEM_SECTION +#define CFG_TUSB_MEM_SECTION +#endif + +#ifndef CFG_TUSB_MEM_ALIGN +#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4))) +#endif + +//-------------------------------------------------------------------- +// DEVICE CONFIGURATION +//-------------------------------------------------------------------- + +#ifndef CFG_TUD_ENDPOINT0_SIZE +#define CFG_TUD_ENDPOINT0_SIZE 64 +#endif + +//------------- CLASS -------------// +#define CFG_TUD_CDC 0 +#define CFG_TUD_MSC 0 +#define CFG_TUD_HID 0 +#define CFG_TUD_MIDI 0 +#define CFG_TUD_AUDIO 1 +#define CFG_TUD_VENDOR 0 + +//-------------------------------------------------------------------- +// AUDIO CLASS DRIVER CONFIGURATION +//-------------------------------------------------------------------- + +// Have a look into audio_device.h for all configurations + +#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_MIC_FOUR_CH_DESC_LEN + +#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1 +#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 + +#define CFG_TUD_AUDIO_ENABLE_EP_IN 1 +#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX 2 // This value is not required by the driver, it parses this information from the descriptor once the alternate interface is set by the host - we use it for the setup +#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 4 // This value is not required by the driver, it parses this information from the descriptor once the alternate interface is set by the host - we use it for the setup +#define CFG_TUD_AUDIO_EP_SZ_IN (48 + 1) * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX // 48 Samples (48 kHz) x 2 Bytes/Sample x CFG_TUD_AUDIO_N_CHANNELS_TX Channels - the Windows driver always needs an extra sample per channel of space more, otherwise it complains... found by trial and error +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX CFG_TUD_AUDIO_EP_SZ_IN +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ CFG_TUD_AUDIO_EP_SZ_IN + +#define CFG_TUD_AUDIO_ENABLE_ENCODING 1 +#define CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING 1 +#define CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX 2 // One I2S stream contains two channels, each stream is saved within one support FIFO - this value is currently fixed, the driver does not support a changing value +#define CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO (CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX / CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX) +#define CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ (CFG_TUD_AUDIO_EP_SZ_IN / CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO) + +#ifdef __cplusplus +} +#endif + +#endif /* _TUSB_CONFIG_H_ */ diff --git a/examples/device/audio_4_channel_mic/src/usb_descriptors.c b/examples/device/audio_4_channel_mic/src/usb_descriptors.c new file mode 100644 index 000000000..93ec6e9f7 --- /dev/null +++ b/examples/device/audio_4_channel_mic/src/usb_descriptors.c @@ -0,0 +1,160 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (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. + * + */ + +#include "tusb.h" + +/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug. + * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC. + * + * Auto ProductID layout's Bitmap: + * [MSB] AUDIO | MIDI | HID | MSC | CDC [LSB] + */ +#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) ) +#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \ + _PID_MAP(MIDI, 3) | _PID_MAP(AUDIO, 4) | _PID_MAP(VENDOR, 5) ) + +//--------------------------------------------------------------------+ +// Device Descriptors +//--------------------------------------------------------------------+ +tusb_desc_device_t const desc_device = +{ + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0200, + + // Use Interface Association Descriptor (IAD) for CDC + // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1) + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + + .idVendor = 0xCafe, + .idProduct = USB_PID, + .bcdDevice = 0x0100, + + .iManufacturer = 0x01, + .iProduct = 0x02, + .iSerialNumber = 0x03, + + .bNumConfigurations = 0x01 +}; + +// Invoked when received GET DEVICE DESCRIPTOR +// Application return pointer to descriptor +uint8_t const * tud_descriptor_device_cb(void) +{ + return (uint8_t const *) &desc_device; +} + +//--------------------------------------------------------------------+ +// Configuration Descriptor +//--------------------------------------------------------------------+ +enum +{ + ITF_NUM_AUDIO_CONTROL = 0, + ITF_NUM_AUDIO_STREAMING, + ITF_NUM_TOTAL +}; + +#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_AUDIO * TUD_AUDIO_MIC_FOUR_CH_DESC_LEN) + +#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX +// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number +// 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ... +#define EPNUM_AUDIO 0x03 +#else +#define EPNUM_AUDIO 0x01 +#endif + +uint8_t const desc_configuration[] = +{ + // Interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), + + // Interface number, string index, EP Out & EP In address, EP size + TUD_AUDIO_MIC_FOUR_CH_DESCRIPTOR(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_stridx*/ 0, /*_nBytesPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, /*_nBitsUsedPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX*8, /*_epin*/ 0x80 | EPNUM_AUDIO, /*_epsize*/ CFG_TUD_AUDIO_EP_SZ_IN) +}; + +// Invoked when received GET CONFIGURATION DESCRIPTOR +// Application return pointer to descriptor +// Descriptor contents must exist long enough for transfer to complete +uint8_t const * tud_descriptor_configuration_cb(uint8_t index) +{ + (void) index; // for multiple configurations + return desc_configuration; +} + +//--------------------------------------------------------------------+ +// String Descriptors +//--------------------------------------------------------------------+ + +// array of pointer to string descriptors +char const* string_desc_arr [] = +{ + (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409) + "PaniRCorp", // 1: Manufacturer + "MicNode_4_Ch", // 2: Product + "123458", // 3: Serials, should use chip ID + "UAC2", // 4: Audio Interface +}; + +static uint16_t _desc_str[32]; + +// Invoked when received GET STRING DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) +{ + (void) langid; + + uint8_t chr_count; + + if ( index == 0) + { + memcpy(&_desc_str[1], string_desc_arr[0], 2); + chr_count = 1; + }else + { + // Convert ASCII string into UTF-16 + + if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL; + + const char* str = string_desc_arr[index]; + + // Cap at max char + chr_count = strlen(str); + if ( chr_count > 31 ) chr_count = 31; + + for(uint8_t i=0; i Date: Thu, 8 Apr 2021 20:11:51 +0200 Subject: [PATCH 112/121] Remove depracted defines in audio_device.c --- src/class/audio/audio_device.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 2e9684cb9..8c0d563e6 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -762,13 +762,8 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t * audio) uint8_t idxDriver, idxItf; uint8_t const *dummy2; -#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_FORMAT_TYPE_TX == AUDIO_FORMAT_TYPE_I - // Required in any case regardless if call backs are used - find index of audio streaming interface and index of interface - TU_VERIFY(audiod_get_AS_interface_index(audio->ep_in_as_intf_num, &idxDriver, &idxItf, &dummy2)); -#else // If a callback is used determine current alternate setting of - find index of audio streaming interface and index of interface if (tud_audio_tx_done_pre_load_cb || tud_audio_tx_done_post_load_cb) TU_VERIFY(audiod_get_AS_interface_index(audio->ep_in_as_intf_num, &idxDriver, &idxItf, &dummy2)); -#endif // Call a weak callback here - a possibility for user to get informed former TX was completed and data gets now loaded into EP in buffer (in case FIFOs are used) or // if no FIFOs are used the user may use this call back to load its data into the EP IN buffer by use of tud_audio_n_write_ep_in_buffer(). From 97d1609c7260f6690a3be119750769a633e46611 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Thu, 8 Apr 2021 20:15:08 +0200 Subject: [PATCH 113/121] Ensure half word alignment in audio 4 channel example --- examples/device/audio_4_channel_mic/src/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/device/audio_4_channel_mic/src/main.c b/examples/device/audio_4_channel_mic/src/main.c index 767ebecdc..58fbd401e 100644 --- a/examples/device/audio_4_channel_mic/src/main.c +++ b/examples/device/audio_4_channel_mic/src/main.c @@ -63,7 +63,7 @@ audio_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX+1]; audio_control_range_4_n_t(1) sampleFreqRng; // Sample frequency range state // Audio test data -uint8_t i2s_dummy_buffer[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ]; +uint16_t i2s_dummy_buffer[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ/2]; // Ensure half word aligned void led_blinking_task(void); void audio_task(void); @@ -411,7 +411,7 @@ bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uin // Generate dummy data for (uint16_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; cnt++) { - uint16_t * p_buff = (uint16_t *) i2s_dummy_buffer[cnt]; // 2 bytes per sample + uint16_t * p_buff = i2s_dummy_buffer[cnt]; // 2 bytes per sample dataVal = 1; for (uint16_t cnt2 = 0; cnt2 < AUDIO_SAMPLE_RATE/1000; cnt2++) { From 2134c1a875d57c79cd431a982d67420101d3c656 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Thu, 8 Apr 2021 21:48:36 +0200 Subject: [PATCH 114/121] Fix defines in audio_device.c --- .../device/audio_4_channel_mic/src/main.c | 1 - src/class/audio/audio_device.c | 28 +++++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/examples/device/audio_4_channel_mic/src/main.c b/examples/device/audio_4_channel_mic/src/main.c index 58fbd401e..6e1ea1e6a 100644 --- a/examples/device/audio_4_channel_mic/src/main.c +++ b/examples/device/audio_4_channel_mic/src/main.c @@ -429,7 +429,6 @@ bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const { (void) rhport; (void) p_request; - startVal = 0; return true; } diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 8c0d563e6..753c0ef6c 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -2085,43 +2085,67 @@ static void audiod_parse_for_AS_params(audiod_interface_t* audio, uint8_t const // Look for a Class-Specific AS Interface Descriptor(4.9.2) to verify format type and format and also to get number of physical channels if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_AS_GENERAL) { +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT if (itf != audio->ep_in_as_intf_num && itf != audio->ep_out_as_intf_num) break; // Abort loop, this interface has no EP, this driver does not support this currently +#endif +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_EP_OUT + if (itf != audio->ep_in_as_intf_num) break; +#endif +#if !CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT + if (itf != audio->ep_out_as_intf_num) break; +#endif +#if CFG_TUD_AUDIO_ENABLE_EP_IN if (itf == audio->ep_in_as_intf_num) { audio->n_channels_tx = ((audio_desc_cs_as_interface_t const * )p_desc)->bNrChannels; audio->format_type_tx = ((audio_desc_cs_as_interface_t const * )p_desc)->bFormatType; -#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING || CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING audio->format_type_I_tx = ((audio_desc_cs_as_interface_t const * )p_desc)->bmFormats; #endif } +#endif +#if CFG_TUD_AUDIO_ENABLE_EP_OUT if (itf == audio->ep_out_as_intf_num) { audio->n_channels_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bNrChannels; audio->format_type_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bFormatType; -#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING || CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING audio->format_type_I_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bmFormats; #endif } +#endif } // Look for a Type I Format Type Descriptor(2.3.1.6 - Audio Formats) #if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING || CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_FORMAT_TYPE && ((audio_desc_type_I_format_t const * )p_desc)->bFormatType == AUDIO_FORMAT_TYPE_I) { +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT if (itf != audio->ep_in_as_intf_num && itf != audio->ep_out_as_intf_num) break; // Abort loop, this interface has no EP, this driver does not support this currently +#endif +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_EP_OUT + if (itf != audio->ep_in_as_intf_num) break; +#endif +#if !CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT + if (itf != audio->ep_out_as_intf_num) break; +#endif +#if CFG_TUD_AUDIO_ENABLE_EP_IN if (itf == audio->ep_in_as_intf_num) { audio->n_bytes_per_sampe_tx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize; } +#endif +#if CFG_TUD_AUDIO_ENABLE_EP_OUT if (itf == audio->ep_out_as_intf_num) { audio->n_bytes_per_sampe_rx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize; } +#endif } #endif From 8d9f60ca5e1b095fd8ab5541bf3190a2035eaf6f Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Wed, 14 Apr 2021 21:52:54 +0200 Subject: [PATCH 115/121] Improve user feedback in case of wrong configuration of audio driver --- src/class/audio/audio_device.c | 71 ++++++++++++++-------------------- 1 file changed, 29 insertions(+), 42 deletions(-) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 753c0ef6c..4057f5f64 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -81,14 +81,14 @@ #endif #if (CFG_TUSB_MCU == OPT_MCU_STM32F1 && defined(STM32F1_SYNOPSYS)) || \ - CFG_TUSB_MCU == OPT_MCU_STM32F2 || \ - CFG_TUSB_MCU == OPT_MCU_STM32F4 || \ - CFG_TUSB_MCU == OPT_MCU_STM32F7 || \ - CFG_TUSB_MCU == OPT_MCU_STM32H7 || \ + CFG_TUSB_MCU == OPT_MCU_STM32F2 || \ + CFG_TUSB_MCU == OPT_MCU_STM32F4 || \ + CFG_TUSB_MCU == OPT_MCU_STM32F7 || \ + CFG_TUSB_MCU == OPT_MCU_STM32H7 || \ (CFG_TUSB_MCU == OPT_MCU_STM32L4 && defined(STM32L4_SYNOPSYS)) - #define USE_LINEAR_BUFFER 0 +#define USE_LINEAR_BUFFER 0 #else - #define USE_LINEAR_BUFFER 1 +#define USE_LINEAR_BUFFER 1 #endif // Declaration of buffers @@ -182,9 +182,7 @@ CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ]; #endif // Active alternate setting of interfaces -#if CFG_TUD_AUDIO_FUNC_1_N_AS_INT > 0 CFG_TUSB_MEM_ALIGN uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT]; -#endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0 CFG_TUSB_MEM_ALIGN uint8_t alt_setting_2[CFG_TUD_AUDIO_FUNC_2_N_AS_INT]; #endif @@ -267,9 +265,7 @@ typedef struct uint8_t ep_int_ctr; // Audio control interrupt EP. #endif -#if CFG_TUD_AUDIO_FUNC_1_N_AS_INT > 0 || CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0 || CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0 - uint8_t * alt_setting_ptr; // We need to save the current alternate setting this way, because it is possible that there are AS interfaces which do not have an EP! -#endif + uint8_t * alt_setting; // We need to save the current alternate setting this way, because it is possible that there are AS interfaces which do not have an EP! /*------------- From this point, data is not cleared by bus reset -------------*/ @@ -486,7 +482,7 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint16_ TU_VERIFY(audiod_get_AS_interface_index(audio->ep_out_as_intf_num, &idxDriver, &idxItf, &dummy2)); // Call a weak callback here - a possibility for user to get informed an audio packet was received and data gets now loaded into EP FIFO (or decoded into support RX software FIFO) - if (tud_audio_rx_done_pre_read_cb) TU_VERIFY(tud_audio_rx_done_pre_read_cb(rhport, n_bytes_received, idxDriver, audio->ep_out, audio->alt_setting_ptr[idxItf])); + if (tud_audio_rx_done_pre_read_cb) TU_VERIFY(tud_audio_rx_done_pre_read_cb(rhport, n_bytes_received, idxDriver, audio->ep_out, audio->alt_setting[idxItf])); #if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT @@ -540,7 +536,7 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint16_ #endif // Call a weak callback here - a possibility for user to get informed decoding was completed - if (tud_audio_rx_done_post_read_cb) TU_VERIFY(tud_audio_rx_done_post_read_cb(rhport, n_bytes_received, idxDriver, audio->ep_out, audio->alt_setting_ptr[idxItf])); + if (tud_audio_rx_done_post_read_cb) TU_VERIFY(tud_audio_rx_done_post_read_cb(rhport, n_bytes_received, idxDriver, audio->ep_out, audio->alt_setting[idxItf])); return true; } @@ -557,12 +553,12 @@ static inline uint8_t * audiod_interleaved_copy_bytes_fast_decode(uint16_t const { // This function is an optimized version of -// while((uint8_t *)dst < dst_end) -// { -// memcpy(dst, src, nBytesToCopy); -// dst = (uint8_t *)dst + nBytesToCopy; -// src += nBytesToCopy * n_ff_used; -// } + // while((uint8_t *)dst < dst_end) + // { + // memcpy(dst, src, nBytesToCopy); + // dst = (uint8_t *)dst + nBytesToCopy; + // src += nBytesToCopy * n_ff_used; + // } // Optimize for fast half word copies typedef struct{ @@ -596,9 +592,9 @@ static inline uint8_t * audiod_interleaved_copy_bytes_fast_decode(uint16_t const case 3: while((uint8_t *)dst < dst_end) { -// memcpy(dst, src, 3); -// dst = (uint8_t *)dst + 3; -// src += 3 * n_ff_used; + // memcpy(dst, src, 3); + // dst = (uint8_t *)dst + 3; + // src += 3 * n_ff_used; // TODO: Is there a faster way to copy 3 bytes? *(uint8_t *)dst++ = *src++; @@ -767,7 +763,7 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t * audio) // Call a weak callback here - a possibility for user to get informed former TX was completed and data gets now loaded into EP in buffer (in case FIFOs are used) or // if no FIFOs are used the user may use this call back to load its data into the EP IN buffer by use of tud_audio_n_write_ep_in_buffer(). - if (tud_audio_tx_done_pre_load_cb) TU_VERIFY(tud_audio_tx_done_pre_load_cb(rhport, idxDriver, audio->ep_in, audio->alt_setting_ptr[idxItf])); + if (tud_audio_tx_done_pre_load_cb) TU_VERIFY(tud_audio_tx_done_pre_load_cb(rhport, idxDriver, audio->ep_in, audio->alt_setting[idxItf])); // Send everything in ISO EP FIFO uint16_t n_bytes_tx; @@ -827,7 +823,7 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t * audio) #endif // Call a weak callback here - a possibility for user to get informed former TX was completed and how many bytes were loaded for the next frame - if (tud_audio_tx_done_post_load_cb) TU_VERIFY(tud_audio_tx_done_post_load_cb(rhport, n_bytes_tx, idxDriver, audio->ep_in, audio->alt_setting_ptr[idxItf])); + if (tud_audio_tx_done_post_load_cb) TU_VERIFY(tud_audio_tx_done_post_load_cb(rhport, n_bytes_tx, idxDriver, audio->ep_in, audio->alt_setting[idxItf])); return true; } @@ -887,9 +883,9 @@ static inline uint8_t * audiod_interleaved_copy_bytes_fast_encode(uint16_t const case 3: while((uint8_t *)src < src_end) { -// memcpy(dst, src, 3); -// src = (uint8_t *)src + 3; -// dst += 3 * n_ff_used; + // memcpy(dst, src, 3); + // src = (uint8_t *)src + 3; + // dst += 3 * n_ff_used; // TODO: Is there a faster way to copy 3 bytes? *dst++ = *(uint8_t *)src++; @@ -1021,26 +1017,24 @@ void audiod_init(void) } // Initialize active alternate interface buffers -#if CFG_TUD_AUDIO_FUNC_1_N_AS_INT > 0 || CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0 || CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0 switch (i) { #if CFG_TUD_AUDIO_FUNC_1_N_AS_INT > 0 case 0: - audio->alt_setting_ptr = alt_setting_1; + audio->alt_setting = alt_setting_1; break; #endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0 case 1: - audio->alt_setting_ptr = alt_setting_2; + audio->alt_setting = alt_setting_2; break; #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0 case 2: - audio->alt_setting_ptr = alt_setting_3; + audio->alt_setting = alt_setting_3; break; #endif } -#endif // Initialize IN EP FIFO if required #if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING @@ -1400,7 +1394,6 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const * p_request) { -#if CFG_TUD_AUDIO_FUNC_1_N_AS_INT > 0 || CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0 || CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0 uint8_t const itf = tu_u16_low(p_request->wIndex); // Find index of audio streaming interface @@ -1408,17 +1401,11 @@ static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const * uint8_t const *dummy; TU_VERIFY(audiod_get_AS_interface_index(itf, &idxDriver, &idxItf, &dummy)); - TU_VERIFY(tud_control_xfer(rhport, p_request, &_audiod_itf[idxDriver].alt_setting_ptr[idxItf], 1)); + TU_VERIFY(tud_control_xfer(rhport, p_request, &_audiod_itf[idxDriver].alt_setting[idxItf], 1)); - TU_LOG2(" Get itf: %u - current alt: %u\r\n", itf, _audiod_itf[idxDriver].alt_setting_ptr[idxItf]); + TU_LOG2(" Get itf: %u - current alt: %u\r\n", itf, _audiod_itf[idxDriver].alt_setting[idxItf]); return true; - -#else - (void) rhport; - (void) p_request; - return false; -#endif } static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * p_request) @@ -1495,7 +1482,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * #endif // Save current alternative interface setting - audio->alt_setting_ptr[idxItf] = alt; + audio->alt_setting[idxItf] = alt; // Open new EP if necessary - EPs are only to be closed or opened for AS interfaces - Look for AS interface with correct alternate interface // Get pointer at end From ad11481dd16112a38ab05754bafb33599af38f9d Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 15 Apr 2021 12:08:50 +0700 Subject: [PATCH 116/121] update plot script to work on macos and linux also add note for installing pip module --- .../device/audio_4_channel_mic/src/main.c | 8 ++++++++ .../src/plot_audio_samples.py | 20 +++++++++++++------ examples/device/audio_test/src/main.c | 8 ++++++++ .../audio_test/src/plot_audio_samples.py | 19 +++++++++++++----- 4 files changed, 44 insertions(+), 11 deletions(-) diff --git a/examples/device/audio_4_channel_mic/src/main.c b/examples/device/audio_4_channel_mic/src/main.c index 6e1ea1e6a..99e850dcc 100644 --- a/examples/device/audio_4_channel_mic/src/main.c +++ b/examples/device/audio_4_channel_mic/src/main.c @@ -23,6 +23,14 @@ * */ +/* plot_audio_samples.py requires following modules: + * $ sudo apt install libportaudio + * $ pip3 install sounddevice matplotlib + * + * Then run + * $ python3 plot_audio_samples.py + */ + #include #include #include diff --git a/examples/device/audio_4_channel_mic/src/plot_audio_samples.py b/examples/device/audio_4_channel_mic/src/plot_audio_samples.py index 0bd6f3b5d..9ab15135d 100644 --- a/examples/device/audio_4_channel_mic/src/plot_audio_samples.py +++ b/examples/device/audio_4_channel_mic/src/plot_audio_samples.py @@ -1,16 +1,24 @@ import sounddevice as sd import matplotlib.pyplot as plt import numpy as np +import platform if __name__ == '__main__': - # Currently tested for Windows - on Linux try to find the device or use default device if not clearly listed - # devList = sd.query_devices() - # print(devList) + # If you got "ValueError: No input device matching", that is because your PC name example device + # differently from tested list below. Uncomment the next line to see full list and try to pick correct one + # print(sd.query_devices()) - fs = 48000 # Sample rate - duration = 100e-3 # Duration of recording - device = 'Microphone (MicNode_4_Ch), Windows WDM-KS' # WDM-KS is needed since there are more than one MicNode device APIs (at least in Windows) + fs = 48000 # Sample rate + duration = 100e-3 # Duration of recording + + if platform.system() == 'Windows': + # WDM-KS is needed since there are more than one MicNode device APIs (at least in Windows) + device = 'Microphone (MicNode_4_Ch), Windows WDM-KS' + elif platform.system() == 'Darwin': + device = 'MicNode_4_Ch' + else: + device ='default' myrecording = sd.rec(int(duration * fs), samplerate=fs, channels=4, dtype='int16', device=device) print('Waiting...') diff --git a/examples/device/audio_test/src/main.c b/examples/device/audio_test/src/main.c index 4de515b3b..9a2fdd3a1 100644 --- a/examples/device/audio_test/src/main.c +++ b/examples/device/audio_test/src/main.c @@ -23,6 +23,14 @@ * */ +/* plot_audio_samples.py requires following modules: + * $ sudo apt install libportaudio + * $ pip3 install sounddevice matplotlib + * + * Then run + * $ python3 plot_audio_samples.py + */ + #include #include #include diff --git a/examples/device/audio_test/src/plot_audio_samples.py b/examples/device/audio_test/src/plot_audio_samples.py index 0b0c3394f..6e3c4978e 100644 --- a/examples/device/audio_test/src/plot_audio_samples.py +++ b/examples/device/audio_test/src/plot_audio_samples.py @@ -1,15 +1,24 @@ import sounddevice as sd import matplotlib.pyplot as plt import numpy as np +import platform if __name__ == '__main__': - # devList = sd.query_devices() - # print(devList) + # If you got "ValueError: No input device matching", that is because your PC name example device + # differently from tested list below. Uncomment the next line to see full list and try to pick correct one + # print(sd.query_devices()) - fs = 48000 # Sample rate - duration = 100e-3 # Duration of recording - device = 'Microphone (MicNode) MME' # MME is needed since there are more than one MicNode device APIs (at least in Windows) + fs = 48000 # Sample rate + duration = 100e-3 # Duration of recording + + if platform.system() == 'Windows': + # MME is needed since there are more than one MicNode device APIs (at least in Windows) + device = 'Microphone (MicNode) MME' + elif platform.system() == 'Darwin': + device = 'MicNode' + else: + device ='default' myrecording = sd.rec(int(duration * fs), samplerate=fs, channels=1, dtype='int16', device=device) print('Waiting...') From 3c84776e0ac926cedfcbda4a3ecf72e2a7c1cde8 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 15 Apr 2021 12:09:12 +0700 Subject: [PATCH 117/121] minor clean up --- src/portable/st/synopsys/dcd_synopsys.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/portable/st/synopsys/dcd_synopsys.c b/src/portable/st/synopsys/dcd_synopsys.c index aa927d5a4..0fe7c2a3c 100644 --- a/src/portable/st/synopsys/dcd_synopsys.c +++ b/src/portable/st/synopsys/dcd_synopsys.c @@ -1007,16 +1007,16 @@ static void handle_epin_ints(uint8_t rhport, USB_OTG_DeviceTypeDef * dev, USB_OT uint16_t remaining_packets = (in_ep[n].DIEPTSIZ & USB_OTG_DIEPTSIZ_PKTCNT_Msk) >> USB_OTG_DIEPTSIZ_PKTCNT_Pos; // Process every single packet (only whole packets can be written to fifo) - for(uint16_t i = 0; i < remaining_packets; i++){ - volatile uint16_t remaining_bytes = (in_ep[n].DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ_Msk) >> USB_OTG_DIEPTSIZ_XFRSIZ_Pos; + for(uint16_t i = 0; i < remaining_packets; i++) + { + uint16_t const remaining_bytes = (in_ep[n].DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ_Msk) >> USB_OTG_DIEPTSIZ_XFRSIZ_Pos; + // Packet can not be larger than ep max size - uint16_t packet_size = tu_min16(remaining_bytes, xfer->max_size); + uint16_t const packet_size = tu_min16(remaining_bytes, xfer->max_size); // It's only possible to write full packets into FIFO. Therefore DTXFSTS register of current // EP has to be checked if the buffer can take another WHOLE packet - if(packet_size > ((in_ep[n].DTXFSTS & USB_OTG_DTXFSTS_INEPTFSAV_Msk) << 2)){ - break; - } + if(packet_size > ((in_ep[n].DTXFSTS & USB_OTG_DTXFSTS_INEPTFSAV_Msk) << 2)) break; // Push packet to Tx-FIFO if (xfer->ff) From 2e65d1543fe24d51862d425ae8822c2f3c7bf3e3 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 15 Apr 2021 12:14:01 +0700 Subject: [PATCH 118/121] update cmakelist for audio_4_channel --- examples/device/audio_4_channel_mic/CMakeLists.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/device/audio_4_channel_mic/CMakeLists.txt b/examples/device/audio_4_channel_mic/CMakeLists.txt index 03f2439e2..9cae652ea 100644 --- a/examples/device/audio_4_channel_mic/CMakeLists.txt +++ b/examples/device/audio_4_channel_mic/CMakeLists.txt @@ -10,9 +10,7 @@ get_filename_component(TOP "${TOP}" REALPATH) if(FAMILY STREQUAL "rp2040") cmake_minimum_required(VERSION 3.12) - set(PICO_SDK_PATH ${TOP}/hw/mcu/raspberrypi/pico-sdk) - include(${PICO_SDK_PATH}/pico_sdk_init.cmake) - + include(${TOP}/hw/bsp/${FAMILY}/pico_sdk_import.cmake) project(${PROJECT}) add_executable(${PROJECT}) From fa0d71f2cf26419d01a78227e7689ecb8771e785 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Thu, 15 Apr 2021 17:04:25 +0200 Subject: [PATCH 119/121] Try to resolve include hassle in uac2_headset --- examples/device/uac2_headset/src/tusb_config.h | 5 ++++- examples/device/uac2_headset/src/usb_descriptors.h | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/device/uac2_headset/src/tusb_config.h b/examples/device/uac2_headset/src/tusb_config.h index 4b4570b77..88f9efcff 100644 --- a/examples/device/uac2_headset/src/tusb_config.h +++ b/examples/device/uac2_headset/src/tusb_config.h @@ -35,6 +35,8 @@ extern "C" { // COMMON CONFIGURATION //-------------------------------------------------------------------- +#include "usb_descriptors.h" + // defined by compiler flags for flexibility #ifndef CFG_TUSB_MCU #error CFG_TUSB_MCU must be defined @@ -94,7 +96,8 @@ extern "C" { #define CFG_TUD_AUDIO_IN_PATH (CFG_TUD_AUDIO) #define CFG_TUD_AUDIO_OUT_PATH (CFG_TUD_AUDIO) -#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN 220 // This equals TUD_AUDIO_HEADSET_STEREO_DESC_LEN, however, including it from usb_descriptors.h is not possible due to some strange include hassle +//#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN 220 // This equals TUD_AUDIO_HEADSET_STEREO_DESC_LEN, however, including it from usb_descriptors.h is not possible due to some strange include hassle +#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_HEADSET_STEREO_DESC_LEN // Audio format type I specifications #define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 1 diff --git a/examples/device/uac2_headset/src/usb_descriptors.h b/examples/device/uac2_headset/src/usb_descriptors.h index 6651897b0..d9c5a63a7 100644 --- a/examples/device/uac2_headset/src/usb_descriptors.h +++ b/examples/device/uac2_headset/src/usb_descriptors.h @@ -26,7 +26,7 @@ #ifndef _USB_DESCRIPTORS_H_ #define _USB_DESCRIPTORS_H_ -#include "tusb.h" +// #include "tusb.h" // Unit numbers are arbitrary selected #define UAC2_ENTITY_CLOCK 0x04 From 9ecb91e1bd0ac54c759ac1e91a0714c5a8c49172 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 15 Apr 2021 23:47:28 +0700 Subject: [PATCH 120/121] fix build with LOG=2 --- src/device/usbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/device/usbd.c b/src/device/usbd.c index 8b126a9f6..8a3d8ec2f 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -1250,7 +1250,7 @@ bool usbd_edpt_iso_xfer(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_ uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr); - TU_LOG2(" Queue ISO EP %02X with %u bytes ... ", ep_addr, count); + TU_LOG2(" Queue ISO EP %02X with %u bytes ... ", ep_addr, total_bytes); // Attempt to transfer on a busy endpoint, sound like an race condition ! TU_ASSERT(_usbd_dev.ep_status[epnum][dir].busy == 0); From c7e4a8616640165b48cfb0ba4f9346982faa4344 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Thu, 15 Apr 2021 19:40:57 +0200 Subject: [PATCH 121/121] Fix bug in audio_4_channel_mic.c --- examples/device/audio_4_channel_mic/src/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/device/audio_4_channel_mic/src/main.c b/examples/device/audio_4_channel_mic/src/main.c index 99e850dcc..983b87e5b 100644 --- a/examples/device/audio_4_channel_mic/src/main.c +++ b/examples/device/audio_4_channel_mic/src/main.c @@ -400,7 +400,7 @@ bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t itf, uint8_t ep_in, u for (uint8_t cnt=0; cnt < CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; cnt++) { - tud_audio_write_support_ff(cnt, i2s_dummy_buffer[cnt], AUDIO_SAMPLE_RATE/1000 * CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX); + tud_audio_write_support_ff(cnt, i2s_dummy_buffer[cnt], AUDIO_SAMPLE_RATE/1000 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX); } return true; @@ -423,7 +423,7 @@ bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uin dataVal = 1; for (uint16_t cnt2 = 0; cnt2 < AUDIO_SAMPLE_RATE/1000; cnt2++) { - for (uint8_t cnt3 = 0; cnt3 < CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX; cnt++) + for (uint8_t cnt3 = 0; cnt3 < CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX; cnt3++) { *p_buff++ = dataVal; }