summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/tusb_common.h161
-rw-r--r--src/common/tusb_compiler.h155
-rw-r--r--src/common/tusb_debug.h31
-rw-r--r--src/common/tusb_fifo.c1254
-rw-r--r--src/common/tusb_fifo.h249
-rw-r--r--src/common/tusb_mcu.h568
-rw-r--r--src/common/tusb_private.h129
-rw-r--r--src/common/tusb_types.h74
-rw-r--r--src/common/tusb_verify.h25
9 files changed, 1347 insertions, 1299 deletions
diff --git a/src/common/tusb_common.h b/src/common/tusb_common.h
index 12dea2183..6ac1405f3 100644
--- a/src/common/tusb_common.h
+++ b/src/common/tusb_common.h
@@ -24,8 +24,8 @@
* This file is part of the TinyUSB stack.
*/
-#ifndef _TUSB_COMMON_H_
-#define _TUSB_COMMON_H_
+#ifndef TUSB_COMMON_H_
+#define TUSB_COMMON_H_
#ifdef __cplusplus
extern "C" {
@@ -34,30 +34,38 @@
//--------------------------------------------------------------------+
// Macros Helper
//--------------------------------------------------------------------+
-#define TU_ARRAY_SIZE(_arr) ( sizeof(_arr) / sizeof(_arr[0]) )
-#define TU_FIELD_SZIE(_type, _field) (sizeof(((_type *)0)->_field))
-#define TU_MIN(_x, _y) ( ( (_x) < (_y) ) ? (_x) : (_y) )
-#define TU_MAX(_x, _y) ( ( (_x) > (_y) ) ? (_x) : (_y) )
-#define TU_DIV_CEIL(n, d) (((n) + (d) - 1) / (d))
+#define TU_ARRAY_SIZE(_arr) ( sizeof(_arr) / sizeof(_arr[0]) )
+#define TU_FIELD_SIZE(_type, _field) (sizeof(((_type *)0)->_field))
+#define TU_MIN(_x, _y) ( ( (_x) < (_y) ) ? (_x) : (_y) )
+#define TU_MAX(_x, _y) ( ( (_x) > (_y) ) ? (_x) : (_y) )
+#define TU_DIV_CEIL(n, d) (((n) + (d) - 1) / (d))
+#define TU_DIV_ROUND_NEAREST(v, d) (((v) + (d)/2) / (d) ) // round to nearest integer
-#define TU_U16(_high, _low) ((uint16_t) (((_high) << 8) | (_low)))
-#define TU_U16_HIGH(_u16) ((uint8_t) (((_u16) >> 8) & 0x00ff))
-#define TU_U16_LOW(_u16) ((uint8_t) ((_u16) & 0x00ff))
-#define U16_TO_U8S_BE(_u16) TU_U16_HIGH(_u16), TU_U16_LOW(_u16)
-#define U16_TO_U8S_LE(_u16) TU_U16_LOW(_u16), TU_U16_HIGH(_u16)
+#define TU_U16(_high, _low) ((uint16_t) ((((uint16_t) (_high)) << 8) | ((uint16_t) (_low))))
+#define TU_U16_HIGH(_u16) ((uint8_t) (((uint16_t) (_u16) >> 8) & 0x00ffu))
+#define TU_U16_LOW(_u16) ((uint8_t) ((uint16_t) (_u16) & 0x00ffu))
+#define U16_TO_U8S_BE(_u16) TU_U16_HIGH(_u16), TU_U16_LOW(_u16)
+#define U16_TO_U8S_LE(_u16) TU_U16_LOW(_u16), TU_U16_HIGH(_u16)
-#define TU_U32_BYTE3(_u32) ((uint8_t) ((((uint32_t) _u32) >> 24) & 0x000000ff)) // MSB
-#define TU_U32_BYTE2(_u32) ((uint8_t) ((((uint32_t) _u32) >> 16) & 0x000000ff))
-#define TU_U32_BYTE1(_u32) ((uint8_t) ((((uint32_t) _u32) >> 8) & 0x000000ff))
-#define TU_U32_BYTE0(_u32) ((uint8_t) (((uint32_t) _u32) & 0x000000ff)) // LSB
+#define TU_U24(_high, _mid, _low) ((uint32_t) ((((uint32_t) (_high)) << 16) | (((uint32_t) (_mid)) << 8) | ((uint32_t) (_low))))
+#define TU_U24_HIGH(_u24) ((uint8_t) (((uint32_t) (_u24) >> 16) & 0x0000ffu))
+#define TU_U24_MID(_u24) ((uint8_t) (((uint32_t) (_u24) >> 8) & 0x0000ffu))
+#define TU_U24_LOW(_u24) ((uint8_t) ((uint32_t) (_u24) & 0x0000ffu))
+#define U24_TO_U8S_BE(_u24) TU_U24_HIGH(_u24), TU_U24_MID(_u24), TU_U24_LOW(_u24)
+#define U24_TO_U8S_LE(_u24) TU_U24_LOW(_u24), TU_U24_MID(_u24), TU_U24_HIGH(_u24)
-#define U32_TO_U8S_BE(_u32) TU_U32_BYTE3(_u32), TU_U32_BYTE2(_u32), TU_U32_BYTE1(_u32), TU_U32_BYTE0(_u32)
-#define U32_TO_U8S_LE(_u32) TU_U32_BYTE0(_u32), TU_U32_BYTE1(_u32), TU_U32_BYTE2(_u32), TU_U32_BYTE3(_u32)
+#define TU_U32_BYTE3(_u32) ((uint8_t) ((((uint32_t) _u32) >> 24) & 0x000000ff)) // MSB
+#define TU_U32_BYTE2(_u32) ((uint8_t) ((((uint32_t) _u32) >> 16) & 0x000000ff))
+#define TU_U32_BYTE1(_u32) ((uint8_t) ((((uint32_t) _u32) >> 8) & 0x000000ff))
+#define TU_U32_BYTE0(_u32) ((uint8_t) (((uint32_t) _u32) & 0x000000ff)) // LSB
-#define TU_BIT(n) (1UL << (n))
+#define U32_TO_U8S_BE(_u32) TU_U32_BYTE3(_u32), TU_U32_BYTE2(_u32), TU_U32_BYTE1(_u32), TU_U32_BYTE0(_u32)
+#define U32_TO_U8S_LE(_u32) TU_U32_BYTE0(_u32), TU_U32_BYTE1(_u32), TU_U32_BYTE2(_u32), TU_U32_BYTE3(_u32)
+
+#define TU_BIT(n) (1UL << (n))
// Generate a mask with bit from high (31) to low (0) set, e.g TU_GENMASK(3, 0) = 0b1111
-#define TU_GENMASK(h, l) ( (UINT32_MAX << (l)) & (UINT32_MAX >> (31 - (h))) )
+#define TU_GENMASK(h, l) ( (UINT32_MAX << (l)) & (UINT32_MAX >> (31 - (h))) )
//--------------------------------------------------------------------+
// Includes
@@ -69,7 +77,6 @@
#include <inttypes.h>
#include <stddef.h>
#include <string.h>
-#include <stdio.h>
// Tinyusb Common Headers
#include "tusb_option.h"
@@ -104,26 +111,47 @@ extern void* tusb_app_phys_to_virt(void *phys_addr);
//--------------------------------------------------------------------+
//------------- Mem -------------//
-#define tu_memclr(buffer, size) memset((buffer), 0, (size))
+#define tu_memclr(buffer, size) (void) memset((buffer), 0, (size))
#define tu_varclr(_var) tu_memclr(_var, sizeof(*(_var)))
// This is a backport of memset_s from c11
TU_ATTR_ALWAYS_INLINE static inline int tu_memset_s(void *dest, size_t destsz, int ch, size_t count) {
- // TODO may check if desst and src is not NULL
- if ( count > destsz ) {
+ // Validate parameters
+ if (dest == NULL) {
+ return -1;
+ }
+
+ if (count == 0u) {
+ return 0;
+ }
+
+ if (count > destsz) {
return -1;
}
- memset(dest, ch, count);
+
+ (void) memset(dest, ch, count);
return 0;
}
// This is a backport of memcpy_s from c11
TU_ATTR_ALWAYS_INLINE static inline int tu_memcpy_s(void *dest, size_t destsz, const void *src, size_t count) {
- // TODO may check if desst and src is not NULL
- if ( count > destsz ) {
+ if (dest == NULL) {
+ return -1;
+ }
+
+ if (count == 0u) {
+ return 0;
+ }
+
+ if (src == NULL) {
+ return -1;
+ }
+
+ if (count > destsz) {
return -1;
}
- memcpy(dest, src, count);
+
+ (void) memcpy(dest, src, count);
return 0;
}
@@ -200,13 +228,17 @@ TU_ATTR_ALWAYS_INLINE static inline bool tu_is_aligned64(uint64_t value) { retur
//------------- Mathematics -------------//
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_div_ceil(uint32_t v, uint32_t d) { return TU_DIV_CEIL(v, d); }
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_div_round_nearest(uint32_t v, uint32_t d) { return TU_DIV_ROUND_NEAREST(v, d); }
+
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_round_up(uint32_t v, uint32_t f) { return tu_div_ceil(v, f) * f; }
// log2 of a value is its MSB's position
// TODO use clz TODO remove
TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_log2(uint32_t value) {
uint8_t result = 0;
- while (value >>= 1) { result++; }
+ while ((value >>= 1u) != 0u) {
+ result++;
+ }
return result;
}
@@ -252,14 +284,12 @@ TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16(void *mem, uint16_
// We have to manually pick up bytes since tu_unaligned_uint32_t will still generate unaligned code
// NOTE: volatile cast to memory to prevent compiler to optimize and generate unaligned code
// TODO Big Endian may need minor changes
-TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_unaligned_read32(const void* mem)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_unaligned_read32(const void* mem) {
volatile uint8_t const* buf8 = (uint8_t const*) mem;
return tu_u32(buf8[3], buf8[2], buf8[1], buf8[0]);
}
-TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write32(void* mem, uint32_t value)
-{
+TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write32(void* mem, uint32_t value) {
volatile uint8_t* buf8 = (uint8_t*) mem;
buf8[0] = tu_u32_byte0(value);
buf8[1] = tu_u32_byte1(value);
@@ -267,20 +297,17 @@ TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write32(void* mem, uint32_
buf8[3] = tu_u32_byte3(value);
}
-TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_unaligned_read16(const void* mem)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_unaligned_read16(const void* mem) {
volatile uint8_t const* buf8 = (uint8_t const*) mem;
return tu_u16(buf8[1], buf8[0]);
}
-TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16(void* mem, uint16_t value)
-{
+TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16(void* mem, uint16_t value) {
volatile uint8_t* buf8 = (uint8_t*) mem;
buf8[0] = tu_u16_low(value);
buf8[1] = tu_u16_high(value);
}
-
#else
// MCU that could access unaligned memory natively
@@ -302,34 +329,38 @@ TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16(void *mem, uint16_
#endif
-// To be removed
-//------------- Binary constant -------------//
-#if defined(__GNUC__) && !defined(__CC_ARM)
+// scatter read 4 bytes from two buffers (LE). 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;
-#define TU_BIN8(x) ((uint8_t) (0b##x))
-#define TU_BIN16(b1, b2) ((uint16_t) (0b##b1##b2))
-#define TU_BIN32(b1, b2, b3, b4) ((uint32_t) (0b##b1##b2##b3##b4))
+ for (uint8_t i = 0; i < len1; ++i) {
+ result |= ((uint32_t)buf1[i]) << shift;
+ shift += 8;
+ }
-#else
+ for (uint8_t i = 0; i < len2; ++i) {
+ result |= ((uint32_t)buf2[i]) << shift;
+ shift += 8;
+ }
-// internal macro of B8, B16, B32
-#define _B8__(x) (((x&0x0000000FUL)?1:0) \
- +((x&0x000000F0UL)?2:0) \
- +((x&0x00000F00UL)?4:0) \
- +((x&0x0000F000UL)?8:0) \
- +((x&0x000F0000UL)?16:0) \
- +((x&0x00F00000UL)?32:0) \
- +((x&0x0F000000UL)?64:0) \
- +((x&0xF0000000UL)?128:0))
+ return result;
+}
-#define TU_BIN8(d) ((uint8_t) _B8__(0x##d##UL))
-#define TU_BIN16(dmsb,dlsb) (((uint16_t)TU_BIN8(dmsb)<<8) + TU_BIN8(dlsb))
-#define TU_BIN32(dmsb,db2,db3,dlsb) \
- (((uint32_t)TU_BIN8(dmsb)<<24) \
- + ((uint32_t)TU_BIN8(db2)<<16) \
- + ((uint32_t)TU_BIN8(db3)<<8) \
- + TU_BIN8(dlsb))
-#endif
+// scatter write 4 bytes (LE) 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
@@ -356,8 +387,8 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_subtype(void const* desc) {
return ((uint8_t const*) desc)[DESC_OFFSET_SUBTYPE];
}
-TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_in_bounds(uint8_t const* p_desc, uint8_t const* desc_end) {
- return (p_desc < desc_end) && (tu_desc_next(p_desc) <= desc_end);
+TU_ATTR_ALWAYS_INLINE static inline bool tu_desc_in_bounds(const uint8_t *p_desc, const uint8_t *desc_end) {
+ return p_desc < desc_end && tu_desc_next(p_desc) <= desc_end;
}
// find descriptor that match byte1 (type)
@@ -373,4 +404,4 @@ uint8_t const * tu_desc_find3(uint8_t const* desc, uint8_t const* end, uint8_t b
}
#endif
-#endif /* _TUSB_COMMON_H_ */
+#endif /* TUSB_COMMON_H_ */
diff --git a/src/common/tusb_compiler.h b/src/common/tusb_compiler.h
index 9b33a6f61..a8971c3df 100644
--- a/src/common/tusb_compiler.h
+++ b/src/common/tusb_compiler.h
@@ -24,30 +24,22 @@
* This file is part of the TinyUSB stack.
*/
-/** \ingroup Group_Common
- * \defgroup Group_Compiler Compiler
- * \brief Group_Compiler brief
- * @{ */
-
-#ifndef _TUSB_COMPILER_H_
-#define _TUSB_COMPILER_H_
+#pragma once
#define TU_TOKEN(x) x
#define TU_STRING(x) #x ///< stringify without expand
#define TU_XSTRING(x) TU_STRING(x) ///< expand then stringify
-
#define TU_STRCAT(a, b) a##b ///< concat without expand
#define TU_STRCAT3(a, b, c) a##b##c ///< concat without expand
-
#define TU_XSTRCAT(a, b) TU_STRCAT(a, b) ///< expand then concat
#define TU_XSTRCAT3(a, b, c) TU_STRCAT3(a, b, c) ///< expand then concat 3 tokens
#define TU_INCLUDE_PATH(_dir,_file) TU_XSTRING( TU_TOKEN(_dir)TU_TOKEN(_file) )
#if defined __COUNTER__ && __COUNTER__ != __COUNTER__
- #define _TU_COUNTER_ __COUNTER__
+ #define TU_COUNTER __COUNTER__
#else
- #define _TU_COUNTER_ __LINE__
+ #define TU_COUNTER __LINE__
#endif
// Compile-time Assert
@@ -56,9 +48,9 @@
#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
#define TU_VERIFY_STATIC _Static_assert
#elif defined(__CCRX__)
- #define TU_VERIFY_STATIC(const_expr, _mess) typedef char TU_XSTRCAT(_verify_static_, _TU_COUNTER_)[(const_expr) ? 1 : 0];
+ #define TU_VERIFY_STATIC(const_expr, _mess) typedef char TU_XSTRCAT(_verify_static_, TU_COUNTER)[(const_expr) ? 1 : 0];
#else
- #define TU_VERIFY_STATIC(const_expr, _mess) enum { TU_XSTRCAT(_verify_static_, _TU_COUNTER_) = 1/(!!(const_expr)) }
+ #define TU_VERIFY_STATIC(const_expr, _mess) enum { TU_XSTRCAT(_verify_static_, TU_COUNTER) = 1/(!!(const_expr)) }
#endif
/* --------------------- Fuzzing types -------------------------------------- */
@@ -68,28 +60,31 @@
#define tu_static static
#endif
-// for declaration of reserved field, make use of _TU_COUNTER_
-#define TU_RESERVED TU_XSTRCAT(reserved, _TU_COUNTER_)
+// for declaration of reserved field, make use of TU_COUNTER
+#define TU_RESERVED TU_XSTRCAT(reserved, TU_COUNTER)
#define TU_LITTLE_ENDIAN (0x12u)
#define TU_BIG_ENDIAN (0x21u)
+#define TU_BITFIELD_LE (0x34u)
+#define TU_BITFIELD_BE (0x43u)
+
/*------------------------------------------------------------------*/
/* Count number of arguments of __VA_ARGS__
- * - reference https://stackoverflow.com/questions/2124339/c-preprocessor-va-args-number-of-arguments
- * - _GET_NTH_ARG() takes args >= N (64) but only expand to Nth one (64th)
- * - _RSEQ_N() is reverse sequential to N to add padding to have
+ * - reference www.stackoverflow.com/questions/2124339/c-preprocessor-va-args-number-of-arguments
+ * - TU_GET_NTH_ARG() takes args >= N (64) but only expand to Nth one (64th)
+ * - TU_NARG_RSEQ_N() is reverse sequential to N to add padding to have
* Nth position is the same as the number of arguments
* - ##__VA_ARGS__ is used to deal with 0 paramerter (swallows comma)
*------------------------------------------------------------------*/
-#if !defined(__CCRX__)
-#define TU_ARGS_NUM(...) _TU_NARG(_0, ##__VA_ARGS__, _RSEQ_N())
+#if defined(__CCRX__)
+#define TU_ARGS_NUM(...) TU_NARG_IMPL(_0, __VA_ARGS__, TU_NARG_RSEQ_N())
#else
-#define TU_ARGS_NUM(...) _TU_NARG(_0, __VA_ARGS__, _RSEQ_N())
+#define TU_ARGS_NUM(...) TU_NARG_IMPL(_0, ##__VA_ARGS__, TU_NARG_RSEQ_N())
#endif
-#define _TU_NARG(...) _GET_NTH_ARG(__VA_ARGS__)
-#define _GET_NTH_ARG( \
+#define TU_NARG_IMPL(...) TU_GET_NTH_ARG(__VA_ARGS__)
+#define TU_GET_NTH_ARG( \
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
@@ -97,7 +92,7 @@
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
_61,_62,_63,N,...) N
-#define _RSEQ_N() \
+#define TU_NARG_RSEQ_N() \
62,61,60, \
59,58,57,56,55,54,53,52,51,50, \
49,48,47,46,45,44,43,42,41,40, \
@@ -106,17 +101,29 @@
19,18,17,16,15,14,13,12,11,10, \
9,8,7,6,5,4,3,2,1,0
-// Apply an macro X to each of the arguments with an separated of choice
-#define TU_ARGS_APPLY(_X, _s, ...) TU_XSTRCAT(_TU_ARGS_APPLY_, TU_ARGS_NUM(__VA_ARGS__))(_X, _s, __VA_ARGS__)
+// Apply a macro X to each of the arguments with a separation/delimiter
+#define TU_ARGS_APPLY(_X, _s, ...) TU_XSTRCAT(TU_ARGS_APPLY_, TU_ARGS_NUM(__VA_ARGS__))(_X, _s, __VA_ARGS__)
+
+#define TU_ARGS_APPLY_1(_X, _s, _a1) _X(_a1)
+#define TU_ARGS_APPLY_2(_X, _s, _a1, _a2) _X(_a1) _s _X(_a2)
+#define TU_ARGS_APPLY_3(_X, _s, _a1, _a2, _a3) _X(_a1) _s TU_ARGS_APPLY_2(_X, _s, _a2, _a3)
+#define TU_ARGS_APPLY_4(_X, _s, _a1, _a2, _a3, _a4) _X(_a1) _s TU_ARGS_APPLY_3(_X, _s, _a2, _a3, _a4)
+#define TU_ARGS_APPLY_5(_X, _s, _a1, _a2, _a3, _a4, _a5) _X(_a1) _s TU_ARGS_APPLY_4(_X, _s, _a2, _a3, _a4, _a5)
+#define TU_ARGS_APPLY_6(_X, _s, _a1, _a2, _a3, _a4, _a5, _a6) _X(_a1) _s TU_ARGS_APPLY_5(_X, _s, _a2, _a3, _a4, _a5, _a6)
+#define TU_ARGS_APPLY_7(_X, _s, _a1, _a2, _a3, _a4, _a5, _a6, _a7) _X(_a1) _s TU_ARGS_APPLY_6(_X, _s, _a2, _a3, _a4, _a5, _a6, _a7)
+#define TU_ARGS_APPLY_8(_X, _s, _a1, _a2, _a3, _a4, _a5, _a6, _a7, _a8) _X(_a1) _s TU_ARGS_APPLY_7(_X, _s, _a2, _a3, _a4, _a5, _a6, _a7, _a8)
-#define _TU_ARGS_APPLY_1(_X, _s, _a1) _X(_a1)
-#define _TU_ARGS_APPLY_2(_X, _s, _a1, _a2) _X(_a1) _s _X(_a2)
-#define _TU_ARGS_APPLY_3(_X, _s, _a1, _a2, _a3) _X(_a1) _s _TU_ARGS_APPLY_2(_X, _s, _a2, _a3)
-#define _TU_ARGS_APPLY_4(_X, _s, _a1, _a2, _a3, _a4) _X(_a1) _s _TU_ARGS_APPLY_3(_X, _s, _a2, _a3, _a4)
-#define _TU_ARGS_APPLY_5(_X, _s, _a1, _a2, _a3, _a4, _a5) _X(_a1) _s _TU_ARGS_APPLY_4(_X, _s, _a2, _a3, _a4, _a5)
-#define _TU_ARGS_APPLY_6(_X, _s, _a1, _a2, _a3, _a4, _a5, _a6) _X(_a1) _s _TU_ARGS_APPLY_5(_X, _s, _a2, _a3, _a4, _a5, _a6)
-#define _TU_ARGS_APPLY_7(_X, _s, _a1, _a2, _a3, _a4, _a5, _a6, _a7) _X(_a1) _s _TU_ARGS_APPLY_6(_X, _s, _a2, _a3, _a4, _a5, _a6, _a7)
-#define _TU_ARGS_APPLY_8(_X, _s, _a1, _a2, _a3, _a4, _a5, _a6, _a7, _a8) _X(_a1) _s _TU_ARGS_APPLY_7(_X, _s, _a2, _a3, _a4, _a5, _a6, _a7, _a8)
+// Apply a macro X to each of the arguments and expand the result with comma
+#define TU_ARGS_APPLY_EXPAND(_X, ...) TU_XSTRCAT(TU_ARGS_APPLY_EXPAND_, TU_ARGS_NUM(__VA_ARGS__))(_X, __VA_ARGS__)
+
+#define TU_ARGS_APPLY_EXPAND_1(_X, _a1) _X(_a1)
+#define TU_ARGS_APPLY_EXPAND_2(_X, _a1, _a2) _X(_a1), _X(_a2)
+#define TU_ARGS_APPLY_EXPAND_3(_X, _a1, _a2, _a3) _X(_a1), TU_ARGS_APPLY_EXPAND_2(_X, _a2, _a3)
+#define TU_ARGS_APPLY_EXPAND_4(_X, _a1, _a2, _a3, _a4) _X(_a1), TU_ARGS_APPLY_EXPAND_3(_X, _a2, _a3, _a4)
+#define TU_ARGS_APPLY_EXPAND_5(_X, _a1, _a2, _a3, _a4, _a5) _X(_a1), TU_ARGS_APPLY_EXPAND_4(_X, _a2, _a3, _a4, _a5)
+#define TU_ARGS_APPLY_EXPAND_6(_X, _a1, _a2, _a3, _a4, _a5, _a6) _X(_a1), TU_ARGS_APPLY_EXPAND_5(_X, _a2, _a3, _a4, _a5, _a6)
+#define TU_ARGS_APPLY_EXPAND_7(_X, _a1, _a2, _a3, _a4, _a5, _a6, _a7) _X(_a1), TU_ARGS_APPLY_EXPAND_6(_X, _a2, _a3, _a4, _a5, _a6, _a7)
+#define TU_ARGS_APPLY_EXPAND_8(_X, _a1, _a2, _a3, _a4, _a5, _a6, _a7, _a8) _X(_a1), TU_ARGS_APPLY_EXPAND_7(_X, _a2, _a3, _a4, _a5, _a6, _a7, _a8)
//--------------------------------------------------------------------+
// Macro for function default arguments
@@ -127,18 +134,20 @@
#define TU_FUNC_OPTIONAL_ARG(func, ...) TU_XSTRCAT(func##_arg, TU_ARGS_NUM(__VA_ARGS__))(__VA_ARGS__)
//--------------------------------------------------------------------+
-// Compiler porting with Attribute and Endian
+// Compiler Attribute Abstraction
//--------------------------------------------------------------------+
+#if defined(__GNUC__) || defined(__ICCARM__) || defined(__TI_COMPILER_VERSION__)
+ #if defined(__ICCARM__)
+ #include <intrinsics.h> // for builtin functions
+ #endif
-// TODO refactor since __attribute__ is supported across many compiler
-#if defined(__GNUC__)
- #define TU_ATTR_ALIGNED(Bytes) __attribute__ ((aligned(Bytes)))
- #define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name)))
- #define TU_ATTR_PACKED __attribute__ ((packed))
- #define TU_ATTR_WEAK __attribute__ ((weak))
- // #define TU_ATTR_WEAK_ALIAS(f) __attribute__ ((weak, alias(#f)))
- #ifndef TU_ATTR_ALWAYS_INLINE // allow to override for debug
- #define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline))
+ #define TU_ATTR_ALIGNED(Bytes) __attribute__((aligned(Bytes)))
+ #define TU_ATTR_SECTION(sec_name) __attribute__((section(#sec_name)))
+ #define TU_ATTR_PACKED __attribute__((packed))
+ #define TU_ATTR_WEAK __attribute__((weak))
+// #define TU_ATTR_WEAK_ALIAS(f) __attribute__ ((weak, alias(#f)))
+ #ifndef TU_ATTR_ALWAYS_INLINE // allow to override for debug
+ #define TU_ATTR_ALWAYS_INLINE __attribute__((always_inline))
#endif
#define TU_ATTR_DEPRECATED(mess) __attribute__ ((deprecated(mess))) // warn if function with this attribute is used
#define TU_ATTR_UNUSED __attribute__ ((unused)) // Function/Variable is meant to be possibly unused
@@ -149,21 +158,22 @@
#define TU_ATTR_BIT_FIELD_ORDER_BEGIN
#define TU_ATTR_BIT_FIELD_ORDER_END
- #if __GNUC__ < 5
- #define TU_ATTR_FALLTHROUGH do {} while (0) /* fallthrough */
+ #if (defined(__has_attribute) && __has_attribute(__fallthrough__)) || defined(__TI_COMPILER_VERSION__)
+ #define TU_ATTR_FALLTHROUGH __attribute__((fallthrough))
#else
- #if __has_attribute(__fallthrough__)
- #define TU_ATTR_FALLTHROUGH __attribute__((fallthrough))
- #else
- #define TU_ATTR_FALLTHROUGH do {} while (0) /* fallthrough */
- #endif
+ #define TU_ATTR_FALLTHROUGH \
+ do { \
+ } while (0) /* fallthrough */
#endif
- // Endian conversion use well-known host to network (big endian) naming
- #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+// Endian conversion use well-known host to network (big endian) naming
+// For TI ARM compiler, __BYTE_ORDER__ is not defined for MSP430 but still LE
+ #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || defined(__MSP430__)
#define TU_BYTE_ORDER TU_LITTLE_ENDIAN
+ #define TU_BITFIELD_ORDER TU_BITFIELD_LE
#else
#define TU_BYTE_ORDER TU_BIG_ENDIAN
+ #define TU_BITFIELD_ORDER TU_BITFIELD_BE
#endif
// Unfortunately XC16 doesn't provide builtins for 32bit endian conversion
@@ -178,39 +188,12 @@
#define TU_BSWAP32(u32) (__builtin_bswap32(u32))
#endif
- #ifndef __ARMCC_VERSION
// List of obsolete callback function that is renamed and should not be defined.
// Put it here since only gcc support this pragma
- #pragma GCC poison tud_vendor_control_request_cb
- #endif
-
-#elif defined(__TI_COMPILER_VERSION__)
- #define TU_ATTR_ALIGNED(Bytes) __attribute__ ((aligned(Bytes)))
- #define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name)))
- #define TU_ATTR_PACKED __attribute__ ((packed))
- #define TU_ATTR_WEAK __attribute__ ((weak))
- // #define TU_ATTR_WEAK_ALIAS(f) __attribute__ ((weak, alias(#f)))
- #define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline))
- #define TU_ATTR_DEPRECATED(mess) __attribute__ ((deprecated(mess))) // warn if function with this attribute is used
- #define TU_ATTR_UNUSED __attribute__ ((unused)) // Function/Variable is meant to be possibly unused
- #define TU_ATTR_USED __attribute__ ((used))
- #define TU_ATTR_FALLTHROUGH __attribute__((fallthrough))
-
- #define TU_ATTR_PACKED_BEGIN
- #define TU_ATTR_PACKED_END
- #define TU_ATTR_BIT_FIELD_ORDER_BEGIN
- #define TU_ATTR_BIT_FIELD_ORDER_END
-
- // __BYTE_ORDER is defined in the TI ARM compiler, but not MSP430 (which is little endian)
- #if ((__BYTE_ORDER__) == (__ORDER_LITTLE_ENDIAN__)) || defined(__MSP430__)
- #define TU_BYTE_ORDER TU_LITTLE_ENDIAN
- #else
- #define TU_BYTE_ORDER TU_BIG_ENDIAN
+ #if !defined(__ARMCC_VERSION) && !defined(__ICCARM__)
+ #pragma GCC poison tud_vendor_control_request_cb
#endif
- #define TU_BSWAP16(u16) (__builtin_bswap16(u16))
- #define TU_BSWAP32(u32) (__builtin_bswap32(u32))
-
#elif defined(__ICCARM__)
#include <intrinsics.h>
#define TU_ATTR_ALIGNED(Bytes) __attribute__ ((aligned(Bytes)))
@@ -234,8 +217,10 @@
// Endian conversion use well-known host to network (big endian) naming
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define TU_BYTE_ORDER TU_LITTLE_ENDIAN
+ #define TU_BITFIELD_ORDER TU_BITFIELD_LE
#else
#define TU_BYTE_ORDER TU_BIG_ENDIAN
+ #define TU_BITFIELD_ORDER TU_BITFIELD_BE
#endif
#define TU_BSWAP16(u16) (__iar_builtin_REV16(u16))
@@ -261,8 +246,10 @@
// Endian conversion use well-known host to network (big endian) naming
#if defined(__LIT)
#define TU_BYTE_ORDER TU_LITTLE_ENDIAN
+ #define TU_BITFIELD_ORDER TU_BITFIELD_LE
#else
#define TU_BYTE_ORDER TU_BIG_ENDIAN
+ #define TU_BITFIELD_ORDER TU_BITFIELD_BE
#endif
#define TU_BSWAP16(u16) ((unsigned short)_builtin_revw((unsigned long)u16))
@@ -304,7 +291,3 @@
#else
#error Byte order is undefined
#endif
-
-#endif /* _TUSB_COMPILER_H_ */
-
-/// @}
diff --git a/src/common/tusb_debug.h b/src/common/tusb_debug.h
index 1d0c6f1ad..ba5b4afd1 100644
--- a/src/common/tusb_debug.h
+++ b/src/common/tusb_debug.h
@@ -24,8 +24,8 @@
* This file is part of the TinyUSB stack.
*/
-#ifndef _TUSB_DEBUG_H_
-#define _TUSB_DEBUG_H_
+#ifndef TUSB_DEBUG_H_
+#define TUSB_DEBUG_H_
#ifdef __cplusplus
extern "C" {
@@ -55,11 +55,14 @@ void tu_print_mem(void const *buf, uint32_t count, uint8_t indent);
extern int CFG_TUSB_DEBUG_PRINTF(const char *format, ...);
#define tu_printf CFG_TUSB_DEBUG_PRINTF
#else
- #define tu_printf printf
+ #include <stdio.h>
+ #define tu_printf(...) (void) printf(__VA_ARGS__)
#endif
-static inline void tu_print_buf(uint8_t const* buf, uint32_t bufsize) {
- for(uint32_t i=0; i<bufsize; i++) tu_printf("%02X ", buf[i]);
+TU_ATTR_ALWAYS_INLINE static inline void tu_print_buf(uint8_t const* buf, uint32_t bufsize) {
+ for(uint32_t i=0; i<bufsize; i++) {
+ tu_printf("%02X ", buf[i]);
+ }
tu_printf("\r\n");
}
@@ -109,13 +112,21 @@ typedef struct {
static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint32_t key) {
for(uint16_t i=0; i<p_table->count; i++) {
- if (p_table->items[i].key == key) { return p_table->items[i].data; }
+ if (p_table->items[i].key == key) {
+ return p_table->items[i].data;
+ }
}
- // not found return the key value in hex
+ #ifndef CFG_TUSB_DEBUG_PRINTF
+ // not found return the key value in hex if no custom printf is defined
static char not_found[11];
- snprintf(not_found, sizeof(not_found), "0x%08lX", (unsigned long) key);
+ if (snprintf(not_found, sizeof(not_found), "0x%08lX", (unsigned long)key) <= 0) {
+ not_found[0] = 0;
+ }
return not_found;
+ #else
+ return "NotFound";
+ #endif
}
#endif // CFG_TUSB_DEBUG
@@ -130,8 +141,6 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3
#define TU_LOG_FAILED()
#endif
-// TODO replace all TU_LOGn with TU_LOG(n)
-
#define TU_LOG0(...)
#define TU_LOG0_MEM(...)
#define TU_LOG0_BUF(...)
@@ -166,4 +175,4 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3
}
#endif
-#endif /* _TUSB_DEBUG_H_ */
+#endif
diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c
index f7679556f..a8ac99fd2 100644
--- a/src/common/tusb_fifo.c
+++ b/src/common/tusb_fifo.c
@@ -28,323 +28,387 @@
#include "osal/osal.h"
#include "tusb_fifo.h"
-#define TU_FIFO_DBG 0
+#define TU_FIFO_DBG 0
-// Suppress IAR warning
-// Warning[Pa082]: undefined behavior: the order of volatile accesses is undefined in this statement
-#if defined(__ICCARM__)
-#pragma diag_suppress = Pa082
-#endif
#if OSAL_MUTEX_REQUIRED
-TU_ATTR_ALWAYS_INLINE static inline void _ff_lock(osal_mutex_t mutex)
-{
- if (mutex) osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER);
+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)
-{
- if (mutex) osal_mutex_unlock(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)
-{
+//--------------------------------------------------------------------+
+// Setup API
+//--------------------------------------------------------------------+
+bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, bool overwritable) {
// 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)
- if (depth > 0x8000) return false;
+ if (depth > 0x8000) {
+ 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->buffer = (uint8_t *)buffer;
f->depth = depth;
- f->item_size = (uint16_t) (item_size & 0x7FFF);
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
-//--------------------------------------------------------------------+
-
-#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)
-{
- volatile const uint32_t * reg_rx = (volatile const uint32_t *) app_buf;
+// clear fifo by resetting read and write indices
+void tu_fifo_clear(tu_fifo_t *f) {
+ ff_lock(f->mutex_wr);
+ ff_lock(f->mutex_rd);
- // 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);
- ff_buf += 4;
- }
+ f->rd_idx = 0;
+ f->wr_idx = 0;
- // Read the remaining 1-3 bytes from const app address
- uint8_t const bytes_rem = len & 0x03;
- if ( bytes_rem )
- {
- uint32_t tmp32 = *reg_rx;
- memcpy(ff_buf, &tmp32, bytes_rem);
- }
+ ff_unlock(f->mutex_wr);
+ ff_unlock(f->mutex_rd);
}
-// 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;
-
- // Write full available 32 bit words to const address
- uint16_t full_words = len >> 2;
- while(full_words--)
- {
- *reg_tx = tu_unaligned_read32(ff_buf);
- ff_buf += 4;
+// Change the fifo overwritable mode
+void tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) {
+ if (f->overwritable == overwritable) {
+ return;
}
- // Write the remaining 1-3 bytes into const address
- uint8_t const bytes_rem = len & 0x03;
- if ( bytes_rem )
- {
- uint32_t tmp32 = 0;
- memcpy(&tmp32, ff_buf, bytes_rem);
+ ff_lock(f->mutex_wr);
+ ff_lock(f->mutex_rd);
- *reg_tx = tmp32;
- }
-}
-#endif
+ f->overwritable = overwritable;
-// send one item to fifo WITHOUT updating write pointer
-static inline void _ff_push(tu_fifo_t* f, void const * app_buf, uint16_t rel)
-{
- memcpy(f->buffer + (rel * f->item_size), app_buf, f->item_size);
+ ff_unlock(f->mutex_wr);
+ ff_unlock(f->mutex_rd);
}
-// 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 wr_ptr, tu_fifo_copy_mode_t copy_mode)
-{
- uint16_t const lin_count = f->depth - wr_ptr;
- uint16_t const wrap_count = n - lin_count;
+//--------------------------------------------------------------------+
+// Hardware FIFO API
+// Support different data access width and address increment scheme
+// Can support multiple i.e both 16 and 32-bit data access if needed
+//--------------------------------------------------------------------+
+#if CFG_TUSB_FIFO_HWFIFO_API
+ #if CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE > 0
+ #define HWFIFO_ADDR_NEXT_N(_hwfifo, _const, _n) _hwfifo = (_const volatile void *)((uintptr_t)(_hwfifo) + _n)
+ #else
+ #define HWFIFO_ADDR_NEXT_N(_hwfifo, _const, _n)
+ #endif
- uint16_t lin_bytes = lin_count * f->item_size;
- uint16_t wrap_bytes = wrap_count * f->item_size;
+ #define HWFIFO_ADDR_NEXT(_hwfifo, _const) HWFIFO_ADDR_NEXT_N(_hwfifo, _const, CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE)
- // current buffer of fifo
- uint8_t* ff_buf = f->buffer + (wr_ptr * f->item_size);
+ // the fixed ratio works since in the only case of dynamic/multiple data_stride (rusb2): addr_stride is 0
+ #define HWFIFO_ADDR_DATA_RATIO (CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE / CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE)
- switch (copy_mode)
+//------------- Write -------------//
+ #ifndef CFG_TUSB_FIFO_HWFIFO_CUSTOM_WRITE
+TU_ATTR_ALWAYS_INLINE static inline void stride_write(volatile void *hwfifo, const void *src, uint8_t data_stride) {
+ (void)data_stride; // possible unused
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE & 4
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE != 4
+ if (data_stride == 4)
+ #endif
{
- case TU_FIFO_COPY_INC:
- if(n <= lin_count)
- {
- // Linear only
- memcpy(ff_buf, app_buf, n*f->item_size);
- }
- else
- {
- // Wrap around
+ *((volatile uint32_t *)hwfifo) = tu_unaligned_read32(src);
+ }
+ #endif
- // Write data to linear part of buffer
- memcpy(ff_buf, app_buf, lin_bytes);
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE & 2
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE != 2
+ if (data_stride == 2)
+ #endif
+ {
+ *((volatile uint16_t *)hwfifo) = tu_unaligned_read16(src);
+ }
+ #endif
- // Write data wrapped around
- // TU_ASSERT(nWrap_bytes <= f->depth, );
- memcpy(f->buffer, ((uint8_t const*) app_buf) + lin_bytes, wrap_bytes);
- }
- 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
- if(n <= lin_count)
- {
- // Linear only
- _ff_push_const_addr(ff_buf, app_buf, n*f->item_size);
- }
- else
- {
- // Wrap around case
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE == 1
+ *((volatile uint8_t *)hwfifo) = *(const uint8_t *)src;
+ #endif
+}
- // 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;
+// Copy from fifo to fixed address buffer (usually a tx register) with TU_FIFO_FIXED_ADDR_RW32 mode
+void tu_hwfifo_write(volatile void *hwfifo, const uint8_t *src, uint16_t len, const tu_hwfifo_access_t *access_mode) {
+ // Write full available 16/32 bit words to dest
+ const uint8_t data_stride = (access_mode != NULL) ? access_mode->data_stride : CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE;
+ while (len >= data_stride) {
+ stride_write(hwfifo, src, data_stride);
+ src += data_stride;
+ len -= data_stride;
+ HWFIFO_ADDR_NEXT(hwfifo, );
+ }
- // There could be odd 1-3 bytes before the wrap-around boundary
- uint8_t rem = lin_bytes & 0x03;
- if (rem > 0)
- {
- volatile const uint32_t * rx_fifo = (volatile const uint32_t *) app_buf;
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE > 1
+ #ifdef CFG_TUSB_FIFO_HWFIFO_DATA_ODD_16BIT_ACCESS
+ // 16-bit access is allowed for odd bytes
+ if (len >= 2) {
+ *((volatile uint16_t *)hwfifo) = tu_unaligned_read16(src);
+ src += 2;
+ len -= 2;
+ HWFIFO_ADDR_NEXT_N(hwfifo, , 2);
+ }
+ #endif
- uint8_t remrem = (uint8_t) tu_min16(wrap_bytes, 4-rem);
- wrap_bytes -= remrem;
+ #ifdef CFG_TUSB_FIFO_HWFIFO_DATA_ODD_8BIT_ACCESS
+ // 8-bit access is allowed for odd bytes
+ while (len > 0) {
+ *((volatile uint8_t *)hwfifo) = *src++;
+ len--;
+ HWFIFO_ADDR_NEXT_N(hwfifo, , 1);
+ }
+ #else
- uint32_t tmp32 = *rx_fifo;
- uint8_t * src_u8 = ((uint8_t *) &tmp32);
+ // Write odd bytes i.e 1 byte for 16 bit or 1-3 bytes for 32 bit
+ if (len > 0) {
+ uint32_t tmp = 0u;
+ memcpy(&tmp, src, len);
+ stride_write(hwfifo, &tmp, data_stride);
+ HWFIFO_ADDR_NEXT(hwfifo, );
+ }
+ #endif
+ #endif
+}
+ #endif
- // Write 1-3 bytes before wrapped boundary
- while(rem--) *ff_buf++ = *src_u8++;
+//------------- Read -------------//
+ #ifndef CFG_TUSB_FIFO_HWFIFO_CUSTOM_READ
+TU_ATTR_ALWAYS_INLINE static inline void stride_read(const volatile void *hwfifo, void *dest, uint8_t data_stride) {
+ (void)data_stride; // possible unused
- // Read more bytes to beginning to complete a word
- ff_buf = f->buffer;
- while(remrem--) *ff_buf++ = *src_u8++;
- }
- else
- {
- ff_buf = f->buffer; // wrap around to beginning
- }
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE & 4
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE != 4
+ if (data_stride == 4)
+ #endif
+ {
+ tu_unaligned_write32(dest, *((const volatile uint32_t *)hwfifo));
+ }
+ #endif
- // Write data wrapped part
- if (wrap_bytes > 0) _ff_push_const_addr(ff_buf, app_buf, wrap_bytes);
- }
- break;
-#endif
- default: break;
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE & 2
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE != 2
+ if (data_stride == 2)
+ #endif
+ {
+ tu_unaligned_write16(dest, *((const volatile uint16_t *)hwfifo));
}
-}
+ #endif
-// 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);
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE == 1
+ *(uint8_t *)dest = *((const volatile uint8_t *)hwfifo);
+ #endif
}
-// 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)
-{
- uint16_t const lin_count = f->depth - rd_ptr;
- uint16_t const wrap_count = n - lin_count; // only used if wrapped
+void tu_hwfifo_read(const volatile void *hwfifo, uint8_t *dest, uint16_t len, const tu_hwfifo_access_t *access_mode) {
+ // Reading full available 16/32-bit hwfifo and write to fifo
+ const uint8_t data_stride = (access_mode != NULL) ? access_mode->data_stride : CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE;
+ while (len >= data_stride) {
+ stride_read(hwfifo, dest, data_stride);
+ dest += data_stride;
+ len -= data_stride;
+ HWFIFO_ADDR_NEXT(hwfifo, const);
+ }
- uint16_t lin_bytes = lin_count * f->item_size;
- uint16_t wrap_bytes = wrap_count * f->item_size;
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE > 1
+ #ifdef CFG_TUSB_FIFO_HWFIFO_DATA_ODD_16BIT_ACCESS
+ // 16-bit access is allowed for odd bytes
+ if (len >= 2) {
+ tu_unaligned_write16(dest, *((const volatile uint16_t *)hwfifo));
+ dest += 2;
+ len -= 2;
+ HWFIFO_ADDR_NEXT_N(hwfifo, const, 2);
+ }
+ #endif
- // current buffer of fifo
- uint8_t* ff_buf = f->buffer + (rd_ptr * f->item_size);
+ #ifdef CFG_TUSB_FIFO_HWFIFO_DATA_ODD_8BIT_ACCESS
+ // 8-bit access is allowed for odd bytes
+ while (len > 0) {
+ *dest++ = *((const volatile uint8_t *)hwfifo);
+ len--;
+ HWFIFO_ADDR_NEXT_N(hwfifo, const, 1);
+ }
+ #else
+ // Read odd bytes i.e 1 byte for 16 bit or 1-3 bytes for 32 bit
+ if (len > 0) {
+ uint32_t tmp;
+ stride_read(hwfifo, &tmp, data_stride);
+ memcpy(dest, &tmp, len);
+ HWFIFO_ADDR_NEXT(hwfifo, const);
+ }
+ #endif
+ #endif
+}
+ #endif
- switch (copy_mode)
- {
- case TU_FIFO_COPY_INC:
- if ( n <= lin_count )
- {
- // Linear only
- memcpy(app_buf, ff_buf, n*f->item_size);
- }
- else
- {
- // Wrap around
+// push to sw fifo from hwfifo
+static void hwff_push_n(const tu_fifo_t *f, const void *app_buf, uint16_t n, uint16_t wr_ptr,
+ const tu_hwfifo_access_t *access_mode) {
+ uint16_t lin_bytes = f->depth - wr_ptr;
+ uint16_t wrap_bytes = n - lin_bytes;
+ uint8_t *ff_buf = f->buffer + wr_ptr;
- // Read data from linear part of buffer
- memcpy(app_buf, ff_buf, lin_bytes);
+ const volatile void *hwfifo = (const volatile void *)app_buf;
+ if (n <= lin_bytes) {
+ // Linear only case
+ tu_hwfifo_read(hwfifo, ff_buf, n, access_mode);
+ } else {
+ // Wrap around case
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE == 1
+ tu_hwfifo_read(hwfifo, ff_buf, lin_bytes, access_mode); // linear part
+ HWFIFO_ADDR_NEXT_N(hwfifo, const, lin_bytes);
+ tu_hwfifo_read(hwfifo, f->buffer, wrap_bytes, access_mode); // wrapped part
+ #else
+ // Write full words to the linear part of the buffer
+ const uint8_t data_stride = access_mode->data_stride;
+ const uint32_t odd_mask = data_stride - 1;
+ uint16_t lin_even = (uint16_t)(lin_bytes & ~odd_mask);
+ tu_hwfifo_read(hwfifo, ff_buf, lin_even, access_mode);
+ HWFIFO_ADDR_NEXT_N(hwfifo, const, lin_even * HWFIFO_ADDR_DATA_RATIO);
+ ff_buf += lin_even;
- // Read data wrapped part
- memcpy((uint8_t*) app_buf + lin_bytes, f->buffer, wrap_bytes);
+ // There could be an odd 1 byte (16bit) or 1-3 bytes (32bit) before the wrap-around boundary
+ // combine it with the wrapped part to form a full word for data stride
+ const uint8_t lin_odd = (uint8_t)(lin_bytes & odd_mask);
+ if (lin_odd > 0) {
+ const uint8_t wrap_odd = (uint8_t)tu_min16(wrap_bytes, data_stride - lin_odd);
+ uint8_t buf_temp[4];
+ tu_hwfifo_read(hwfifo, buf_temp, lin_odd + wrap_odd, access_mode);
+ HWFIFO_ADDR_NEXT(hwfifo, const);
+
+ for (uint8_t i = 0; i < lin_odd; ++i) {
+ ff_buf[i] = buf_temp[i];
}
- break;
-#ifdef TUP_MEM_CONST_ADDR
- case TU_FIFO_COPY_CST_FULL_WORDS:
- if ( n <= lin_count )
- {
- // Linear only
- _ff_pull_const_addr(app_buf, ff_buf, n*f->item_size);
+ for (uint8_t i = 0; i < wrap_odd; ++i) {
+ f->buffer[i] = buf_temp[lin_odd + i];
}
- else
- {
- // Wrap around case
-
- // Read full words from linear part of buffer
- uint16_t lin_4n_bytes = lin_bytes & 0xFFFC;
- _ff_pull_const_addr(app_buf, 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;
- if (rem > 0)
- {
- volatile uint32_t * reg_tx = (volatile uint32_t *) app_buf;
+ wrap_bytes -= wrap_odd;
+ ff_buf = f->buffer + wrap_odd; // wrap around
+ } else {
+ ff_buf = f->buffer; // wrap around to beginning
+ }
- uint8_t remrem = (uint8_t) tu_min16(wrap_bytes, 4-rem);
- wrap_bytes -= remrem;
+ // Write data wrapped part
+ if (wrap_bytes > 0) {
+ tu_hwfifo_read(hwfifo, ff_buf, wrap_bytes, access_mode);
+ }
+ #endif
+ }
+}
- uint32_t tmp32=0;
- uint8_t * dst_u8 = (uint8_t *)&tmp32;
+// pull from sw fifo to hwfifo
+static void hwff_pull_n(const tu_fifo_t *f, void *app_buf, uint16_t n, uint16_t rd_ptr,
+ const tu_hwfifo_access_t *access_mode) {
+ uint16_t lin_bytes = f->depth - rd_ptr;
+ uint16_t wrap_bytes = n - lin_bytes; // only used if wrapped
+ const uint8_t *ff_buf = f->buffer + rd_ptr;
- // Read 1-3 bytes before wrapped boundary
- while(rem--) *dst_u8++ = *ff_buf++;
+ volatile void *hwfifo = (volatile void *)app_buf;
- // Read more bytes from beginning to complete a word
- ff_buf = f->buffer;
- while(remrem--) *dst_u8++ = *ff_buf++;
+ if (n <= lin_bytes) {
+ // Linear only case
+ tu_hwfifo_write(hwfifo, ff_buf, n, access_mode);
+ } else {
+ // Wrap around case
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE == 1
+ tu_hwfifo_write(hwfifo, ff_buf, lin_bytes, access_mode); // linear part
+ HWFIFO_ADDR_NEXT_N(hwfifo, , lin_bytes);
+ tu_hwfifo_write(hwfifo, f->buffer, wrap_bytes, access_mode); // wrapped part
+ #else
+ // Read full words from linear part
+ const uint8_t data_stride = access_mode->data_stride;
+ const uint32_t odd_mask = data_stride - 1;
+ uint16_t lin_even = (uint16_t)(lin_bytes & ~odd_mask);
+ tu_hwfifo_write(hwfifo, ff_buf, lin_even, access_mode);
+ HWFIFO_ADDR_NEXT_N(hwfifo, , lin_even * HWFIFO_ADDR_DATA_RATIO);
+ ff_buf += lin_even;
- *reg_tx = tmp32;
- }
- else
- {
- ff_buf = f->buffer; // wrap around to beginning
- }
+ // There could be odd 1 byte (16bit) or 1-3 bytes (32bit) before the wrap-around boundary
+ const uint8_t lin_odd = (uint8_t)(lin_bytes & odd_mask);
+ if (lin_odd > 0) {
+ const uint8_t wrap_odd = (uint8_t)tu_min16(wrap_bytes, data_stride - lin_odd);
- // Read data wrapped part
- if (wrap_bytes > 0) _ff_pull_const_addr(app_buf, ff_buf, wrap_bytes);
+ uint8_t buf_temp[4];
+ for (uint8_t i = 0; i < lin_odd; ++i) {
+ buf_temp[i] = ff_buf[i];
}
- break;
-#endif
- default: break;
+ for (uint8_t i = 0; i < wrap_odd; ++i) {
+ buf_temp[lin_odd + i] = f->buffer[i];
+ }
+
+ tu_hwfifo_write(hwfifo, buf_temp, lin_odd + wrap_odd, access_mode);
+ HWFIFO_ADDR_NEXT(hwfifo, );
+
+ wrap_bytes -= wrap_odd;
+ ff_buf = f->buffer + wrap_odd; // wrap around
+ } else {
+ ff_buf = f->buffer; // wrap around to beginning
+ }
+
+ // Read data wrapped part
+ if (wrap_bytes > 0) {
+ tu_hwfifo_write(hwfifo, ff_buf, wrap_bytes, access_mode);
+ }
+ #endif
}
}
+#endif
//--------------------------------------------------------------------+
-// Helper
+// Pull & Push
+// copy data to/from fifo without updating read/write pointers
//--------------------------------------------------------------------+
+// send n items to fifo WITHOUT updating write pointer
+static void ff_push_n(const tu_fifo_t *f, const void *app_buf, uint16_t n, uint16_t wr_ptr) {
+ uint16_t lin_bytes = f->depth - wr_ptr;
+ uint16_t wrap_bytes = n - lin_bytes;
+ uint8_t *ff_buf = f->buffer + wr_ptr;
-// 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));
+ if (n <= lin_bytes) {
+ // Linear only case
+ memcpy(ff_buf, app_buf, n);
+ } else {
+ // Wrap around case
+ memcpy(ff_buf, app_buf, lin_bytes); // linear part
+ memcpy(f->buffer, ((const uint8_t *)app_buf) + lin_bytes, wrap_bytes); // wrapped part
}
}
-// 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)
-{
- uint16_t const count = _ff_count(depth, wr_idx, rd_idx);
- return (depth > count) ? (depth - count) : 0;
+// get n items from fifo WITHOUT updating read pointer
+static void ff_pull_n(const tu_fifo_t *f, void *app_buf, uint16_t n, uint16_t rd_ptr) {
+ uint16_t lin_bytes = f->depth - rd_ptr;
+ uint16_t wrap_bytes = n - lin_bytes; // only used if wrapped
+ const uint8_t *ff_buf = f->buffer + rd_ptr;
+
+ // single byte access
+ if (n <= lin_bytes) {
+ // Linear only
+ memcpy(app_buf, ff_buf, n);
+ } else {
+ // Wrap around
+ memcpy(app_buf, ff_buf, lin_bytes); // linear part
+ memcpy((uint8_t *)app_buf + lin_bytes, f->buffer, wrap_bytes); // wrapped part
+ }
}
//--------------------------------------------------------------------+
@@ -353,152 +417,134 @@ uint16_t _ff_remaining(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx)
// 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)
-{
+static 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
- 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);
+ uint16_t new_idx = (uint16_t)(idx + offset);
+ if ((idx > new_idx) || (new_idx >= 2 * depth)) {
+ const uint16_t non_used_index_space = (uint16_t)(UINT16_MAX - (2 * depth - 1));
+ new_idx = (uint16_t)(new_idx + non_used_index_space);
}
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.
-TU_ATTR_ALWAYS_INLINE static inline
-uint16_t idx2ptr(uint16_t depth, uint16_t idx)
-{
+// 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 ) idx -= depth;
+ while (idx >= depth) {
+ idx -= depth;
+ }
return idx;
}
// 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
+static uint16_t correct_read_index(tu_fifo_t *f, uint16_t wr_idx) {
uint16_t rd_idx;
- if ( wr_idx >= f->depth )
- {
+ if (wr_idx >= f->depth) {
rd_idx = wr_idx - f->depth;
- }else
- {
+ } else {
rd_idx = wr_idx + f->depth;
}
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);
+//--------------------------------------------------------------------+
+// n-API
+//--------------------------------------------------------------------+
- // nothing to peek
- if ( cnt == 0 ) return false;
+// Works on local copies of w and r
+// Must be protected by read mutex since in case of an overflow read pointer gets modified
+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,
+ const tu_hwfifo_access_t *access_mode) {
+ uint16_t count = tu_ff_overflow_count(f->depth, wr_idx, rd_idx);
+ if (count == 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);
+ if (count > f->depth) {
+ rd_idx = correct_read_index(f, wr_idx);
+ count = f->depth;
}
- uint16_t rd_ptr = idx2ptr(f->depth, rd_idx);
-
- // Peek data
- _ff_pull(f, p_buffer, rd_ptr);
-
- return true;
-}
-
-// 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);
+ if (count < n) {
+ n = count; // limit to available count
+ }
- // nothing to peek
- if ( cnt == 0 ) return 0;
+ const uint16_t rd_ptr = idx2ptr(f->depth, rd_idx);
- // Check overflow and correct if required
- if ( cnt > f->depth )
+#if CFG_TUSB_FIFO_HWFIFO_API
+ if (access_mode != NULL) {
+ hwff_pull_n(f, p_buffer, n, rd_ptr, access_mode);
+ } else
+#endif
{
- rd_idx = _ff_correct_read_index(f, wr_idx);
- cnt = f->depth;
+ (void)access_mode;
+ ff_pull_n(f, p_buffer, n, rd_ptr);
}
- // Check if we can read something at and after offset - if too less is available we read what remains
- if ( cnt < n ) n = cnt;
+ return n;
+}
+
+// Read n items without removing it from the FIFO, correct read pointer if overflowed
+uint16_t tu_fifo_peek_n(tu_fifo_t *f, void *p_buffer, uint16_t n) {
+ ff_lock(f->mutex_rd);
+ const uint16_t wr_idx = f->wr_idx;
+ const uint16_t rd_idx = f->rd_idx;
+ const uint16_t ret = tu_fifo_peek_n_access_mode(f, p_buffer, n, wr_idx, rd_idx, NULL);
+ ff_unlock(f->mutex_rd);
+ return ret;
+}
- uint16_t rd_ptr = idx2ptr(f->depth, rd_idx);
+// Read n items from fifo with access mode
+uint16_t tu_fifo_read_n_access_mode(tu_fifo_t *f, void *buffer, uint16_t n, const tu_hwfifo_access_t *access_mode) {
+ ff_lock(f->mutex_rd);
- // Peek data
- _ff_pull_n(f, p_buffer, n, rd_ptr, copy_mode);
+ // Peek the data: f->rd_idx might get modified in case of an overflow so we can not use a local variable
+ const uint16_t wr_idx = f->wr_idx;
+ n = tu_fifo_peek_n_access_mode(f, buffer, n, wr_idx, f->rd_idx, access_mode);
+ f->rd_idx = advance_index(f->depth, f->rd_idx, n);
+ ff_unlock(f->mutex_rd);
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)
-{
- if ( n == 0 ) return 0;
+// Write n items to fifo with access mode
+uint16_t tu_fifo_write_n_access_mode(tu_fifo_t *f, const void *data, uint16_t n,
+ const tu_hwfifo_access_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;
- uint8_t const* buf8 = (uint8_t const*) data;
+ 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 )
- {
+ if (!f->overwritable) {
// limit up to full
- uint16_t const remain = _ff_remaining(f->depth, wr_idx, rd_idx);
- n = tu_min16(n, remain);
- }
- else
- {
+ 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!
- if ( n >= f->depth )
- {
+ // 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 )
- {
- buf8 += (n - f->depth) * f->item_size;
- }else
- {
+ if (access_mode == NULL) {
+ buf8 += (n - f->depth);
+ } else {
// TODO should read from hw fifo to discard data, however reading an odd number could
// accidentally discard data.
}
@@ -507,12 +553,9 @@ 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
- {
- uint16_t const overflowable_count = _ff_count(f->depth, wr_idx, rd_idx);
- if (overflowable_count + n >= 2*f->depth)
- {
+ } else {
+ 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)
// re-position write index to have a full fifo after pushed
@@ -522,8 +565,7 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu
// However memmove() is expensive due to actual copying + wrapping consideration.
// Also race condition could happen anyway if read() is invoke while moving result in corrupted memory
// currently deliberately not implemented --> result in incorrect data read back
- }else
- {
+ } else {
// normal + single overflowed:
// Index is in the range of [0,2*depth) and thus detect and recoverable. Recovering is handled in read()
// Therefore we just increase write index
@@ -532,404 +574,108 @@ 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);
-
+ if (n) {
+ const uint16_t wr_ptr = idx2ptr(f->depth, wr_idx);
TU_LOG(TU_FIFO_DBG, "actual_n = %u, wr_ptr = %u", n, wr_ptr);
- // Write data
- _ff_push_n(f, buf8, n, wr_ptr, copy_mode);
-
- // Advance index
+#if CFG_TUSB_FIFO_HWFIFO_API
+ if (access_mode != NULL) {
+ hwff_push_n(f, buf8, n, wr_ptr, access_mode);
+ } else
+#endif
+ {
+ ff_push_n(f, buf8, n, wr_ptr);
+ }
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_discard_n(tu_fifo_t *f, uint16_t n) {
+ const uint16_t count = tu_min16(n, tu_fifo_count(f)); // limit to available count
+ ff_lock(f->mutex_rd);
+ f->rd_idx = advance_index(f->depth, f->rd_idx, count);
+ ff_unlock(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
- f->rd_idx = advance_index(f->depth, f->rd_idx, n);
-
- _ff_unlock(f->mutex_rd);
- return n;
+ return count;
}
//--------------------------------------------------------------------+
-// Application API
+// One 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(tu_fifo_t* f)
-{
- return tu_min16(_ff_count(f->depth, f->wr_idx, f->rd_idx), f->depth);
-}
-
-/******************************************************************************/
-/*!
- @brief Check if FIFO is empty.
-
- 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_empty(tu_fifo_t* f)
-{
- return f->wr_idx == f->rd_idx;
-}
-
-/******************************************************************************/
-/*!
- @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(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(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().
+// peek() using local write/read index, correct read index if overflowed
+// Be careful, caller must not lock mutex, since this Will also try to lock mutex
+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
+ }
- @param[in] f
- Pointer to the FIFO buffer to manipulate
+ // 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);
+ }
- @returns True if overflow happened
- */
-/******************************************************************************/
-bool tu_fifo_overflowed(tu_fifo_t* f)
-{
- return _ff_count(f->depth, f->wr_idx, f->rd_idx) > f->depth;
-}
+ const uint16_t rd_ptr = idx2ptr(f->depth, rd_idx);
+ memcpy(buf, f->buffer + rd_ptr, 1);
-// 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);
+ return true;
}
-/******************************************************************************/
-/*!
- @brief Read one element out of the buffer.
-
- This function will return the element located at the array index of the
- read pointer, and then increment the read pointer 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
- Pointer to the place holder for data read from the buffer
-
- @returns TRUE if the queue is not empty
- */
-/******************************************************************************/
-bool tu_fifo_read(tu_fifo_t* f, void * buffer)
-{
- _ff_lock(f->mutex_rd);
-
+// Read one element out of the buffer, correct read index if overflowed
+bool tu_fifo_read(tu_fifo_t *f, void *buffer) {
// 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);
-
- _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.
-
- @param[in] f
- Pointer to the FIFO buffer to manipulate
- @param[in] p_buffer
- Pointer to the place holder for data read from the buffer
+ const uint16_t wr_idx = f->wr_idx;
+ const bool ret = ff_peek_local(f, buffer, 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);
+ }
- @returns TRUE if the queue is not empty
- */
-/******************************************************************************/
-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;
}
-/******************************************************************************/
-/*!
- @brief Read n items without removing it from the 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] p_buffer
- Pointer to the place holder for data read from the buffer
- @param[in] n
- Number of items to peek
-
- @returns Number of bytes written to 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);
- return ret;
+// Read one item without removing it from the FIFO, correct read index if overflowed
+bool tu_fifo_peek(tu_fifo_t *f, void *p_buffer) {
+ const uint16_t wr_idx = f->wr_idx;
+ const uint16_t rd_idx = f->rd_idx;
+ return ff_peek_local(f, p_buffer, wr_idx, rd_idx);
}
-/******************************************************************************/
-/*!
- @brief Write one element into the buffer.
-
- This function will write one element 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 byte to add to the FIFO
-
- @returns TRUE if the data was written to the FIFO (overwrittable
- FIFO will always return TRUE)
- */
-/******************************************************************************/
-bool tu_fifo_write(tu_fifo_t* f, const void * data)
-{
- _ff_lock(f->mutex_wr);
-
+// Write one element into the buffer
+bool tu_fifo_write(tu_fifo_t *f, const void *data) {
bool ret;
- uint16_t const 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_lock(f->mutex_wr);
- // Write data
- _ff_push(f, data, wr_ptr);
+ const uint16_t wr_idx = f->wr_idx;
- // Advance pointer
+ if (tu_fifo_full(f) && !f->overwritable) {
+ ret = false;
+ } else {
+ const uint16_t wr_ptr = idx2ptr(f->depth, wr_idx);
+ memcpy(f->buffer + wr_ptr, data, 1);
f->wr_idx = advance_index(f->depth, wr_idx, 1);
-
- ret = true;
+ 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
- Pointer to the FIFO buffer to manipulate
- */
-/******************************************************************************/
-bool tu_fifo_clear(tu_fifo_t *f)
-{
- _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);
- return true;
-}
-
-/******************************************************************************/
-/*!
- @brief Change the fifo mode to overwritable or not overwritable
-
- @param[in] 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) {
- if (f->overwritable == overwritable) {
- return true;
- }
-
- _ff_lock(f->mutex_wr);
- _ff_lock(f->mutex_rd);
-
- f->overwritable = overwritable;
-
- _ff_unlock(f->mutex_wr);
- _ff_unlock(f->mutex_rd);
-
- return true;
-}
+//--------------------------------------------------------------------+
+// Index API
+//--------------------------------------------------------------------+
/******************************************************************************/
/*!
@@ -947,11 +693,17 @@ bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) {
Number of items the write pointer moves forward
*/
/******************************************************************************/
-void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n)
-{
+void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n) {
f->wr_idx = advance_index(f->depth, f->wr_idx, n);
}
+// Correct the read index in case tu_fifo_overflow() returned true!
+void tu_fifo_correct_read_pointer(tu_fifo_t *f) {
+ ff_lock(f->mutex_rd);
+ correct_read_index(f, f->wr_idx);
+ ff_unlock(f->mutex_rd);
+}
+
/******************************************************************************/
/*!
@brief Advance read pointer - intended to be used in combination with DMA.
@@ -968,8 +720,7 @@ void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n)
Number of items the read pointer moves forward
*/
/******************************************************************************/
-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) {
f->rd_idx = advance_index(f->depth, f->rd_idx, n);
}
@@ -988,31 +739,28 @@ void tu_fifo_advance_read_pointer(tu_fifo_t *f, uint16_t n)
Pointer to struct which holds the desired infos
*/
/******************************************************************************/
-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) {
// Operate on temporary values in case they change in between
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);
+ if (cnt > f->depth) {
+ 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;
+ if (cnt == 0) {
+ info->linear.len = 0;
+ info->wrapped.len = 0;
+ info->linear.ptr = NULL;
+ info->wrapped.ptr = NULL;
return;
}
@@ -1021,23 +769,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)
- {
+ if (wr_ptr > rd_ptr) {
// Non wrapping case
- info->len_lin = cnt;
+ info->linear.len = cnt;
- info->len_wrap = 0;
- info->ptr_wrap = NULL;
- }
- else
- {
- info->len_lin = f->depth - rd_ptr; // Also the case if FIFO was full
+ info->wrapped.len = 0;
+ info->wrapped.ptr = NULL;
+ } else {
+ 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;
}
}
@@ -1056,18 +801,16 @@ void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info)
Pointer to struct which holds the desired infos
*/
/******************************************************************************/
-void tu_fifo_get_write_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;
+ if (remain == 0) {
+ info->linear.len = 0;
+ info->wrapped.len = 0;
+ info->linear.ptr = NULL;
+ info->wrapped.ptr = NULL;
return;
}
@@ -1076,19 +819,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)
- {
+ if (wr_ptr < rd_ptr) {
// Non wrapping case
- info->len_lin = rd_ptr-wr_ptr;
- info->len_wrap = 0;
- info->ptr_wrap = 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 = rd_ptr - wr_ptr;
+ info->wrapped.len = 0;
+ info->wrapped.ptr = NULL;
+ } else {
+ 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 879acda4f..b31a0802e 100644
--- a/src/common/tusb_fifo.h
+++ b/src/common/tusb_fifo.h
@@ -25,13 +25,32 @@
* This file is part of the TinyUSB stack.
*/
-#ifndef _TUSB_FIFO_H_
-#define _TUSB_FIFO_H_
+#ifndef TUSB_FIFO_H_
+#define TUSB_FIFO_H_
#ifdef __cplusplus
extern "C" {
#endif
+#include "common/tusb_common.h"
+#include "osal/osal.h"
+
+//--------------------------------------------------------------------+
+// Configuration
+//--------------------------------------------------------------------+
+// mutex is only needed for RTOS. For OS None, we don't get preempted
+#define CFG_FIFO_MUTEX OSAL_MUTEX_REQUIRED
+
+#define CFG_TUSB_FIFO_HWFIFO_API (CFG_TUD_EDPT_DEDICATED_HWFIFO || CFG_TUH_EDPT_DEDICATED_HWFIFO)
+
+#ifndef CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE
+ #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 0
+#endif
+
+#ifndef CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE
+ #define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 0
+#endif
+
// Due to the use of unmasked pointers, this FIFO does not suffer from losing
// one item slice. Furthermore, write and read operations are completely
// decoupled as write and read functions do not modify a common state. Henceforth,
@@ -41,15 +60,9 @@ extern "C" {
// read pointers can be updated from within a DMA ISR. Overflows are detectable
// within a certain number (see tu_fifo_overflow()).
-#include "common/tusb_common.h"
-#include "osal/osal.h"
-
-// mutex is only needed for RTOS
-// 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
+/* 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
*
@@ -104,45 +117,55 @@ extern "C" {
* | R | 1 | 2 | W | 4 | 5 |
*/
typedef struct {
- uint8_t* buffer ; // buffer pointer
- uint16_t depth ; // max items
+ uint8_t *buffer; // buffer pointer
+ uint16_t depth; // max items
+ bool overwritable; // overwritable when full
+ // 1 byte padding here
- struct TU_ATTR_PACKED {
- uint16_t item_size : 15; // size of each item
- bool overwritable : 1 ; // ovwerwritable when full
- };
-
- volatile uint16_t wr_idx ; // write index
- volatile uint16_t rd_idx ; // read index
+ volatile uint16_t wr_idx; // write index
+ volatile uint16_t rd_idx; // read index
#if OSAL_MUTEX_REQUIRED
osal_mutex_t mutex_wr;
osal_mutex_t mutex_rd;
#endif
-
} 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){\
- .buffer = _buffer, \
- .depth = _depth, \
- .item_size = sizeof(_type), \
- .overwritable = _overwritable, \
-}
+// Access mode for hardware fifo read/write
+typedef struct {
+ uint8_t data_stride;
+ uintptr_t param;
+} tu_hwfifo_access_t;
-#define TU_FIFO_DEF(_name, _depth, _type, _overwritable) \
- uint8_t _name##_buf[_depth*sizeof(_type)]; \
- tu_fifo_t _name = TU_FIFO_INIT(_name##_buf, _depth, _type, _overwritable)
+#define TU_FIFO_INIT(_buffer, _depth, _overwritable) \
+ { \
+ .buffer = _buffer, \
+ .depth = _depth, \
+ .overwritable = _overwritable, \
+ }
-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);
+#define TU_FIFO_DEF(_name, _depth, _overwritable) \
+ uint8_t _name##_buf[_depth]; \
+ tu_fifo_t _name = TU_FIFO_INIT(_name##_buf, _depth, _overwritable)
+
+// Moving data from tusb_fifo <-> USB hardware FIFOs e.g. STM32s need to use a special stride mode which reads/writes
+// data in 2/4 byte chunks from/to a fixed address (USB FIFO register) instead of incrementing the address. For this use
+// read/write access_mode with stride_mode = true. The STRIDE DATA and ADDR stride must be configured with
+// CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE and CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE
+
+//--------------------------------------------------------------------+
+// Setup API
+//--------------------------------------------------------------------+
+bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, bool overwritable);
+void tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable);
+void tu_fifo_clear(tu_fifo_t *f);
#if OSAL_MUTEX_REQUIRED
TU_ATTR_ALWAYS_INLINE static inline
@@ -154,46 +177,140 @@ 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, void const * data, 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);
-#endif
-
-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_read_n_const_addr_full_words (tu_fifo_t* f, void * buffer, uint16_t n);
-#endif
-
-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 (tu_fifo_t* f);
-uint16_t tu_fifo_remaining (tu_fifo_t* f);
-bool tu_fifo_empty (tu_fifo_t* f);
-bool tu_fifo_full (tu_fifo_t* f);
-bool tu_fifo_overflowed (tu_fifo_t* f);
-void tu_fifo_correct_read_pointer (tu_fifo_t* f);
-
-TU_ATTR_ALWAYS_INLINE static inline
-uint16_t tu_fifo_depth(tu_fifo_t* f) {
- return f->depth;
-}
+//--------------------------------------------------------------------+
+// 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);
+//--------------------------------------------------------------------+
+// 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,
+ const tu_hwfifo_access_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);
+
+//--------------------------------------------------------------------+
+// Read API
+// peek() + advance read index
+//--------------------------------------------------------------------+
+uint16_t tu_fifo_read_n_access_mode(tu_fifo_t *f, void *buffer, uint16_t n, const tu_hwfifo_access_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, NULL);
+}
+
+// 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);
+
+//--------------------------------------------------------------------+
+// Write API
+//--------------------------------------------------------------------+
+uint16_t tu_fifo_write_n_access_mode(tu_fifo_t *f, const void *data, uint16_t n, const tu_hwfifo_access_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, NULL);
+}
+
+//--------------------------------------------------------------------+
+// Hardware FIFO API
+// Special hardware FIFO/Buffer to hold USB data, usually requires certain access method these can be configured with
+// CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE (data width) and CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE (address increment)
+// Note: these usually has opposite direction (read/write) to/from our software FIFO (tu_fifo_t)
+//--------------------------------------------------------------------+
+TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_hwfifo_write_from_fifo(volatile void *hwfifo, tu_fifo_t *f, uint16_t n,
+ const tu_hwfifo_access_t *access_mode) {
+ const tu_hwfifo_access_t default_access = {.data_stride = CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE, .param = 0};
+ return tu_fifo_read_n_access_mode(f, (void *)(uintptr_t)hwfifo, n,
+ (access_mode != NULL) ? access_mode : &default_access);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_hwfifo_read_to_fifo(const volatile void *hwfifo, tu_fifo_t *f,
+ uint16_t n, const tu_hwfifo_access_t *access_mode) {
+ const tu_hwfifo_access_t default_access = {.data_stride = CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE, .param = 0};
+ return tu_fifo_write_n_access_mode(f, (const void *)(uintptr_t)hwfifo, n,
+ (access_mode != NULL) ? access_mode : &default_access);
+}
+
+#if CFG_TUSB_FIFO_HWFIFO_API
+// read from hwfifo to buffer
+void tu_hwfifo_read(const volatile void *hwfifo, uint8_t *dest, uint16_t len, const tu_hwfifo_access_t *access_mode);
+
+// write to hwfifo from buffer with access mode
+void tu_hwfifo_write(volatile void *hwfifo, const uint8_t *src, uint16_t len, const tu_hwfifo_access_t *access_mode);
+
+#endif
+
+//--------------------------------------------------------------------+
+// 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) {
+ const int32_t diff = (int32_t)wr_idx - (int32_t)rd_idx;
+ if (diff >= 0) {
+ return (uint16_t)diff;
+ } else {
+ return (uint16_t)(2 * depth + diff);
+ }
+}
+
+// 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) {
+ const uint16_t wr_idx = f->wr_idx;
+ const uint16_t rd_idx = f->rd_idx;
+ return tu_min16(tu_ff_overflow_count(f->depth, wr_idx, rd_idx), f->depth);
+}
+
+// check if fifo is full
+TU_ATTR_ALWAYS_INLINE static inline bool tu_fifo_full(const tu_fifo_t *f) {
+ const uint16_t wr_idx = f->wr_idx;
+ const uint16_t rd_idx = f->rd_idx;
+ return tu_ff_overflow_count(f->depth, wr_idx, rd_idx) >= f->depth;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_fifo_remaining(const tu_fifo_t *f) {
+ const uint16_t wr_idx = f->wr_idx;
+ const uint16_t rd_idx = f->rd_idx;
+ return tu_ff_remaining_local(f->depth, wr_idx, rd_idx);
+}
+
#ifdef __cplusplus
}
#endif
-#endif /* _TUSB_FIFO_H_ */
+#endif
diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h
index 1c11df114..b5390a59d 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
@@ -37,14 +36,14 @@
#ifdef __ARM_ARCH
// ARM Architecture set __ARM_FEATURE_UNALIGNED to 1 for mcu supports unaligned access
#if defined(__ARM_FEATURE_UNALIGNED) && __ARM_FEATURE_UNALIGNED == 1
- #define TUP_ARCH_STRICT_ALIGN 0
+ #define TUP_ARCH_STRICT_ALIGN 0
#else
- #define TUP_ARCH_STRICT_ALIGN 1
+ #define TUP_ARCH_STRICT_ALIGN 1
#endif
#else
// TODO default to strict align for others
// Should investigate other architecture such as risv, xtensa, mips for optimal setting
- #define TUP_ARCH_STRICT_ALIGN 1
+ #define TUP_ARCH_STRICT_ALIGN 1
#endif
/* USB Controller Attributes for Device, Host or MCU (both)
@@ -57,36 +56,52 @@
//--------------------------------------------------------------------+
// NXP
//--------------------------------------------------------------------+
-#if TU_CHECK_MCU(OPT_MCU_LPC11UXX, OPT_MCU_LPC13XX, OPT_MCU_LPC15XX)
+#if TU_CHECK_MCU(OPT_MCU_LPC11UXX, OPT_MCU_LPC13XX, OPT_MCU_LPC15XX)
#define TUP_USBIP_IP3511
- #define TUP_DCD_ENDPOINT_MAX 5
+ #define TUP_DCD_ENDPOINT_MAX 5
#elif TU_CHECK_MCU(OPT_MCU_LPC175X_6X, OPT_MCU_LPC177X_8X, OPT_MCU_LPC40XX)
- #define TUP_DCD_ENDPOINT_MAX 16
+ #define TUP_DCD_ENDPOINT_MAX 16
#define TUP_USBIP_OHCI
- #define TUP_OHCI_RHPORTS 2
+ #define TUP_USBIP_OHCI_NXP
+ #define TUP_OHCI_RHPORTS 2
#elif TU_CHECK_MCU(OPT_MCU_LPC51UXX)
- #define TUP_USBIP_IP3511
- #define TUP_DCD_ENDPOINT_MAX 5
+ #define TUP_USBIP_IP3511
+ #define TUP_DCD_ENDPOINT_MAX 5
#elif TU_CHECK_MCU(OPT_MCU_LPC54)
+ #include "fsl_device_registers.h"
+
// TODO USB0 has 5, USB1 has 6
#define TUP_USBIP_IP3511
- #define TUP_DCD_ENDPOINT_MAX 6
+
+ #if !defined(LPC54114_cm4_SERIES) && !defined(LPC54114_cm0plus_SERIES)
+ #define TUP_USBIP_IP3516
+ #define TUP_USBIP_OHCI
+ #define TUP_USBIP_OHCI_NXP
+ #define TUP_OHCI_RHPORTS 1 // 1 downstream port
+ #endif
+
+ #define TUP_DCD_ENDPOINT_MAX 6
#elif TU_CHECK_MCU(OPT_MCU_LPC55)
// TODO USB0 has 5, USB1 has 6
#define TUP_USBIP_IP3511
- #define TUP_DCD_ENDPOINT_MAX 6
+ #define TUP_USBIP_IP3516
+ #define TUP_USBIP_OHCI
+ #define TUP_USBIP_OHCI_NXP
+ #define TUP_OHCI_RHPORTS 1 // 1 downstream port
+
+ #define TUP_DCD_ENDPOINT_MAX 6
#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
// USB0 has 6 with HS PHY, USB1 has 4 only FS
#define TUP_USBIP_CHIPIDEA_HS
#define TUP_USBIP_EHCI
- #define TUP_DCD_ENDPOINT_MAX 6
- #define TUP_RHPORT_HIGHSPEED 1
+ #define TUP_DCD_ENDPOINT_MAX 6
+ #define TUP_RHPORT_HIGHSPEED 1
#elif TU_CHECK_MCU(OPT_MCU_MCXN9)
// USB0 is chipidea FS
@@ -97,15 +112,23 @@
#define TUP_USBIP_CHIPIDEA_HS
#define TUP_USBIP_EHCI
- #define TUP_DCD_ENDPOINT_MAX 8
- #define TUP_RHPORT_HIGHSPEED 1
+ #define TUP_DCD_ENDPOINT_MAX 8
+ #define TUP_RHPORT_HIGHSPEED 1
#elif TU_CHECK_MCU(OPT_MCU_MCXA15)
// USB0 is chipidea FS
#define TUP_USBIP_CHIPIDEA_FS
#define TUP_USBIP_CHIPIDEA_FS_MCX
- #define TUP_DCD_ENDPOINT_MAX 16
+ #define TUP_DCD_ENDPOINT_MAX 16
+
+#elif TU_CHECK_MCU(OPT_MCU_RW61X)
+ // USB0 is chipidea HS
+ #define TUP_USBIP_CHIPIDEA_HS
+ #define TUP_USBIP_EHCI
+
+ #define TUP_DCD_ENDPOINT_MAX 8
+ #define TUP_RHPORT_HIGHSPEED 1
#elif TU_CHECK_MCU(OPT_MCU_MIMXRT1XXX)
#include "fsl_device_registers.h"
@@ -113,78 +136,102 @@
#define TUP_USBIP_CHIPIDEA_HS
#define TUP_USBIP_EHCI
- #define TUP_DCD_ENDPOINT_MAX 8
- #define TUP_RHPORT_HIGHSPEED 1
+ #define TUP_DCD_ENDPOINT_MAX 8
+ #define TUP_RHPORT_HIGHSPEED 1
#if __CORTEX_M == 7
- #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT 1
- #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT 1
- #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32
+ #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT 1
+ #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT 1
+ #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32
#endif
#elif TU_CHECK_MCU(OPT_MCU_KINETIS_KL, OPT_MCU_KINETIS_K32L, OPT_MCU_KINETIS_K)
#define TUP_USBIP_CHIPIDEA_FS
#define TUP_USBIP_CHIPIDEA_FS_KINETIS
- #define TUP_DCD_ENDPOINT_MAX 16
+ #define TUP_DCD_ENDPOINT_MAX 16
#elif TU_CHECK_MCU(OPT_MCU_MM32F327X)
- #define TUP_DCD_ENDPOINT_MAX 16
+ #define TUP_DCD_ENDPOINT_MAX 16
+ #define TUP_DCD_EDPT_CLOSE_API
//--------------------------------------------------------------------+
// Nordic
//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_NRF5X)
// 8 CBI + 1 ISO
- #define TUP_DCD_ENDPOINT_MAX 9
+ #define TUP_DCD_ENDPOINT_MAX 9
+ #define TUP_DCD_EDPT_CLOSE_API
+
+#elif TU_CHECK_MCU(OPT_MCU_NRF54)
+ #define TUP_USBIP_DWC2
+ #define TUP_USBIP_DWC2_NRF
+ #define TUP_DCD_ENDPOINT_MAX 16
+ #define TUP_RHPORT_HIGHSPEED 1
+ #define CFG_TUH_DWC2_DMA_ENABLE_DEFAULT 0
//--------------------------------------------------------------------+
// Microchip
//--------------------------------------------------------------------+
-#elif TU_CHECK_MCU(OPT_MCU_SAMD21, OPT_MCU_SAMD51, OPT_MCU_SAME5X) || \
- TU_CHECK_MCU(OPT_MCU_SAMD11, OPT_MCU_SAML21, OPT_MCU_SAML22)
- #define TUP_DCD_ENDPOINT_MAX 8
+#elif TU_CHECK_MCU(OPT_MCU_SAMD11, OPT_MCU_SAML2X, OPT_MCU_SAMD21) || TU_CHECK_MCU(OPT_MCU_SAMD51, OPT_MCU_SAME5X)
+ #define TUP_DCD_ENDPOINT_MAX 8
#elif TU_CHECK_MCU(OPT_MCU_SAMG)
- #define TUP_DCD_ENDPOINT_MAX 6
- #define TUD_ENDPOINT_ONE_DIRECTION_ONLY
+ #define TUP_DCD_ENDPOINT_MAX 6
+ #define CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY 1
#elif TU_CHECK_MCU(OPT_MCU_SAMX7X)
- #define TUP_DCD_ENDPOINT_MAX 10
- #define TUP_RHPORT_HIGHSPEED 1
- #define TUD_ENDPOINT_ONE_DIRECTION_ONLY
+ #define TUP_DCD_ENDPOINT_MAX 10
+ #define TUP_RHPORT_HIGHSPEED 1
+ #define CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY 1
+
+ // Enable dcache if DMA is enabled
+ #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_SAMX7X_DMA_ENABLE
+ #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32
#elif TU_CHECK_MCU(OPT_MCU_PIC32MZ)
- #define TUP_DCD_ENDPOINT_MAX 8
- #define TUD_ENDPOINT_ONE_DIRECTION_ONLY
+ #define TUP_DCD_ENDPOINT_MAX 8
+ #define CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY 1
-#elif TU_CHECK_MCU(OPT_MCU_PIC32MX, OPT_MCU_PIC32MM, OPT_MCU_PIC32MK) || \
- TU_CHECK_MCU(OPT_MCU_PIC24, OPT_MCU_DSPIC33)
- #define TUP_DCD_ENDPOINT_MAX 16
- #define TUD_ENDPOINT_ONE_DIRECTION_ONLY
+#elif TU_CHECK_MCU(OPT_MCU_PIC32MX, OPT_MCU_PIC32MM, OPT_MCU_PIC32MK) || TU_CHECK_MCU(OPT_MCU_PIC24, OPT_MCU_DSPIC33)
+ #define TUP_DCD_ENDPOINT_MAX 16
+ #define CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY 1
+ #define TUP_DCD_EDPT_CLOSE_API
//--------------------------------------------------------------------+
// ST
//--------------------------------------------------------------------+
+#elif TU_CHECK_MCU(OPT_MCU_STM32C0)
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
+ #define TUP_USBIP_FSDEV_DRD
+ #define CFG_TUSB_FSDEV_PMA_SIZE 2048u
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32C5)
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
+ #define TUP_USBIP_FSDEV_DRD
+ #define CFG_TUSB_FSDEV_PMA_SIZE 2048u
+
#elif TU_CHECK_MCU(OPT_MCU_STM32F0)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define CFG_TUSB_FSDEV_PMA_SIZE 1024u
#elif TU_CHECK_MCU(OPT_MCU_STM32F1)
// - F102, F103 use fsdev
// - F105, F107 use dwc2
- #if defined (STM32F105x8) || defined (STM32F105xB) || defined (STM32F105xC) || \
- defined (STM32F107xB) || defined (STM32F107xC)
+ #if defined(STM32F105x8) || defined(STM32F105xB) || defined(STM32F105xC) || defined(STM32F107xB) || \
+ defined(STM32F107xC)
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_STM32
#define CFG_TUH_DWC2_DMA_ENABLE_DEFAULT 0
- #define TUP_DCD_ENDPOINT_MAX 4
- #elif defined(STM32F102x6) || defined(STM32F102xB) || \
- defined(STM32F103x6) || defined(STM32F103xB) || defined(STM32F103xE) || defined(STM32F103xG)
+ #define TUP_DCD_ENDPOINT_MAX 4
+ #elif defined(STM32F102x6) || defined(STM32F102xB) || defined(STM32F103x6) || defined(STM32F103xB) || \
+ defined(STM32F103xE) || defined(STM32F103xG)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define CFG_TUSB_FSDEV_PMA_SIZE 512u
#else
#error "Unsupported STM32F1 mcu"
#endif
@@ -194,195 +241,213 @@
#define TUP_USBIP_DWC2_STM32
// FS has 4 ep, HS has 5 ep
- #define TUP_DCD_ENDPOINT_MAX 6
+ #define TUP_DCD_ENDPOINT_MAX 6
#elif TU_CHECK_MCU(OPT_MCU_STM32F3)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+
+ #if defined(STM32F302xB) || defined(STM32F302xC) || defined(STM32F303xB) || defined(STM32F303xC) || \
+ defined(STM32F373xC)
+ // xB, and xC: 512
+ #define CFG_TUSB_FSDEV_PMA_SIZE 512u
+ #elif defined(STM32F302x6) || defined(STM32F302x8) || defined(STM32F302xD) || defined(STM32F302xE) || \
+ defined(STM32F303xD) || defined(STM32F303xE)
+ // x6, x8, xD, and xE: 1024 + LPM Support
+ #define CFG_TUSB_FSDEV_PMA_SIZE 1024u
+ #else
+ #error "Unsupported STM32F3 mcu"
+ #endif
#elif TU_CHECK_MCU(OPT_MCU_STM32F4)
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_STM32
// For most mcu, FS has 4, HS has 6. TODO 446/469/479 HS has 9
- #define TUP_DCD_ENDPOINT_MAX 6
+ #define TUP_DCD_ENDPOINT_MAX 6
#elif TU_CHECK_MCU(OPT_MCU_STM32F7)
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_STM32
// FS has 6, HS has 9
- #define TUP_DCD_ENDPOINT_MAX 9
+ #define TUP_DCD_ENDPOINT_MAX 9
// MCU with on-chip HS Phy
#if defined(STM32F723xx) || defined(STM32F730xx) || defined(STM32F733xx)
- #define TUP_RHPORT_HIGHSPEED 1 // Port0: FS, Port1: HS
+ #define TUP_RHPORT_HIGHSPEED 1 // Port0: FS, Port1: HS
#endif
// Enable dcache if DMA is enabled
- #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE
- #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE
- #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32
-
-#elif TU_CHECK_MCU(OPT_MCU_STM32H7)
- #include "stm32h7xx.h"
- #define TUP_USBIP_DWC2
- #define TUP_USBIP_DWC2_STM32
-
- #define TUP_DCD_ENDPOINT_MAX 9
-
- #if __CORTEX_M == 7
- // Enable dcache if DMA is enabled
- #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE
- #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE
- #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32
- #endif
+ #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE
+ #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE
+ #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32
-#elif TU_CHECK_MCU(OPT_MCU_STM32H5)
+#elif TU_CHECK_MCU(OPT_MCU_STM32G0)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define TUP_USBIP_FSDEV_DRD
+ #define CFG_TUSB_FSDEV_PMA_SIZE 2048u
#elif TU_CHECK_MCU(OPT_MCU_STM32G4)
// Device controller
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
+ #define CFG_TUSB_FSDEV_PMA_SIZE 1024u
// TypeC controller
#define TUP_USBIP_TYPEC_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
#define TUP_TYPEC_RHPORTS_NUM 1
-#elif TU_CHECK_MCU(OPT_MCU_STM32G0)
+#elif TU_CHECK_MCU(OPT_MCU_STM32H5)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define TUP_USBIP_FSDEV_DRD
+ #define CFG_TUSB_FSDEV_PMA_SIZE 2048u
-#elif TU_CHECK_MCU(OPT_MCU_STM32C0)
+#elif TU_CHECK_MCU(OPT_MCU_STM32H7)
+ #define TUP_USBIP_DWC2
+ #define TUP_USBIP_DWC2_STM32
+
+ #define TUP_DCD_ENDPOINT_MAX 9
+
+ #ifndef CORE_CM4
+ // Enable dcache if DMA is enabled
+ #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE
+ #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE
+ #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32
+ #endif
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32H7RS, OPT_MCU_STM32N6)
+ #define TUP_USBIP_DWC2
+ #define TUP_USBIP_DWC2_STM32
+
+ // FS has 6, HS has 9
+ #define TUP_DCD_ENDPOINT_MAX 9
+
+ // MCU with on-chip HS Phy
+ #define TUP_RHPORT_HIGHSPEED 1
+
+ // Enable dcache if DMA is enabled
+ #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE
+ #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE
+ #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32L0)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define CFG_TUSB_FSDEV_PMA_SIZE 1024u
-#elif TU_CHECK_MCU(OPT_MCU_STM32L0, OPT_MCU_STM32L1)
+#elif TU_CHECK_MCU(OPT_MCU_STM32L1)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define CFG_TUSB_FSDEV_PMA_SIZE 512u
#elif TU_CHECK_MCU(OPT_MCU_STM32L4)
// - L4x2, L4x3 use fsdev
// - L4x4, L4x6, L4x7, L4x9 use dwc2
- #if defined (STM32L475xx) || defined (STM32L476xx) || \
- defined (STM32L485xx) || defined (STM32L486xx) || defined (STM32L496xx) || \
- defined (STM32L4A6xx) || defined (STM32L4P5xx) || defined (STM32L4Q5xx) || \
- defined (STM32L4R5xx) || defined (STM32L4R7xx) || defined (STM32L4R9xx) || \
- defined (STM32L4S5xx) || defined (STM32L4S7xx) || defined (STM32L4S9xx)
+ #if defined(STM32L475xx) || defined(STM32L476xx) || defined(STM32L485xx) || defined(STM32L486xx) || \
+ defined(STM32L496xx) || defined(STM32L4A6xx) || defined(STM32L4P5xx) || defined(STM32L4Q5xx) || \
+ defined(STM32L4R5xx) || defined(STM32L4R7xx) || defined(STM32L4R9xx) || defined(STM32L4S5xx) || \
+ defined(STM32L4S7xx) || defined(STM32L4S9xx)
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_STM32
- #define TUP_DCD_ENDPOINT_MAX 6
+ #define TUP_DCD_ENDPOINT_MAX 6
#elif defined(STM32L412xx) || defined(STM32L422xx) || defined(STM32L432xx) || defined(STM32L433xx) || \
- defined(STM32L442xx) || defined(STM32L443xx) || defined(STM32L452xx) || defined(STM32L462xx)
+ defined(STM32L442xx) || defined(STM32L443xx) || defined(STM32L452xx) || defined(STM32L462xx)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define CFG_TUSB_FSDEV_PMA_SIZE 1024u
#else
#error "Unsupported STM32L4 mcu"
#endif
-#elif TU_CHECK_MCU(OPT_MCU_STM32WB)
+#elif TU_CHECK_MCU(OPT_MCU_STM32L5)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define CFG_TUSB_FSDEV_PMA_SIZE (1024u)
-#elif TU_CHECK_MCU(OPT_MCU_STM32WBA)
- #define TUP_USBIP_DWC2
- #define TUP_USBIP_DWC2_STM32
- #define TUP_DCD_ENDPOINT_MAX 9
- #define TUP_RHPORT_HIGHSPEED 1
+#elif TU_CHECK_MCU(OPT_MCU_STM32U0)
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
+ #define CFG_TUSB_FSDEV_PMA_SIZE 1024u
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32U3)
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
+ #define TUP_USBIP_FSDEV_DRD
+ #define CFG_TUSB_FSDEV_PMA_SIZE 2048u
#elif TU_CHECK_MCU(OPT_MCU_STM32U5)
- #if defined (STM32U535xx) || defined (STM32U545xx)
+ // U535/545 use fsdev
+ #if defined(STM32U535xx) || defined(STM32U545xx)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
-
+ #define TUP_USBIP_FSDEV_DRD
+ #define CFG_TUSB_FSDEV_PMA_SIZE 2048u
#else
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_STM32
// U59x/5Ax/5Fx/5Gx are highspeed with built-in HS PHY
#if defined(STM32U595xx) || defined(STM32U599xx) || defined(STM32U5A5xx) || defined(STM32U5A9xx) || \
- defined(STM32U5F7xx) || defined(STM32U5F9xx) || defined(STM32U5G7xx) || defined(STM32U5G9xx)
- #define TUP_DCD_ENDPOINT_MAX 9
- #define TUP_RHPORT_HIGHSPEED 1
+ defined(STM32U5F7xx) || defined(STM32U5F9xx) || defined(STM32U5G7xx) || defined(STM32U5G9xx)
+ #define TUP_DCD_ENDPOINT_MAX 9
+ #define TUP_RHPORT_HIGHSPEED 1
#else
- #define TUP_DCD_ENDPOINT_MAX 6
+ #define TUP_DCD_ENDPOINT_MAX 6
#endif
#endif
-#elif TU_CHECK_MCU(OPT_MCU_STM32L5)
- #define TUP_USBIP_FSDEV
- #define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
-
-#elif TU_CHECK_MCU(OPT_MCU_STM32U0)
+#elif TU_CHECK_MCU(OPT_MCU_STM32WB)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define CFG_TUSB_FSDEV_PMA_SIZE 1024u
-#elif TU_CHECK_MCU(OPT_MCU_STM32H7RS, OPT_MCU_STM32N6)
+#elif TU_CHECK_MCU(OPT_MCU_STM32WBA)
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_STM32
-
- // FS has 6, HS has 9
- #define TUP_DCD_ENDPOINT_MAX 9
-
- // MCU with on-chip HS Phy
- #define TUP_RHPORT_HIGHSPEED 1
-
- // Enable dcache if DMA is enabled
- #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE
- #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE
- #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32
+ #define TUP_DCD_ENDPOINT_MAX 9
+ #define TUP_RHPORT_HIGHSPEED 1
//--------------------------------------------------------------------+
// Sony
//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_CXD56)
- #define TUP_DCD_ENDPOINT_MAX 7
- #define TUP_RHPORT_HIGHSPEED 1
- #define TUD_ENDPOINT_ONE_DIRECTION_ONLY
+ #define TUP_DCD_ENDPOINT_MAX 7
+ #define TUP_RHPORT_HIGHSPEED 1
+ #define CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY 1
//--------------------------------------------------------------------+
// TI
//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_MSP430x5xx)
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define TUP_DCD_ENDPOINT_MAX 8
#elif TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129)
#define TUP_USBIP_MUSB
#define TUP_USBIP_MUSB_TI
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define TUP_DCD_ENDPOINT_MAX 8
//--------------------------------------------------------------------+
// ValentyUSB (Litex)
//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_VALENTYUSB_EPTRI)
- #define TUP_DCD_ENDPOINT_MAX 16
+ #define TUP_DCD_ENDPOINT_MAX 16
//--------------------------------------------------------------------+
// Nuvoton
//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_NUC121, OPT_MCU_NUC126)
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define TUP_DCD_ENDPOINT_MAX 8
#elif TU_CHECK_MCU(OPT_MCU_NUC120)
- #define TUP_DCD_ENDPOINT_MAX 6
+ #define TUP_DCD_ENDPOINT_MAX 6
#elif TU_CHECK_MCU(OPT_MCU_NUC505)
- #define TUP_DCD_ENDPOINT_MAX 12
- #define TUP_RHPORT_HIGHSPEED 1
+ #define TUP_DCD_ENDPOINT_MAX 12
+ #define TUP_RHPORT_HIGHSPEED 1
//--------------------------------------------------------------------+
// Espressif
@@ -390,114 +455,133 @@
#elif TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3, OPT_MCU_ESP32H4)
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_ESP32
- #define TUP_DCD_ENDPOINT_MAX 7 // only 5 TX FIFO for endpoint IN
- #define CFG_TUSB_OS_INC_PATH_DEFAULT freertos/
+ #define TUP_DCD_ENDPOINT_MAX 7 // only 5 TX FIFO for endpoint IN
- #if CFG_TUSB_MCU == OPT_MCU_ESP32S3
+ // clang-format off
+ #define CFG_TUSB_OS_INC_PATH_DEFAULT freertos/
+ // clang-format on
+
+ #if CFG_TUSB_MCU == OPT_MCU_ESP32S3 || CFG_TUSB_MCU == OPT_MCU_ESP32H4
#define TUP_MCU_MULTIPLE_CORE 1
#endif
- // Disable slave if DMA is enabled
- #define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE
- #define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_DWC2_DMA_ENABLE
-
#elif TU_CHECK_MCU(OPT_MCU_ESP32P4)
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_ESP32
- #define TUP_RHPORT_HIGHSPEED 1 // port0 FS, port1 HS
- #define TUP_DCD_ENDPOINT_MAX 16 // FS 7 ep, HS 16 ep
+ #define TUP_RHPORT_HIGHSPEED 1 // port0 FS, port1 HS
+ #define TUP_DCD_ENDPOINT_MAX 16 // FS 7 ep, HS 16 ep
- #define CFG_TUSB_OS_INC_PATH_DEFAULT freertos/
+ // clang-format off
+ #define CFG_TUSB_OS_INC_PATH_DEFAULT freertos/
+ // clang-format on
- #define TUP_MCU_MULTIPLE_CORE 1
-
- // Disable slave if DMA is enabled
- #define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE
- #define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_DWC2_DMA_ENABLE
+ #define TUP_MCU_MULTIPLE_CORE 1
// Enable dcache if DMA is enabled
- #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE
- #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE
- #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 64
+ #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE
+ #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE
+ #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 64
+
+#elif TU_CHECK_MCU(OPT_MCU_ESP32S31)
+ #define TUP_USBIP_DWC2
+ #define TUP_USBIP_DWC2_ESP32
+ #define TUP_RHPORT_HIGHSPEED 1
+ #define TUP_DCD_ENDPOINT_MAX 16
+
+ // clang-format off
+ #define CFG_TUSB_OS_INC_PATH_DEFAULT freertos/
+ // clang-format on
-#elif TU_CHECK_MCU(OPT_MCU_ESP32, OPT_MCU_ESP32C2, OPT_MCU_ESP32C3, OPT_MCU_ESP32C5, OPT_MCU_ESP32C6, OPT_MCU_ESP32C61, OPT_MCU_ESP32H2)
+ #define TUP_MCU_MULTIPLE_CORE 1
+
+ // Disable slave if DMA is enabled
+ #define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE
+ #define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_DWC2_DMA_ENABLE
+
+#elif TU_CHECK_MCU(OPT_MCU_ESP32, OPT_MCU_ESP32C2, OPT_MCU_ESP32C3, OPT_MCU_ESP32C5, OPT_MCU_ESP32C6, \
+ OPT_MCU_ESP32C61, OPT_MCU_ESP32H2)
#if (CFG_TUD_ENABLED || !(defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421))
- #error "MCUs are only supported with CFG_TUH_MAX3421 enabled"
+ #error "MCUs are only supported with CFG_TUH_MAX3421 enabled"
#endif
- #define TUP_DCD_ENDPOINT_MAX 0
- #define CFG_TUSB_OS_INC_PATH_DEFAULT freertos/
+ #define TUP_DCD_ENDPOINT_MAX 0
+
+ // clang-format off
+ #define CFG_TUSB_OS_INC_PATH_DEFAULT freertos/
+ // clang-format on
+
//--------------------------------------------------------------------+
// Dialog
//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_DA1469X)
- #define TUP_DCD_ENDPOINT_MAX 4
+ #define TUP_DCD_ENDPOINT_MAX 4
+ #define TUP_DCD_EDPT_CLOSE_API
//--------------------------------------------------------------------+
// Raspberry Pi
//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_RP2040)
- #define TUP_DCD_EDPT_ISO_ALLOC
- #define TUP_DCD_ENDPOINT_MAX 16
- #define TUP_MCU_MULTIPLE_CORE 1
+ #define TUP_DCD_ENDPOINT_MAX 16
+ #define TUP_MCU_MULTIPLE_CORE 1
- #define TU_ATTR_FAST_FUNC __not_in_flash("tinyusb")
+ #define TU_ATTR_FAST_FUNC __not_in_flash("tinyusb")
//--------------------------------------------------------------------+
// Silabs
//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_EFM32GG)
#define TUP_USBIP_DWC2
- #define TUP_DCD_ENDPOINT_MAX 7
+ #define TUP_DCD_ENDPOINT_MAX 7
//--------------------------------------------------------------------+
// Renesas
//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N, OPT_MCU_RAXXX)
#define TUP_USBIP_RUSB2
- #define TUP_DCD_ENDPOINT_MAX 10
+ #define TUP_DCD_ENDPOINT_MAX 10
//--------------------------------------------------------------------+
// GigaDevice
//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_GD32VF103)
#define TUP_USBIP_DWC2
- #define TUP_DCD_ENDPOINT_MAX 4
+ #define TUP_DCD_ENDPOINT_MAX 4
//--------------------------------------------------------------------+
// Broadcom
//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_BCM2711, OPT_MCU_BCM2835, OPT_MCU_BCM2837)
#define TUP_USBIP_DWC2
- #define TUP_DCD_ENDPOINT_MAX 8
- #define TUP_RHPORT_HIGHSPEED 1
+ #define TUP_DCD_ENDPOINT_MAX 8
+ #define TUP_RHPORT_HIGHSPEED 1
//--------------------------------------------------------------------+
// Infineon
//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_XMC4000)
#define TUP_USBIP_DWC2
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define TUP_DCD_ENDPOINT_MAX 8
//--------------------------------------------------------------------+
// BridgeTek
//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_FT90X)
- #define TUP_DCD_ENDPOINT_MAX 8
- #define TUP_RHPORT_HIGHSPEED 1
- #define TUD_ENDPOINT_ONE_DIRECTION_ONLY
+ #define TUP_DCD_ENDPOINT_MAX 8
+ #define TUP_RHPORT_HIGHSPEED 1
+ #define CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY 1
#elif TU_CHECK_MCU(OPT_MCU_FT93X)
- #define TUP_DCD_ENDPOINT_MAX 16
- #define TUP_RHPORT_HIGHSPEED 1
- #define TUD_ENDPOINT_ONE_DIRECTION_ONLY
+ #define TUP_DCD_ENDPOINT_MAX 16
+ #define TUP_RHPORT_HIGHSPEED 1
+ #define CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY 1
//--------------------------------------------------------------------+
// Allwinner
//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_F1C100S)
- #define TUP_DCD_ENDPOINT_MAX 4
+ #define TUP_DCD_ENDPOINT_MAX 4
+ #define TUP_DCD_EDPT_CLOSE_API
//--------------------------------------------------------------------+
// WCH
@@ -507,46 +591,53 @@
#define TUP_USBIP_WCH_USBFS
#if !defined(CFG_TUD_WCH_USBIP_USBFS)
- #define CFG_TUD_WCH_USBIP_USBFS 0
+ #define CFG_TUD_WCH_USBIP_USBFS 0
#endif
#if !defined(CFG_TUD_WCH_USBIP_USBHS)
- #define CFG_TUD_WCH_USBIP_USBHS (CFG_TUD_WCH_USBIP_USBFS ? 0 : 1)
+ #define CFG_TUD_WCH_USBIP_USBHS (CFG_TUD_WCH_USBIP_USBFS ? 0 : 1)
#endif
- #define TUP_RHPORT_HIGHSPEED CFG_TUD_WCH_USBIP_USBHS
- #define TUP_DCD_ENDPOINT_MAX (CFG_TUD_WCH_USBIP_USBHS ? 16 : 8)
+ #define TUP_RHPORT_HIGHSPEED CFG_TUD_WCH_USBIP_USBHS
+ #define TUP_DCD_ENDPOINT_MAX (CFG_TUD_WCH_USBIP_USBHS ? 16 : 8)
+
+ #if CFG_TUD_WCH_USBIP_USBHS
+ #define TUP_DCD_EDPT_CLOSE_API
+ #endif
#elif TU_CHECK_MCU(OPT_MCU_CH32V103)
#define TUP_USBIP_WCH_USBFS
#if !defined(CFG_TUD_WCH_USBIP_USBFS)
- #define CFG_TUD_WCH_USBIP_USBFS 1
+ #define CFG_TUD_WCH_USBIP_USBFS 1
#endif
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define TUP_DCD_ENDPOINT_MAX 8
#elif TU_CHECK_MCU(OPT_MCU_CH32V20X)
// v20x support both port0 FSDEV (USBD) and port1 USBFS
#define TUP_USBIP_WCH_USBFS
#ifndef CFG_TUH_WCH_USBIP_USBFS
- #define CFG_TUH_WCH_USBIP_USBFS 1
+ #define CFG_TUH_WCH_USBIP_USBFS 1
#endif
- #define TUP_USBIP_FSDEV
- #define TUP_USBIP_FSDEV_CH32
-
// default to FSDEV for device
#if !defined(CFG_TUD_WCH_USBIP_USBFS)
- #define CFG_TUD_WCH_USBIP_USBFS 0
+ #define CFG_TUD_WCH_USBIP_USBFS 0
#endif
#if !defined(CFG_TUD_WCH_USBIP_FSDEV)
- #define CFG_TUD_WCH_USBIP_FSDEV (CFG_TUD_WCH_USBIP_USBFS ? 0 : 1)
+ #define CFG_TUD_WCH_USBIP_FSDEV (CFG_TUD_WCH_USBIP_USBFS ? 0 : 1)
#endif
- #define TUP_DCD_ENDPOINT_MAX 8
+ #if CFG_TUD_WCH_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_CH32
+ #define CFG_TUSB_FSDEV_PMA_SIZE 512u
+ #endif
+
+ #define TUP_DCD_ENDPOINT_MAX 8
#elif TU_CHECK_MCU(OPT_MCU_CH32V307)
// v307 support both FS and HS, default to HS
@@ -554,15 +645,32 @@
#define TUP_USBIP_WCH_USBFS
#if !defined(CFG_TUD_WCH_USBIP_USBFS)
- #define CFG_TUD_WCH_USBIP_USBFS 0
+ #define CFG_TUD_WCH_USBIP_USBFS 0
#endif
#if !defined(CFG_TUD_WCH_USBIP_USBHS)
- #define CFG_TUD_WCH_USBIP_USBHS (CFG_TUD_WCH_USBIP_USBFS ? 0 : 1)
+ #define CFG_TUD_WCH_USBIP_USBHS (CFG_TUD_WCH_USBIP_USBFS ? 0 : 1)
#endif
- #define TUP_RHPORT_HIGHSPEED CFG_TUD_WCH_USBIP_USBHS
- #define TUP_DCD_ENDPOINT_MAX (CFG_TUD_WCH_USBIP_USBHS ? 16 : 8)
+ #define TUP_RHPORT_HIGHSPEED CFG_TUD_WCH_USBIP_USBHS
+ #define TUP_DCD_ENDPOINT_MAX (CFG_TUD_WCH_USBIP_USBHS ? 16 : 8)
+
+ #if CFG_TUD_WCH_USBIP_USBHS
+ #define TUP_DCD_EDPT_CLOSE_API
+ #endif
+
+#elif TU_CHECK_MCU(OPT_MCU_CH583)
+ // CH582/583 USBFS: older WCH USBFS IP with a single combined per-endpoint control register
+ // (like CH32V103), driven by the shared dcd_ch32_usbfs.c on USB0 (rhport 0). Device only:
+ // the shared hcd_ch32_usbfs.c is CH32V20x-specific and does not support CH58x, so host /
+ // USB2 (rhport 1) is not provided here.
+ #define TUP_USBIP_WCH_USBFS
+
+ #ifndef CFG_TUD_WCH_USBIP_USBFS
+ #define CFG_TUD_WCH_USBIP_USBFS 1
+ #endif
+
+ #define TUP_DCD_ENDPOINT_MAX 8
//--------------------------------------------------------------------+
// Analog Devices
@@ -570,66 +678,53 @@
#elif TU_CHECK_MCU(OPT_MCU_MAX32650, OPT_MCU_MAX32666, OPT_MCU_MAX32690, OPT_MCU_MAX78002)
#define TUP_USBIP_MUSB
#define TUP_USBIP_MUSB_ADI
- #define TUP_DCD_ENDPOINT_MAX 12
- #define TUP_RHPORT_HIGHSPEED 1
- #define TUD_ENDPOINT_ONE_DIRECTION_ONLY
+ #define TUP_DCD_ENDPOINT_MAX 12
+ #define TUP_RHPORT_HIGHSPEED 1
+ #define CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY 1
//--------------------------------------------------------------------+
// ArteryTek
//--------------------------------------------------------------------+
-#elif TU_CHECK_MCU(OPT_MCU_AT32F403A_407)
+#elif TU_CHECK_MCU(OPT_MCU_AT32F403A_407, OPT_MCU_AT32F413)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_AT32
- #define TUP_DCD_ENDPOINT_MAX 8
-
-#elif TU_CHECK_MCU(OPT_MCU_AT32F413)
- #define TUP_USBIP_FSDEV
- #define TUP_USBIP_FSDEV_AT32
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define CFG_TUSB_FSDEV_PMA_SIZE 512u
#elif TU_CHECK_MCU(OPT_MCU_AT32F415)
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_AT32
- #define TUP_DCD_ENDPOINT_MAX 4
+ #define TUP_DCD_ENDPOINT_MAX 4
-#elif TU_CHECK_MCU(OPT_MCU_AT32F435_437)
+#elif TU_CHECK_MCU(OPT_MCU_AT32F402_405, OPT_MCU_AT32F423, OPT_MCU_AT32F425, OPT_MCU_AT32F435_437, OPT_MCU_AT32F45X)
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_AT32
- #define TUP_DCD_ENDPOINT_MAX 8
-
-#elif TU_CHECK_MCU(OPT_MCU_AT32F423)
- #define TUP_USBIP_DWC2
- #define TUP_USBIP_DWC2_AT32
- #define TUP_DCD_ENDPOINT_MAX 8
-
-#elif TU_CHECK_MCU(OPT_MCU_AT32F402_405)
- #define TUP_USBIP_DWC2
- #define TUP_USBIP_DWC2_AT32
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define TUP_DCD_ENDPOINT_MAX 8
// AT32F405xx has on-chip HS PHY
- #if defined(AT32F405CBT7) || defined(AT32F405CBU7) || \
- defined(AT32F405CCT7) || defined(AT32F405CCU7) || \
- defined(AT32F405KBU7_4) || defined(AT32F405KCU7_4) || \
- defined(AT32F405RBT7_7) || defined(AT32F405RBT7) || \
- defined(AT32F405RCT7_7) || defined(AT32F405RCT7)
- #define TUP_RHPORT_HIGHSPEED 1 // Port0: FS, Port1: HS
+ #if defined(AT32F405CBT7) || defined(AT32F405CBU7) || defined(AT32F405CCT7) || defined(AT32F405CCU7) || \
+ defined(AT32F405KBU7_4) || defined(AT32F405KCU7_4) || defined(AT32F405RBT7_7) || defined(AT32F405RBT7) || \
+ defined(AT32F405RCT7_7) || defined(AT32F405RCT7)
+ #define TUP_RHPORT_HIGHSPEED 1 // Port0: FS, Port1: HS
#endif
-#elif TU_CHECK_MCU(OPT_MCU_AT32F425)
- #define TUP_USBIP_DWC2
- #define TUP_USBIP_DWC2_AT32
- #define TUP_DCD_ENDPOINT_MAX 8
+//--------------------------------------------------------------------+
+// HPMicro
+//--------------------------------------------------------------------+
+#elif TU_CHECK_MCU(OPT_MCU_HPM)
+ #define TUP_USBIP_CHIPIDEA_HS
+ #define TUP_USBIP_EHCI
+
+ #define TUP_DCD_ENDPOINT_MAX 16
+ #define TUP_RHPORT_HIGHSPEED 1
+
+ #define TU_ATTR_FAST_FUNC __attribute__((section(".fast")))
#endif
-//--------------------------------------------------------------------+
// External USB controller
-//--------------------------------------------------------------------+
-
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
#ifndef CFG_TUH_MAX3421_ENDPOINT_TOTAL
- #define CFG_TUH_MAX3421_ENDPOINT_TOTAL (8 + 4*(CFG_TUH_DEVICE_MAX-1))
+ #define CFG_TUH_MAX3421_ENDPOINT_TOTAL (8 + 4 * (CFG_TUH_DEVICE_MAX - 1))
#endif
#endif
@@ -638,18 +733,22 @@
// Default Values
//--------------------------------------------------------------------+
+#if defined(TUP_USBIP_FSDEV)
+ #define TUP_DCD_ENDPOINT_MAX 8
+#endif
+
#ifndef TUP_MCU_MULTIPLE_CORE
-#define TUP_MCU_MULTIPLE_CORE 0
+ #define TUP_MCU_MULTIPLE_CORE 0
#endif
#if !defined(TUP_DCD_ENDPOINT_MAX) && defined(CFG_TUD_ENABLED) && CFG_TUD_ENABLED
#warning "TUP_DCD_ENDPOINT_MAX is not defined for this MCU, default to 8"
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define TUP_DCD_ENDPOINT_MAX 8
#endif
// Default to fullspeed if not defined
#ifndef TUP_RHPORT_HIGHSPEED
- #define TUP_RHPORT_HIGHSPEED 0
+ #define TUP_RHPORT_HIGHSPEED 0
#endif
// fast function, normally mean placing function in SRAM
@@ -657,13 +756,22 @@
#define TU_ATTR_FAST_FUNC
#endif
-// USBIP that support ISO alloc & activate API
-#if defined(TUP_USBIP_DWC2) || defined(TUP_USBIP_FSDEV) || defined(TUP_USBIP_MUSB)
+#if defined(TUP_USBIP_IP3511) || defined(TUP_USBIP_RUSB2)
+ #define TUP_DCD_EDPT_CLOSE_API
+#endif
+
+// USBIP implement dcd_edpt_close() and does not support ISO alloc & activate API
+#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
+// Some USBIPs (SAMG, SAMX7X, PIC32, MAX3266x/MAX78002) cannot assign the same endpoint
+// number to both IN and OUT. Default to 0 (same endpoint number may be used for IN and OUT).
+#ifndef CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY
+ #define CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY 0
#endif
+// Backward-compatible alias: legacy code only tests defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY)
+#if CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY && !defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY)
+ #define TUD_ENDPOINT_ONE_DIRECTION_ONLY
#endif
diff --git a/src/common/tusb_private.h b/src/common/tusb_private.h
index 31aca8a31..a31bf7b03 100644
--- a/src/common/tusb_private.h
+++ b/src/common/tusb_private.h
@@ -24,8 +24,8 @@
* This file is part of the TinyUSB stack.
*/
-#ifndef TUSB_PRIVATE_H_
-#define TUSB_PRIVATE_H_
+#ifndef TUSB_PRIVATE_H
+#define TUSB_PRIVATE_H
// Internal Helper used by Host and Device Stack
@@ -33,6 +33,12 @@
extern "C" {
#endif
+typedef void (*tusb_defer_func_t)(uintptr_t param);
+
+ //--------------------------------------------------------------------+
+ // Configuration
+ //--------------------------------------------------------------------+
+
#define TUP_USBIP_CONTROLLER_NUM 2
extern tusb_role_t _tusb_rhport_role[TUP_USBIP_CONTROLLER_NUM];
@@ -40,75 +46,94 @@ extern tusb_role_t _tusb_rhport_role[TUP_USBIP_CONTROLLER_NUM];
// Endpoint
//--------------------------------------------------------------------+
-typedef struct TU_ATTR_PACKED {
- volatile uint8_t busy : 1;
- volatile uint8_t stalled : 1;
- volatile uint8_t claimed : 1;
-}tu_edpt_state_t;
+// Endpoint state bits — manipulate the bare uint8_t with these masks.
+#define TU_EDPT_STATE_BUSY 0x01u
+#define TU_EDPT_STATE_STALLED 0x02u
+#define TU_EDPT_STATE_CLAIMED 0x04u
typedef struct {
- struct TU_ATTR_PACKED {
- uint8_t is_host : 1; // 1: host, 0: device
- uint8_t is_mps512 : 1; // 1: 512, 0: 64 since stream is used for Bulk only
- };
+ uint8_t hwid; // device: rhport, host: daddr
+ bool is_host; // 1: host, 0: device
uint8_t ep_addr;
- uint16_t ep_bufsize;
+ // 1 byte padding
- uint8_t* ep_buf; // TODO xfer_fifo can skip this buffer
+ uint16_t mps;
+ uint16_t xfer_len;
+ 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
OSAL_MUTEX_DEF(ff_mutexdef);
-
}tu_edpt_stream_t;
//--------------------------------------------------------------------+
// Endpoint
//--------------------------------------------------------------------+
-// Check if endpoint descriptor is valid per USB specs
-bool tu_edpt_validate(tusb_desc_endpoint_t const * desc_ep, tusb_speed_t speed, bool is_host);
-
-// Bind all endpoint of a interface descriptor to class driver
-void tu_edpt_bind_driver(uint8_t ep2drv[][2], tusb_desc_interface_t const* p_desc, uint16_t desc_len, uint8_t driver_id);
+// Check if endpoint descriptor is valid per USB specs if debug is enabled
+#if CFG_TUSB_DEBUG
+bool tu_edpt_validate(const tusb_desc_endpoint_t *desc_ep, tusb_speed_t speed);
+#else
+TU_ATTR_ALWAYS_INLINE static inline bool tu_edpt_validate(const tusb_desc_endpoint_t *desc_ep, tusb_speed_t speed) {
+ (void)speed;
+ return tu_edpt_packet_size(desc_ep) > 0;
+}
+#endif
-// Calculate total length of n interfaces (depending on IAD)
-uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_t itf_count, uint16_t max_len);
+// Bind drivers to all interfaces and endpoints in the provided configuration descriptor
+bool tu_bind_driver_to_ep_itf(uint8_t driver_id, uint8_t ep2drv[][2], uint8_t itf2drv[], uint8_t itf_max,
+ const uint8_t *p_desc, uint16_t desc_len);
// Claim an endpoint with provided mutex
-bool tu_edpt_claim(tu_edpt_state_t* ep_state, osal_mutex_t mutex);
+bool tu_edpt_claim(volatile uint8_t* ep_state, osal_mutex_t mutex);
// Release an endpoint with provided mutex
-bool tu_edpt_release(tu_edpt_state_t* ep_state, osal_mutex_t mutex);
+bool tu_edpt_release(volatile uint8_t* ep_state, osal_mutex_t mutex);
//--------------------------------------------------------------------+
// Endpoint Stream
//--------------------------------------------------------------------+
// Init an endpoint stream
-bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool is_host, bool is_tx, bool overwritable,
- void* ff_buf, uint16_t ff_bufsize, uint8_t* ep_buf, uint16_t ep_bufsize);
+bool tu_edpt_stream_init(tu_edpt_stream_t *s, bool is_host, bool is_tx, bool overwritable, void *ff_buf,
+ uint16_t ff_bufsize, uint8_t *ep_buf);
// Deinit an endpoint stream
-bool tu_edpt_stream_deinit(tu_edpt_stream_t* s);
+TU_ATTR_ALWAYS_INLINE static inline void tu_edpt_stream_deinit(tu_edpt_stream_t *s) {
+ (void)s;
+#if OSAL_MUTEX_REQUIRED
+ if (s->ff.mutex_wr) {
+ osal_mutex_delete(s->ff.mutex_wr);
+ }
+ if (s->ff.mutex_rd) {
+ osal_mutex_delete(s->ff.mutex_rd);
+ }
+#endif
+}
-// Open an stream for an endpoint
-TU_ATTR_ALWAYS_INLINE static inline
-void tu_edpt_stream_open(tu_edpt_stream_t* s, tusb_desc_endpoint_t const *desc_ep) {
- tu_fifo_clear(&s->ff);
+// Open an endpoint stream
+TU_ATTR_ALWAYS_INLINE static inline void tu_edpt_stream_open(tu_edpt_stream_t *s, uint8_t hwid,
+ const tusb_desc_endpoint_t *desc_ep, uint16_t xfer_len) {
+ s->hwid = hwid;
s->ep_addr = desc_ep->bEndpointAddress;
- s->is_mps512 = (tu_edpt_packet_size(desc_ep) == 512) ? 1 : 0;
+ s->mps = tu_edpt_packet_size(desc_ep);
+ s->xfer_len = xfer_len;
}
-TU_ATTR_ALWAYS_INLINE static inline
-void tu_edpt_stream_close(tu_edpt_stream_t* s) {
+TU_ATTR_ALWAYS_INLINE static inline bool tu_edpt_stream_is_opened(const tu_edpt_stream_t *s) {
+ return s->ep_addr != 0;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void tu_edpt_stream_close(tu_edpt_stream_t* s) {
s->ep_addr = 0;
}
-// Clear fifo
-TU_ATTR_ALWAYS_INLINE static inline
-bool tu_edpt_stream_clear(tu_edpt_stream_t* s) {
- return tu_fifo_clear(&s->ff);
+TU_ATTR_ALWAYS_INLINE static inline void tu_edpt_stream_clear(tu_edpt_stream_t *s) {
+ tu_fifo_clear(&s->ff);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool tu_edpt_stream_empty(tu_edpt_stream_t *s) {
+ return tu_fifo_empty(&s->ff);
}
//--------------------------------------------------------------------+
@@ -116,52 +141,48 @@ bool tu_edpt_stream_clear(tu_edpt_stream_t* s) {
//--------------------------------------------------------------------+
// Write to stream
-uint32_t tu_edpt_stream_write(uint8_t hwid, tu_edpt_stream_t* s, void const *buffer, uint32_t bufsize);
+uint32_t tu_edpt_stream_write(tu_edpt_stream_t *s, const void *buffer, uint32_t bufsize);
-// Start an usb transfer if endpoint is not busy
-uint32_t tu_edpt_stream_write_xfer(uint8_t hwid, tu_edpt_stream_t* s);
+// Start an usb transfer if endpoint is not busy. Return number of queued bytes
+uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t *s);
// Start an zero-length packet if needed
-bool tu_edpt_stream_write_zlp_if_needed(uint8_t hwid, tu_edpt_stream_t* s, uint32_t last_xferred_bytes);
+bool tu_edpt_stream_write_zlp_if_needed(tu_edpt_stream_t *s, uint32_t last_xferred_bytes);
// Get the number of bytes available for writing to FIFO
// Note: if no fifo, return endpoint size if not busy, 0 otherwise
-uint32_t tu_edpt_stream_write_available(uint8_t hwid, tu_edpt_stream_t* s);
+uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t *s);
//--------------------------------------------------------------------+
// Stream Read
//--------------------------------------------------------------------+
// Read from stream
-uint32_t tu_edpt_stream_read(uint8_t hwid, tu_edpt_stream_t* s, void* buffer, uint32_t bufsize);
+uint32_t tu_edpt_stream_read(tu_edpt_stream_t *s, void *buffer, uint32_t bufsize);
// Start an usb transfer if endpoint is not busy
-uint32_t tu_edpt_stream_read_xfer(uint8_t hwid, tu_edpt_stream_t* s);
+uint32_t tu_edpt_stream_read_xfer(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 (tu_fifo_depth(&s->ff)) {
- tu_fifo_write_n(&s->ff, s->ep_buf, (uint16_t) xferred_bytes);
+ if (s->ep_buf != NULL) {
+ tu_fifo_write_n(&s->ff, s->ep_buf, (uint16_t)xferred_bytes);
}
}
// Complete read transfer with provided buffer
TU_ATTR_ALWAYS_INLINE static inline
-void tu_edpt_stream_read_xfer_complete_with_buf(tu_edpt_stream_t* s, const void * buf, uint32_t xferred_bytes) {
- if (tu_fifo_depth(&s->ff)) {
- tu_fifo_write_n(&s->ff, buf, (uint16_t) xferred_bytes);
- }
+void tu_edpt_stream_read_xfer_complete_with_buf(tu_edpt_stream_t *s, const void *buf, uint32_t xferred_bytes) {
+ tu_fifo_write_n(&s->ff, buf, (uint16_t)xferred_bytes);
}
// Get the number of bytes available for reading
-TU_ATTR_ALWAYS_INLINE static inline
-uint32_t tu_edpt_stream_read_available(tu_edpt_stream_t* s) {
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_edpt_stream_read_available(const tu_edpt_stream_t *s) {
return (uint32_t) tu_fifo_count(&s->ff);
}
-TU_ATTR_ALWAYS_INLINE static inline
-bool tu_edpt_stream_peek(tu_edpt_stream_t* s, uint8_t* ch) {
+TU_ATTR_ALWAYS_INLINE static inline bool tu_edpt_stream_peek(tu_edpt_stream_t *s, uint8_t *ch) {
return tu_fifo_peek(&s->ff, ch);
}
diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h
index b3ef1e9c9..cb06b89bb 100644
--- a/src/common/tusb_types.h
+++ b/src/common/tusb_types.h
@@ -77,7 +77,7 @@
*------------------------------------------------------------------*/
typedef enum {
- TUSB_ROLE_INVALID = 0,
+ TUSB_ROLE_INVALID = 0u,
TUSB_ROLE_DEVICE = 0x1,
TUSB_ROLE_HOST = 0x2,
} tusb_role_t;
@@ -100,11 +100,14 @@ typedef enum {
} tusb_xfer_type_t;
typedef enum {
- TUSB_DIR_OUT = 0,
- TUSB_DIR_IN = 1,
+ TUSB_DIR_OUT = 0u,
+ TUSB_DIR_IN = 1u,
+} tusb_dir_t;
+enum {
+ TUSB_EPNUM_MASK = 0x0F,
TUSB_DIR_IN_MASK = 0x80
-} tusb_dir_t;
+};
enum {
TUSB_EPSIZE_BULK_FS = 64,
@@ -114,6 +117,10 @@ enum {
TUSB_EPSIZE_ISO_HS_MAX = 1024,
};
+// Endpoint Bulk size depending on host/device max speed
+#define TUD_EPSIZE_BULK_MAX (TUD_OPT_HIGH_SPEED ? 512 : 64)
+#define TUH_EPSIZE_BULK_MAX (TUH_OPT_HIGH_SPEED ? 512 : 64)
+
/// Isochronous Endpoint Attributes
typedef enum {
TUSB_ISO_EP_ATT_NO_SYNC = 0x00,
@@ -178,7 +185,7 @@ typedef enum {
} tusb_request_feature_selector_t;
typedef enum {
- TUSB_REQ_TYPE_STANDARD = 0,
+ TUSB_REQ_TYPE_STANDARD = 0u,
TUSB_REQ_TYPE_CLASS,
TUSB_REQ_TYPE_VENDOR,
TUSB_REQ_TYPE_INVALID
@@ -252,8 +259,8 @@ typedef enum {
} device_capability_type_t;
enum {
- TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP = 1u << 5,
- TUSB_DESC_CONFIG_ATT_SELF_POWERED = 1u << 6,
+ TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP = 1 << 5,
+ TUSB_DESC_CONFIG_ATT_SELF_POWERED = 1 << 6,
};
#define TUSB_DESC_CONFIG_POWER_MA(x) ((x)/2)
@@ -275,6 +282,7 @@ typedef enum {
XFER_RESULT_FAILED,
XFER_RESULT_STALLED,
XFER_RESULT_TIMEOUT,
+ XFER_RESULT_ABORTED,
XFER_RESULT_INVALID
} xfer_result_t;
@@ -311,9 +319,15 @@ enum {
};
enum {
- TUSB_INDEX_INVALID_8 = 0xFFu
+ TUSB_INDEX_INVALID_8 = 0xFF
};
+enum {
+ TU_EP0_OUT = 0x00,
+ TU_EP0_IN = 0x80
+};
+
+
//--------------------------------------------------------------------+
//
//--------------------------------------------------------------------+
@@ -322,6 +336,11 @@ typedef struct {
tusb_speed_t speed;
} tusb_rhport_init_t;
+typedef struct {
+ uint16_t len;
+ uint8_t *buffer;
+} tusb_buffer_t;
+
//--------------------------------------------------------------------+
// USB Descriptors
//--------------------------------------------------------------------+
@@ -335,12 +354,10 @@ typedef struct TU_ATTR_PACKED {
uint8_t bLength ; ///< Size of this descriptor in bytes.
uint8_t bDescriptorType ; ///< DEVICE Descriptor Type.
uint16_t bcdUSB ; ///< BUSB Specification Release Number in Binary-Coded Decimal (i.e., 2.10 is 210H).
-
uint8_t bDeviceClass ; ///< Class code (assigned by the USB-IF).
uint8_t bDeviceSubClass ; ///< Subclass code (assigned by the USB-IF).
uint8_t bDeviceProtocol ; ///< Protocol code (assigned by the USB-IF).
uint8_t bMaxPacketSize0 ; ///< Maximum packet size for endpoint zero (only 8, 16, 32, or 64 are valid). For HS devices is fixed to 64.
-
uint16_t idVendor ; ///< Vendor ID (assigned by the USB-IF).
uint16_t idProduct ; ///< Product ID (assigned by the manufacturer).
uint16_t bcdDevice ; ///< Device release number in binary-coded decimal.
@@ -350,7 +367,7 @@ typedef struct TU_ATTR_PACKED {
uint8_t bNumConfigurations ; ///< Number of possible configurations.
} tusb_desc_device_t;
-TU_VERIFY_STATIC( sizeof(tusb_desc_device_t) == 18, "size is not correct");
+TU_VERIFY_STATIC( sizeof(tusb_desc_device_t) == 18u, "size is not correct");
// USB Binary Device Object Store (BOS) Descriptor
typedef struct TU_ATTR_PACKED {
@@ -360,7 +377,7 @@ typedef struct TU_ATTR_PACKED {
uint8_t bNumDeviceCaps ; ///< Number of device capability descriptors in the BOS
} tusb_desc_bos_t;
-TU_VERIFY_STATIC( sizeof(tusb_desc_bos_t) == 5, "size is not correct");
+TU_VERIFY_STATIC( sizeof(tusb_desc_bos_t) == 5u, "size is not correct");
/// USB Configuration Descriptor
typedef struct TU_ATTR_PACKED {
@@ -375,7 +392,7 @@ typedef struct TU_ATTR_PACKED {
uint8_t bMaxPower ; ///< Maximum power consumption of the USB device from the bus in this specific configuration when the device is fully operational. Expressed in 2 mA units (i.e., 50 = 100 mA).
} tusb_desc_configuration_t;
-TU_VERIFY_STATIC( sizeof(tusb_desc_configuration_t) == 9, "size is not correct");
+TU_VERIFY_STATIC( sizeof(tusb_desc_configuration_t) == 9u, "size is not correct");
/// USB Interface Descriptor
typedef struct TU_ATTR_PACKED {
@@ -391,7 +408,7 @@ typedef struct TU_ATTR_PACKED {
uint8_t iInterface ; ///< Index of string descriptor describing this interface
} tusb_desc_interface_t;
-TU_VERIFY_STATIC( sizeof(tusb_desc_interface_t) == 9, "size is not correct");
+TU_VERIFY_STATIC( sizeof(tusb_desc_interface_t) == 9u, "size is not correct");
/// USB Endpoint Descriptor
typedef struct TU_ATTR_PACKED {
@@ -401,17 +418,26 @@ typedef struct TU_ATTR_PACKED {
uint8_t bEndpointAddress ; // The address of the endpoint
struct TU_ATTR_PACKED {
+#if (TU_BITFIELD_ORDER == TU_BITFIELD_LE)
uint8_t xfer : 2; // Control, ISO, Bulk, Interrupt
uint8_t sync : 2; // None, Asynchronous, Adaptive, Synchronous
uint8_t usage : 2; // Data, Feedback, Implicit feedback
uint8_t : 2;
+#elif (TU_BITFIELD_ORDER == TU_BITFIELD_BE)
+ uint8_t : 2;
+ uint8_t usage : 2;
+ uint8_t sync : 2;
+ uint8_t xfer : 2;
+#else
+ #error "Please define TU_BITFIELD_ORDER as TU_BITFIELD_LE or TU_BITFIELD_BE"
+#endif
} bmAttributes;
uint16_t wMaxPacketSize ; // Bit 10..0 : max packet size, bit 12..11 additional transaction per highspeed micro-frame
uint8_t bInterval ; // Polling interval, in frames or microframes depending on the operating speed
} tusb_desc_endpoint_t;
-TU_VERIFY_STATIC( sizeof(tusb_desc_endpoint_t) == 7, "size is not correct");
+TU_VERIFY_STATIC( sizeof(tusb_desc_endpoint_t) == 7u, "size is not correct");
/// USB Other Speed Configuration Descriptor
typedef struct TU_ATTR_PACKED {
@@ -441,7 +467,7 @@ typedef struct TU_ATTR_PACKED {
uint8_t bReserved ; ///< Reserved for future use, must be zero
} tusb_desc_device_qualifier_t;
-TU_VERIFY_STATIC( sizeof(tusb_desc_device_qualifier_t) == 10, "size is not correct");
+TU_VERIFY_STATIC( sizeof(tusb_desc_device_qualifier_t) == 10u, "size is not correct");
/// USB Interface Association Descriptor (IAD ECN)
typedef struct TU_ATTR_PACKED {
@@ -458,7 +484,7 @@ typedef struct TU_ATTR_PACKED {
uint8_t iFunction ; ///< Index of the string descriptor describing the interface association.
} tusb_desc_interface_assoc_t;
-TU_VERIFY_STATIC( sizeof(tusb_desc_interface_assoc_t) == 8, "size is not correct");
+TU_VERIFY_STATIC( sizeof(tusb_desc_interface_assoc_t) == 8u, "size is not correct");
// USB String Descriptor
typedef struct TU_ATTR_PACKED {
@@ -514,9 +540,17 @@ typedef struct TU_ATTR_PACKED {
typedef struct TU_ATTR_PACKED {
union {
struct TU_ATTR_PACKED {
+#if (TU_BITFIELD_ORDER == TU_BITFIELD_LE)
uint8_t recipient : 5; ///< Recipient type tusb_request_recipient_t.
uint8_t type : 2; ///< Request type tusb_request_type_t.
uint8_t direction : 1; ///< Direction type. tusb_dir_t
+#elif (TU_BITFIELD_ORDER == TU_BITFIELD_BE)
+ uint8_t direction : 1; ///< Direction type. tusb_dir_t
+ uint8_t type : 2; ///< Request type tusb_request_type_t.
+ uint8_t recipient : 5; ///< Recipient type tusb_request_recipient_t.
+#else
+ #error "Please define TU_BITFIELD_ORDER as TU_BITFIELD_LE or TU_BITFIELD_BE"
+#endif
} bmRequestType_bit;
uint8_t bmRequestType;
@@ -528,7 +562,7 @@ typedef struct TU_ATTR_PACKED {
uint16_t wLength;
} tusb_control_request_t;
-TU_VERIFY_STATIC( sizeof(tusb_control_request_t) == 8, "size is not correct");
+TU_VERIFY_STATIC( sizeof(tusb_control_request_t) == 8u, "size is not correct");
TU_ATTR_PACKED_END // End of all packed definitions
TU_ATTR_BIT_FIELD_ORDER_END
@@ -544,11 +578,11 @@ TU_ATTR_ALWAYS_INLINE static inline tusb_dir_t tu_edpt_dir(uint8_t addr) {
// Get Endpoint number from address
TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_number(uint8_t addr) {
- return (uint8_t)(addr & (~TUSB_DIR_IN_MASK));
+ return (uint8_t) (addr & TUSB_EPNUM_MASK);
}
TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_addr(uint8_t num, uint8_t dir) {
- return (uint8_t)(num | (dir ? TUSB_DIR_IN_MASK : 0));
+ return (uint8_t) (num | (dir == (uint8_t)TUSB_DIR_IN ? (uint8_t)TUSB_DIR_IN_MASK : 0u));
}
TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_edpt_packet_size(tusb_desc_endpoint_t const* desc_ep) {
diff --git a/src/common/tusb_verify.h b/src/common/tusb_verify.h
index db91a73d9..c0e4d0883 100644
--- a/src/common/tusb_verify.h
+++ b/src/common/tusb_verify.h
@@ -67,23 +67,26 @@
//--------------------------------------------------------------------+
// TU_VERIFY Helper
//--------------------------------------------------------------------+
-
#if CFG_TUSB_DEBUG
- #include <stdio.h>
- #define TU_MESS_FAILED() tu_printf("%s %d: ASSERT FAILED\r\n", __func__, __LINE__)
+ #define TU_MESS_FAILED() TU_LOG1("%s %d: ASSERT FAILED\r\n", __func__, __LINE__)
#else
#define TU_MESS_FAILED() do {} while (0)
#endif
+// Custom defined application function
+#ifdef CFG_TUSB_DEBUG_BREAKPOINT
+ extern void CFG_TUSB_DEBUG_BREAKPOINT(void);
+ #define TU_BREAKPOINT() CFG_TUSB_DEBUG_BREAKPOINT()
+
// Halt CPU (breakpoint) when hitting error, only apply for Cortex M3, M4, M7, M33. M55
-#if defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8_1M_MAIN__) || \
+#elif defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8_1M_MAIN__) || \
defined(__ARM7M__) || defined (__ARM7EM__) || defined(__ARM8M_MAINLINE__) || defined(__ARM8EM_MAINLINE__)
#define TU_BREAKPOINT() do { \
volatile uint32_t* ARM_CM_DHCSR = ((volatile uint32_t*) 0xE000EDF0UL); /* Cortex M CoreDebug->DHCSR */ \
- if ( (*ARM_CM_DHCSR) & 1UL ) __asm("BKPT #0\n"); /* Only halt mcu if debugger is attached */ \
+ if (0u != ((*ARM_CM_DHCSR) & 1UL)) { __asm("BKPT #0\n"); } /* Only halt mcu if debugger is attached */ \
} while(0)
-#elif defined(__riscv) && !TUSB_MCU_VENDOR_ESPRESSIF
+#elif defined(__riscv) && !defined(ESP_PLATFORM)
#define TU_BREAKPOINT() do { __asm("ebreak\n"); } while(0)
#elif defined(_mips)
@@ -98,10 +101,12 @@
* - TU_VERIFY_1ARGS : return false if failed
* - TU_VERIFY_2ARGS : return provided value if failed
*------------------------------------------------------------------*/
-#define TU_VERIFY_DEFINE(_cond, _ret) \
- do { \
- if ( !(_cond) ) { return _ret; } \
- } while(0)
+#define TU_VERIFY_DEFINE(_cond, _ret) \
+ do { \
+ if (!(_cond)) { \
+ return _ret; \
+ } \
+ } while (0)
#define TU_VERIFY_1ARGS(_cond) TU_VERIFY_DEFINE(_cond, false)
#define TU_VERIFY_2ARGS(_cond, _ret) TU_VERIFY_DEFINE(_cond, _ret)