make fifo access mode fixed addr work with 16 bit also

This commit is contained in:
hathach
2025-12-16 00:19:13 +07:00
parent 77fcf62f9f
commit 0a9e05f47a
5 changed files with 80 additions and 51 deletions

View File

@ -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;

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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.