From 03f974c9b92bf9e0fc6e74ab4d15ad77a4a8b339 Mon Sep 17 00:00:00 2001 From: Reinhard Panhuber Date: Fri, 23 Apr 2021 10:27:48 +0200 Subject: [PATCH] Implement functions to allow for DMA usage in audio driver. - Add tud_audio_n_get_ep_out_ff(), tud_audio_n_get_ep_in_ff(), tud_audio_n_get_rx_support_ff(), and tud_audio_n_get_tx_support_ff() - Change get_linear_read/write_info() to return linear and wrapped part at once - Adjusted affected code in audio_device.c and tested with audio_4_channel. --- src/class/audio/audio_device.c | 77 +++++++++++-------- src/class/audio/audio_device.h | 29 +++++++ src/common/tusb_fifo.c | 35 +++++---- src/common/tusb_fifo.h | 6 +- src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c | 4 +- 5 files changed, 103 insertions(+), 48 deletions(-) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 0a60d9ee..f96878b5 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -447,27 +447,39 @@ bool tud_audio_n_clear_ep_out_ff(uint8_t func_id) return tu_fifo_clear(&_audiod_fct[func_id].ep_out_ff); } +tu_fifo_t* tud_audio_n_get_ep_out_ff(uint8_t func_id) +{ + if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL) return &_audiod_fct[func_id].ep_out_ff; + return NULL; +} + #endif #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 func_id, uint8_t ff_idx) { - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL, ff_idx < _audiod_fct[func_id].n_rx_supp_ff); + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff); return tu_fifo_clear(&_audiod_fct[func_id].rx_supp_ff[ff_idx]); } uint16_t tud_audio_n_available_support_ff(uint8_t func_id, uint8_t ff_idx) { - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL, ff_idx < _audiod_fct[func_id].n_rx_supp_ff); + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff); return tu_fifo_count(&_audiod_fct[func_id].rx_supp_ff[ff_idx]); } uint16_t tud_audio_n_read_support_ff(uint8_t func_id, uint8_t ff_idx, void* buffer, uint16_t bufsize) { - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL, ff_idx < _audiod_fct[func_id].n_rx_supp_ff); + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff); return tu_fifo_read_n(&_audiod_fct[func_id].rx_supp_ff[ff_idx], buffer, bufsize); } + +tu_fifo_t* tud_audio_n_get_rx_support_ff(uint8_t func_id, uint8_t ff_idx) +{ + if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff) return &_audiod_fct[func_id].rx_supp_ff[ff_idx]; + return NULL; +} #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). @@ -635,32 +647,26 @@ static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, u uint8_t cnt_ff; // Decode - void * dst; + void * dst, * dst_wrap; uint8_t * src; uint8_t * dst_end; - uint16_t len; + uint16_t len, len_wrap; for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++) { 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, nBytesPerFFToRead); - tu_fifo_advance_write_pointer(&audio->rx_supp_ff[cnt_ff], len); + len = tu_fifo_get_linear_write_info(&audio->rx_supp_ff[cnt_ff], 0, nBytesPerFFToRead, &dst, &len_wrap, &dst_wrap); dst_end = dst + len; - src = audiod_interleaved_copy_bytes_fast_decode(nBytesToCopy, dst, dst_end, src, n_ff_used); // Handle wrapped part of FIFO - if (len < nBytesPerFFToRead) + if (len_wrap != 0) { - 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; - - audiod_interleaved_copy_bytes_fast_decode(nBytesToCopy, dst, dst_end, src, n_ff_used); + dst_end = dst_wrap + len_wrap; + audiod_interleaved_copy_bytes_fast_decode(nBytesToCopy, dst_wrap, dst_end, src, n_ff_used); } + tu_fifo_advance_write_pointer(&audio->rx_supp_ff[cnt_ff], len + len_wrap); } // 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 @@ -699,9 +705,16 @@ bool tud_audio_n_clear_ep_in_ff(uint8_t func_id) // Del return tu_fifo_clear(&_audiod_fct[func_id].ep_in_ff); } +tu_fifo_t* tud_audio_n_get_ep_in_ff(uint8_t func_id) +{ + if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL) return &_audiod_fct[func_id].ep_in_ff; + return NULL; +} + #endif #if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN + uint16_t tud_audio_n_flush_tx_support_ff(uint8_t func_id) // Force all content in the support TX FIFOs to be written into linear buffer and schedule a transmit { TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); @@ -719,15 +732,22 @@ uint16_t tud_audio_n_flush_tx_support_ff(uint8_t func_id) // For bool tud_audio_n_clear_tx_support_ff(uint8_t func_id, uint8_t ff_idx) { - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL, ff_idx < _audiod_fct[func_id].n_tx_supp_ff); + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff); return tu_fifo_clear(&_audiod_fct[func_id].tx_supp_ff[ff_idx]); } uint16_t tud_audio_n_write_support_ff(uint8_t func_id, uint8_t ff_idx, const void * data, uint16_t len) { - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL, ff_idx < _audiod_fct[func_id].n_tx_supp_ff); + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff); return tu_fifo_write_n(&_audiod_fct[func_id].tx_supp_ff[ff_idx], data, len); } + +tu_fifo_t* tud_audio_n_get_tx_support_ff(uint8_t func_id, uint8_t ff_idx) +{ + if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff) return &_audiod_fct[func_id].tx_supp_ff[ff_idx]; + return NULL; +} + #endif @@ -751,6 +771,7 @@ uint16_t tud_audio_int_ctr_n_write(uint8_t func_id, uint8_t const* buffer, uint1 return true; } + #endif @@ -952,32 +973,28 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi nBytesPerFFToSend = (nBytesPerFFToSend / nBytesToCopy) * nBytesToCopy; // Encode - void * src; + void * src, * src_wrap; uint8_t * dst; uint8_t * src_end; - uint16_t len; + uint16_t len, len_wrap; for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++) { 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, nBytesPerFFToSend); - tu_fifo_advance_read_pointer(&audio->tx_supp_ff[cnt_ff], len); + len = tu_fifo_get_linear_read_info(&audio->tx_supp_ff[cnt_ff], 0, nBytesPerFFToSend, &src, &len_wrap, &src_wrap); src_end = src + len; - dst = audiod_interleaved_copy_bytes_fast_encode(nBytesToCopy, src, src_end, dst, n_ff_used); // Handle wrapped part of FIFO - if (len < nBytesPerFFToSend) + if (len_wrap != 0) { - 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; - - audiod_interleaved_copy_bytes_fast_encode(nBytesToCopy, src, src_end, dst, n_ff_used); + src_end = src_wrap + len_wrap; + audiod_interleaved_copy_bytes_fast_encode(nBytesToCopy, src_wrap, src_end, dst, n_ff_used); } + + tu_fifo_advance_read_pointer(&audio->tx_supp_ff[cnt_ff], len + len_wrap); } return nBytesPerFFToSend * n_ff_used; diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index c070e48c..66cc2973 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -33,6 +33,7 @@ #include "device/usbd.h" #include "audio.h" +#include "tusb_fifo.h" //--------------------------------------------------------------------+ // Class Driver Configuration @@ -364,23 +365,27 @@ bool tud_audio_n_mounted (uint8_t func_id); uint16_t tud_audio_n_available (uint8_t func_id); uint16_t tud_audio_n_read (uint8_t func_id, void* buffer, uint16_t bufsize); bool tud_audio_n_clear_ep_out_ff (uint8_t func_id); // Delete all content in the EP OUT FIFO +tu_fifo_t* tud_audio_n_get_ep_out_ff (uint8_t func_id); #endif #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING bool tud_audio_n_clear_rx_support_ff (uint8_t func_id, uint8_t ff_idx); // Delete all content in the support RX FIFOs uint16_t tud_audio_n_available_support_ff (uint8_t func_id, uint8_t ff_idx); uint16_t tud_audio_n_read_support_ff (uint8_t func_id, uint8_t ff_idx, void* buffer, uint16_t bufsize); +tu_fifo_t* tud_audio_n_get_rx_support_ff (uint8_t func_id, uint8_t ff_idx); #endif #if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING uint16_t tud_audio_n_write (uint8_t func_id, const void * data, uint16_t len); bool tud_audio_n_clear_ep_in_ff (uint8_t func_id); // Delete all content in the EP IN FIFO +tu_fifo_t* tud_audio_n_get_ep_in_ff (uint8_t func_id); #endif #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING uint16_t tud_audio_n_flush_tx_support_ff (uint8_t func_id); // 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 func_id, uint8_t ff_idx); uint16_t tud_audio_n_write_support_ff (uint8_t func_id, uint8_t ff_idx, const void * data, uint16_t len); +tu_fifo_t* tud_audio_n_get_tx_support_ff (uint8_t func_id, uint8_t ff_idx); #endif #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN @@ -399,12 +404,14 @@ static inline bool tud_audio_mounted (void); 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); +static inline tu_fifo_t* tud_audio_get_ep_out_ff (void); #endif #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING static inline bool tud_audio_clear_rx_support_ff (uint8_t ff_idx); static inline uint16_t tud_audio_available_support_ff (uint8_t ff_idx); static inline uint16_t tud_audio_read_support_ff (uint8_t ff_idx, void* buffer, uint16_t bufsize); +static inline tu_fifo_t* tud_audio_get_rx_support_ff (uint8_t ff_idx); #endif // TX API @@ -412,12 +419,14 @@ static inline uint16_t tud_audio_read_support_ff (uint8_t ff_idx, voi #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); +static inline tu_fifo_t* tud_audio_get_ep_in_ff (void); #endif #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 ff_idx); static inline uint16_t tud_audio_write_support_ff (uint8_t ff_idx, const void * data, uint16_t len); +static inline tu_fifo_t* tud_audio_get_tx_support_ff (uint8_t ff_idx); #endif // INT CTR API @@ -514,6 +523,11 @@ static inline bool tud_audio_clear_ep_out_ff(void) return tud_audio_n_clear_ep_out_ff(0); } +static inline tu_fifo_t* tud_audio_get_ep_out_ff(void) +{ + return tud_audio_n_get_ep_out_ff(0); +} + #endif #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING @@ -533,6 +547,11 @@ static inline uint16_t tud_audio_read_support_ff(uint8_t ff_idx, void* buffer, u return tud_audio_n_read_support_ff(0, ff_idx, buffer, bufsize); } +static inline tu_fifo_t* tud_audio_get_rx_support_ff(uint8_t ff_idx) +{ + return tud_audio_n_get_rx_support_ff(0, ff_idx); +} + #endif // TX API @@ -549,6 +568,11 @@ static inline bool tud_audio_clear_ep_in_ff(void) return tud_audio_n_clear_ep_in_ff(0); } +static inline tu_fifo_t* tud_audio_get_ep_in_ff(void) +{ + return tud_audio_n_get_ep_in_ff(0); +} + #endif #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING @@ -568,6 +592,11 @@ static inline uint16_t tud_audio_write_support_ff(uint8_t ff_idx, const void * d return tud_audio_n_write_support_ff(0, ff_idx, data, len); } +static inline tu_fifo_t* tud_audio_get_tx_support_ff(uint8_t ff_idx) +{ + return tud_audio_n_get_tx_support_ff(0, ff_idx); +} + #endif #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 098d5480..3bca8397 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -905,7 +905,7 @@ void tu_fifo_advance_read_pointer(tu_fifo_t *f, uint16_t n) 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) +uint16_t tu_fifo_get_linear_read_info(tu_fifo_t *f, uint16_t offset, uint16_t n, void **ptr_lin, uint16_t *len_wrap, void **ptr_wrap) { // Operate on temporary values in case they change in between uint16_t w = f->wr_idx, r = f->rd_idx; @@ -933,23 +933,26 @@ uint16_t tu_fifo_get_linear_read_info(tu_fifo_t *f, uint16_t offset, void **ptr, w = get_relative_pointer(f, w, 0); r = get_relative_pointer(f, r, offset); + // Copy pointer to buffer to start reading from + *ptr_lin = &f->buffer[r]; + *ptr_wrap = f->buffer; + // Check if there is a wrap around necessary uint16_t len; if (w > r) { + // Non wrapping case len = w - r; + len = tu_min16(n, len); // Limit to required length + *len_wrap = 0; } else { len = f->depth - r; // Also the case if FIFO was full + len = tu_min16(n, len); + *len_wrap = n-len; // n was already limited to what is available } - // Limit to required length - len = tu_min16(n, len); - - // Copy pointer to buffer to start reading from - *ptr = &f->buffer[r]; - return len; } @@ -976,7 +979,7 @@ uint16_t tu_fifo_get_linear_read_info(tu_fifo_t *f, uint16_t offset, void **ptr, 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 tu_fifo_get_linear_write_info(tu_fifo_t *f, uint16_t offset, uint16_t n, void **ptr_lin, uint16_t *len_wrap, void **ptr_wrap) { uint16_t w = f->wr_idx, r = f->rd_idx; uint16_t free = _tu_fifo_remaining(f, w, r); @@ -1004,22 +1007,26 @@ uint16_t tu_fifo_get_linear_write_info(tu_fifo_t *f, uint16_t offset, void **ptr // Get relative pointers w = get_relative_pointer(f, w, offset); r = get_relative_pointer(f, r, 0); + + // Copy pointer to buffer to start writing to + *ptr_lin = &f->buffer[w]; + *ptr_wrap = f->buffer; // Always start of buffer + uint16_t len; if (w < r) { + // Non wrapping case len = r-w; + len = tu_min16(n, len); // Limit to required length + *len_wrap = 0; } else { len = f->depth - w; + len = tu_min16(n, len); // Limit to required length + *len_wrap = n-len; // Remaining length - n already was limited to free or FIFO depth } - // 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 b2d0b5be..28998ad2 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -134,8 +134,10 @@ void tu_fifo_advance_read_pointer (tu_fifo_t *f, uint16_t n); // 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); +// TODO - update comments + +uint16_t tu_fifo_get_linear_read_info(tu_fifo_t *f, uint16_t offset, uint16_t n, void **ptr_lin, uint16_t *len_wrap, void **ptr_wrap); +uint16_t tu_fifo_get_linear_write_info(tu_fifo_t *f, uint16_t offset, uint16_t n, void **ptr_lin, uint16_t *len_wrap, void **ptr_wrap); static inline bool tu_fifo_peek(tu_fifo_t* f, void * p_buffer) { diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index b8b0fc10..dd0d76c1 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -993,7 +993,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 * src; - uint16_t len = tu_fifo_get_linear_read_info(ff, 0, &src, wNBytes); // We want to read from the FIFO + uint16_t len = tu_fifo_get_linear_read_info(ff, 0, &src, wNBytes); // We want to read from the FIFO - THIS FUNCTION CHANGED!!! TU_VERIFY(len && dcd_write_packet_memory(dst, src, len)); // and write it into the PMA tu_fifo_advance_read_pointer(ff, len); @@ -1075,7 +1075,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 * dst; - uint16_t len = tu_fifo_get_linear_write_info(ff, 0, &dst, wNBytes); + uint16_t len = tu_fifo_get_linear_write_info(ff, 0, &dst, wNBytes); // THIS FUNCTION CHANGED!!!! TU_VERIFY(len && dcd_read_packet_memory(dst, src, len)); tu_fifo_advance_write_pointer(ff, len);