diff options
| author | Ha Thach <[email protected]> | 2025-11-27 11:42:31 +0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-11-27 11:42:31 +0700 |
| commit | 5ef55bfa30d6f8cf175b3d327f621c76aae7b138 (patch) | |
| tree | 26fd4779ccaa8b7b2d6cb5aa3badc02fa1cd6a67 /src/common | |
| parent | 38842491bb55260c0cc7d7709abe5b0e73a0de61 (diff) | |
| parent | 8cf2c3b00b2f8188571e4bd9f0e66ffc5ae188a3 (diff) | |
Merge pull request #3359 from hathach/xfer-fifo
remove ep buffer for port with dedicated hw fifo
Diffstat (limited to 'src/common')
| -rw-r--r-- | src/common/tusb_common.h | 33 | ||||
| -rw-r--r-- | src/common/tusb_fifo.c | 608 | ||||
| -rw-r--r-- | src/common/tusb_fifo.h | 125 | ||||
| -rw-r--r-- | src/common/tusb_mcu.h | 10 | ||||
| -rw-r--r-- | src/common/tusb_private.h | 6 |
5 files changed, 302 insertions, 480 deletions
diff --git a/src/common/tusb_common.h b/src/common/tusb_common.h index f377d5272..b53fa5c02 100644 --- a/src/common/tusb_common.h +++ b/src/common/tusb_common.h @@ -329,6 +329,39 @@ TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16(void *mem, uint16_ #endif +// scatter read 4 bytes from two buffers. Parameter are not checked +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_scatter_read32(const uint8_t *buf1, uint8_t len1, const uint8_t *buf2, + uint8_t len2) { + uint32_t result = 0; + uint8_t shift = 0; + + for (uint8_t i = 0; i < len1; ++i) { + result |= ((uint32_t)buf1[i]) << shift; + shift += 8; + } + + for (uint8_t i = 0; i < len2; ++i) { + result |= ((uint32_t)buf2[i]) << shift; + shift += 8; + } + + return result; +} + +// scatter write 4 bytes to two buffers. Parameter are not checked +TU_ATTR_ALWAYS_INLINE static inline void tu_scatter_write32(uint32_t value, uint8_t *buf1, uint8_t len1, + uint8_t *buf2, uint8_t len2) { + for (uint8_t i = 0; i < len1; ++i) { + buf1[i] = (uint8_t)(value & 0xFF); + value >>= 8; + } + + for (uint8_t i = 0; i < len2; ++i) { + buf2[i] = (uint8_t)(value & 0xFF); + value >>= 8; + } +} + //--------------------------------------------------------------------+ // Descriptor helper //--------------------------------------------------------------------+ diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 5c9e586fb..27b97310a 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -38,35 +38,23 @@ #if OSAL_MUTEX_REQUIRED -TU_ATTR_ALWAYS_INLINE static inline void _ff_lock(osal_mutex_t mutex) { +TU_ATTR_ALWAYS_INLINE static inline void ff_lock(osal_mutex_t mutex) { if (mutex != NULL) { osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER); } } -TU_ATTR_ALWAYS_INLINE static inline void _ff_unlock(osal_mutex_t mutex) { +TU_ATTR_ALWAYS_INLINE static inline void ff_unlock(osal_mutex_t mutex) { if (mutex != NULL) { osal_mutex_unlock(mutex); } } #else + #define ff_lock(_mutex) + #define ff_unlock(_mutex) -#define _ff_lock(_mutex) -#define _ff_unlock(_mutex) - -#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 and others - */ -typedef enum { - TU_FIFO_COPY_INC, ///< Copy from/to an increasing source/destination address - default mode -#ifdef TUP_MEM_CONST_ADDR - 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 #endif -} tu_fifo_copy_mode_t; bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, uint16_t item_size, bool overwritable) { // Limit index space to 2*depth - this allows for a fast "modulo" calculation @@ -76,78 +64,67 @@ bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, uint16_t item_si return false; } - _ff_lock(f->mutex_wr); - _ff_lock(f->mutex_rd); + ff_lock(f->mutex_wr); + ff_lock(f->mutex_rd); f->buffer = (uint8_t *)buffer; f->depth = depth; - f->item_size = (uint16_t)(item_size & 0x7FFF); + f->item_size = (uint16_t)(item_size & 0x7FFFu); f->overwritable = overwritable; - f->rd_idx = 0; - f->wr_idx = 0; + f->rd_idx = 0u; + f->wr_idx = 0u; - _ff_unlock(f->mutex_wr); - _ff_unlock(f->mutex_rd); + ff_unlock(f->mutex_wr); + ff_unlock(f->mutex_rd); return true; } //--------------------------------------------------------------------+ // Pull & Push +// copy data to/from fifo without updating read/write pointers //--------------------------------------------------------------------+ - -#ifdef TUP_MEM_CONST_ADDR -// 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_synopsys.c -// TODO generalize with configurable 1 byte or 4 byte each read -static void _ff_push_const_addr(uint8_t *ff_buf, const void *app_buf, uint16_t len) { - const volatile uint32_t *reg_rx = (volatile const uint32_t *)app_buf; - +#ifdef CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32 +// Copy to fifo from fixed address buffer (usually a rx register) with TU_FIFO_FIXED_ADDR_RW32 mode +static void ff_push_fixed_addr_rw32(uint8_t *ff_buf, const volatile uint32_t *reg_rx, uint16_t len) { // Reading full available 32 bit words from const app address uint16_t full_words = len >> 2; while (full_words--) { - tu_unaligned_write32(ff_buf, *reg_rx); + const uint32_t tmp32 = *reg_rx; + tu_unaligned_write32(ff_buf, tmp32); ff_buf += 4; } // Read the remaining 1-3 bytes from const app address const uint8_t bytes_rem = len & 0x03; if (bytes_rem) { - uint32_t tmp32 = *reg_rx; + const uint32_t tmp32 = *reg_rx; 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 *app_buf, const uint8_t *ff_buf, uint16_t len) { - volatile uint32_t *reg_tx = (volatile uint32_t *)app_buf; - +// Copy from fifo to fixed address buffer (usually a tx register) with TU_FIFO_FIXED_ADDR_RW32 mode +static void ff_pull_fixed_addr_rw32(volatile uint32_t *reg_tx, const uint8_t *ff_buf, uint16_t len) { // Write full available 32 bit words to const address - uint16_t full_words = len >> 2; + uint16_t full_words = len >> 2u; while (full_words--) { *reg_tx = tu_unaligned_read32(ff_buf); - ff_buf += 4; + ff_buf += 4u; } - // Write the remaining 1-3 bytes into const address + // Write the remaining 1-3 bytes const uint8_t bytes_rem = len & 0x03; if (bytes_rem) { - uint32_t tmp32 = 0; + uint32_t tmp32 = 0u; memcpy(&tmp32, ff_buf, bytes_rem); - *reg_tx = tmp32; } } #endif -// send one item to fifo WITHOUT updating write pointer -static inline void _ff_push(tu_fifo_t *f, const void *app_buf, uint16_t rel) { - 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, const void *app_buf, uint16_t n, uint16_t wr_ptr, tu_fifo_copy_mode_t copy_mode) { +static void ff_push_n(const tu_fifo_t *f, const void *app_buf, uint16_t n, uint16_t wr_ptr, + tu_fifo_access_mode_t copy_mode) { const uint16_t lin_count = f->depth - wr_ptr; const uint16_t wrap_count = n - lin_count; @@ -158,67 +135,51 @@ static void _ff_push_n(tu_fifo_t *f, const void *app_buf, uint16_t n, uint16_t w uint8_t *ff_buf = f->buffer + (wr_ptr * f->item_size); switch (copy_mode) { - case TU_FIFO_COPY_INC: + case TU_FIFO_INC_ADDR_RW8: if (n <= lin_count) { // Linear only memcpy(ff_buf, app_buf, n * f->item_size); } else { // Wrap around - - // Write data to linear part of buffer - memcpy(ff_buf, app_buf, lin_bytes); - - // Write data wrapped around - // TU_ASSERT(nWrap_bytes <= f->depth, ); - memcpy(f->buffer, ((const uint8_t *)app_buf) + lin_bytes, wrap_bytes); + memcpy(ff_buf, app_buf, lin_bytes); // linear part + memcpy(f->buffer, ((const uint8_t *)app_buf) + lin_bytes, wrap_bytes); // wrapped part } break; -#ifdef TUP_MEM_CONST_ADDR - case TU_FIFO_COPY_CST_FULL_WORDS: - // Intended for hardware buffers from which it can be read word by word only +#ifdef CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32 + case TU_FIFO_FIXED_ADDR_RW32: { + const volatile uint32_t *reg_rx = (volatile const uint32_t *)app_buf; if (n <= lin_count) { // Linear only - _ff_push_const_addr(ff_buf, app_buf, n * f->item_size); + ff_push_fixed_addr_rw32(ff_buf, reg_rx, n * f->item_size); } else { - // Wrap around case + // Wrap around // Write full words to linear part of buffer - uint16_t nLin_4n_bytes = lin_bytes & 0xFFFC; - _ff_push_const_addr(ff_buf, app_buf, nLin_4n_bytes); - ff_buf += nLin_4n_bytes; + uint16_t lin_4n_bytes = lin_bytes & 0xFFFC; + ff_push_fixed_addr_rw32(ff_buf, reg_rx, lin_4n_bytes); + ff_buf += lin_4n_bytes; // There could be odd 1-3 bytes before the wrap-around boundary - uint8_t rem = lin_bytes & 0x03; + const uint8_t rem = lin_bytes & 0x03; if (rem > 0) { - const volatile uint32_t *rx_fifo = (volatile const uint32_t *)app_buf; + const uint8_t remrem = (uint8_t)tu_min16(wrap_bytes, 4 - rem); + const uint32_t tmp32 = *reg_rx; + tu_scatter_write32(tmp32, ff_buf, rem, f->buffer, remrem); - uint8_t remrem = (uint8_t)tu_min16(wrap_bytes, 4 - rem); wrap_bytes -= remrem; - - uint32_t tmp32 = *rx_fifo; - uint8_t *src_u8 = ((uint8_t *)&tmp32); - - // Write 1-3 bytes before wrapped boundary - while (rem--) { - *ff_buf++ = *src_u8++; - } - - // Read more bytes to beginning to complete a word - ff_buf = f->buffer; - while (remrem--) { - *ff_buf++ = *src_u8++; - } + ff_buf = f->buffer + remrem; // wrap around } else { ff_buf = f->buffer; // wrap around to beginning } // Write data wrapped part if (wrap_bytes > 0) { - _ff_push_const_addr(ff_buf, app_buf, wrap_bytes); + ff_push_fixed_addr_rw32(ff_buf, reg_rx, wrap_bytes); } } break; + } #endif default: @@ -226,13 +187,8 @@ static void _ff_push_n(tu_fifo_t *f, const void *app_buf, uint16_t n, uint16_t w } } -// get one item from fifo WITHOUT updating read pointer -static inline void _ff_pull(tu_fifo_t *f, void *app_buf, uint16_t rel) { - 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 rd_ptr, tu_fifo_copy_mode_t copy_mode) { +static void ff_pull_n(const tu_fifo_t *f, void *app_buf, uint16_t n, uint16_t rd_ptr, tu_fifo_access_mode_t copy_mode) { const uint16_t lin_count = f->depth - rd_ptr; const uint16_t wrap_count = n - lin_count; // only used if wrapped @@ -240,70 +196,56 @@ static void _ff_pull_n(tu_fifo_t *f, void *app_buf, uint16_t n, uint16_t rd_ptr, uint16_t wrap_bytes = wrap_count * f->item_size; // current buffer of fifo - uint8_t *ff_buf = f->buffer + (rd_ptr * f->item_size); + const uint8_t *ff_buf = f->buffer + (rd_ptr * f->item_size); switch (copy_mode) { - case TU_FIFO_COPY_INC: + case TU_FIFO_INC_ADDR_RW8: if (n <= lin_count) { // Linear only memcpy(app_buf, ff_buf, n * f->item_size); } else { // Wrap around - - // Read data from linear part of buffer - memcpy(app_buf, ff_buf, lin_bytes); - - // Read data wrapped part - memcpy((uint8_t *)app_buf + lin_bytes, f->buffer, wrap_bytes); + memcpy(app_buf, ff_buf, lin_bytes); // linear part + memcpy((uint8_t *)app_buf + lin_bytes, f->buffer, wrap_bytes); // wrapped part } break; -#ifdef TUP_MEM_CONST_ADDR - case TU_FIFO_COPY_CST_FULL_WORDS: +#ifdef CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32 + case TU_FIFO_FIXED_ADDR_RW32: { + volatile uint32_t *reg_tx = (volatile uint32_t *)app_buf; + if (n <= lin_count) { // Linear only - _ff_pull_const_addr(app_buf, ff_buf, n * f->item_size); + ff_pull_fixed_addr_rw32(reg_tx, ff_buf, n * f->item_size); } else { // Wrap around case - // Read full words from linear part of buffer + // Read full words from linear part uint16_t lin_4n_bytes = lin_bytes & 0xFFFC; - _ff_pull_const_addr(app_buf, ff_buf, lin_4n_bytes); + ff_pull_fixed_addr_rw32(reg_tx, ff_buf, lin_4n_bytes); ff_buf += lin_4n_bytes; // There could be odd 1-3 bytes before the wrap-around boundary - uint8_t rem = lin_bytes & 0x03; + const uint8_t rem = lin_bytes & 0x03; if (rem > 0) { - volatile uint32_t *reg_tx = (volatile uint32_t *)app_buf; + const uint8_t remrem = (uint8_t)tu_min16(wrap_bytes, 4 - rem); + const uint32_t scatter32 = tu_scatter_read32(ff_buf, rem, f->buffer, remrem); - uint8_t remrem = (uint8_t)tu_min16(wrap_bytes, 4 - rem); - wrap_bytes -= remrem; + *reg_tx = scatter32; - uint32_t tmp32 = 0; - uint8_t *dst_u8 = (uint8_t *)&tmp32; - - // Read 1-3 bytes before wrapped boundary - while (rem--) { - *dst_u8++ = *ff_buf++; - } - - // Read more bytes from beginning to complete a word - ff_buf = f->buffer; - while (remrem--) { - *dst_u8++ = *ff_buf++; - } - - *reg_tx = tmp32; + wrap_bytes -= remrem; + ff_buf = f->buffer + remrem; // wrap around } else { - ff_buf = f->buffer; // wrap around to beginning + ff_buf = f->buffer; // wrap around to beginning } // Read data wrapped part if (wrap_bytes > 0) { - _ff_pull_const_addr(app_buf, ff_buf, wrap_bytes); + ff_pull_fixed_addr_rw32(reg_tx, ff_buf, wrap_bytes); } } break; + } #endif default: @@ -312,32 +254,12 @@ static void _ff_pull_n(tu_fifo_t *f, void *app_buf, uint16_t n, uint16_t rd_ptr, } //--------------------------------------------------------------------+ -// Helper -//--------------------------------------------------------------------+ - -// return only the index difference and as such can be used to determine an overflow i.e overflowable count -TU_ATTR_ALWAYS_INLINE static inline uint16_t _ff_count(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx) { - // In case we have non-power of two depth we need a further modification - if (wr_idx >= rd_idx) { - return (uint16_t)(wr_idx - rd_idx); - } else { - return (uint16_t)(2 * depth - (rd_idx - wr_idx)); - } -} - -// return remaining slot in fifo -TU_ATTR_ALWAYS_INLINE static inline uint16_t _ff_remaining(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx) { - const uint16_t count = _ff_count(depth, wr_idx, rd_idx); - return (depth > count) ? (depth - count) : 0; -} - -//--------------------------------------------------------------------+ // Index Helper //--------------------------------------------------------------------+ // Advance an absolute index // "absolute" index is only in the range of [0..2*depth) -static uint16_t advance_index(uint16_t depth, uint16_t idx, uint16_t offset) { +TU_ATTR_ALWAYS_INLINE static inline uint16_t advance_index(uint16_t depth, uint16_t idx, uint16_t offset) { // We limit the index space of p such that a correct wrap around happens // Check for a wrap around or if we are in unused index space - This has to be checked first!! // We are exploiting the wrap around to the correct index @@ -350,23 +272,7 @@ static uint16_t advance_index(uint16_t depth, uint16_t idx, uint16_t offset) { return new_idx; } -#if 0 // not used but -// Backward an absolute index -static uint16_t backward_index(uint16_t depth, uint16_t idx, uint16_t offset) { - // We limit the index space of p such that a correct wrap around happens - // Check for a wrap around or if we are in unused index space - This has to be checked first!! - // We are exploiting the wrap around to the correct index - uint16_t new_idx = (uint16_t) (idx - offset); - if ( (idx < new_idx) || (new_idx >= 2*depth) ) { - uint16_t const non_used_index_space = (uint16_t) (UINT16_MAX - (2*depth-1)); - new_idx = (uint16_t) (new_idx - non_used_index_space); - } - - return new_idx; -} -#endif - -// index to pointer, simply an modulo with minus. +// index to pointer (0..depth-1), simply a modulo with minus. TU_ATTR_ALWAYS_INLINE static inline uint16_t idx2ptr(uint16_t depth, uint16_t idx) { // Only run at most 3 times since index is limit in the range of [0..2*depth) while (idx >= depth) { @@ -376,9 +282,8 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t idx2ptr(uint16_t depth, uint16_t id } // Works on local copies of w -// When an overwritable fifo is overflowed, rd_idx will be re-index so that it forms -// an full fifo i.e _ff_count() = depth -TU_ATTR_ALWAYS_INLINE static inline uint16_t _ff_correct_read_index(tu_fifo_t *f, uint16_t wr_idx) { +// When an overwritable fifo is overflowed, rd_idx will be re-index so that it forms a full fifo +TU_ATTR_ALWAYS_INLINE static inline uint16_t correct_read_index(tu_fifo_t *f, uint16_t wr_idx) { uint16_t rd_idx; if (wr_idx >= f->depth) { rd_idx = wr_idx - f->depth; @@ -387,91 +292,87 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t _ff_correct_read_index(tu_fifo_t *f } f->rd_idx = rd_idx; - return rd_idx; } -// Works on local copies of w and r -// Must be protected by mutexes since in case of an overflow read pointer gets modified -static bool _tu_fifo_peek(tu_fifo_t *f, void *p_buffer, uint16_t wr_idx, uint16_t rd_idx) { - uint16_t cnt = _ff_count(f->depth, wr_idx, rd_idx); - - // nothing to peek - if (cnt == 0) { - return false; +// peek() using local write/read index. Be careful, caller must not lock mutex, since this Will also try to lock mutex +// in case of overflowed to correct read index +static bool ff_peek_local(tu_fifo_t *f, void *buf, uint16_t wr_idx, uint16_t rd_idx) { + const uint16_t ovf_count = tu_ff_overflow_count(f->depth, wr_idx, rd_idx); + if (ovf_count == 0) { + return false; // nothing to peek } - // Check overflow and correct if required - if (cnt > f->depth) { - rd_idx = _ff_correct_read_index(f, wr_idx); + // Correct read index if overflow + if (ovf_count > f->depth) { + ff_lock(f->mutex_rd); + rd_idx = correct_read_index(f, wr_idx); + ff_unlock(f->mutex_rd); } - uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); - - // Peek data - _ff_pull(f, p_buffer, rd_ptr); + const uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); + memcpy(buf, f->buffer + (rd_ptr * f->item_size), f->item_size); return true; } +//--------------------------------------------------------------------+ +// Application API +//--------------------------------------------------------------------+ + // 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_n( - tu_fifo_t *f, void *p_buffer, uint16_t n, uint16_t wr_idx, uint16_t rd_idx, tu_fifo_copy_mode_t copy_mode) { - uint16_t cnt = _ff_count(f->depth, wr_idx, rd_idx); +uint16_t tu_fifo_peek_n_access_mode(tu_fifo_t *f, void *p_buffer, uint16_t n, uint16_t wr_idx, uint16_t rd_idx, + tu_fifo_access_mode_t access_mode) { + uint16_t ovf_cnt = tu_ff_overflow_count(f->depth, wr_idx, rd_idx); - // nothing to peek - if (cnt == 0) { - return 0; + if (ovf_cnt == 0) { + return 0; // nothing to peek } // Check overflow and correct if required - if (cnt > f->depth) { - rd_idx = _ff_correct_read_index(f, wr_idx); - cnt = f->depth; + if (ovf_cnt > f->depth) { + rd_idx = correct_read_index(f, wr_idx); + ovf_cnt = f->depth; } - // Check if we can read something at and after offset - if too less is available we read what remains - if (cnt < n) { - n = cnt; + if (ovf_cnt < n) { + n = ovf_cnt; // limit to available count } - uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); - - // Peek data - _ff_pull_n(f, p_buffer, n, rd_ptr, copy_mode); + const uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); + ff_pull_n(f, p_buffer, n, rd_ptr, access_mode); return n; } -static uint16_t _tu_fifo_write_n(tu_fifo_t *f, const void *data, uint16_t n, tu_fifo_copy_mode_t copy_mode) { +uint16_t tu_fifo_write_n_access_mode(tu_fifo_t *f, const void *data, uint16_t n, tu_fifo_access_mode_t access_mode) { if (n == 0) { return 0; } - _ff_lock(f->mutex_wr); + ff_lock(f->mutex_wr); uint16_t wr_idx = f->wr_idx; uint16_t rd_idx = f->rd_idx; const uint8_t *buf8 = (const uint8_t *)data; - TU_LOG( - TU_FIFO_DBG, "rd = %3u, wr = %3u, count = %3u, remain = %3u, n = %3u: ", rd_idx, wr_idx, - _ff_count(f->depth, wr_idx, rd_idx), _ff_remaining(f->depth, wr_idx, rd_idx), n); + TU_LOG(TU_FIFO_DBG, "rd = %3u, wr = %3u, count = %3u, remain = %3u, n = %3u: ", rd_idx, wr_idx, + tu_ff_overflow_count(f->depth, wr_idx, rd_idx), tu_ff_remaining_local(f->depth, wr_idx, rd_idx), n); if (!f->overwritable) { // limit up to full - const uint16_t remain = _ff_remaining(f->depth, wr_idx, rd_idx); + const uint16_t remain = tu_ff_remaining_local(f->depth, wr_idx, rd_idx); n = tu_min16(n, remain); } else { // In over-writable mode, fifo_write() is allowed even when fifo is full. In such case, - // oldest data in fifo i.e at read pointer data will be overwritten - // Note: we can modify read buffer contents but we must not modify the read index itself within a write function! - // Since it would end up in a race condition with read functions! + // oldest data in fifo i.e. at read pointer data will be overwritten + // Note: we can modify read buffer contents however we must not modify the read index itself within a write + // function! Since it would end up in a race condition with read functions! if (n >= f->depth) { // Only copy last part - if (copy_mode == TU_FIFO_COPY_INC) { + if (access_mode == TU_FIFO_INC_ADDR_RW8) { buf8 += (n - f->depth) * f->item_size; } else { // TODO should read from hw fifo to discard data, however reading an odd number could @@ -483,7 +384,7 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t *f, const void *data, uint16_t n, tu_ // We start writing at the read pointer's position since we fill the whole buffer wr_idx = rd_idx; } else { - const uint16_t overflowable_count = _ff_count(f->depth, wr_idx, rd_idx); + const uint16_t overflowable_count = tu_ff_overflow_count(f->depth, wr_idx, rd_idx); if (overflowable_count + n >= 2 * f->depth) { // Double overflowed // Index is bigger than the allowed range [0,2*depth) @@ -504,121 +405,36 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t *f, const void *data, uint16_t n, tu_ } if (n) { - uint16_t wr_ptr = idx2ptr(f->depth, wr_idx); + const uint16_t wr_ptr = idx2ptr(f->depth, wr_idx); TU_LOG(TU_FIFO_DBG, "actual_n = %u, wr_ptr = %u", n, wr_ptr); - _ff_push_n(f, buf8, n, wr_ptr, copy_mode); + ff_push_n(f, buf8, n, wr_ptr, access_mode); f->wr_idx = advance_index(f->depth, wr_idx, n); TU_LOG(TU_FIFO_DBG, "\tnew_wr = %u\r\n", f->wr_idx); } - _ff_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) { - _ff_lock(f->mutex_rd); +uint16_t tu_fifo_read_n_access_mode(tu_fifo_t *f, void *buffer, uint16_t n, tu_fifo_access_mode_t access_mode) { + ff_lock(f->mutex_rd); - // Peek the data - // f->rd_idx might get modified in case of an overflow so we can not use a local variable - n = _tu_fifo_peek_n(f, buffer, n, f->wr_idx, f->rd_idx, copy_mode); - - // Advance read pointer + // Peek the data: f->rd_idx might get modified in case of an overflow so we can not use a local variable + n = tu_fifo_peek_n_access_mode(f, buffer, n, f->wr_idx, f->rd_idx, access_mode); f->rd_idx = advance_index(f->depth, f->rd_idx, n); - _ff_unlock(f->mutex_rd); + ff_unlock(f->mutex_rd); return n; } -//--------------------------------------------------------------------+ -// Application API -//--------------------------------------------------------------------+ - -/******************************************************************************/ -/*! - @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. 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 - - @returns Number of items in FIFO - */ -/******************************************************************************/ -uint16_t tu_fifo_count(const tu_fifo_t *f) { - return tu_min16(_ff_count(f->depth, f->wr_idx, f->rd_idx), f->depth); -} - -/******************************************************************************/ -/*! - @brief Check if FIFO is full. - - As this function only reads the read and write pointers once, this function is - reentrant and thus thread and ISR save without any mutexes. - - @param[in] f - Pointer to the FIFO buffer to manipulate - - @returns Number of items in FIFO - */ -/******************************************************************************/ -bool tu_fifo_full(const tu_fifo_t *f) { - return _ff_count(f->depth, f->wr_idx, f->rd_idx) >= f->depth; -} - -/******************************************************************************/ -/*! - @brief Get remaining space 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. - - @param[in] f - Pointer to the FIFO buffer to manipulate - - @returns Number of items in FIFO - */ -/******************************************************************************/ -uint16_t tu_fifo_remaining(const tu_fifo_t *f) { - return _ff_remaining(f->depth, f->wr_idx, f->rd_idx); -} - -/******************************************************************************/ -/*! - @brief Check if overflow happened. - - 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 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 - that latest items are read. - If required (e.g. for DMA use) you can also correct the read pointer by - tu_fifo_correct_read_pointer(). - - @param[in] f - Pointer to the FIFO buffer to manipulate - - @returns True if overflow happened - */ -/******************************************************************************/ -bool tu_fifo_overflowed(const tu_fifo_t *f) { - return _ff_count(f->depth, f->wr_idx, f->rd_idx) > f->depth; -} - // Only use in case tu_fifo_overflow() returned true! void tu_fifo_correct_read_pointer(tu_fifo_t *f) { - _ff_lock(f->mutex_rd); - _ff_correct_read_index(f, f->wr_idx); - _ff_unlock(f->mutex_rd); + ff_lock(f->mutex_rd); + correct_read_index(f, f->wr_idx); + ff_unlock(f->mutex_rd); } /******************************************************************************/ @@ -638,64 +454,20 @@ void tu_fifo_correct_read_pointer(tu_fifo_t *f) { */ /******************************************************************************/ bool tu_fifo_read(tu_fifo_t *f, void *buffer) { - _ff_lock(f->mutex_rd); - // Peek the data // f->rd_idx might get modified in case of an overflow so we can not use a local variable - bool ret = _tu_fifo_peek(f, buffer, f->wr_idx, f->rd_idx); - - // Advance pointer - f->rd_idx = advance_index(f->depth, f->rd_idx, ret); + const bool ret = ff_peek_local(f, buffer, f->wr_idx, f->rd_idx); + if (ret) { + ff_lock(f->mutex_rd); + f->rd_idx = advance_index(f->depth, f->rd_idx, 1); + ff_unlock(f->mutex_rd); + } - _ff_unlock(f->mutex_rd); return ret; } /******************************************************************************/ /*! - @brief This function will read n elements from the array index specified by - the read pointer and increment the read index. - This function checks for an overflow and corrects read pointer if required. - - @param[in] f - Pointer to the FIFO buffer to manipulate - @param[in] buffer - The pointer to data location - @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 n) { - return _tu_fifo_read_n(f, buffer, n, TU_FIFO_COPY_INC); -} - -#ifdef TUP_MEM_CONST_ADDR -/******************************************************************************/ -/*! - @brief This function will read n elements from the array index specified by - the read pointer and increment the read index. - This function checks for an overflow and corrects read pointer if required. - The dest address will not be incremented which is useful for writing to registers. - - @param[in] f - Pointer to the FIFO buffer to manipulate - @param[in] buffer - The pointer to data location - @param[in] n - Number of element that buffer can afford - - @returns number of items read from the FIFO - */ -/******************************************************************************/ -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_FULL_WORDS); -} -#endif - -/******************************************************************************/ -/*! @brief Read one item without removing it from the FIFO. This function checks for an overflow and corrects read pointer if required. @@ -708,10 +480,7 @@ uint16_t tu_fifo_read_n_const_addr_full_words(tu_fifo_t *f, void *buffer, uint16 */ /******************************************************************************/ bool tu_fifo_peek(tu_fifo_t *f, void *p_buffer) { - _ff_lock(f->mutex_rd); - bool ret = _tu_fifo_peek(f, p_buffer, f->wr_idx, f->rd_idx); - _ff_unlock(f->mutex_rd); - return ret; + return ff_peek_local(f, p_buffer, f->wr_idx, f->rd_idx); } /******************************************************************************/ @@ -730,9 +499,9 @@ bool tu_fifo_peek(tu_fifo_t *f, void *p_buffer) { */ /******************************************************************************/ uint16_t tu_fifo_peek_n(tu_fifo_t *f, void *p_buffer, uint16_t n) { - _ff_lock(f->mutex_rd); - uint16_t ret = _tu_fifo_peek_n(f, p_buffer, n, f->wr_idx, f->rd_idx, TU_FIFO_COPY_INC); - _ff_unlock(f->mutex_rd); + ff_lock(f->mutex_rd); + const uint16_t ret = tu_fifo_peek_n_access_mode(f, p_buffer, n, f->wr_idx, f->rd_idx, TU_FIFO_INC_ADDR_RW8); + ff_unlock(f->mutex_rd); return ret; } @@ -753,66 +522,27 @@ uint16_t tu_fifo_peek_n(tu_fifo_t *f, void *p_buffer, uint16_t n) { */ /******************************************************************************/ bool tu_fifo_write(tu_fifo_t *f, const void *data) { - _ff_lock(f->mutex_wr); + bool ret; + ff_lock(f->mutex_wr); - bool ret; const uint16_t wr_idx = f->wr_idx; if (tu_fifo_full(f) && !f->overwritable) { ret = false; } else { - uint16_t wr_ptr = idx2ptr(f->depth, wr_idx); - _ff_push(f, data, wr_ptr); + const uint16_t wr_ptr = idx2ptr(f->depth, wr_idx); + memcpy(f->buffer + (wr_ptr * f->item_size), data, f->item_size); f->wr_idx = advance_index(f->depth, wr_idx, 1); ret = true; } - _ff_unlock(f->mutex_wr); + ff_unlock(f->mutex_wr); return ret; } /******************************************************************************/ /*! - @brief This function will write n elements into the array index specified by - the write pointer and increment the write index. - - @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(tu_fifo_t *f, const void *data, uint16_t n) { - return _tu_fifo_write_n(f, data, n, TU_FIFO_COPY_INC); -} - -#ifdef TUP_MEM_CONST_ADDR -/******************************************************************************/ -/*! - @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. - - @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_full_words(tu_fifo_t *f, const void *data, uint16_t n) { - return _tu_fifo_write_n(f, data, n, TU_FIFO_COPY_CST_FULL_WORDS); -} -#endif - -/******************************************************************************/ -/*! @brief Clear the fifo read and write pointers @param[in] f @@ -820,14 +550,14 @@ uint16_t tu_fifo_write_n_const_addr_full_words(tu_fifo_t *f, const void *data, u */ /******************************************************************************/ bool tu_fifo_clear(tu_fifo_t *f) { - _ff_lock(f->mutex_wr); - _ff_lock(f->mutex_rd); + ff_lock(f->mutex_wr); + ff_lock(f->mutex_rd); f->rd_idx = 0; f->wr_idx = 0; - _ff_unlock(f->mutex_wr); - _ff_unlock(f->mutex_rd); + ff_unlock(f->mutex_wr); + ff_unlock(f->mutex_rd); return true; } @@ -846,13 +576,13 @@ bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) { return true; } - _ff_lock(f->mutex_wr); - _ff_lock(f->mutex_rd); + ff_lock(f->mutex_wr); + ff_lock(f->mutex_rd); f->overwritable = overwritable; - _ff_unlock(f->mutex_wr); - _ff_unlock(f->mutex_rd); + ff_unlock(f->mutex_wr); + ff_unlock(f->mutex_rd); return true; } @@ -917,23 +647,23 @@ void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) { uint16_t wr_idx = f->wr_idx; uint16_t rd_idx = f->rd_idx; - uint16_t cnt = _ff_count(f->depth, wr_idx, rd_idx); + uint16_t cnt = tu_ff_overflow_count(f->depth, wr_idx, rd_idx); // Check overflow and correct if required - may happen in case a DMA wrote too fast if (cnt > f->depth) { - _ff_lock(f->mutex_rd); - rd_idx = _ff_correct_read_index(f, wr_idx); - _ff_unlock(f->mutex_rd); + ff_lock(f->mutex_rd); + rd_idx = correct_read_index(f, wr_idx); + ff_unlock(f->mutex_rd); cnt = f->depth; } // Check if fifo is empty if (cnt == 0) { - info->len_lin = 0; - info->len_wrap = 0; - info->ptr_lin = NULL; - info->ptr_wrap = NULL; + info->linear.len = 0; + info->wrapped.len = 0; + info->linear.ptr = NULL; + info->wrapped.ptr = NULL; return; } @@ -942,20 +672,20 @@ void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) { uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); // Copy pointer to buffer to start reading from - info->ptr_lin = &f->buffer[rd_ptr]; + info->linear.ptr = &f->buffer[rd_ptr]; // Check if there is a wrap around necessary if (wr_ptr > rd_ptr) { // Non wrapping case - info->len_lin = cnt; + info->linear.len = cnt; - info->len_wrap = 0; - info->ptr_wrap = NULL; + info->wrapped.len = 0; + info->wrapped.ptr = NULL; } else { - info->len_lin = f->depth - rd_ptr; // Also the case if FIFO was full + info->linear.len = f->depth - rd_ptr; // Also the case if FIFO was full - info->len_wrap = cnt - info->len_lin; - info->ptr_wrap = f->buffer; + info->wrapped.len = cnt - info->linear.len; + info->wrapped.ptr = f->buffer; } } @@ -977,13 +707,13 @@ void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) { void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) { uint16_t wr_idx = f->wr_idx; uint16_t rd_idx = f->rd_idx; - uint16_t remain = _ff_remaining(f->depth, wr_idx, rd_idx); + uint16_t remain = tu_ff_remaining_local(f->depth, wr_idx, rd_idx); if (remain == 0) { - info->len_lin = 0; - info->len_wrap = 0; - info->ptr_lin = NULL; - info->ptr_wrap = NULL; + info->linear.len = 0; + info->wrapped.len = 0; + info->linear.ptr = NULL; + info->wrapped.ptr = NULL; return; } @@ -992,16 +722,16 @@ void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) { uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); // Copy pointer to buffer to start writing to - info->ptr_lin = &f->buffer[wr_ptr]; + info->linear.ptr = &f->buffer[wr_ptr]; if (wr_ptr < rd_ptr) { // Non wrapping case - info->len_lin = rd_ptr - wr_ptr; - info->len_wrap = 0; - info->ptr_wrap = NULL; + info->linear.len = rd_ptr - wr_ptr; + info->wrapped.len = 0; + info->wrapped.ptr = NULL; } else { - info->len_lin = f->depth - wr_ptr; - info->len_wrap = remain - info->len_lin; // Remaining length - n already was limited to remain or FIFO depth - info->ptr_wrap = f->buffer; // Always start of buffer + info->linear.len = f->depth - wr_ptr; + info->wrapped.len = remain - info->linear.len; // Remaining length - n already was limited to remain or FIFO depth + info->wrapped.ptr = f->buffer; // Always start of buffer } } diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h index 2fb4f37d4..4d8448c44 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -48,8 +48,13 @@ extern "C" { // for OS None, we don't get preempted #define CFG_FIFO_MUTEX OSAL_MUTEX_REQUIRED -/* Write/Read index is always in the range of: - * 0 .. 2*depth-1 +#if CFG_TUD_EDPT_DEDICATED_HWFIFO || CFG_TUH_EDPT_DEDICATED_HWFIFO + #define CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32 +#endif + +/* Write/Read "pointer" is in the range of: 0 .. depth - 1, and is used to get the fifo data. + * Write/Read "index" is always in the range of: 0 .. 2*depth-1 + * * The extra window allow us to determine the fifo state of empty or full with only 2 indices * Following are examples with depth = 3 * @@ -123,10 +128,10 @@ typedef struct { } tu_fifo_t; typedef struct { - uint16_t len_lin ; ///< linear length in item size - uint16_t len_wrap ; ///< wrapped length in item size - void * ptr_lin ; ///< linear part start pointer - void * ptr_wrap ; ///< wrapped part start pointer + struct { + uint16_t len; // length + uint8_t *ptr; // buffer pointer + } linear, wrapped; } tu_fifo_buffer_info_t; #define TU_FIFO_INIT(_buffer, _depth, _type, _overwritable) \ @@ -141,6 +146,16 @@ typedef struct { uint8_t _name##_buf[_depth*sizeof(_type)]; \ tu_fifo_t _name = TU_FIFO_INIT(_name##_buf, _depth, _type, _overwritable) +// 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 { + TU_FIFO_INC_ADDR_RW8, // increased address read/write by bytes - normal (default) mode + TU_FIFO_FIXED_ADDR_RW32, // fixed address read/write by 4 bytes (word). Used for STM32 access into USB hardware FIFO +} tu_fifo_access_mode_t; + +//--------------------------------------------------------------------+ +// Setup API +//--------------------------------------------------------------------+ bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable); 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); @@ -155,48 +170,98 @@ void tu_fifo_config_mutex(tu_fifo_t *f, osal_mutex_t wr_mutex, osal_mutex_t rd_m #define tu_fifo_config_mutex(_f, _wr_mutex, _rd_mutex) #endif -bool tu_fifo_write(tu_fifo_t *f, void const *data); -uint16_t tu_fifo_write_n(tu_fifo_t *f, const void *data, uint16_t n); - -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); - -#ifdef TUP_MEM_CONST_ADDR -uint16_t tu_fifo_write_n_const_addr_full_words(tu_fifo_t *f, const void *data, uint16_t n); -uint16_t tu_fifo_read_n_const_addr_full_words(tu_fifo_t *f, void *buffer, uint16_t n); -#endif - +//--------------------------------------------------------------------+ +// Peek API +// peek() will correct/re-index read pointer in case of an overflowed fifo to form a full fifo +//--------------------------------------------------------------------+ +uint16_t tu_fifo_peek_n_access_mode(tu_fifo_t *f, void *p_buffer, uint16_t n, uint16_t wr_idx, uint16_t rd_idx, + tu_fifo_access_mode_t access_mode); bool tu_fifo_peek(tu_fifo_t *f, void *p_buffer); uint16_t tu_fifo_peek_n(tu_fifo_t *f, void *p_buffer, uint16_t n); -uint16_t tu_fifo_count(const tu_fifo_t *f); -uint16_t tu_fifo_remaining(const tu_fifo_t *f); -bool tu_fifo_full(const tu_fifo_t *f); -bool tu_fifo_overflowed(const tu_fifo_t *f); - -TU_ATTR_ALWAYS_INLINE static inline bool tu_fifo_empty(const tu_fifo_t *f) { - uint16_t wr_idx = f->wr_idx; - uint16_t rd_idx = f->rd_idx; - return wr_idx == rd_idx; +//--------------------------------------------------------------------+ +// Read API +// peek() + advance read index +//--------------------------------------------------------------------+ +uint16_t tu_fifo_read_n_access_mode(tu_fifo_t *f, void *buffer, uint16_t n, tu_fifo_access_mode_t access_mode); +bool tu_fifo_read(tu_fifo_t *f, void *buffer); +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_fifo_read_n(tu_fifo_t *f, void *buffer, uint16_t n) { + return tu_fifo_read_n_access_mode(f, buffer, n, TU_FIFO_INC_ADDR_RW8); } -TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_fifo_depth(const tu_fifo_t *f) { - return f->depth; +//--------------------------------------------------------------------+ +// Write API +//--------------------------------------------------------------------+ +uint16_t tu_fifo_write_n_access_mode(tu_fifo_t *f, const void *data, uint16_t n, tu_fifo_access_mode_t access_mode); +bool tu_fifo_write(tu_fifo_t *f, const void *data); +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_fifo_write_n(tu_fifo_t *f, const void *data, uint16_t n) { + return tu_fifo_write_n_access_mode(f, data, n, TU_FIFO_INC_ADDR_RW8); } +//--------------------------------------------------------------------+ +// Index API +//--------------------------------------------------------------------+ void tu_fifo_correct_read_pointer(tu_fifo_t *f); // Pointer modifications intended to be used in combinations with DMAs. // USE WITH CARE - NO SAFETY CHECKS CONDUCTED HERE! NOT MUTEX PROTECTED! void tu_fifo_advance_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_advance_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. These functions deliver a pointer to start // reading/writing from/to and a valid linear length along which no wrap occurs. -void tu_fifo_get_read_info (tu_fifo_t *f, tu_fifo_buffer_info_t *info); +void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info); void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info); +//--------------------------------------------------------------------+ +// Internal Helper Local +// work on local copies of read/write indices in order to only access them once for re-entrancy +//--------------------------------------------------------------------+ +// return overflowable count (index difference), which can be used to determine both fifo count and an overflow state +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_ff_overflow_count(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx) { + if (wr_idx >= rd_idx) { + return (uint16_t)(wr_idx - rd_idx); + } else { + return (uint16_t)(2 * depth - (rd_idx - wr_idx)); + } +} + +// return remaining slot in fifo +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_ff_remaining_local(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx) { + const uint16_t ovf_count = tu_ff_overflow_count(depth, wr_idx, rd_idx); + return (depth > ovf_count) ? (depth - ovf_count) : 0; +} + +//--------------------------------------------------------------------+ +// State API +// Following functions are reentrant since they only access read/write indices once, therefore can be used in thread and +// ISRs context without the need of mutexes +//--------------------------------------------------------------------+ +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_fifo_depth(const tu_fifo_t *f) { + return f->depth; +} + +TU_ATTR_ALWAYS_INLINE static inline bool tu_fifo_empty(const tu_fifo_t *f) { + const uint16_t wr_idx = f->wr_idx; + const uint16_t rd_idx = f->rd_idx; + return wr_idx == rd_idx; +} + +// return number of items in fifo, capped to fifo's depth +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_fifo_count(const tu_fifo_t *f) { + return tu_min16(tu_ff_overflow_count(f->depth, f->wr_idx, f->rd_idx), f->depth); +} + +// check if fifo is full +TU_ATTR_ALWAYS_INLINE static inline bool tu_fifo_full(const tu_fifo_t *f) { + return tu_ff_overflow_count(f->depth, f->wr_idx, f->rd_idx) >= f->depth; +} + +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_fifo_remaining(const tu_fifo_t *f) { + return tu_ff_remaining_local(f->depth, f->wr_idx, f->rd_idx); +} + #ifdef __cplusplus } #endif diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index 002cd3a0e..1e773bf96 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -24,8 +24,7 @@ * This file is part of the TinyUSB stack. */ -#ifndef TUSB_MCU_H_ -#define TUSB_MCU_H_ +#pragma once //--------------------------------------------------------------------+ // Port/Platform Specific @@ -524,6 +523,7 @@ //--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_F1C100S) #define TUP_DCD_ENDPOINT_MAX 4 + #define TUP_DCD_EDPT_CLOSE_API //--------------------------------------------------------------------+ // WCH @@ -697,9 +697,3 @@ #ifndef TUP_DCD_EDPT_CLOSE_API #define TUP_DCD_EDPT_ISO_ALLOC #endif - -#if defined(TUP_USBIP_DWC2) // && CFG_TUD_DWC2_DMA_ENABLE == 0 - #define TUP_MEM_CONST_ADDR -#endif - -#endif diff --git a/src/common/tusb_private.h b/src/common/tusb_private.h index be1264a71..48fd1d6d2 100644 --- a/src/common/tusb_private.h +++ b/src/common/tusb_private.h @@ -60,7 +60,7 @@ typedef struct { uint8_t ep_addr; uint16_t ep_bufsize; - uint8_t* ep_buf; // TODO xfer_fifo can skip this buffer + uint8_t *ep_buf; // set to NULL to use xfer_fifo when CFG_TUD_EDPT_DEDICATED_HWFIFO = 1 tu_fifo_t ff; // mutex: read if rx, otherwise write @@ -98,7 +98,7 @@ bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool is_host, bool is_tx, bool ove // Deinit an endpoint stream bool tu_edpt_stream_deinit(tu_edpt_stream_t* s); -// Open an stream for an endpoint +// Open an endpoint stream TU_ATTR_ALWAYS_INLINE static inline void tu_edpt_stream_open(tu_edpt_stream_t* s, tusb_desc_endpoint_t const *desc_ep) { s->ep_addr = desc_ep->bEndpointAddress; s->is_mps512 = tu_edpt_packet_size(desc_ep) == 512; @@ -150,7 +150,7 @@ uint32_t tu_edpt_stream_read_xfer(uint8_t hwid, tu_edpt_stream_t* s); // Complete read transfer by writing EP -> FIFO. Must be called in the transfer complete callback TU_ATTR_ALWAYS_INLINE static inline void tu_edpt_stream_read_xfer_complete(tu_edpt_stream_t* s, uint32_t xferred_bytes) { - if (0u != tu_fifo_depth(&s->ff)) { + if (0u != tu_fifo_depth(&s->ff) && s->ep_buf != NULL) { tu_fifo_write_n(&s->ff, s->ep_buf, (uint16_t) xferred_bytes); } } |
