From 0a9e05f47adca971eb4af8b08adf0debbc6b83db Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 16 Dec 2025 00:19:13 +0700 Subject: [PATCH] make fifo access mode fixed addr work with 16 bit also --- src/common/tusb_fifo.c | 106 +++++++++++++++++++--------------- src/common/tusb_fifo.h | 19 +++++- src/osal/osal_none.h | 2 +- test/unit-test/CMakeLists.txt | 2 +- test/unit-test/project.yml | 2 +- 5 files changed, 80 insertions(+), 51 deletions(-) diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index e97b6ccce..450c31f57 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -114,40 +114,54 @@ void tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) { // Pull & Push // copy data to/from fifo without updating read/write pointers //--------------------------------------------------------------------+ -#ifdef CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32 +#if CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_WIDTH + #if CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_WIDTH == 32 + #define fixed_unaligned_write tu_unaligned_write32 + #define fixed_unaligned_read tu_unaligned_read32 +typedef uint32_t fixed_access_item_t; + #elif CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_WIDTH == 16 + #define fixed_unaligned_write tu_unaligned_write16 + #define fixed_unaligned_read tu_unaligned_read16 +typedef uint16_t fixed_access_item_t; + #endif + +enum { + FIXED_ACCESS_REMAINDER_MASK = sizeof(fixed_access_item_t) - 1u +}; + // 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--) { - const uint32_t tmp32 = *reg_rx; - tu_unaligned_write32(ff_buf, tmp32); - ff_buf += 4; +static void ff_push_fixed_addr(uint8_t *ff_buf, const volatile fixed_access_item_t *reg_rx, uint16_t len) { + // Reading full available 16/32-bit data from const app address + uint16_t n_items = len / sizeof(fixed_access_item_t); + while (n_items--) { + const fixed_access_item_t tmp = *reg_rx; + fixed_unaligned_write(ff_buf, tmp); + ff_buf += sizeof(fixed_access_item_t); } - // Read the remaining 1-3 bytes from const app address - const uint8_t bytes_rem = len & 0x03; + // Read the remaining 1 byte (16bit) or 1-3 bytes (32bit) from const app address + const uint8_t bytes_rem = len & FIXED_ACCESS_REMAINDER_MASK; if (bytes_rem) { - const uint32_t tmp32 = *reg_rx; - memcpy(ff_buf, &tmp32, bytes_rem); + const fixed_access_item_t tmp = *reg_rx; + memcpy(ff_buf, &tmp, bytes_rem); } } // 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) { +static void ff_pull_fixed_addr(volatile fixed_access_item_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 >> 2u; - while (full_words--) { - *reg_tx = tu_unaligned_read32(ff_buf); - ff_buf += 4u; + uint16_t n_itmes = len / sizeof(fixed_access_item_t); + while (n_itmes--) { + *reg_tx = fixed_unaligned_read(ff_buf); + ff_buf += sizeof(fixed_access_item_t); } - // Write the remaining 1-3 bytes - const uint8_t bytes_rem = len & 0x03; + // Write the remaining 1 byte (16bit) or 1-3 bytes (32bit) + const uint8_t bytes_rem = len & FIXED_ACCESS_REMAINDER_MASK; if (bytes_rem) { - uint32_t tmp32 = 0u; - memcpy(&tmp32, ff_buf, bytes_rem); - *reg_tx = tmp32; + fixed_access_item_t tmp = 0u; + memcpy(&tmp, ff_buf, bytes_rem); + *reg_tx = tmp; } } #endif @@ -176,26 +190,26 @@ static void ff_push_n(const tu_fifo_t *f, const void *app_buf, uint16_t n, uint1 } break; -#ifdef CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32 +#if CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_WIDTH case TU_FIFO_FIXED_ADDR_RW32: { - const volatile uint32_t *reg_rx = (volatile const uint32_t *)app_buf; + const volatile fixed_access_item_t *reg_rx = (volatile const fixed_access_item_t *)app_buf; if (n <= lin_count) { // Linear only - ff_push_fixed_addr_rw32(ff_buf, reg_rx, n * f->item_size); + ff_push_fixed_addr(ff_buf, reg_rx, n * f->item_size); } else { // Wrap around // Write full words to linear part of buffer - 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; + uint16_t lin_nitems_bytes = lin_bytes & ~FIXED_ACCESS_REMAINDER_MASK; + ff_push_fixed_addr(ff_buf, reg_rx, lin_nitems_bytes); + ff_buf += lin_nitems_bytes; - // There could be odd 1-3 bytes before the wrap-around boundary - const uint8_t rem = lin_bytes & 0x03; + // There could be odd 1 byte (16bit) or 1-3 bytes (32bit) before the wrap-around boundary + const uint8_t rem = lin_bytes & FIXED_ACCESS_REMAINDER_MASK; if (rem > 0) { - 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); + const uint8_t remrem = (uint8_t)tu_min16(wrap_bytes, sizeof(fixed_access_item_t) - rem); + const fixed_access_item_t tmp = *reg_rx; + tu_scatter_write32(tmp, ff_buf, rem, f->buffer, remrem); wrap_bytes -= remrem; ff_buf = f->buffer + remrem; // wrap around @@ -205,7 +219,7 @@ static void ff_push_n(const tu_fifo_t *f, const void *app_buf, uint16_t n, uint1 // Write data wrapped part if (wrap_bytes > 0) { - ff_push_fixed_addr_rw32(ff_buf, reg_rx, wrap_bytes); + ff_push_fixed_addr(ff_buf, reg_rx, wrap_bytes); } } break; @@ -240,28 +254,28 @@ static void ff_pull_n(const tu_fifo_t *f, void *app_buf, uint16_t n, uint16_t rd } break; -#ifdef CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32 +#ifdef CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_WIDTH case TU_FIFO_FIXED_ADDR_RW32: { - volatile uint32_t *reg_tx = (volatile uint32_t *)app_buf; + volatile fixed_access_item_t *reg_tx = (volatile fixed_access_item_t *)app_buf; if (n <= lin_count) { // Linear only - ff_pull_fixed_addr_rw32(reg_tx, ff_buf, n * f->item_size); + ff_pull_fixed_addr(reg_tx, ff_buf, n * f->item_size); } else { // Wrap around case // Read full words from linear part - uint16_t lin_4n_bytes = lin_bytes & 0xFFFC; - ff_pull_fixed_addr_rw32(reg_tx, ff_buf, lin_4n_bytes); - ff_buf += lin_4n_bytes; + uint16_t lin_nitems_bytes = lin_bytes & ~FIXED_ACCESS_REMAINDER_MASK; + ff_pull_fixed_addr(reg_tx, ff_buf, lin_nitems_bytes); + ff_buf += lin_nitems_bytes; - // There could be odd 1-3 bytes before the wrap-around boundary - const uint8_t rem = lin_bytes & 0x03; + // There could be odd 1 byte (16bit) or 1-3 bytes (32bit) before the wrap-around boundary + const uint8_t rem = lin_bytes & FIXED_ACCESS_REMAINDER_MASK; if (rem > 0) { - 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); + const uint8_t remrem = (uint8_t)tu_min16(wrap_bytes, sizeof(fixed_access_item_t) - rem); + const fixed_access_item_t scatter = (fixed_access_item_t)tu_scatter_read32(ff_buf, rem, f->buffer, remrem); - *reg_tx = scatter32; + *reg_tx = scatter; wrap_bytes -= remrem; ff_buf = f->buffer + remrem; // wrap around @@ -271,7 +285,7 @@ static void ff_pull_n(const tu_fifo_t *f, void *app_buf, uint16_t n, uint16_t rd // Read data wrapped part if (wrap_bytes > 0) { - ff_pull_fixed_addr_rw32(reg_tx, ff_buf, wrap_bytes); + ff_pull_fixed_addr(reg_tx, ff_buf, wrap_bytes); } } break; diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h index 2e2a0db6f..f58cc3fcb 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -49,9 +49,16 @@ extern "C" { #define CFG_FIFO_MUTEX OSAL_MUTEX_REQUIRED #if CFG_TUD_EDPT_DEDICATED_HWFIFO || CFG_TUH_EDPT_DEDICATED_HWFIFO - #define CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32 + #ifndef CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_WIDTH + #define CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_WIDTH 32 + #endif #endif +#ifndef CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_WIDTH + #define CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_WIDTH 0 +#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 * @@ -150,7 +157,7 @@ typedef struct { // 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_FIXED_ADDR_RW32, // fixed address read/write by 2/4 bytes (items). } tu_fifo_access_mode_t; //--------------------------------------------------------------------+ @@ -205,6 +212,10 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_fifo_read_n(tu_fifo_t *f, void * 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_read_n_fixed_addr(tu_fifo_t *f, void *buffer, uint16_t n) { + return tu_fifo_read_n_access_mode(f, buffer, n, TU_FIFO_FIXED_ADDR_RW32); +} + // discard first n items from fifo i.e advance read pointer by n with mutex // return number of discarded items uint16_t tu_fifo_discard_n(tu_fifo_t *f, uint16_t n); @@ -218,6 +229,10 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_fifo_write_n(tu_fifo_t *f, const return tu_fifo_write_n_access_mode(f, data, n, TU_FIFO_INC_ADDR_RW8); } +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_fifo_write_n_fixed_addr(tu_fifo_t *f, const void *data, uint16_t n) { + return tu_fifo_write_n_access_mode(f, data, n, TU_FIFO_FIXED_ADDR_RW32); +} + //--------------------------------------------------------------------+ // Internal Helper Local // work on local copies of read/write indices in order to only access them once for re-entrancy diff --git a/src/osal/osal_none.h b/src/osal/osal_none.h index 174136e38..aa6111a16 100644 --- a/src/osal/osal_none.h +++ b/src/osal/osal_none.h @@ -171,7 +171,7 @@ typedef osal_queue_def_t* osal_queue_t; } TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) { - (void) tu_fifo_clear(&qdef->ff); + tu_fifo_clear(&qdef->ff); return (osal_queue_t) qdef; } diff --git a/test/unit-test/CMakeLists.txt b/test/unit-test/CMakeLists.txt index 7172f5575..3339361db 100644 --- a/test/unit-test/CMakeLists.txt +++ b/test/unit-test/CMakeLists.txt @@ -113,7 +113,7 @@ add_ceedling_test( ${CEEDLING_WORKDIR}/../../src/common/tusb_fifo.c "" ) -target_compile_definitions(test_fifo PRIVATE CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32=1) +target_compile_definitions(test_fifo PRIVATE CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_WIDTH=32) add_ceedling_test( test_usbd diff --git a/test/unit-test/project.yml b/test/unit-test/project.yml index d971d098d..3968faaef 100644 --- a/test/unit-test/project.yml +++ b/test/unit-test/project.yml @@ -128,7 +128,7 @@ :defines: :test: - _UNITY_TEST_ - - CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32 + - CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_WIDTH=32 :release: [] # Enable to inject name of a test as a unique compilation symbol into its respective executable build.