mirror of
https://github.com/hathach/tinyusb.git
synced 2026-02-04 06:15:29 +00:00
Merge branch 'master' into fork/zhiqiang-ch/master
This commit is contained in:
14
README.rst
14
README.rst
@ -139,7 +139,7 @@ Supported CPUs
|
||||
| | MAX32 650, 666, 690, | ✔ | | ✔ | musb | 1-dir ep |
|
||||
| | MAX78002 | | | | | |
|
||||
+--------------+-----------------------------+--------+------+-----------+------------------------+--------------------+
|
||||
| Artery AT32 | F403a_407, F413 | ✔ | | | fsdev | Packet SRAM 512 |
|
||||
| Artery AT32 | F403a_407, F413 | ✔ | | | fsdev | 512 USB RAM |
|
||||
| +-----------------------------+--------+------+-----------+------------------------+--------------------+
|
||||
| | F415, F435_437, F423, | ✔ | ✔ | | dwc2 | |
|
||||
| | F425, F45x | | | | | |
|
||||
@ -226,25 +226,25 @@ Supported CPUs
|
||||
+--------------+-----------------------------+--------+------+-----------+------------------------+--------------------+
|
||||
| ST STM32 | F0, F3, L0, L1, L5, WBx5 | ✔ | ✖ | ✖ | stm32_fsdev | |
|
||||
| +----+------------------------+--------+------+-----------+------------------------+--------------------+
|
||||
| | F1 | 102, 103 | ✔ | ✖ | ✖ | stm32_fsdev | Packet SRAM 512 |
|
||||
| | F1 | 102, 103 | ✔ | ✖ | ✖ | stm32_fsdev | 512 USB RAM |
|
||||
| | +------------------------+--------+------+-----------+------------------------+--------------------+
|
||||
| | | 105, 107 | ✔ | ✔ | ✖ | dwc2 | |
|
||||
| +----+------------------------+--------+------+-----------+------------------------+--------------------+
|
||||
| | F2, F4, F7, H7, H7RS | ✔ | ✔ | ✔ | dwc2 | |
|
||||
| +-----------------------------+--------+------+-----------+------------------------+--------------------+
|
||||
| | C0, G0, H5, U3 | ✔ | ✔ | ✖ | stm32_fsdev | Packet SRAM 2KB |
|
||||
| | C0, G0, H5, U3 | ✔ | ✔ | ✖ | stm32_fsdev | 2KB USB RAM |
|
||||
| +-----------------------------+--------+------+-----------+------------------------+--------------------+
|
||||
| | G4 | ✔ | ✖ | ✖ | stm32_fsdev | Packet SRAM 1KB |
|
||||
| | G4 | ✔ | ✖ | ✖ | stm32_fsdev | 1KB USB RAM |
|
||||
| +----+------------------------+--------+------+-----------+------------------------+--------------------+
|
||||
| | L4 | 4x2, 4x3 | ✔ | ✖ | ✖ | stm32_fsdev | Packet SRAM 1KB |
|
||||
| | L4 | 4x2, 4x3 | ✔ | ✖ | ✖ | stm32_fsdev | 1KB USB RAM |
|
||||
| | +------------------------+--------+------+-----------+------------------------+--------------------+
|
||||
| | | 4x5, 4x6, 4+ | ✔ | ✔ | ✖ | dwc2 | |
|
||||
| +----+------------------------+--------+------+-----------+------------------------+--------------------+
|
||||
| | N6 | ✔ | ✔ | ✔ | dwc2 | |
|
||||
| +-----------------------------+--------+------+-----------+------------------------+--------------------+
|
||||
| | U0 | ✔ | ✖ | ✖ | stm32_fsdev | Packet SRAM 1KB |
|
||||
| | U0 | ✔ | ✖ | ✖ | stm32_fsdev | 1KB USB RAM |
|
||||
| +----+------------------------+--------+------+-----------+------------------------+--------------------+
|
||||
| | U5 | 535, 545 | ✔ | ✔ | ✖ | stm32_fsdev | Packet SRAM 2KB |
|
||||
| | U5 | 535, 545 | ✔ | ✔ | ✖ | stm32_fsdev | 2KB USB RAM |
|
||||
| | +------------------------+--------+------+-----------+------------------------+--------------------+
|
||||
| | | 575, 585 | ✔ | ✔ | ✖ | dwc2 | |
|
||||
| | +------------------------+--------+------+-----------+------------------------+--------------------+
|
||||
|
||||
@ -674,17 +674,17 @@ void audiod_init(void) {
|
||||
switch (i) {
|
||||
#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0
|
||||
case 0:
|
||||
tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ, 1, true);
|
||||
tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ, true);
|
||||
break;
|
||||
#endif
|
||||
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0
|
||||
case 1:
|
||||
tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_2, CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ, 1, true);
|
||||
tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_2, CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ, true);
|
||||
break;
|
||||
#endif
|
||||
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0
|
||||
case 2:
|
||||
tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ, 1, true);
|
||||
tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ, true);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
@ -716,17 +716,17 @@ void audiod_init(void) {
|
||||
switch (i) {
|
||||
#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0
|
||||
case 0:
|
||||
tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ, 1, true);
|
||||
tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ, true);
|
||||
break;
|
||||
#endif
|
||||
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0
|
||||
case 1:
|
||||
tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_2, CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ, 1, true);
|
||||
tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_2, CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ, true);
|
||||
break;
|
||||
#endif
|
||||
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0
|
||||
case 2:
|
||||
tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ, 1, true);
|
||||
tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ, true);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -329,7 +329,7 @@ TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16(void *mem, uint16_
|
||||
|
||||
#endif
|
||||
|
||||
// scatter read 4 bytes from two buffers. Parameter are not checked
|
||||
// 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;
|
||||
@ -348,7 +348,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_scatter_read32(const uint8_t *bu
|
||||
return result;
|
||||
}
|
||||
|
||||
// scatter write 4 bytes to two buffers. Parameter are not checked
|
||||
// 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) {
|
||||
|
||||
@ -59,7 +59,7 @@ TU_ATTR_ALWAYS_INLINE static inline void ff_unlock(osal_mutex_t mutex) {
|
||||
//--------------------------------------------------------------------+
|
||||
// Setup API
|
||||
//--------------------------------------------------------------------+
|
||||
bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, uint16_t item_size, bool overwritable) {
|
||||
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)
|
||||
@ -72,7 +72,6 @@ bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, uint16_t item_si
|
||||
|
||||
f->buffer = (uint8_t *)buffer;
|
||||
f->depth = depth;
|
||||
f->item_size = (uint16_t)(item_size & 0x7FFFu);
|
||||
f->overwritable = overwritable;
|
||||
f->rd_idx = 0u;
|
||||
f->wr_idx = 0u;
|
||||
@ -114,172 +113,265 @@ void tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) {
|
||||
// Pull & Push
|
||||
// copy data to/from fifo without updating read/write pointers
|
||||
//--------------------------------------------------------------------+
|
||||
#ifdef CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32
|
||||
// Copy to fifo from fixed address buffer (usually a rx register) with TU_FIFO_FIXED_ADDR_RW32 mode
|
||||
static void ff_push_fixed_addr_rw32(uint8_t *ff_buf, const volatile uint32_t *reg_rx, uint16_t len) {
|
||||
// Reading full available 32 bit words from const app address
|
||||
uint16_t full_words = len >> 2;
|
||||
while (full_words--) {
|
||||
const uint32_t tmp32 = *reg_rx;
|
||||
tu_unaligned_write32(ff_buf, tmp32);
|
||||
ff_buf += 4;
|
||||
}
|
||||
#if CFG_TUSB_FIFO_HWFIFO_API
|
||||
#if CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE
|
||||
#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
|
||||
|
||||
// Read the remaining 1-3 bytes from const app address
|
||||
const uint8_t bytes_rem = len & 0x03;
|
||||
if (bytes_rem) {
|
||||
const uint32_t tmp32 = *reg_rx;
|
||||
memcpy(ff_buf, &tmp32, bytes_rem);
|
||||
#define HWFIFO_ADDR_NEXT(_hwfifo, _const) HWFIFO_ADDR_NEXT_N(_hwfifo, _const, CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE)
|
||||
|
||||
#ifndef CFG_TUSB_FIFO_HWFIFO_CUSTOM_WRITE
|
||||
static inline void stride_write(volatile void *hwfifo, const void *src, uint8_t data_stride) {
|
||||
#if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE & 4
|
||||
if (data_stride == 4) {
|
||||
*((volatile uint32_t *)hwfifo) = tu_unaligned_read32(src);
|
||||
}
|
||||
#endif
|
||||
#if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE & 2
|
||||
if (data_stride == 2) {
|
||||
*((volatile uint16_t *)hwfifo) = tu_unaligned_read16(src);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Copy from fifo to fixed address buffer (usually a tx register) with TU_FIFO_FIXED_ADDR_RW32 mode
|
||||
static void ff_pull_fixed_addr_rw32(volatile uint32_t *reg_tx, const uint8_t *ff_buf, uint16_t len) {
|
||||
// Write full available 32 bit words to const address
|
||||
uint16_t full_words = len >> 2u;
|
||||
while (full_words--) {
|
||||
*reg_tx = tu_unaligned_read32(ff_buf);
|
||||
ff_buf += 4u;
|
||||
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, );
|
||||
}
|
||||
|
||||
// Write the remaining 1-3 bytes
|
||||
const uint8_t bytes_rem = len & 0x03;
|
||||
if (bytes_rem) {
|
||||
uint32_t tmp32 = 0u;
|
||||
memcpy(&tmp32, ff_buf, bytes_rem);
|
||||
*reg_tx = tmp32;
|
||||
#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
|
||||
|
||||
#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
|
||||
|
||||
// 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
|
||||
|
||||
#ifndef CFG_TUSB_FIFO_HWFIFO_CUSTOM_READ
|
||||
static inline void stride_read(const volatile void *hwfifo, void *dest, 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
|
||||
{
|
||||
tu_unaligned_write32(dest, *((const volatile uint32_t *)hwfifo));
|
||||
}
|
||||
#endif
|
||||
|
||||
#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
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
#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
|
||||
|
||||
// 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;
|
||||
|
||||
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
|
||||
|
||||
// Write full words to linear part of buffer
|
||||
const uint8_t data_stride = access_mode->data_stride;
|
||||
const uint32_t odd_mask = data_stride - 1;
|
||||
uint16_t lin_even = lin_bytes & ~odd_mask;
|
||||
tu_hwfifo_read(hwfifo, ff_buf, lin_even, access_mode);
|
||||
HWFIFO_ADDR_NEXT_N(hwfifo, const, lin_even);
|
||||
ff_buf += lin_even;
|
||||
|
||||
// There could be 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 = 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];
|
||||
}
|
||||
for (uint8_t i = 0; i < wrap_odd; ++i) {
|
||||
f->buffer[i] = buf_temp[lin_odd + i];
|
||||
}
|
||||
|
||||
wrap_bytes -= wrap_odd;
|
||||
ff_buf = f->buffer + wrap_odd; // wrap around
|
||||
} else {
|
||||
ff_buf = f->buffer; // wrap around to beginning
|
||||
}
|
||||
|
||||
// Write data wrapped part
|
||||
if (wrap_bytes > 0) {
|
||||
tu_hwfifo_read(hwfifo, ff_buf, wrap_bytes, access_mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
volatile void *hwfifo = (volatile void *)app_buf;
|
||||
|
||||
if (n <= lin_bytes) {
|
||||
// Linear only case
|
||||
tu_hwfifo_write(hwfifo, ff_buf, n, access_mode);
|
||||
} else {
|
||||
// Wrap around case
|
||||
|
||||
// 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 = lin_bytes & ~odd_mask;
|
||||
tu_hwfifo_write(hwfifo, ff_buf, lin_even, access_mode);
|
||||
HWFIFO_ADDR_NEXT_N(hwfifo, , lin_even);
|
||||
ff_buf += lin_even;
|
||||
|
||||
// There could be odd 1 byte (16bit) or 1-3 bytes (32bit) before the wrap-around boundary
|
||||
const uint8_t lin_odd = 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];
|
||||
for (uint8_t i = 0; i < lin_odd; ++i) {
|
||||
buf_temp[i] = ff_buf[i];
|
||||
}
|
||||
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
|
||||
|
||||
// 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,
|
||||
tu_fifo_access_mode_t copy_mode) {
|
||||
const uint16_t lin_count = f->depth - wr_ptr;
|
||||
const uint16_t wrap_count = n - lin_count;
|
||||
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;
|
||||
|
||||
uint16_t lin_bytes = lin_count * f->item_size;
|
||||
uint16_t wrap_bytes = wrap_count * f->item_size;
|
||||
|
||||
// current buffer of fifo
|
||||
uint8_t *ff_buf = f->buffer + (wr_ptr * f->item_size);
|
||||
|
||||
switch (copy_mode) {
|
||||
case TU_FIFO_INC_ADDR_RW8:
|
||||
if (n <= lin_count) {
|
||||
// Linear only
|
||||
memcpy(ff_buf, app_buf, n * f->item_size);
|
||||
} else {
|
||||
// Wrap around
|
||||
memcpy(ff_buf, app_buf, lin_bytes); // linear part
|
||||
memcpy(f->buffer, ((const uint8_t *)app_buf) + lin_bytes, wrap_bytes); // wrapped part
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32
|
||||
case TU_FIFO_FIXED_ADDR_RW32: {
|
||||
const volatile uint32_t *reg_rx = (volatile const uint32_t *)app_buf;
|
||||
if (n <= lin_count) {
|
||||
// Linear only
|
||||
ff_push_fixed_addr_rw32(ff_buf, reg_rx, n * f->item_size);
|
||||
} else {
|
||||
// Wrap around
|
||||
|
||||
// Write full words to linear part of buffer
|
||||
uint16_t lin_4n_bytes = lin_bytes & 0xFFFC;
|
||||
ff_push_fixed_addr_rw32(ff_buf, reg_rx, lin_4n_bytes);
|
||||
ff_buf += lin_4n_bytes;
|
||||
|
||||
// There could be odd 1-3 bytes before the wrap-around boundary
|
||||
const uint8_t rem = lin_bytes & 0x03;
|
||||
if (rem > 0) {
|
||||
const uint8_t remrem = (uint8_t)tu_min16(wrap_bytes, 4 - rem);
|
||||
const uint32_t tmp32 = *reg_rx;
|
||||
tu_scatter_write32(tmp32, ff_buf, rem, f->buffer, remrem);
|
||||
|
||||
wrap_bytes -= remrem;
|
||||
ff_buf = f->buffer + remrem; // wrap around
|
||||
} else {
|
||||
ff_buf = f->buffer; // wrap around to beginning
|
||||
}
|
||||
|
||||
// Write data wrapped part
|
||||
if (wrap_bytes > 0) {
|
||||
ff_push_fixed_addr_rw32(ff_buf, reg_rx, wrap_bytes);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
default:
|
||||
break; // unknown mode
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
// 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, tu_fifo_access_mode_t copy_mode) {
|
||||
const uint16_t lin_count = f->depth - rd_ptr;
|
||||
const uint16_t wrap_count = n - lin_count; // only used if wrapped
|
||||
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;
|
||||
|
||||
uint16_t lin_bytes = lin_count * f->item_size;
|
||||
uint16_t wrap_bytes = wrap_count * f->item_size;
|
||||
|
||||
// current buffer of fifo
|
||||
const uint8_t *ff_buf = f->buffer + (rd_ptr * f->item_size);
|
||||
|
||||
switch (copy_mode) {
|
||||
case TU_FIFO_INC_ADDR_RW8:
|
||||
if (n <= lin_count) {
|
||||
// Linear only
|
||||
memcpy(app_buf, ff_buf, n * f->item_size);
|
||||
} 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
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32
|
||||
case TU_FIFO_FIXED_ADDR_RW32: {
|
||||
volatile uint32_t *reg_tx = (volatile uint32_t *)app_buf;
|
||||
|
||||
if (n <= lin_count) {
|
||||
// Linear only
|
||||
ff_pull_fixed_addr_rw32(reg_tx, ff_buf, n * f->item_size);
|
||||
} else {
|
||||
// Wrap around case
|
||||
|
||||
// Read full words from linear part
|
||||
uint16_t lin_4n_bytes = lin_bytes & 0xFFFC;
|
||||
ff_pull_fixed_addr_rw32(reg_tx, ff_buf, lin_4n_bytes);
|
||||
ff_buf += lin_4n_bytes;
|
||||
|
||||
// There could be odd 1-3 bytes before the wrap-around boundary
|
||||
const uint8_t rem = lin_bytes & 0x03;
|
||||
if (rem > 0) {
|
||||
const uint8_t remrem = (uint8_t)tu_min16(wrap_bytes, 4 - rem);
|
||||
const uint32_t scatter32 = tu_scatter_read32(ff_buf, rem, f->buffer, remrem);
|
||||
|
||||
*reg_tx = scatter32;
|
||||
|
||||
wrap_bytes -= remrem;
|
||||
ff_buf = f->buffer + remrem; // wrap around
|
||||
} else {
|
||||
ff_buf = f->buffer; // wrap around to beginning
|
||||
}
|
||||
|
||||
// Read data wrapped part
|
||||
if (wrap_bytes > 0) {
|
||||
ff_pull_fixed_addr_rw32(reg_tx, ff_buf, wrap_bytes);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
default:
|
||||
break; // unknown mode
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
@ -332,7 +424,7 @@ static uint16_t correct_read_index(tu_fifo_t *f, uint16_t wr_idx) {
|
||||
// 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,
|
||||
tu_fifo_access_mode_t access_mode) {
|
||||
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
|
||||
@ -349,7 +441,16 @@ uint16_t tu_fifo_peek_n_access_mode(tu_fifo_t *f, void *p_buffer, uint16_t n, ui
|
||||
}
|
||||
|
||||
const uint16_t rd_ptr = idx2ptr(f->depth, rd_idx);
|
||||
ff_pull_n(f, p_buffer, n, rd_ptr, access_mode);
|
||||
|
||||
#if CFG_TUSB_FIFO_HWFIFO_API
|
||||
if (access_mode != NULL) {
|
||||
hwff_pull_n(f, p_buffer, n, rd_ptr, access_mode);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
(void)access_mode;
|
||||
ff_pull_n(f, p_buffer, n, rd_ptr);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
@ -357,13 +458,13 @@ uint16_t tu_fifo_peek_n_access_mode(tu_fifo_t *f, void *p_buffer, uint16_t n, ui
|
||||
// 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 ret = tu_fifo_peek_n_access_mode(f, p_buffer, n, f->wr_idx, f->rd_idx, TU_FIFO_INC_ADDR_RW8);
|
||||
const uint16_t ret = tu_fifo_peek_n_access_mode(f, p_buffer, n, f->wr_idx, f->rd_idx, NULL);
|
||||
ff_unlock(f->mutex_rd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 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, tu_fifo_access_mode_t 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 the data: f->rd_idx might get modified in case of an overflow so we can not use a local variable
|
||||
@ -375,7 +476,8 @@ uint16_t tu_fifo_read_n_access_mode(tu_fifo_t *f, void *buffer, uint16_t n, tu_f
|
||||
}
|
||||
|
||||
// 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, tu_fifo_access_mode_t 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;
|
||||
}
|
||||
@ -401,8 +503,8 @@ uint16_t tu_fifo_write_n_access_mode(tu_fifo_t *f, const void *data, uint16_t n,
|
||||
// function! Since it would end up in a race condition with read functions!
|
||||
if (n >= f->depth) {
|
||||
// Only copy last part
|
||||
if (access_mode == TU_FIFO_INC_ADDR_RW8) {
|
||||
buf8 += (n - f->depth) * f->item_size;
|
||||
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.
|
||||
@ -437,7 +539,14 @@ uint16_t tu_fifo_write_n_access_mode(tu_fifo_t *f, const void *data, uint16_t 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);
|
||||
|
||||
ff_push_n(f, buf8, n, wr_ptr, access_mode);
|
||||
#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);
|
||||
@ -477,7 +586,7 @@ static bool ff_peek_local(tu_fifo_t *f, void *buf, uint16_t wr_idx, uint16_t rd_
|
||||
}
|
||||
|
||||
const uint16_t rd_ptr = idx2ptr(f->depth, rd_idx);
|
||||
memcpy(buf, f->buffer + (rd_ptr * f->item_size), f->item_size);
|
||||
memcpy(buf, f->buffer + rd_ptr, 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -512,7 +621,7 @@ bool tu_fifo_write(tu_fifo_t *f, const void *data) {
|
||||
ret = false;
|
||||
} else {
|
||||
const uint16_t wr_ptr = idx2ptr(f->depth, wr_idx);
|
||||
memcpy(f->buffer + (wr_ptr * f->item_size), data, f->item_size);
|
||||
memcpy(f->buffer + wr_ptr, data, 1);
|
||||
f->wr_idx = advance_index(f->depth, wr_idx, 1);
|
||||
ret = true;
|
||||
}
|
||||
|
||||
@ -32,6 +32,25 @@
|
||||
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,17 +60,6 @@ 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
|
||||
|
||||
#if CFG_TUD_EDPT_DEDICATED_HWFIFO || CFG_TUH_EDPT_DEDICATED_HWFIFO
|
||||
#define CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32
|
||||
#endif
|
||||
|
||||
/* Write/Read "pointer" is in the range of: 0 .. depth - 1, and is used to get the fifo data.
|
||||
* Write/Read "index" is always in the range of: 0 .. 2*depth-1
|
||||
*
|
||||
@ -111,20 +119,16 @@ extern "C" {
|
||||
typedef struct {
|
||||
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 wr_idx; // write index TODO maybe can drop volatile
|
||||
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 {
|
||||
@ -134,29 +138,32 @@ typedef struct {
|
||||
} 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_INIT(_buffer, _depth, _overwritable) \
|
||||
{ \
|
||||
.buffer = _buffer, \
|
||||
.depth = _depth, \
|
||||
.overwritable = _overwritable, \
|
||||
}
|
||||
|
||||
#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_DEF(_name, _depth, _overwritable) \
|
||||
uint8_t _name##_buf[_depth]; \
|
||||
tu_fifo_t _name = TU_FIFO_INIT(_name##_buf, _depth, _overwritable)
|
||||
|
||||
// Write modes intended to allow special read and write functions to be able to
|
||||
// copy data to and from USB hardware FIFOs as needed for e.g. STM32s and others
|
||||
typedef enum {
|
||||
TU_FIFO_INC_ADDR_RW8, // increased address read/write by bytes - normal (default) mode
|
||||
TU_FIFO_FIXED_ADDR_RW32, // fixed address read/write by 4 bytes (word). Used for STM32 access into USB hardware FIFO
|
||||
} tu_fifo_access_mode_t;
|
||||
// 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, uint16_t item_size, bool overwritable);
|
||||
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);
|
||||
|
||||
@ -191,7 +198,7 @@ void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info);
|
||||
// peek() will correct/re-index read pointer in case of an overflowed fifo to form a full fifo
|
||||
//--------------------------------------------------------------------+
|
||||
uint16_t tu_fifo_peek_n_access_mode(tu_fifo_t *f, void *p_buffer, uint16_t n, uint16_t wr_idx, uint16_t rd_idx,
|
||||
tu_fifo_access_mode_t access_mode);
|
||||
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);
|
||||
|
||||
@ -199,10 +206,10 @@ 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, tu_fifo_access_mode_t 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);
|
||||
bool tu_fifo_read(tu_fifo_t *f, void *buffer);
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_fifo_read_n(tu_fifo_t *f, void *buffer, uint16_t n) {
|
||||
return tu_fifo_read_n_access_mode(f, buffer, n, TU_FIFO_INC_ADDR_RW8);
|
||||
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
|
||||
@ -212,12 +219,41 @@ 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, tu_fifo_access_mode_t 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);
|
||||
bool tu_fifo_write(tu_fifo_t *f, const void *data);
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_fifo_write_n(tu_fifo_t *f, const void *data, uint16_t n) {
|
||||
return tu_fifo_write_n_access_mode(f, data, n, TU_FIFO_INC_ADDR_RW8);
|
||||
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
|
||||
|
||||
@ -184,10 +184,15 @@
|
||||
//--------------------------------------------------------------------+
|
||||
// ST
|
||||
//--------------------------------------------------------------------+
|
||||
#elif TU_CHECK_MCU(OPT_MCU_STM32C0)
|
||||
#define TUP_USBIP_FSDEV
|
||||
#define TUP_USBIP_FSDEV_STM32
|
||||
#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
|
||||
@ -203,7 +208,7 @@
|
||||
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
|
||||
@ -218,7 +223,16 @@
|
||||
#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)
|
||||
#define CFG_TUSB_FSDEV_PMA_SIZE 512u
|
||||
#elif defined(STM32F302x6) || defined(STM32F302x8) || defined(STM32F302xD) || defined(STM32F302xE) || \
|
||||
defined(STM32F303xD) || defined(STM32F303xE)
|
||||
#define CFG_TUSB_FSDEV_PMA_SIZE 1024u
|
||||
#else
|
||||
#error "Unsupported STM32F3 mcu"
|
||||
#endif
|
||||
|
||||
#elif TU_CHECK_MCU(OPT_MCU_STM32F4)
|
||||
#define TUP_USBIP_DWC2
|
||||
@ -244,6 +258,26 @@
|
||||
#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_STM32G0)
|
||||
#define TUP_USBIP_FSDEV
|
||||
#define TUP_USBIP_FSDEV_STM32
|
||||
#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_TYPEC_RHPORTS_NUM 1
|
||||
|
||||
#elif TU_CHECK_MCU(OPT_MCU_STM32H5)
|
||||
#define TUP_USBIP_FSDEV
|
||||
#define TUP_USBIP_FSDEV_STM32
|
||||
#define CFG_TUSB_FSDEV_PMA_SIZE 2048u
|
||||
|
||||
#elif TU_CHECK_MCU(OPT_MCU_STM32H7)
|
||||
#define TUP_USBIP_DWC2
|
||||
#define TUP_USBIP_DWC2_STM32
|
||||
@ -257,35 +291,30 @@
|
||||
#define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32
|
||||
#endif
|
||||
|
||||
#elif TU_CHECK_MCU(OPT_MCU_STM32H5)
|
||||
#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_STM32G4)
|
||||
// Device controller
|
||||
#elif TU_CHECK_MCU(OPT_MCU_STM32L1)
|
||||
#define TUP_USBIP_FSDEV
|
||||
#define TUP_USBIP_FSDEV_STM32
|
||||
|
||||
// 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)
|
||||
#define TUP_USBIP_FSDEV
|
||||
#define TUP_USBIP_FSDEV_STM32
|
||||
#define TUP_DCD_ENDPOINT_MAX 8
|
||||
|
||||
#elif TU_CHECK_MCU(OPT_MCU_STM32C0)
|
||||
#define TUP_USBIP_FSDEV
|
||||
#define TUP_USBIP_FSDEV_STM32
|
||||
#define TUP_DCD_ENDPOINT_MAX 8
|
||||
|
||||
#elif TU_CHECK_MCU(OPT_MCU_STM32L0, 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
|
||||
@ -302,28 +331,32 @@
|
||||
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 CFG_TUSB_FSDEV_PMA_SIZE 2048u
|
||||
|
||||
#elif TU_CHECK_MCU(OPT_MCU_STM32U5)
|
||||
// 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 CFG_TUSB_FSDEV_PMA_SIZE 2048u
|
||||
#else
|
||||
#define TUP_USBIP_DWC2
|
||||
#define TUP_USBIP_DWC2_STM32
|
||||
@ -338,35 +371,16 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#elif TU_CHECK_MCU(OPT_MCU_STM32L5)
|
||||
#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_STM32U0)
|
||||
#define TUP_USBIP_FSDEV
|
||||
#define TUP_USBIP_FSDEV_STM32
|
||||
#define TUP_DCD_ENDPOINT_MAX 8
|
||||
|
||||
#elif TU_CHECK_MCU(OPT_MCU_STM32U3)
|
||||
#define TUP_USBIP_FSDEV
|
||||
#define TUP_USBIP_FSDEV_STM32
|
||||
#define TUP_DCD_ENDPOINT_MAX 8
|
||||
|
||||
#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
|
||||
@ -422,10 +436,6 @@
|
||||
#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
|
||||
@ -438,10 +448,6 @@
|
||||
|
||||
#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
|
||||
|
||||
// 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
|
||||
@ -573,6 +579,7 @@
|
||||
|
||||
#define TUP_USBIP_FSDEV
|
||||
#define TUP_USBIP_FSDEV_CH32
|
||||
#define CFG_TUSB_FSDEV_PMA_SIZE 512u
|
||||
|
||||
// default to FSDEV for device
|
||||
#if !defined(CFG_TUD_WCH_USBIP_USBFS)
|
||||
@ -618,15 +625,10 @@
|
||||
//--------------------------------------------------------------------+
|
||||
// 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
|
||||
@ -679,10 +681,7 @@
|
||||
|
||||
#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))
|
||||
@ -694,6 +693,10 @@
|
||||
// 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
|
||||
#endif
|
||||
|
||||
@ -96,10 +96,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)
|
||||
|
||||
@ -1405,12 +1405,13 @@ static void remove_device_tree(uint8_t rhport, uint8_t hub_addr, uint8_t hub_por
|
||||
// NOTE: due to the shared control buffer, we must complete enumerating
|
||||
// one device before enumerating another one.
|
||||
//--------------------------------------------------------------------+
|
||||
enum { // USB 2.0 specs 7.1.7 for timing
|
||||
ENUM_DEBOUNCING_DELAY_MS = 150, // T(ATTDB) minimum 100 ms for stable connection
|
||||
ENUM_RESET_ROOT_DELAY_MS = 50, // T(DRSTr) minimum 50 ms for reset from root port
|
||||
ENUM_RESET_HUB_DELAY_MS = 20, // T(DRST) 10-20 ms for hub reset
|
||||
ENUM_RESET_RECOVERY_DELAY_MS = 10, // T(RSTRCY) minimum 10 ms for reset recovery
|
||||
ENUM_SET_ADDRESS_RECOVERY_DELAY_MS = 2, // USB 2.0 Spec 9.2.6.3 min is 2 ms
|
||||
enum { // USB 2.0 specs 7.1.7 for timing
|
||||
ENUM_DEBOUNCING_DELAY_MS = 150, // T(ATTDB) minimum 100 ms for stable connection
|
||||
ENUM_RESET_ROOT_DELAY_MS = 50, // T(DRSTr) minimum 50 ms for reset from root port
|
||||
ENUM_RESET_ROOT_POST_DELAY_MS = 2, // 2 ms delay after root port reset before getting speed/status
|
||||
ENUM_RESET_HUB_DELAY_MS = 20, // T(DRST) 10-20 ms for hub reset
|
||||
ENUM_RESET_RECOVERY_DELAY_MS = 10, // T(RSTRCY) minimum 10 ms for reset recovery
|
||||
ENUM_SET_ADDRESS_RECOVERY_DELAY_MS = 2, // USB 2.0 Spec 9.2.6.3 min is 2 ms
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -1469,6 +1470,7 @@ static bool enum_new_device(hcd_event_t* event) {
|
||||
hcd_port_reset(dev0_bus->rhport);
|
||||
tusb_time_delay_ms_api(ENUM_RESET_ROOT_DELAY_MS);
|
||||
hcd_port_reset_end(dev0_bus->rhport);
|
||||
tusb_time_delay_ms_api(ENUM_RESET_ROOT_POST_DELAY_MS);
|
||||
|
||||
if (!hcd_port_connect_status(dev0_bus->rhport)) {
|
||||
// device unplugged while delaying
|
||||
|
||||
@ -157,21 +157,21 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hd
|
||||
|
||||
typedef struct {
|
||||
void (* interrupt_set)(bool enabled);
|
||||
uint16_t item_size;
|
||||
tu_fifo_t ff;
|
||||
} osal_queue_def_t;
|
||||
|
||||
typedef osal_queue_def_t* osal_queue_t;
|
||||
|
||||
// _int_set is used as mutex in OS NONE (disable/enable USB ISR)
|
||||
#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
|
||||
uint8_t _name##_buf[_depth*sizeof(_type)]; \
|
||||
osal_queue_def_t _name = { \
|
||||
.interrupt_set = _int_set, \
|
||||
.ff = TU_FIFO_INIT(_name##_buf, _depth, _type, false) \
|
||||
}
|
||||
#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
|
||||
uint8_t _name##_buf[_depth * sizeof(_type)]; \
|
||||
osal_queue_def_t _name = {.interrupt_set = _int_set, \
|
||||
.item_size = sizeof(_type), \
|
||||
.ff = TU_FIFO_INIT(_name##_buf, _depth * sizeof(_type), false)}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) {
|
||||
(void) tu_fifo_clear(&qdef->ff);
|
||||
tu_fifo_clear(&qdef->ff);
|
||||
return (osal_queue_t) qdef;
|
||||
}
|
||||
|
||||
@ -184,7 +184,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, v
|
||||
(void) msec; // not used, always behave as msec = 0
|
||||
|
||||
qhdl->interrupt_set(false);
|
||||
const bool success = tu_fifo_read(&qhdl->ff, data);
|
||||
const bool success = tu_fifo_read_n(&qhdl->ff, data, qhdl->item_size);
|
||||
qhdl->interrupt_set(true);
|
||||
|
||||
return success;
|
||||
@ -195,7 +195,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void
|
||||
qhdl->interrupt_set(false);
|
||||
}
|
||||
|
||||
const bool success = tu_fifo_write(&qhdl->ff, data);
|
||||
const bool success = tu_fifo_write_n(&qhdl->ff, data, qhdl->item_size);
|
||||
|
||||
if (!in_isr) {
|
||||
qhdl->interrupt_set(true);
|
||||
|
||||
@ -47,40 +47,39 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
|
||||
// Spinlock API
|
||||
//--------------------------------------------------------------------+
|
||||
typedef critical_section_t osal_spinlock_t; // pico implement critical section with spinlock
|
||||
#define OSAL_SPINLOCK_DEF(_name, _int_set) \
|
||||
osal_spinlock_t _name
|
||||
#define OSAL_SPINLOCK_DEF(_name, _int_set) osal_spinlock_t _name
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) {
|
||||
critical_section_init(ctx);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) {
|
||||
(void) in_isr;
|
||||
(void)in_isr;
|
||||
critical_section_enter_blocking(ctx);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) {
|
||||
(void) in_isr;
|
||||
(void)in_isr;
|
||||
critical_section_exit(ctx);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Binary Semaphore API
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct semaphore osal_semaphore_def_t, * osal_semaphore_t;
|
||||
typedef struct semaphore osal_semaphore_def_t, *osal_semaphore_t;
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef) {
|
||||
TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t *semdef) {
|
||||
sem_init(semdef, 0, 255);
|
||||
return semdef;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_delete(osal_semaphore_t semd_hdl) {
|
||||
(void) semd_hdl;
|
||||
(void)semd_hdl;
|
||||
return true; // nothing to do
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) {
|
||||
(void) in_isr;
|
||||
(void)in_isr;
|
||||
return sem_release(sem_hdl);
|
||||
}
|
||||
|
||||
@ -96,15 +95,15 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t s
|
||||
// MUTEX API
|
||||
// Within tinyusb, mutex is never used in ISR context
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct mutex osal_mutex_def_t, * osal_mutex_t;
|
||||
typedef struct mutex osal_mutex_def_t, *osal_mutex_t;
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) {
|
||||
TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t *mdef) {
|
||||
mutex_init(mdef);
|
||||
return mdef;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_delete(osal_mutex_t mutex_hdl) {
|
||||
(void) mutex_hdl;
|
||||
(void)mutex_hdl;
|
||||
return true; // nothing to do
|
||||
}
|
||||
|
||||
@ -123,46 +122,45 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hd
|
||||
#include "common/tusb_fifo.h"
|
||||
|
||||
typedef struct {
|
||||
tu_fifo_t ff;
|
||||
uint16_t item_size;
|
||||
tu_fifo_t ff;
|
||||
struct critical_section critsec; // osal_queue may be used in IRQs, so need critical section
|
||||
} osal_queue_def_t;
|
||||
|
||||
typedef osal_queue_def_t* osal_queue_t;
|
||||
typedef osal_queue_def_t *osal_queue_t;
|
||||
|
||||
// role device/host is used by OS NONE for mutex (disable usb isr) only
|
||||
#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
|
||||
uint8_t _name##_buf[_depth*sizeof(_type)]; \
|
||||
osal_queue_def_t _name = { \
|
||||
.ff = TU_FIFO_INIT(_name##_buf, _depth, _type, false) \
|
||||
}
|
||||
#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
|
||||
uint8_t _name##_buf[_depth * sizeof(_type)]; \
|
||||
osal_queue_def_t _name = {.item_size = sizeof(_type), .ff = TU_FIFO_INIT(_name##_buf, _depth * sizeof(_type), false)}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) {
|
||||
TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t *qdef) {
|
||||
critical_section_init(&qdef->critsec);
|
||||
(void) tu_fifo_clear(&qdef->ff);
|
||||
return (osal_queue_t) qdef;
|
||||
tu_fifo_clear(&qdef->ff);
|
||||
return (osal_queue_t)qdef;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_delete(osal_queue_t qhdl) {
|
||||
osal_queue_def_t* qdef = (osal_queue_def_t*) qhdl;
|
||||
osal_queue_def_t *qdef = (osal_queue_def_t *)qhdl;
|
||||
critical_section_deinit(&qdef->critsec);
|
||||
return true;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) {
|
||||
(void) msec; // not used, always behave as msec = 0
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void *data, uint32_t msec) {
|
||||
(void)msec; // not used, always behave as msec = 0
|
||||
|
||||
critical_section_enter_blocking(&qhdl->critsec);
|
||||
bool success = tu_fifo_read(&qhdl->ff, data);
|
||||
bool success = tu_fifo_read_n(&qhdl->ff, data, qhdl->item_size);
|
||||
critical_section_exit(&qhdl->critsec);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const* data, bool in_isr) {
|
||||
(void) in_isr;
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, const void *data, bool in_isr) {
|
||||
(void)in_isr;
|
||||
|
||||
critical_section_enter_blocking(&qhdl->critsec);
|
||||
bool success = tu_fifo_write(&qhdl->ff, data);
|
||||
bool success = tu_fifo_write_n(&qhdl->ff, data, qhdl->item_size);
|
||||
critical_section_exit(&qhdl->critsec);
|
||||
|
||||
return success;
|
||||
|
||||
@ -170,68 +170,6 @@ TU_ATTR_ALWAYS_INLINE static inline void hwfifo_flush(musb_regs_t* musb, unsigne
|
||||
}
|
||||
}
|
||||
|
||||
static void pipe_write_packet(void *buf, volatile void *fifo, unsigned len)
|
||||
{
|
||||
volatile hw_fifo_t *reg = (volatile hw_fifo_t*)fifo;
|
||||
uintptr_t addr = (uintptr_t)buf;
|
||||
while (len >= 4) {
|
||||
reg->u32 = *(uint32_t const *)addr;
|
||||
addr += 4;
|
||||
len -= 4;
|
||||
}
|
||||
if (len >= 2) {
|
||||
reg->u16 = *(uint16_t const *)addr;
|
||||
addr += 2;
|
||||
len -= 2;
|
||||
}
|
||||
if (len) {
|
||||
reg->u8 = *(uint8_t const *)addr;
|
||||
}
|
||||
}
|
||||
|
||||
static void pipe_read_packet(void *buf, volatile void *fifo, unsigned len)
|
||||
{
|
||||
volatile hw_fifo_t *reg = (volatile hw_fifo_t*)fifo;
|
||||
uintptr_t addr = (uintptr_t)buf;
|
||||
while (len >= 4) {
|
||||
*(uint32_t *)addr = reg->u32;
|
||||
addr += 4;
|
||||
len -= 4;
|
||||
}
|
||||
if (len >= 2) {
|
||||
*(uint16_t *)addr = reg->u16;
|
||||
addr += 2;
|
||||
len -= 2;
|
||||
}
|
||||
if (len) {
|
||||
*(uint8_t *)addr = reg->u8;
|
||||
}
|
||||
}
|
||||
|
||||
static void pipe_read_write_packet_ff(tu_fifo_t *f, volatile void *fifo, unsigned len, unsigned dir)
|
||||
{
|
||||
static const struct {
|
||||
void (*tu_fifo_get_info)(tu_fifo_t *f, tu_fifo_buffer_info_t *info);
|
||||
void (*tu_fifo_advance)(tu_fifo_t *f, uint16_t n);
|
||||
void (*pipe_read_write)(void *buf, volatile void *fifo, unsigned len);
|
||||
} ops[] = {
|
||||
/* OUT */ {tu_fifo_get_write_info,tu_fifo_advance_write_pointer,pipe_read_packet},
|
||||
/* IN */ {tu_fifo_get_read_info, tu_fifo_advance_read_pointer, pipe_write_packet},
|
||||
};
|
||||
tu_fifo_buffer_info_t info;
|
||||
ops[dir].tu_fifo_get_info(f, &info);
|
||||
unsigned total_len = len;
|
||||
len = TU_MIN(total_len, info.linear.len);
|
||||
ops[dir].pipe_read_write(info.linear.ptr, fifo, len);
|
||||
unsigned rem = total_len - len;
|
||||
if (rem) {
|
||||
len = TU_MIN(rem, info.wrapped.len);
|
||||
ops[dir].pipe_read_write(info.wrapped.ptr, fifo, len);
|
||||
rem -= len;
|
||||
}
|
||||
ops[dir].tu_fifo_advance(f, total_len - rem);
|
||||
}
|
||||
|
||||
static void process_setup_packet(uint8_t rhport) {
|
||||
musb_regs_t* musb_regs = MUSB_REGS(rhport);
|
||||
|
||||
@ -277,9 +215,9 @@ static bool handle_xfer_in(uint8_t rhport, uint_fast8_t ep_addr)
|
||||
// TU_LOG1(" %p mps %d len %d rem %d\r\n", buf, mps, len, rem);
|
||||
if (len) {
|
||||
if (_dcd.pipe_buf_is_fifo[TUSB_DIR_IN] & TU_BIT(epnum_minus1)) {
|
||||
pipe_read_write_packet_ff(buf, fifo_ptr, len, TUSB_DIR_IN);
|
||||
tu_hwfifo_write_from_fifo(fifo_ptr, (tu_fifo_t *)buf, len, NULL);
|
||||
} else {
|
||||
pipe_write_packet(buf, fifo_ptr, len);
|
||||
tu_hwfifo_write(fifo_ptr, buf, len, NULL);
|
||||
pipe->buf = buf + len;
|
||||
}
|
||||
pipe->remaining = rem - len;
|
||||
@ -308,9 +246,9 @@ static bool handle_xfer_out(uint8_t rhport, uint_fast8_t ep_addr)
|
||||
volatile void *fifo_ptr = &musb_regs->fifo[epnum];
|
||||
if (len) {
|
||||
if (_dcd.pipe_buf_is_fifo[TUSB_DIR_OUT] & TU_BIT(epnum_minus1)) {
|
||||
pipe_read_write_packet_ff(buf, fifo_ptr, len, TUSB_DIR_OUT);
|
||||
tu_hwfifo_read_to_fifo(fifo_ptr, (tu_fifo_t *)buf, len, NULL);
|
||||
} else {
|
||||
pipe_read_packet(buf, fifo_ptr, len);
|
||||
tu_hwfifo_read(fifo_ptr, buf, len, NULL);
|
||||
pipe->buf = buf + len;
|
||||
}
|
||||
pipe->remaining = rem - len;
|
||||
@ -378,7 +316,7 @@ static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_
|
||||
const unsigned len = TU_MIN(TU_MIN(rem, 64), total_bytes);
|
||||
volatile void *fifo_ptr = &musb_regs->fifo[0];
|
||||
if (dir_in) {
|
||||
pipe_write_packet(buffer, fifo_ptr, len);
|
||||
tu_hwfifo_write(fifo_ptr, buffer, len, NULL);
|
||||
|
||||
_dcd.pipe0.buf = buffer + len;
|
||||
_dcd.pipe0.length = len;
|
||||
@ -458,7 +396,7 @@ static void process_ep0(uint8_t rhport)
|
||||
const unsigned rem = _dcd.pipe0.remaining;
|
||||
const unsigned len = TU_MIN(TU_MIN(rem, 64), vld);
|
||||
volatile void *fifo_ptr = &musb_regs->fifo[0];
|
||||
pipe_read_packet(_dcd.pipe0.buf, fifo_ptr, len);
|
||||
tu_hwfifo_read(fifo_ptr, _dcd.pipe0.buf, len, NULL);
|
||||
|
||||
_dcd.pipe0.remaining = rem - len;
|
||||
_dcd.remaining_ctrl -= len;
|
||||
|
||||
@ -437,7 +437,7 @@ void dcd_int_handler(uint8_t rhport)
|
||||
// write to EP fifo
|
||||
#if 0 // TODO support dcd_edpt_xfer_fifo
|
||||
if (xfer->ff) {
|
||||
tu_fifo_read_n_access_mode(xfer->ff, (void *) &UDP->UDP_FDR[epnum], xact_len, TU_FIFO_FIXED_ADDR_RW32);
|
||||
tu_fifo_read_n_access_mode(xfer->ff, (void *) &UDP->UDP_FDR[epnum], xact_len, true);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@ -471,7 +471,7 @@ void dcd_int_handler(uint8_t rhport)
|
||||
// Read from EP fifo
|
||||
#if 0 // TODO support dcd_edpt_xfer_fifo API
|
||||
if (xfer->ff) {
|
||||
tu_fifo_write_n_access_mode(xfer->ff, (const void *) &UDP->UDP_FDR[epnum], xact_len, TU_FIFO_FIXED_ADDR_RW32);
|
||||
tu_fifo_write_n_access_mode(xfer->ff, (const void *) &UDP->UDP_FDR[epnum], xact_len, true);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
||||
@ -194,7 +194,7 @@ static void dcd_userEP_in_xfer(struct xfer_ctl_t *xfer, USBD_EP_T *ep)
|
||||
/* provided buffers are thankfully 32-bit aligned, allowing most data to be transferred as 32-bit */
|
||||
#if 0 // TODO support dcd_edpt_xfer_fifo API
|
||||
if (xfer->ff) {
|
||||
tu_fifo_read_n_access_mode(xfer->ff, (void *) (&ep->EPDAT_BYTE), bytes_now, TU_FIFO_FIXED_ADDR_RW32);
|
||||
tu_fifo_read_n_access_mode(xfer->ff, (void *) (&ep->EPDAT_BYTE), bytes_now, true);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@ -696,7 +696,7 @@ void dcd_int_handler(uint8_t rhport)
|
||||
/* copy the data from the PC to the previously provided buffer */
|
||||
#if 0 // TODO support dcd_edpt_xfer_fifo API
|
||||
if (xfer->ff) {
|
||||
tu_fifo_write_n_access_mode(xfer->ff, (const void *) &ep->EPDAT_BYTE, tu_min16(available_bytes, xfer->total_bytes - xfer->out_bytes_so_far), TU_FIFO_FIXED_ADDR_RW32);
|
||||
tu_fifo_write_n_access_mode(xfer->ff, (const void *) &ep->EPDAT_BYTE, tu_min16(available_bytes, xfer->total_bytes - xfer->out_bytes_so_far), true);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
||||
@ -30,25 +30,7 @@
|
||||
#if CFG_TUD_ENABLED && defined(TUP_USBIP_RUSB2)
|
||||
|
||||
#include "device/dcd.h"
|
||||
#include "rusb2_type.h"
|
||||
|
||||
#if TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N)
|
||||
#include "rusb2_rx.h"
|
||||
#elif TU_CHECK_MCU(OPT_MCU_RAXXX)
|
||||
#include "rusb2_ra.h"
|
||||
#if defined(RENESAS_CORTEX_M23)
|
||||
#define D0FIFO CFIFO
|
||||
#define D0FIFOSEL CFIFOSEL
|
||||
#define D0FIFOSEL_b CFIFOSEL_b
|
||||
#define D1FIFOSEL CFIFOSEL
|
||||
#define D1FIFOSEL_b CFIFOSEL_b
|
||||
#define D0FIFOCTR CFIFOCTR
|
||||
#define D0FIFOCTR_b CFIFOCTR_b
|
||||
#endif
|
||||
|
||||
#else
|
||||
#error "Unsupported MCU"
|
||||
#endif
|
||||
#include "rusb2_common.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO TYPEDEF CONSTANT ENUM
|
||||
@ -160,107 +142,12 @@ static inline void pipe_wait_for_ready(rusb2_reg_t * rusb, unsigned num) {
|
||||
while ( !rusb->D0FIFOCTR_b.FRDY ) {}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Pipe FIFO
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Write data buffer --> hw fifo
|
||||
static void pipe_write_packet(rusb2_reg_t * rusb, void *buf, volatile void *fifo, unsigned len)
|
||||
{
|
||||
(void) rusb;
|
||||
|
||||
volatile uint16_t *ff16;
|
||||
volatile uint8_t *ff8;
|
||||
|
||||
// Highspeed FIFO is 32-bit
|
||||
if ( rusb2_is_highspeed_reg(rusb) ) {
|
||||
// TODO 32-bit access for better performance
|
||||
ff16 = (volatile uint16_t*) ((uintptr_t) fifo+2);
|
||||
ff8 = (volatile uint8_t *) ((uintptr_t) fifo+3);
|
||||
}else {
|
||||
ff16 = (volatile uint16_t*) fifo;
|
||||
ff8 = ((volatile uint8_t*) fifo);
|
||||
}
|
||||
|
||||
uint8_t const* buf8 = (uint8_t const*) buf;
|
||||
|
||||
while (len >= 2) {
|
||||
*ff16 = tu_unaligned_read16(buf8);
|
||||
buf8 += 2;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
if (len > 0) {
|
||||
*ff8 = *buf8;
|
||||
++buf8;
|
||||
}
|
||||
}
|
||||
|
||||
// Read data buffer <-- hw fifo
|
||||
static void pipe_read_packet(rusb2_reg_t * rusb, void *buf, volatile void *fifo, unsigned len)
|
||||
{
|
||||
(void) rusb;
|
||||
|
||||
// TODO 16/32-bit access for better performance
|
||||
|
||||
uint8_t *p = (uint8_t*)buf;
|
||||
volatile uint8_t *reg = (volatile uint8_t*)fifo; /* byte access is always at base register address */
|
||||
while (len--) *p++ = *reg;
|
||||
}
|
||||
|
||||
// Write data sw fifo --> hw fifo
|
||||
static void pipe_write_packet_ff(rusb2_reg_t * rusb, tu_fifo_t *f, volatile void *fifo, uint16_t total_len) {
|
||||
tu_fifo_buffer_info_t info;
|
||||
tu_fifo_get_read_info(f, &info);
|
||||
|
||||
uint16_t cnt_lin = tu_min16(total_len, info.linear.len);
|
||||
uint16_t cnt_wrap = tu_min16(total_len - cnt_lin, info.wrapped.len);
|
||||
uint16_t const cnt_written = cnt_lin + cnt_wrap;
|
||||
|
||||
// Ensure only the last write is odd if total_len is odd
|
||||
if (cnt_wrap == 0) {
|
||||
pipe_write_packet(rusb, info.linear.ptr, fifo, cnt_lin);
|
||||
} else {
|
||||
pipe_write_packet(rusb, info.linear.ptr, fifo, cnt_lin & ~1);
|
||||
|
||||
if (cnt_lin & 1) {
|
||||
uint8_t glue[2] = {info.linear.ptr[cnt_lin & ~1], info.wrapped.ptr[0]};
|
||||
pipe_write_packet(rusb, glue, fifo, 2);
|
||||
cnt_wrap--;
|
||||
info.wrapped.ptr++;
|
||||
}
|
||||
|
||||
pipe_write_packet(rusb, info.wrapped.ptr, fifo, cnt_wrap);
|
||||
}
|
||||
tu_fifo_advance_read_pointer(f, cnt_written);
|
||||
}
|
||||
|
||||
// Read data sw fifo <-- hw fifo
|
||||
static void pipe_read_packet_ff(rusb2_reg_t * rusb, tu_fifo_t *f, volatile void *fifo, uint16_t total_len) {
|
||||
tu_fifo_buffer_info_t info;
|
||||
tu_fifo_get_write_info(f, &info);
|
||||
|
||||
uint16_t count = tu_min16(total_len, info.linear.len);
|
||||
pipe_read_packet(rusb, info.linear.ptr, fifo, count);
|
||||
|
||||
uint16_t rem = total_len - count;
|
||||
if (rem) {
|
||||
rem = tu_min16(rem, info.wrapped.len);
|
||||
pipe_read_packet(rusb, info.wrapped.ptr, fifo, rem);
|
||||
count += rem;
|
||||
}
|
||||
|
||||
tu_fifo_advance_write_pointer(f, count);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Pipe Transfer
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
static bool pipe0_xfer_in(rusb2_reg_t* rusb)
|
||||
{
|
||||
pipe_state_t *pipe = &_dcd.pipe[0];
|
||||
const unsigned rem = pipe->remaining;
|
||||
static bool pipe0_xfer_in(rusb2_reg_t *rusb) {
|
||||
pipe_state_t *pipe = &_dcd.pipe[0];
|
||||
const unsigned rem = pipe->remaining;
|
||||
|
||||
if (!rem) {
|
||||
pipe->buf = NULL;
|
||||
@ -272,11 +159,25 @@ static bool pipe0_xfer_in(rusb2_reg_t* rusb)
|
||||
void *buf = pipe->buf;
|
||||
|
||||
if (len) {
|
||||
if (pipe->ff) {
|
||||
pipe_write_packet_ff(rusb, (tu_fifo_t*)buf, (volatile void*)&rusb->CFIFO, len);
|
||||
// uint16_t fifo_sel = RUSB2_CFIFOSEL_ISEL_WRITE | FIFOSEL_BIGEND;
|
||||
tu_hwfifo_access_t access_mode;
|
||||
access_mode.param = (uintptr_t)rusb;
|
||||
//
|
||||
if (rusb2_is_highspeed_reg(rusb)) {
|
||||
// fifo_sel |= RUSB2_FIFOSEL_MBW_32BIT;
|
||||
access_mode.data_stride = 4u;
|
||||
} else {
|
||||
pipe_write_packet(rusb, buf, (volatile void*)&rusb->CFIFO, len);
|
||||
pipe->buf = (uint8_t*)buf + len;
|
||||
// fifo_sel |= RUSB2_FIFOSEL_MBW_16BIT;
|
||||
access_mode.data_stride = 2u;
|
||||
}
|
||||
// rusb->CFIFOSEL = fifo_sel;
|
||||
// while (0 == (rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE)) {}
|
||||
|
||||
if (pipe->ff) {
|
||||
tu_hwfifo_write_from_fifo(&rusb->CFIFO, (tu_fifo_t *)buf, len, &access_mode);
|
||||
} else {
|
||||
tu_hwfifo_write(&rusb->CFIFO, buf, len, &access_mode);
|
||||
pipe->buf = (uint8_t *)buf + len;
|
||||
}
|
||||
}
|
||||
|
||||
@ -288,10 +189,9 @@ static bool pipe0_xfer_in(rusb2_reg_t* rusb)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool pipe0_xfer_out(rusb2_reg_t* rusb)
|
||||
{
|
||||
pipe_state_t *pipe = &_dcd.pipe[0];
|
||||
const unsigned rem = pipe->remaining;
|
||||
static bool pipe0_xfer_out(rusb2_reg_t *rusb) {
|
||||
pipe_state_t *pipe = &_dcd.pipe[0];
|
||||
const unsigned rem = pipe->remaining;
|
||||
|
||||
const uint16_t mps = edpt0_max_packet_size(rusb);
|
||||
const uint16_t vld = rusb->CFIFOCTR_b.DTLN;
|
||||
@ -299,11 +199,14 @@ static bool pipe0_xfer_out(rusb2_reg_t* rusb)
|
||||
void *buf = pipe->buf;
|
||||
|
||||
if (len) {
|
||||
tu_hwfifo_access_t access_mode = {.data_stride = (rusb2_is_highspeed_reg(rusb) ? 4u : 2u),
|
||||
.param = (uintptr_t)rusb};
|
||||
|
||||
if (pipe->ff) {
|
||||
pipe_read_packet_ff(rusb, (tu_fifo_t*)buf, (volatile void*)&rusb->CFIFO, len);
|
||||
tu_hwfifo_read_to_fifo(&rusb->CFIFO, (tu_fifo_t *)buf, len, &access_mode);
|
||||
} else {
|
||||
pipe_read_packet(rusb, buf, (volatile void*)&rusb->CFIFO, len);
|
||||
pipe->buf = (uint8_t*)buf + len;
|
||||
tu_hwfifo_read(&rusb->CFIFO, buf, len, &access_mode);
|
||||
pipe->buf = (uint8_t *)buf + len;
|
||||
}
|
||||
}
|
||||
|
||||
@ -330,18 +233,27 @@ static bool pipe_xfer_in(rusb2_reg_t* rusb, unsigned num)
|
||||
return true;
|
||||
}
|
||||
|
||||
rusb->D0FIFOSEL = num | RUSB2_FIFOSEL_MBW_16BIT | (TU_BYTE_ORDER == TU_BIG_ENDIAN ? RUSB2_FIFOSEL_BIGEND : 0);
|
||||
const uint16_t mps = edpt_max_packet_size(rusb, num);
|
||||
const uint16_t fifo_sel = num | FIFOSEL_BIGEND;
|
||||
const bool is_highspeed = rusb2_is_highspeed_reg(rusb);
|
||||
if (is_highspeed) {
|
||||
rusb->D0FIFOSEL = fifo_sel | RUSB2_FIFOSEL_MBW_32BIT;
|
||||
} else {
|
||||
rusb->D0FIFOSEL = fifo_sel | RUSB2_FIFOSEL_MBW_16BIT;
|
||||
}
|
||||
|
||||
const uint16_t mps = edpt_max_packet_size(rusb, num);
|
||||
pipe_wait_for_ready(rusb, num);
|
||||
const uint16_t len = tu_min16(rem, mps);
|
||||
void *buf = pipe->buf;
|
||||
uint16_t len = tu_min16(rem, mps);
|
||||
void *buf = pipe->buf;
|
||||
|
||||
if (len) {
|
||||
tu_hwfifo_access_t access_mode = {.data_stride = (rusb2_is_highspeed_reg(rusb) ? 4u : 2u),
|
||||
.param = (uintptr_t)rusb};
|
||||
if (pipe->ff) {
|
||||
pipe_write_packet_ff(rusb, (tu_fifo_t*)buf, (volatile void*)&rusb->D0FIFO, len);
|
||||
tu_hwfifo_write_from_fifo(&rusb->D0FIFO, (tu_fifo_t *)buf, len, &access_mode);
|
||||
} else {
|
||||
pipe_write_packet(rusb, buf, (volatile void*)&rusb->D0FIFO, len);
|
||||
pipe->buf = (uint8_t*)buf + len;
|
||||
tu_hwfifo_write(&rusb->D0FIFO, buf, len, &access_mode);
|
||||
pipe->buf = (uint8_t *)buf + len;
|
||||
}
|
||||
}
|
||||
|
||||
@ -362,7 +274,14 @@ static bool pipe_xfer_out(rusb2_reg_t* rusb, unsigned num)
|
||||
pipe_state_t *pipe = &_dcd.pipe[num];
|
||||
const uint16_t rem = pipe->remaining;
|
||||
|
||||
rusb->D0FIFOSEL = num | RUSB2_FIFOSEL_MBW_8BIT;
|
||||
uint16_t fifo_sel = num | FIFOSEL_BIGEND;
|
||||
if (rusb2_is_highspeed_reg(rusb)) {
|
||||
fifo_sel |= RUSB2_FIFOSEL_MBW_32BIT;
|
||||
} else {
|
||||
fifo_sel |= RUSB2_FIFOSEL_MBW_16BIT;
|
||||
}
|
||||
rusb->D0FIFOSEL = fifo_sel;
|
||||
|
||||
const uint16_t mps = edpt_max_packet_size(rusb, num);
|
||||
pipe_wait_for_ready(rusb, num);
|
||||
|
||||
@ -371,11 +290,13 @@ static bool pipe_xfer_out(rusb2_reg_t* rusb, unsigned num)
|
||||
void *buf = pipe->buf;
|
||||
|
||||
if (len) {
|
||||
tu_hwfifo_access_t access_mode = {.data_stride = (rusb2_is_highspeed_reg(rusb) ? 4u : 2u),
|
||||
.param = (uintptr_t)rusb};
|
||||
if (pipe->ff) {
|
||||
pipe_read_packet_ff(rusb, (tu_fifo_t*)buf, (volatile void*)&rusb->D0FIFO, len);
|
||||
tu_hwfifo_read_to_fifo(&rusb->D0FIFO, (tu_fifo_t *)buf, len, &access_mode);
|
||||
} else {
|
||||
pipe_read_packet(rusb, buf, (volatile void*)&rusb->D0FIFO, len);
|
||||
pipe->buf = (uint8_t*)buf + len;
|
||||
tu_hwfifo_read(&rusb->D0FIFO, buf, len, &access_mode);
|
||||
pipe->buf = (uint8_t *)buf + len;
|
||||
}
|
||||
}
|
||||
|
||||
@ -428,28 +349,29 @@ static void process_status_completion(uint8_t rhport)
|
||||
dcd_event_xfer_complete(rhport, ep_addr, 0, XFER_RESULT_SUCCESS, true);
|
||||
}
|
||||
|
||||
static bool process_pipe0_xfer(rusb2_reg_t* rusb, int buffer_type, uint8_t ep_addr, void* buffer, uint16_t total_bytes)
|
||||
{
|
||||
static bool process_pipe0_xfer(rusb2_reg_t *rusb, int buffer_type, uint8_t ep_addr, void *buffer,
|
||||
uint16_t total_bytes) {
|
||||
uint16_t fifo_sel =
|
||||
(rusb2_is_highspeed_reg(rusb) ? RUSB2_FIFOSEL_MBW_32BIT : RUSB2_FIFOSEL_MBW_16BIT) | FIFOSEL_BIGEND;
|
||||
|
||||
/* configure fifo direction and access unit settings */
|
||||
if ( ep_addr ) {
|
||||
/* IN, 2 bytes */
|
||||
rusb->CFIFOSEL = RUSB2_CFIFOSEL_ISEL_WRITE | RUSB2_FIFOSEL_MBW_16BIT |
|
||||
(TU_BYTE_ORDER == TU_BIG_ENDIAN ? RUSB2_FIFOSEL_BIGEND : 0);
|
||||
while ( !(rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE) ) {}
|
||||
} else {
|
||||
/* OUT, a byte */
|
||||
rusb->CFIFOSEL = RUSB2_FIFOSEL_MBW_8BIT;
|
||||
while ( rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE ) {}
|
||||
if (ep_addr != 0) {
|
||||
// Control IN
|
||||
fifo_sel |= RUSB2_CFIFOSEL_ISEL_WRITE;
|
||||
}
|
||||
rusb->CFIFOSEL = fifo_sel;
|
||||
while ((rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE) != (fifo_sel & RUSB2_CFIFOSEL_ISEL_WRITE)) {
|
||||
// wait until ISEL_WRITE take effect
|
||||
}
|
||||
|
||||
pipe_state_t *pipe = &_dcd.pipe[0];
|
||||
pipe->ff = buffer_type;
|
||||
pipe->length = total_bytes;
|
||||
pipe->remaining = total_bytes;
|
||||
pipe->ff = buffer_type;
|
||||
pipe->length = total_bytes;
|
||||
pipe->remaining = total_bytes;
|
||||
|
||||
if ( total_bytes ) {
|
||||
if (total_bytes) {
|
||||
pipe->buf = buffer;
|
||||
if ( ep_addr ) {
|
||||
if (ep_addr) {
|
||||
/* IN */
|
||||
TU_ASSERT(rusb->DCPCTR_b.BSTS && (rusb->USBREQ & 0x80));
|
||||
pipe0_xfer_in(rusb);
|
||||
@ -525,7 +447,7 @@ static bool process_edpt_xfer(rusb2_reg_t* rusb, int buffer_type, uint8_t ep_add
|
||||
static void process_pipe0_bemp(uint8_t rhport)
|
||||
{
|
||||
rusb2_reg_t* rusb = RUSB2_REG(rhport);
|
||||
bool completed = pipe0_xfer_in(rusb);
|
||||
bool completed = pipe0_xfer_in(rusb);
|
||||
if (completed) {
|
||||
pipe_state_t *pipe = &_dcd.pipe[0];
|
||||
dcd_event_xfer_complete(rhport, tu_edpt_addr(0, TUSB_DIR_IN),
|
||||
@ -621,18 +543,20 @@ static void process_set_address(uint8_t rhport)
|
||||
{
|
||||
rusb2_reg_t* rusb = RUSB2_REG(rhport);
|
||||
const uint16_t addr = rusb->USBADDR_b.USBADDR;
|
||||
if (!addr) return;
|
||||
if (!addr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tusb_control_request_t setup_packet = {
|
||||
#if defined(__CCRX__)
|
||||
.bmRequestType = { 0 }, /* Note: CCRX needs the braces over this struct member */
|
||||
#else
|
||||
.bmRequestType = 0,
|
||||
#endif
|
||||
.bRequest = TUSB_REQ_SET_ADDRESS,
|
||||
.wValue = addr,
|
||||
.wIndex = 0,
|
||||
.wLength = 0,
|
||||
#else
|
||||
.bmRequestType = 0,
|
||||
#endif
|
||||
.bRequest = TUSB_REQ_SET_ADDRESS,
|
||||
.wValue = addr,
|
||||
.wIndex = 0,
|
||||
.wLength = 0,
|
||||
};
|
||||
|
||||
dcd_event_setup_received(rhport, (const uint8_t *) &setup_packet, true);
|
||||
@ -899,7 +823,6 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_
|
||||
{
|
||||
(void) is_isr;
|
||||
// USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1
|
||||
TU_ASSERT(ff->item_size == 1);
|
||||
rusb2_reg_t* rusb = RUSB2_REG(rhport);
|
||||
|
||||
dcd_int_disable(rhport);
|
||||
@ -912,7 +835,9 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_
|
||||
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
|
||||
{
|
||||
volatile uint16_t *ctr = ep_addr_to_pipectr(rhport, ep_addr);
|
||||
if (!ctr) return;
|
||||
if (!ctr) {
|
||||
return;
|
||||
}
|
||||
dcd_int_disable(rhport);
|
||||
const uint32_t pid = *ctr & 0x3;
|
||||
*ctr = pid | RUSB2_PIPE_CTR_PID_STALL;
|
||||
@ -924,7 +849,9 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
|
||||
{
|
||||
rusb2_reg_t * rusb = RUSB2_REG(rhport);
|
||||
volatile uint16_t *ctr = ep_addr_to_pipectr(rhport, ep_addr);
|
||||
if (!ctr) return;
|
||||
if (!ctr) {
|
||||
return;
|
||||
}
|
||||
|
||||
dcd_int_disable(rhport);
|
||||
*ctr = RUSB2_PIPE_CTR_SQCLR_Msk;
|
||||
|
||||
@ -31,17 +31,9 @@
|
||||
|
||||
#include "host/hcd.h"
|
||||
#include "host/usbh.h"
|
||||
#include "rusb2_type.h"
|
||||
#include "rusb2_common.h"
|
||||
|
||||
#if TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N)
|
||||
#include "rusb2_rx.h"
|
||||
#elif TU_CHECK_MCU(OPT_MCU_RAXXX)
|
||||
#include "rusb2_ra.h"
|
||||
#else
|
||||
#error "Unsupported MCU"
|
||||
#endif
|
||||
|
||||
#define TU_RUSB2_HCD_DBG 2
|
||||
#define TU_RUSB2_HCD_DBG 2
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
|
||||
@ -76,12 +68,10 @@ typedef struct TU_ATTR_PACKED {
|
||||
TU_ATTR_PACKED_END // End of definition of packed structs (used by the CCRX toolchain)
|
||||
TU_ATTR_BIT_FIELD_ORDER_END
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool need_reset; /* The device has not been reset after connection. */
|
||||
typedef struct {
|
||||
pipe_state_t pipe[PIPE_COUNT];
|
||||
uint8_t ep[4][2][15]; /* a lookup table for a pipe index from an endpoint address */
|
||||
uint8_t ctl_mps[5]; /* EP0 max packet size for each device */
|
||||
uint8_t ep[4][2][15]; /* a lookup table for a pipe index from an endpoint address */
|
||||
uint8_t ctl_mps[5]; /* EP0 max packet size for each device */
|
||||
} hcd_data_t;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
@ -166,29 +156,6 @@ static inline void pipe_wait_for_ready(rusb2_reg_t* rusb, unsigned num)
|
||||
while (!rusb->D0FIFOCTR_b.FRDY) {}
|
||||
}
|
||||
|
||||
static void pipe_write_packet(void *buf, volatile void *fifo, unsigned len)
|
||||
{
|
||||
// NOTE: unlike DCD, Highspeed 32-bit FIFO does not need to adjust the fifo address
|
||||
volatile hw_fifo_t *reg = (volatile hw_fifo_t*)fifo;
|
||||
uintptr_t addr = (uintptr_t)buf;
|
||||
while (len >= 2) {
|
||||
reg->u16 = *(const uint16_t *)addr;
|
||||
addr += 2;
|
||||
len -= 2;
|
||||
}
|
||||
if (len) {
|
||||
reg->u8 = *(const uint8_t *)addr;
|
||||
++addr;
|
||||
}
|
||||
}
|
||||
|
||||
static void pipe_read_packet(void *buf, volatile void *fifo, unsigned len)
|
||||
{
|
||||
uint8_t *p = (uint8_t*)buf;
|
||||
volatile uint8_t *reg = (volatile uint8_t*)fifo; /* byte access is always at base register address */
|
||||
while (len--) *p++ = *reg;
|
||||
}
|
||||
|
||||
static bool pipe0_xfer_in(rusb2_reg_t* rusb)
|
||||
{
|
||||
pipe_state_t *pipe = &_hcd.pipe[0];
|
||||
@ -199,8 +166,12 @@ static bool pipe0_xfer_in(rusb2_reg_t* rusb)
|
||||
const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
|
||||
void *buf = pipe->buf;
|
||||
if (len) {
|
||||
tu_hwfifo_access_t access_mode = {.data_stride = (rusb2_is_highspeed_reg(rusb) ? 4u : 2u),
|
||||
.param = (uintptr_t)rusb};
|
||||
|
||||
rusb->DCPCTR = RUSB2_PIPE_CTR_PID_NAK;
|
||||
pipe_read_packet(buf, (volatile void*)&rusb->CFIFO, len);
|
||||
// pipe_read_packet(buf, (volatile void*)&rusb->CFIFO, len);
|
||||
tu_hwfifo_read(&rusb->CFIFO, buf, len, &access_mode);
|
||||
pipe->buf = (uint8_t*)buf + len;
|
||||
}
|
||||
if (len < mps) {
|
||||
@ -227,7 +198,11 @@ static bool pipe0_xfer_out(rusb2_reg_t* rusb)
|
||||
const unsigned len = TU_MIN(mps, rem);
|
||||
void *buf = pipe->buf;
|
||||
if (len) {
|
||||
pipe_write_packet(buf, (volatile void*)&rusb->CFIFO, len);
|
||||
tu_hwfifo_access_t access_mode = {.data_stride = (rusb2_is_highspeed_reg(rusb) ? 4u : 2u),
|
||||
.param = (uintptr_t)rusb};
|
||||
|
||||
// pipe_write_packet(buf, (volatile void*)&rusb->CFIFO, len);
|
||||
tu_hwfifo_write(&rusb->CFIFO, buf, len, &access_mode);
|
||||
pipe->buf = (uint8_t*)buf + len;
|
||||
}
|
||||
if (len < mps) {
|
||||
@ -242,14 +217,24 @@ static bool pipe_xfer_in(rusb2_reg_t* rusb, unsigned num)
|
||||
pipe_state_t *pipe = &_hcd.pipe[num];
|
||||
const unsigned rem = pipe->remaining;
|
||||
|
||||
rusb->D0FIFOSEL = num | RUSB2_FIFOSEL_MBW_8BIT;
|
||||
uint16_t fifo_sel = num | FIFOSEL_BIGEND;
|
||||
if (rusb2_is_highspeed_reg(rusb)) {
|
||||
fifo_sel |= RUSB2_FIFOSEL_MBW_32BIT;
|
||||
} else {
|
||||
fifo_sel |= RUSB2_FIFOSEL_MBW_16BIT;
|
||||
}
|
||||
rusb->D0FIFOSEL = fifo_sel;
|
||||
|
||||
const unsigned mps = edpt_max_packet_size(rusb, num);
|
||||
pipe_wait_for_ready(rusb, num);
|
||||
const unsigned vld = rusb->D0FIFOCTR_b.DTLN;
|
||||
const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
|
||||
void *buf = pipe->buf;
|
||||
if (len) {
|
||||
pipe_read_packet(buf, (volatile void*)&rusb->D0FIFO, len);
|
||||
// pipe_read_packet(buf, (volatile void*)&rusb->D0FIFO, len);
|
||||
tu_hwfifo_access_t access_mode = {.data_stride = (rusb2_is_highspeed_reg(rusb) ? 4u : 2u),
|
||||
.param = (uintptr_t)rusb};
|
||||
tu_hwfifo_read(&rusb->D0FIFO, buf, len, &access_mode);
|
||||
pipe->buf = (uint8_t*)buf + len;
|
||||
}
|
||||
if (len < mps) {
|
||||
@ -275,13 +260,23 @@ static bool pipe_xfer_out(rusb2_reg_t* rusb, unsigned num)
|
||||
return true;
|
||||
}
|
||||
|
||||
rusb->D0FIFOSEL = num | RUSB2_FIFOSEL_MBW_16BIT | (TU_BYTE_ORDER == TU_BIG_ENDIAN ? RUSB2_FIFOSEL_BIGEND : 0);
|
||||
uint16_t fifo_sel = num | FIFOSEL_BIGEND;
|
||||
if (rusb2_is_highspeed_reg(rusb)) {
|
||||
fifo_sel |= RUSB2_FIFOSEL_MBW_32BIT;
|
||||
} else {
|
||||
fifo_sel |= RUSB2_FIFOSEL_MBW_16BIT;
|
||||
}
|
||||
rusb->D0FIFOSEL = fifo_sel;
|
||||
|
||||
const unsigned mps = edpt_max_packet_size(rusb, num);
|
||||
pipe_wait_for_ready(rusb, num);
|
||||
const unsigned len = TU_MIN(rem, mps);
|
||||
void *buf = pipe->buf;
|
||||
if (len) {
|
||||
pipe_write_packet(buf, (volatile void*)&rusb->D0FIFO, len);
|
||||
// pipe_write_packet(buf, (volatile void*)&rusb->D0FIFO, len);
|
||||
tu_hwfifo_access_t access_mode = {.data_stride = (rusb2_is_highspeed_reg(rusb) ? 4u : 2u),
|
||||
.param = (uintptr_t)rusb};
|
||||
tu_hwfifo_write(&rusb->D0FIFO, buf, len, &access_mode);
|
||||
pipe->buf = (uint8_t*)buf + len;
|
||||
}
|
||||
if (len < mps) {
|
||||
@ -296,18 +291,19 @@ static bool pipe_xfer_out(rusb2_reg_t* rusb, unsigned num)
|
||||
static bool process_pipe0_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, void* buffer, uint16_t buflen)
|
||||
{
|
||||
(void)dev_addr;
|
||||
|
||||
rusb2_reg_t* rusb = RUSB2_REG(rhport);
|
||||
const unsigned dir_in = tu_edpt_dir(ep_addr);
|
||||
|
||||
uint16_t fifo_sel =
|
||||
(rusb2_is_highspeed_reg(rusb) ? RUSB2_FIFOSEL_MBW_32BIT : RUSB2_FIFOSEL_MBW_16BIT) | FIFOSEL_BIGEND;
|
||||
|
||||
/* configure fifo direction and access unit settings */
|
||||
if (dir_in) { /* IN, a byte */
|
||||
rusb->CFIFOSEL = RUSB2_FIFOSEL_MBW_8BIT;
|
||||
while (rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE) ;
|
||||
} else { /* OUT, 2 bytes */
|
||||
rusb->CFIFOSEL = RUSB2_CFIFOSEL_ISEL_WRITE | RUSB2_FIFOSEL_MBW_16BIT |
|
||||
(TU_BYTE_ORDER == TU_BIG_ENDIAN ? RUSB2_FIFOSEL_BIGEND : 0);
|
||||
while (!(rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE)) ;
|
||||
if (dir_in == TUSB_DIR_OUT) {
|
||||
fifo_sel |= RUSB2_CFIFOSEL_ISEL_WRITE;
|
||||
}
|
||||
rusb->CFIFOSEL = fifo_sel;
|
||||
while ((rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE) != (fifo_sel & RUSB2_CFIFOSEL_ISEL_WRITE)) {
|
||||
// wait until ISEL_WRITE take effect
|
||||
}
|
||||
|
||||
pipe_state_t *pipe = &_hcd.pipe[0];
|
||||
@ -535,13 +531,8 @@ void hcd_int_disable(uint8_t rhport) {
|
||||
rusb2_int_disable(rhport);
|
||||
}
|
||||
|
||||
uint32_t hcd_frame_number(uint8_t rhport)
|
||||
{
|
||||
rusb2_reg_t* rusb = RUSB2_REG(rhport);
|
||||
|
||||
/* The device must be reset at least once after connection
|
||||
* in order to start the frame counter. */
|
||||
if (_hcd.need_reset) hcd_port_reset(rhport);
|
||||
uint32_t hcd_frame_number(uint8_t rhport) {
|
||||
rusb2_reg_t *rusb = RUSB2_REG(rhport);
|
||||
return rusb->FRMNUM_b.FRNM;
|
||||
}
|
||||
|
||||
@ -550,32 +541,18 @@ uint32_t hcd_frame_number(uint8_t rhport)
|
||||
*--------------------------------------------------------------------+*/
|
||||
bool hcd_port_connect_status(uint8_t rhport) {
|
||||
rusb2_reg_t* rusb = RUSB2_REG(rhport);
|
||||
return rusb->INTSTS1_b.ATTCH ? true : false;
|
||||
const uint16_t line_state = rusb->SYSSTS0 & RUSB2_SYSSTS0_LNST_Msk;
|
||||
return line_state == RUSB2_SYSSTS0_LNST_FS_J || line_state == RUSB2_SYSSTS0_LNST_FS_K;
|
||||
}
|
||||
|
||||
void hcd_port_reset(uint8_t rhport) {
|
||||
rusb2_reg_t* rusb = RUSB2_REG(rhport);
|
||||
rusb->DCPCTR = RUSB2_PIPE_CTR_PID_NAK;
|
||||
while (rusb->DCPCTR_b.PBUSY) {}
|
||||
|
||||
hcd_int_disable(rhport);
|
||||
rusb->DVSTCTR0_b.UACT = 0;
|
||||
if (rusb->DCPCTR_b.SUREQ) {
|
||||
rusb->DCPCTR_b.SUREQCLR = 1;
|
||||
}
|
||||
hcd_int_enable(rhport);
|
||||
|
||||
/* Reset should be asserted 10-20ms. */
|
||||
rusb->DVSTCTR0_b.USBRST = 1;
|
||||
for (volatile int i = 0; i < 2400000; ++i) {}
|
||||
rusb->DVSTCTR0_b.USBRST = 0;
|
||||
|
||||
rusb->DVSTCTR0_b.UACT = 1;
|
||||
_hcd.need_reset = false;
|
||||
}
|
||||
|
||||
void hcd_port_reset_end(uint8_t rhport) {
|
||||
(void) rhport;
|
||||
rusb2_reg_t *rusb = RUSB2_REG(rhport);
|
||||
rusb->DVSTCTR0_b.USBRST = 0;
|
||||
}
|
||||
|
||||
tusb_speed_t hcd_port_speed_get(uint8_t rhport) {
|
||||
@ -584,7 +561,8 @@ tusb_speed_t hcd_port_speed_get(uint8_t rhport) {
|
||||
case RUSB2_DVSTCTR0_RHST_HS: return TUSB_SPEED_HIGH;
|
||||
case RUSB2_DVSTCTR0_RHST_FS: return TUSB_SPEED_FULL;
|
||||
case RUSB2_DVSTCTR0_RHST_LS: return TUSB_SPEED_LOW;
|
||||
default: return TUSB_SPEED_INVALID;
|
||||
default:
|
||||
return TUSB_SPEED_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
@ -802,7 +780,6 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
|
||||
|
||||
if (is1 & RUSB2_INTSTS1_ATTCH_Msk) {
|
||||
rusb->DVSTCTR0_b.UACT = 1;
|
||||
_hcd.need_reset = true;
|
||||
rusb->INTENB1 = (rusb->INTENB1 & ~RUSB2_INTSTS1_ATTCH_Msk) | RUSB2_INTSTS1_DTCH_Msk;
|
||||
hcd_event_device_attach(rhport, true);
|
||||
}
|
||||
|
||||
@ -27,20 +27,19 @@
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if defined(TUP_USBIP_RUSB2) && (CFG_TUH_ENABLED || CFG_TUD_ENABLED)
|
||||
#include "osal/osal.h"
|
||||
#include "common/tusb_fifo.h"
|
||||
|
||||
#include "rusb2_type.h"
|
||||
#include "rusb2_common.h"
|
||||
|
||||
#if TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N)
|
||||
#include "rusb2_rx.h"
|
||||
|
||||
#elif TU_CHECK_MCU(OPT_MCU_RAXXX)
|
||||
#include "rusb2_ra.h"
|
||||
#if TU_CHECK_MCU(OPT_MCU_RAXXX)
|
||||
#include "rusb2_ra.h"
|
||||
|
||||
// USBFS_INT_IRQn and USBHS_USB_INT_RESUME_IRQn are generated by FSP
|
||||
rusb2_controller_t rusb2_controller[] = {
|
||||
{ .reg_base = R_USB_FS0_BASE, .irqnum = USBFS_INT_IRQn },
|
||||
{.reg_base = R_USB_FS0_BASE, .irqnum = USBFS_INT_IRQn},
|
||||
#ifdef RUSB2_SUPPORT_HIGHSPEED
|
||||
{ .reg_base = R_USB_HS0_BASE, .irqnum = USBHS_USB_INT_RESUME_IRQn },
|
||||
{.reg_base = R_USB_HS0_BASE, .irqnum = USBHS_USB_INT_RESUME_IRQn},
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -49,10 +48,69 @@ void tusb_rusb2_set_irqnum(uint8_t rhport, int32_t irqnum);
|
||||
void tusb_rusb2_set_irqnum(uint8_t rhport, int32_t irqnum) {
|
||||
rusb2_controller[rhport].irqnum = irqnum;
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
#error "Unsupported MCU"
|
||||
#endif
|
||||
//--------------------------------------------------------------------+
|
||||
//
|
||||
//--------------------------------------------------------------------+
|
||||
static void hwfifo_set_mbw(rusb2_reg_t *rusb, uintptr_t hwfifo, uint16_t mbw) {
|
||||
volatile uint16_t *fifo_sel;
|
||||
if (hwfifo == (uintptr_t)&rusb->CFIFO) {
|
||||
fifo_sel = &rusb->CFIFOSEL;
|
||||
} else if (hwfifo == (uintptr_t)&rusb->D0FIFO) {
|
||||
fifo_sel = &rusb->D0FIFOSEL;
|
||||
} else if (hwfifo == (uintptr_t)&rusb->D1FIFO) {
|
||||
fifo_sel = &rusb->D1FIFOSEL;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
*fifo_sel = (*fifo_sel & ~RUSB2_CFIFOSEL_MBW_Msk) | mbw;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
rusb2_reg_t *rusb = (rusb2_reg_t *)access_mode->param;
|
||||
const uint8_t *buf8 = (const uint8_t *)src;
|
||||
|
||||
volatile uint16_t *ff16;
|
||||
volatile uint8_t *ff8;
|
||||
const bool is_highspeed = rusb2_is_highspeed_reg(rusb);
|
||||
if (is_highspeed) {
|
||||
ff16 = (volatile uint16_t *)((uintptr_t)hwfifo + 2);
|
||||
ff8 = (volatile uint8_t *)((uintptr_t)hwfifo + 3);
|
||||
} else {
|
||||
ff16 = (volatile uint16_t *)hwfifo;
|
||||
ff8 = ((volatile uint8_t *)hwfifo);
|
||||
}
|
||||
|
||||
// 32-bit access for highspeed
|
||||
if (is_highspeed) {
|
||||
volatile uint32_t *ff32 = (volatile uint32_t *)hwfifo;
|
||||
while (len >= 4) {
|
||||
*ff32 = tu_unaligned_read32(buf8);
|
||||
buf8 += 4;
|
||||
len -= 4;
|
||||
}
|
||||
|
||||
if (len >= 2) {
|
||||
// switch to 16-bit access
|
||||
hwfifo_set_mbw(rusb, (uintptr_t)hwfifo, RUSB2_FIFOSEL_MBW_16BIT);
|
||||
}
|
||||
}
|
||||
|
||||
// 16-bit access
|
||||
while (len >= 2) {
|
||||
*ff16 = tu_unaligned_read16(buf8);
|
||||
buf8 += 2;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
// 8-bit access does not need to change MBW
|
||||
if (len > 0) {
|
||||
*ff8 = *buf8;
|
||||
++buf8;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
58
src/portable/renesas/rusb2/rusb2_common.h
Normal file
58
src/portable/renesas/rusb2/rusb2_common.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2025 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
#include "rusb2_type.h"
|
||||
|
||||
#if TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N)
|
||||
#include "rusb2_rx.h"
|
||||
#elif TU_CHECK_MCU(OPT_MCU_RAXXX)
|
||||
#include "rusb2_ra.h"
|
||||
|
||||
// Hack for D0FIFO definitions on RA Cortex-M23
|
||||
#if defined(RENESAS_CORTEX_M23)
|
||||
#define D0FIFO CFIFO
|
||||
#define D0FIFOSEL CFIFOSEL
|
||||
#define D0FIFOSEL_b CFIFOSEL_b
|
||||
#define D1FIFOSEL CFIFOSEL
|
||||
#define D1FIFOSEL_b CFIFOSEL_b
|
||||
#define D0FIFOCTR CFIFOCTR
|
||||
#define D0FIFOCTR_b CFIFOCTR_b
|
||||
#endif
|
||||
|
||||
#else
|
||||
#error "Unsupported MCU"
|
||||
#endif
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Common
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
enum {
|
||||
FIFOSEL_BIGEND = (TU_BYTE_ORDER == TU_BIG_ENDIAN ? RUSB2_FIFOSEL_BIGEND : 0)
|
||||
};
|
||||
@ -41,10 +41,9 @@ extern "C" {
|
||||
#define _ccrx_evenaccess
|
||||
#endif
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/* Register Definitions */
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Register Definitions
|
||||
//--------------------------------------------------------------------+
|
||||
/* Start of definition of packed structs (used by the CCRX toolchain) */
|
||||
TU_ATTR_PACKED_BEGIN
|
||||
TU_ATTR_BIT_FIELD_ORDER_BEGIN
|
||||
@ -1669,15 +1668,20 @@ TU_ATTR_BIT_FIELD_ORDER_END
|
||||
/*--------------------------------------------------------------------*/
|
||||
/* Register Bit Utils */
|
||||
/*--------------------------------------------------------------------*/
|
||||
#define RUSB2_PIPE_CTR_PID_NAK (0U << RUSB2_PIPE_CTR_PID_Pos) /* NAK response */
|
||||
#define RUSB2_PIPE_CTR_PID_BUF (1U << RUSB2_PIPE_CTR_PID_Pos) /* BUF response (depends buffer state) */
|
||||
#define RUSB2_PIPE_CTR_PID_STALL (2U << RUSB2_PIPE_CTR_PID_Pos) /* STALL response */
|
||||
#define RUSB2_PIPE_CTR_PID_STALL2 (3U << RUSB2_PIPE_CTR_PID_Pos) /* Also STALL response */
|
||||
#define RUSB2_SYSSTS0_LNST_SE0 (0)
|
||||
#define RUSB2_SYSSTS0_LNST_FS_J (1u << RUSB2_SYSSTS0_LNST_Pos) /* Full-speed J state */
|
||||
#define RUSB2_SYSSTS0_LNST_FS_K (2u << RUSB2_SYSSTS0_LNST_Pos) /* Full-speed K state */
|
||||
#define RUSB2_SYSSTS0_LNST_LS_SE1 (3u << RUSB2_SYSSTS0_LNST_Pos) /* Low-speed SE1 state */
|
||||
|
||||
#define RUSB2_DVSTCTR0_RHST_LS (1U << RUSB2_DVSTCTR0_RHST_Pos) /* Low-speed connection */
|
||||
#define RUSB2_DVSTCTR0_RHST_FS (2U << RUSB2_DVSTCTR0_RHST_Pos) /* Full-speed connection */
|
||||
#define RUSB2_DVSTCTR0_RHST_HS (3U << RUSB2_DVSTCTR0_RHST_Pos) /* Full-speed connection */
|
||||
|
||||
#define RUSB2_PIPE_CTR_PID_NAK (0U << RUSB2_PIPE_CTR_PID_Pos) /* NAK response */
|
||||
#define RUSB2_PIPE_CTR_PID_BUF (1U << RUSB2_PIPE_CTR_PID_Pos) /* BUF response (depends buffer state) */
|
||||
#define RUSB2_PIPE_CTR_PID_STALL (2U << RUSB2_PIPE_CTR_PID_Pos) /* STALL response */
|
||||
#define RUSB2_PIPE_CTR_PID_STALL2 (3U << RUSB2_PIPE_CTR_PID_Pos) /* Also STALL response */
|
||||
|
||||
#define RUSB2_DEVADD_USBSPD_LS (1U << RUSB2_DEVADD_USBSPD_Pos) /* Target Device Low-speed */
|
||||
#define RUSB2_DEVADD_USBSPD_FS (2U << RUSB2_DEVADD_USBSPD_Pos) /* Target Device Full-speed */
|
||||
|
||||
|
||||
@ -108,11 +108,10 @@
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if CFG_TUD_ENABLED && defined(TUP_USBIP_FSDEV) && \
|
||||
!(defined(TUP_USBIP_FSDEV_CH32) && CFG_TUD_WCH_USBIP_FSDEV == 0)
|
||||
#if CFG_TUD_ENABLED && defined(TUP_USBIP_FSDEV) && !(defined(TUP_USBIP_FSDEV_CH32) && CFG_TUD_WCH_USBIP_FSDEV == 0)
|
||||
|
||||
#include "device/dcd.h"
|
||||
#include "fsdev_common.h"
|
||||
#include "device/dcd.h"
|
||||
#include "fsdev_common.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
@ -120,25 +119,25 @@
|
||||
|
||||
// One of these for every EP IN & OUT, uses a bit of RAM....
|
||||
typedef struct {
|
||||
uint8_t *buffer;
|
||||
uint8_t *buffer;
|
||||
tu_fifo_t *ff;
|
||||
uint16_t total_len;
|
||||
uint16_t queued_len;
|
||||
uint16_t max_packet_size;
|
||||
uint8_t ep_idx; // index for USB_EPnR register
|
||||
bool iso_in_sending; // Workaround for ISO IN EP doesn't have interrupt mask
|
||||
uint16_t total_len;
|
||||
uint16_t queued_len;
|
||||
uint16_t max_packet_size;
|
||||
uint8_t ep_idx; // index for USB_EPnR register
|
||||
bool iso_in_sending; // Workaround for ISO IN EP doesn't have interrupt mask
|
||||
} xfer_ctl_t;
|
||||
|
||||
// EP allocator
|
||||
typedef struct {
|
||||
uint8_t ep_num;
|
||||
uint8_t ep_type;
|
||||
bool allocated[2];
|
||||
bool allocated[2];
|
||||
} ep_alloc_t;
|
||||
|
||||
static xfer_ctl_t xfer_status[CFG_TUD_ENDPPOINT_MAX][2];
|
||||
static ep_alloc_t ep_alloc_status[FSDEV_EP_COUNT];
|
||||
static uint8_t remoteWakeCountdown; // When wake is requested
|
||||
static uint8_t remoteWakeCountdown; // When wake is requested
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Prototypes
|
||||
@ -152,12 +151,12 @@ static bool edpt_xfer(uint8_t rhport, uint8_t ep_num, tusb_dir_t dir);
|
||||
// PMA allocation/access
|
||||
static uint16_t ep_buf_ptr; ///< Points to first free memory location
|
||||
static uint32_t dcd_pma_alloc(uint16_t len, bool dbuf);
|
||||
static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type);
|
||||
static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type);
|
||||
|
||||
static void edpt0_open(uint8_t rhport);
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void edpt0_prepare_setup(void) {
|
||||
btable_set_rx_bufsize(0, BTABLE_BUF_RX, 8);
|
||||
btable_set_rx_bufsize(0, BTABLE_BUF_RX, 8);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
@ -171,21 +170,21 @@ TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t *xfer_ctl_ptr(uint8_t epnum, uint
|
||||
//--------------------------------------------------------------------+
|
||||
// Controller API
|
||||
//--------------------------------------------------------------------+
|
||||
bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
|
||||
(void) rh_init;
|
||||
bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) {
|
||||
(void)rh_init;
|
||||
|
||||
fsdev_core_reset();
|
||||
|
||||
FSDEV_REG->CNTR = 0; // Enable USB
|
||||
|
||||
#if !defined(FSDEV_BUS_32BIT)
|
||||
#if !defined(FSDEV_BUS_32BIT)
|
||||
// BTABLE register does not exist any more on 32-bit bus devices
|
||||
FSDEV_REG->BTABLE = FSDEV_BTABLE_BASE;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Enable interrupts for device mode
|
||||
FSDEV_REG->CNTR |= USB_CNTR_RESETM | USB_CNTR_ESOFM | USB_CNTR_CTRM |
|
||||
USB_CNTR_SUSPM | USB_CNTR_WKUPM | USB_CNTR_PMAOVRM;
|
||||
FSDEV_REG->CNTR |=
|
||||
USB_CNTR_RESETM | USB_CNTR_ESOFM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM | USB_CNTR_PMAOVRM;
|
||||
|
||||
handle_bus_reset(rhport);
|
||||
|
||||
@ -236,8 +235,8 @@ static void handle_bus_reset(uint8_t rhport) {
|
||||
|
||||
for (uint32_t i = 0; i < FSDEV_EP_COUNT; i++) {
|
||||
// Clear EP allocation status
|
||||
ep_alloc_status[i].ep_num = 0xFF;
|
||||
ep_alloc_status[i].ep_type = 0xFF;
|
||||
ep_alloc_status[i].ep_num = 0xFF;
|
||||
ep_alloc_status[i].ep_type = 0xFF;
|
||||
ep_alloc_status[i].allocated[0] = false;
|
||||
ep_alloc_status[i].allocated[1] = false;
|
||||
}
|
||||
@ -245,7 +244,7 @@ static void handle_bus_reset(uint8_t rhport) {
|
||||
// Reset PMA allocation
|
||||
ep_buf_ptr = FSDEV_BTABLE_BASE + 8 * FSDEV_EP_COUNT;
|
||||
|
||||
edpt0_open(rhport); // open control endpoint (both IN & OUT)
|
||||
edpt0_open(rhport); // open control endpoint (both IN & OUT)
|
||||
|
||||
FSDEV_REG->DADDR = USB_DADDR_EF; // Enable USB Function
|
||||
}
|
||||
@ -254,8 +253,8 @@ static void handle_bus_reset(uint8_t rhport) {
|
||||
static void handle_ctr_tx(uint32_t ep_id) {
|
||||
uint32_t ep_reg = ep_read(ep_id) | USB_EP_CTR_TX | USB_EP_CTR_RX;
|
||||
|
||||
uint8_t const ep_num = ep_reg & USB_EPADDR_FIELD;
|
||||
xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, TUSB_DIR_IN);
|
||||
const uint8_t ep_num = ep_reg & USB_EPADDR_FIELD;
|
||||
xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, TUSB_DIR_IN);
|
||||
|
||||
if (ep_is_iso(ep_reg)) {
|
||||
// Ignore spurious interrupts that we don't schedule
|
||||
@ -265,11 +264,11 @@ static void handle_ctr_tx(uint32_t ep_id) {
|
||||
return;
|
||||
}
|
||||
xfer->iso_in_sending = false;
|
||||
#if FSDEV_USE_SBUF_ISO == 0
|
||||
#if FSDEV_USE_SBUF_ISO == 0
|
||||
uint8_t buf_id = (ep_reg & USB_EP_DTOG_TX) ? 0 : 1;
|
||||
#else
|
||||
#else
|
||||
uint8_t buf_id = BTABLE_BUF_TX;
|
||||
#endif
|
||||
#endif
|
||||
btable_set_count(ep_id, buf_id, 0);
|
||||
}
|
||||
|
||||
@ -282,17 +281,17 @@ static void handle_ctr_tx(uint32_t ep_id) {
|
||||
|
||||
static void handle_ctr_setup(uint32_t ep_id) {
|
||||
uint16_t rx_count = btable_get_count(ep_id, BTABLE_BUF_RX);
|
||||
uint16_t rx_addr = btable_get_addr(ep_id, BTABLE_BUF_RX);
|
||||
uint8_t setup_packet[8] TU_ATTR_ALIGNED(4);
|
||||
uint16_t rx_addr = btable_get_addr(ep_id, BTABLE_BUF_RX);
|
||||
uint8_t setup_packet[8] TU_ATTR_ALIGNED(4);
|
||||
|
||||
fsdev_read_packet_memory(setup_packet, rx_addr, rx_count);
|
||||
tu_hwfifo_read(PMA_BUF_AT(rx_addr), setup_packet, rx_count, NULL);
|
||||
|
||||
// Clear CTR RX if another setup packet arrived before this, it will be discarded
|
||||
ep_write_clear_ctr(ep_id, TUSB_DIR_OUT);
|
||||
|
||||
// Setup packet should always be 8 bytes. If not, we probably missed the packet
|
||||
if (rx_count == 8) {
|
||||
dcd_event_setup_received(0, (uint8_t*) setup_packet, true);
|
||||
dcd_event_setup_received(0, (uint8_t *)setup_packet, true);
|
||||
// Hardware should reset EP0 RX/TX to NAK and both toggle to 1
|
||||
} else {
|
||||
// Missed setup packet !!!
|
||||
@ -303,29 +302,30 @@ static void handle_ctr_setup(uint32_t ep_id) {
|
||||
|
||||
// Handle CTR interrupt for the RX/OUT direction
|
||||
static void handle_ctr_rx(uint32_t ep_id) {
|
||||
uint32_t ep_reg = ep_read(ep_id) | USB_EP_CTR_TX | USB_EP_CTR_RX;
|
||||
uint8_t const ep_num = ep_reg & USB_EPADDR_FIELD;
|
||||
bool const is_iso = ep_is_iso(ep_reg);
|
||||
xfer_ctl_t* xfer = xfer_ctl_ptr(ep_num, TUSB_DIR_OUT);
|
||||
uint32_t ep_reg = ep_read(ep_id) | USB_EP_CTR_TX | USB_EP_CTR_RX;
|
||||
const uint8_t ep_num = ep_reg & USB_EPADDR_FIELD;
|
||||
const bool is_iso = ep_is_iso(ep_reg);
|
||||
xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, TUSB_DIR_OUT);
|
||||
|
||||
uint8_t buf_id;
|
||||
#if FSDEV_USE_SBUF_ISO == 0
|
||||
#if FSDEV_USE_SBUF_ISO == 0
|
||||
bool const dbl_buf = is_iso;
|
||||
#else
|
||||
#else
|
||||
bool const dbl_buf = false;
|
||||
#endif
|
||||
#endif
|
||||
if (dbl_buf) {
|
||||
buf_id = (ep_reg & USB_EP_DTOG_RX) ? 0 : 1;
|
||||
} else {
|
||||
buf_id = BTABLE_BUF_RX;
|
||||
}
|
||||
uint16_t const rx_count = btable_get_count(ep_id, buf_id);
|
||||
uint16_t pma_addr = (uint16_t) btable_get_addr(ep_id, buf_id);
|
||||
const uint16_t rx_count = btable_get_count(ep_id, buf_id);
|
||||
uint16_t pma_addr = (uint16_t)btable_get_addr(ep_id, buf_id);
|
||||
fsdev_pma_buf_t *pma_buf = PMA_BUF_AT(pma_addr);
|
||||
|
||||
if (xfer->ff) {
|
||||
fsdev_read_packet_memory_ff(xfer->ff, pma_addr, rx_count);
|
||||
tu_hwfifo_read_to_fifo(pma_buf, xfer->ff, rx_count, NULL);
|
||||
} else {
|
||||
fsdev_read_packet_memory(xfer->buffer + xfer->queued_len, pma_addr, rx_count);
|
||||
tu_hwfifo_read(pma_buf, xfer->buffer + xfer->queued_len, rx_count, NULL);
|
||||
}
|
||||
xfer->queued_len += rx_count;
|
||||
|
||||
@ -343,7 +343,7 @@ static void handle_ctr_rx(uint32_t ep_id) {
|
||||
} else {
|
||||
// Set endpoint active again for receiving more data. Note that isochronous endpoints stay active always
|
||||
if (!is_iso) {
|
||||
uint16_t const cnt = tu_min16(xfer->total_len - xfer->queued_len, xfer->max_packet_size);
|
||||
const uint16_t cnt = tu_min16(xfer->total_len - xfer->queued_len, xfer->max_packet_size);
|
||||
btable_set_rx_bufsize(ep_id, BTABLE_BUF_RX, cnt);
|
||||
}
|
||||
ep_reg &= USB_EPREG_MASK | EP_STAT_MASK(TUSB_DIR_OUT); // will change RX Status, reserved other toggle bits
|
||||
@ -403,18 +403,18 @@ void dcd_int_handler(uint8_t rhport) {
|
||||
// loop to handle all pending CTR interrupts
|
||||
while (FSDEV_REG->ISTR & USB_ISTR_CTR) {
|
||||
// skip DIR bit, and use CTR TX/RX instead, since there is chance we have both TX/RX completed in one interrupt
|
||||
uint32_t const ep_id = FSDEV_REG->ISTR & USB_ISTR_EP_ID;
|
||||
uint32_t const ep_reg = ep_read(ep_id);
|
||||
const uint32_t ep_id = FSDEV_REG->ISTR & USB_ISTR_EP_ID;
|
||||
const uint32_t ep_reg = ep_read(ep_id);
|
||||
|
||||
if (ep_reg & USB_EP_CTR_RX) {
|
||||
#ifdef FSDEV_BUS_32BIT
|
||||
#ifdef FSDEV_BUS_32BIT
|
||||
/* https://www.st.com/resource/en/errata_sheet/es0561-stm32h503cbebkbrb-device-errata-stmicroelectronics.pdf
|
||||
* https://www.st.com/resource/en/errata_sheet/es0587-stm32u535xx-and-stm32u545xx-device-errata-stmicroelectronics.pdf
|
||||
* From H503/U535 errata: Buffer description table update completes after CTR interrupt triggers
|
||||
* Description:
|
||||
* - During OUT transfers, the correct transfer interrupt (CTR) is triggered a little before the last USB SRAM accesses
|
||||
* have completed. If the software responds quickly to the interrupt, the full buffer contents may not be correct.
|
||||
* Workaround:
|
||||
* - During OUT transfers, the correct transfer interrupt (CTR) is triggered a little before the last USB SRAM
|
||||
* accesses have completed. If the software responds quickly to the interrupt, the full buffer contents may not be
|
||||
* correct. Workaround:
|
||||
* - Software should ensure that a small delay is included before accessing the SRAM contents. This delay
|
||||
* should be 800 ns in Full Speed mode and 6.4 μs in Low Speed mode
|
||||
* - Since H5 can run up to 250Mhz -> 1 cycle = 4ns. Per errata, we need to wait 200 cycles. Though executing code
|
||||
@ -425,9 +425,9 @@ void dcd_int_handler(uint8_t rhport) {
|
||||
*/
|
||||
volatile uint32_t cycle_count = 20; // defined as PCD_RX_PMA_CNT in stm32 hal_driver
|
||||
while (cycle_count > 0U) {
|
||||
cycle_count--; // each count take 3 cycles (1 for sub, jump, and compare)
|
||||
cycle_count--; // each count take 3 cycles (1 for sub, jump, and compare)
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (ep_reg & USB_EP_SETUP) {
|
||||
handle_ctr_setup(ep_id); // CTR will be clear after copied setup packet
|
||||
@ -455,14 +455,13 @@ void dcd_int_handler(uint8_t rhport) {
|
||||
|
||||
// Invoked when a control transfer's status stage is complete.
|
||||
// May help DCD to prepare for next control transfer, this API is optional.
|
||||
void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *request) {
|
||||
void dcd_edpt0_status_complete(uint8_t rhport, const tusb_control_request_t *request) {
|
||||
(void)rhport;
|
||||
|
||||
if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
|
||||
request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
|
||||
request->bRequest == TUSB_REQ_SET_ADDRESS) {
|
||||
uint8_t const dev_addr = (uint8_t)request->wValue;
|
||||
FSDEV_REG->DADDR = (USB_DADDR_EF | dev_addr);
|
||||
request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && request->bRequest == TUSB_REQ_SET_ADDRESS) {
|
||||
const uint8_t dev_addr = (uint8_t)request->wValue;
|
||||
FSDEV_REG->DADDR = (USB_DADDR_EF | dev_addr);
|
||||
}
|
||||
|
||||
edpt0_prepare_setup();
|
||||
@ -473,15 +472,14 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *req
|
||||
* In case of double buffering, high 16bit is the address of 2nd buffer
|
||||
* During failure, TU_ASSERT is used. If this happens, rework/reallocate memory manually.
|
||||
*/
|
||||
static uint32_t dcd_pma_alloc(uint16_t len, bool dbuf)
|
||||
{
|
||||
uint8_t blsize, num_block;
|
||||
static uint32_t dcd_pma_alloc(uint16_t len, bool dbuf) {
|
||||
uint8_t blsize, num_block;
|
||||
uint16_t aligned_len = pma_align_buffer_size(len, &blsize, &num_block);
|
||||
(void) blsize;
|
||||
(void) num_block;
|
||||
(void)blsize;
|
||||
(void)num_block;
|
||||
|
||||
uint32_t addr = ep_buf_ptr;
|
||||
ep_buf_ptr = (uint16_t)(ep_buf_ptr + aligned_len); // increment buffer pointer
|
||||
ep_buf_ptr = (uint16_t)(ep_buf_ptr + aligned_len); // increment buffer pointer
|
||||
|
||||
if (dbuf) {
|
||||
addr |= ((uint32_t)ep_buf_ptr) << 16;
|
||||
@ -489,7 +487,7 @@ static uint32_t dcd_pma_alloc(uint16_t len, bool dbuf)
|
||||
}
|
||||
|
||||
// Verify packet buffer is not overflowed
|
||||
TU_ASSERT(ep_buf_ptr <= FSDEV_PMA_SIZE, 0xFFFF);
|
||||
TU_ASSERT(ep_buf_ptr <= CFG_TUSB_FSDEV_PMA_SIZE, 0xFFFF);
|
||||
|
||||
return addr;
|
||||
}
|
||||
@ -497,35 +495,32 @@ static uint32_t dcd_pma_alloc(uint16_t len, bool dbuf)
|
||||
/***
|
||||
* Allocate hardware endpoint
|
||||
*/
|
||||
static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type)
|
||||
{
|
||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type) {
|
||||
const uint8_t epnum = tu_edpt_number(ep_addr);
|
||||
const uint8_t dir = tu_edpt_dir(ep_addr);
|
||||
|
||||
for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) {
|
||||
// Check if already allocated
|
||||
if (ep_alloc_status[i].allocated[dir] &&
|
||||
ep_alloc_status[i].ep_type == ep_type &&
|
||||
if (ep_alloc_status[i].allocated[dir] && ep_alloc_status[i].ep_type == ep_type &&
|
||||
ep_alloc_status[i].ep_num == epnum) {
|
||||
return i;
|
||||
}
|
||||
|
||||
#if FSDEV_USE_SBUF_ISO == 0
|
||||
#if FSDEV_USE_SBUF_ISO == 0
|
||||
bool const dbl_buf = ep_type == TUSB_XFER_ISOCHRONOUS;
|
||||
#else
|
||||
#else
|
||||
bool const dbl_buf = false;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// If EP of current direction is not allocated
|
||||
// For double-buffered mode both directions needs to be free
|
||||
if (!ep_alloc_status[i].allocated[dir] &&
|
||||
(!dbl_buf || !ep_alloc_status[i].allocated[dir ^ 1])) {
|
||||
if (!ep_alloc_status[i].allocated[dir] && (!dbl_buf || !ep_alloc_status[i].allocated[dir ^ 1])) {
|
||||
// Check if EP number is the same
|
||||
if (ep_alloc_status[i].ep_num == 0xFF || ep_alloc_status[i].ep_num == epnum) {
|
||||
// One EP pair has to be the same type
|
||||
if (ep_alloc_status[i].ep_type == 0xFF || ep_alloc_status[i].ep_type == ep_type) {
|
||||
ep_alloc_status[i].ep_num = epnum;
|
||||
ep_alloc_status[i].ep_type = ep_type;
|
||||
ep_alloc_status[i].ep_num = epnum;
|
||||
ep_alloc_status[i].ep_type = ep_type;
|
||||
ep_alloc_status[i].allocated[dir] = true;
|
||||
|
||||
return i;
|
||||
@ -539,16 +534,16 @@ static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type)
|
||||
}
|
||||
|
||||
void edpt0_open(uint8_t rhport) {
|
||||
(void) rhport;
|
||||
(void)rhport;
|
||||
|
||||
dcd_ep_alloc(0x0, TUSB_XFER_CONTROL);
|
||||
dcd_ep_alloc(0x80, TUSB_XFER_CONTROL);
|
||||
|
||||
xfer_status[0][0].max_packet_size = CFG_TUD_ENDPOINT0_SIZE;
|
||||
xfer_status[0][0].ep_idx = 0;
|
||||
xfer_status[0][0].ep_idx = 0;
|
||||
|
||||
xfer_status[0][1].max_packet_size = CFG_TUD_ENDPOINT0_SIZE;
|
||||
xfer_status[0][1].ep_idx = 0;
|
||||
xfer_status[0][1].ep_idx = 0;
|
||||
|
||||
uint16_t pma_addr0 = dcd_pma_alloc(CFG_TUD_ENDPOINT0_SIZE, false);
|
||||
uint16_t pma_addr1 = dcd_pma_alloc(CFG_TUD_ENDPOINT0_SIZE, false);
|
||||
@ -566,13 +561,13 @@ void edpt0_open(uint8_t rhport) {
|
||||
ep_write(0, ep_reg, false);
|
||||
}
|
||||
|
||||
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep) {
|
||||
bool dcd_edpt_open(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) {
|
||||
(void)rhport;
|
||||
uint8_t const ep_addr = desc_ep->bEndpointAddress;
|
||||
uint8_t const ep_num = tu_edpt_number(ep_addr);
|
||||
tusb_dir_t const dir = tu_edpt_dir(ep_addr);
|
||||
const uint16_t packet_size = tu_edpt_packet_size(desc_ep);
|
||||
uint8_t const ep_idx = dcd_ep_alloc(ep_addr, desc_ep->bmAttributes.xfer);
|
||||
const uint8_t ep_addr = desc_ep->bEndpointAddress;
|
||||
const uint8_t ep_num = tu_edpt_number(ep_addr);
|
||||
const tusb_dir_t dir = tu_edpt_dir(ep_addr);
|
||||
const uint16_t packet_size = tu_edpt_packet_size(desc_ep);
|
||||
const uint8_t ep_idx = dcd_ep_alloc(ep_addr, desc_ep->bmAttributes.xfer);
|
||||
TU_ASSERT(ep_idx < FSDEV_EP_COUNT);
|
||||
|
||||
uint32_t ep_reg = ep_read(ep_idx) & ~USB_EPREG_MASK;
|
||||
@ -596,9 +591,9 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep) {
|
||||
uint16_t pma_addr = dcd_pma_alloc(packet_size, false);
|
||||
btable_set_addr(ep_idx, dir == TUSB_DIR_IN ? BTABLE_BUF_TX : BTABLE_BUF_RX, pma_addr);
|
||||
|
||||
xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
|
||||
xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
|
||||
xfer->max_packet_size = packet_size;
|
||||
xfer->ep_idx = ep_idx;
|
||||
xfer->ep_idx = ep_idx;
|
||||
|
||||
ep_change_status(&ep_reg, dir, EP_STAT_NAK);
|
||||
ep_change_dtog(&ep_reg, dir, 0);
|
||||
@ -622,8 +617,8 @@ void dcd_edpt_close_all(uint8_t rhport) {
|
||||
// Reset endpoint
|
||||
ep_write(i, 0, false);
|
||||
// Clear EP allocation status
|
||||
ep_alloc_status[i].ep_num = 0xFF;
|
||||
ep_alloc_status[i].ep_type = 0xFF;
|
||||
ep_alloc_status[i].ep_num = 0xFF;
|
||||
ep_alloc_status[i].ep_type = 0xFF;
|
||||
ep_alloc_status[i].allocated[0] = false;
|
||||
ep_alloc_status[i].allocated[1] = false;
|
||||
}
|
||||
@ -637,46 +632,46 @@ void dcd_edpt_close_all(uint8_t rhport) {
|
||||
bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) {
|
||||
(void)rhport;
|
||||
|
||||
uint8_t const ep_num = tu_edpt_number(ep_addr);
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
uint8_t const ep_idx = dcd_ep_alloc(ep_addr, TUSB_XFER_ISOCHRONOUS);
|
||||
const uint8_t ep_num = tu_edpt_number(ep_addr);
|
||||
const uint8_t dir = tu_edpt_dir(ep_addr);
|
||||
const uint8_t ep_idx = dcd_ep_alloc(ep_addr, TUSB_XFER_ISOCHRONOUS);
|
||||
|
||||
#if CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP != 0
|
||||
uint32_t pma_addr = dcd_pma_alloc(largest_packet_size, true);
|
||||
#if CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP != 0
|
||||
uint32_t pma_addr = dcd_pma_alloc(largest_packet_size, true);
|
||||
uint16_t pma_addr2 = pma_addr >> 16;
|
||||
#else
|
||||
uint32_t pma_addr = dcd_pma_alloc(largest_packet_size, false);
|
||||
#else
|
||||
uint32_t pma_addr = dcd_pma_alloc(largest_packet_size, false);
|
||||
uint16_t pma_addr2 = pma_addr;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if FSDEV_USE_SBUF_ISO == 0
|
||||
#if FSDEV_USE_SBUF_ISO == 0
|
||||
btable_set_addr(ep_idx, 0, pma_addr);
|
||||
btable_set_addr(ep_idx, 1, pma_addr2);
|
||||
#else
|
||||
#else
|
||||
btable_set_addr(ep_idx, dir == TUSB_DIR_IN ? BTABLE_BUF_TX : BTABLE_BUF_RX, pma_addr);
|
||||
(void) pma_addr2;
|
||||
#endif
|
||||
(void)pma_addr2;
|
||||
#endif
|
||||
|
||||
xfer_ctl_t* xfer = xfer_ctl_ptr(ep_num, dir);
|
||||
xfer->ep_idx = ep_idx;
|
||||
xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
|
||||
xfer->ep_idx = ep_idx;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep) {
|
||||
bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) {
|
||||
(void)rhport;
|
||||
uint8_t const ep_addr = desc_ep->bEndpointAddress;
|
||||
uint8_t const ep_num = tu_edpt_number(ep_addr);
|
||||
tusb_dir_t const dir = tu_edpt_dir(ep_addr);
|
||||
xfer_ctl_t* xfer = xfer_ctl_ptr(ep_num, dir);
|
||||
const uint8_t ep_addr = desc_ep->bEndpointAddress;
|
||||
const uint8_t ep_num = tu_edpt_number(ep_addr);
|
||||
const tusb_dir_t dir = tu_edpt_dir(ep_addr);
|
||||
xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
|
||||
|
||||
uint8_t const ep_idx = xfer->ep_idx;
|
||||
const uint8_t ep_idx = xfer->ep_idx;
|
||||
|
||||
xfer->max_packet_size = tu_edpt_packet_size(desc_ep);
|
||||
|
||||
uint32_t ep_reg = ep_read(ep_idx) & ~USB_EPREG_MASK;
|
||||
ep_reg |= tu_edpt_number(ep_addr) | USB_EP_ISOCHRONOUS | USB_EP_CTR_TX | USB_EP_CTR_RX;
|
||||
#if FSDEV_USE_SBUF_ISO != 0
|
||||
#if FSDEV_USE_SBUF_ISO != 0
|
||||
ep_reg |= USB_EP_KIND;
|
||||
|
||||
ep_change_status(&ep_reg, dir, EP_STAT_DISABLED);
|
||||
@ -687,12 +682,12 @@ bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep)
|
||||
} else {
|
||||
ep_reg &= ~(USB_EPTX_STAT | USB_EP_DTOG_TX);
|
||||
}
|
||||
#else
|
||||
#else
|
||||
ep_change_status(&ep_reg, TUSB_DIR_IN, EP_STAT_DISABLED);
|
||||
ep_change_status(&ep_reg, TUSB_DIR_OUT, EP_STAT_DISABLED);
|
||||
ep_change_dtog(&ep_reg, dir, 0);
|
||||
ep_change_dtog(&ep_reg, (tusb_dir_t)(1 - dir), 1);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
ep_write(ep_idx, ep_reg, true);
|
||||
|
||||
@ -701,28 +696,29 @@ bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep)
|
||||
|
||||
// Currently, single-buffered, and only 64 bytes at a time (max)
|
||||
static void dcd_transmit_packet(xfer_ctl_t *xfer, uint16_t ep_ix) {
|
||||
uint16_t len = tu_min16(xfer->total_len - xfer->queued_len, xfer->max_packet_size);
|
||||
uint16_t len = tu_min16(xfer->total_len - xfer->queued_len, xfer->max_packet_size);
|
||||
uint32_t ep_reg = ep_read(ep_ix) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR
|
||||
|
||||
bool const is_iso = ep_is_iso(ep_reg);
|
||||
const bool is_iso = ep_is_iso(ep_reg);
|
||||
|
||||
uint8_t buf_id;
|
||||
#if FSDEV_USE_SBUF_ISO == 0
|
||||
#if FSDEV_USE_SBUF_ISO == 0
|
||||
bool const dbl_buf = is_iso;
|
||||
#else
|
||||
#else
|
||||
bool const dbl_buf = false;
|
||||
#endif
|
||||
#endif
|
||||
if (dbl_buf) {
|
||||
buf_id = (ep_reg & USB_EP_DTOG_TX) ? 1 : 0;
|
||||
} else {
|
||||
buf_id = BTABLE_BUF_TX;
|
||||
}
|
||||
uint16_t addr_ptr = (uint16_t) btable_get_addr(ep_ix, buf_id);
|
||||
uint16_t addr_ptr = (uint16_t)btable_get_addr(ep_ix, buf_id);
|
||||
fsdev_pma_buf_t *pma_buf = PMA_BUF_AT(addr_ptr);
|
||||
|
||||
if (xfer->ff) {
|
||||
fsdev_write_packet_memory_ff(xfer->ff, addr_ptr, len);
|
||||
tu_hwfifo_write_from_fifo(pma_buf, xfer->ff, len, NULL);
|
||||
} else {
|
||||
fsdev_write_packet_memory(addr_ptr, &(xfer->buffer[xfer->queued_len]), len);
|
||||
tu_hwfifo_write(pma_buf, &(xfer->buffer[xfer->queued_len]), len, NULL);
|
||||
}
|
||||
xfer->queued_len += len;
|
||||
|
||||
@ -737,10 +733,10 @@ static void dcd_transmit_packet(xfer_ctl_t *xfer, uint16_t ep_ix) {
|
||||
}
|
||||
|
||||
static bool edpt_xfer(uint8_t rhport, uint8_t ep_num, tusb_dir_t dir) {
|
||||
(void) rhport;
|
||||
(void)rhport;
|
||||
|
||||
xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
|
||||
uint8_t const ep_idx = xfer->ep_idx;
|
||||
xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
|
||||
const uint8_t ep_idx = xfer->ep_idx;
|
||||
|
||||
if (dir == TUSB_DIR_IN) {
|
||||
dcd_transmit_packet(xfer, ep_idx);
|
||||
@ -750,11 +746,11 @@ static bool edpt_xfer(uint8_t rhport, uint8_t ep_num, tusb_dir_t dir) {
|
||||
|
||||
uint16_t cnt = tu_min16(xfer->total_len, xfer->max_packet_size);
|
||||
|
||||
#if FSDEV_USE_SBUF_ISO == 0
|
||||
#if FSDEV_USE_SBUF_ISO == 0
|
||||
bool const dbl_buf = ep_is_iso(ep_reg);
|
||||
#else
|
||||
#else
|
||||
bool const dbl_buf = false;
|
||||
#endif
|
||||
#endif
|
||||
if (dbl_buf) {
|
||||
btable_set_rx_bufsize(ep_idx, 0, cnt);
|
||||
btable_set_rx_bufsize(ep_idx, 1, cnt);
|
||||
@ -769,29 +765,29 @@ static bool edpt_xfer(uint8_t rhport, uint8_t ep_num, tusb_dir_t dir) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) {
|
||||
(void) is_isr;
|
||||
uint8_t const ep_num = tu_edpt_number(ep_addr);
|
||||
tusb_dir_t const dir = tu_edpt_dir(ep_addr);
|
||||
xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
|
||||
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes, bool is_isr) {
|
||||
(void)is_isr;
|
||||
const uint8_t ep_num = tu_edpt_number(ep_addr);
|
||||
const tusb_dir_t dir = tu_edpt_dir(ep_addr);
|
||||
xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
|
||||
|
||||
xfer->buffer = buffer;
|
||||
xfer->ff = NULL;
|
||||
xfer->total_len = total_bytes;
|
||||
xfer->buffer = buffer;
|
||||
xfer->ff = NULL;
|
||||
xfer->total_len = total_bytes;
|
||||
xfer->queued_len = 0;
|
||||
|
||||
return edpt_xfer(rhport, ep_num, dir);
|
||||
}
|
||||
|
||||
bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes, bool is_isr) {
|
||||
(void) is_isr;
|
||||
uint8_t const ep_num = tu_edpt_number(ep_addr);
|
||||
tusb_dir_t const dir = tu_edpt_dir(ep_addr);
|
||||
xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
|
||||
bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes, bool is_isr) {
|
||||
(void)is_isr;
|
||||
const uint8_t ep_num = tu_edpt_number(ep_addr);
|
||||
const tusb_dir_t dir = tu_edpt_dir(ep_addr);
|
||||
xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
|
||||
|
||||
xfer->buffer = NULL;
|
||||
xfer->ff = ff;
|
||||
xfer->total_len = total_bytes;
|
||||
xfer->buffer = NULL;
|
||||
xfer->ff = ff;
|
||||
xfer->total_len = total_bytes;
|
||||
xfer->queued_len = 0;
|
||||
|
||||
return edpt_xfer(rhport, ep_num, dir);
|
||||
@ -799,10 +795,10 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_
|
||||
|
||||
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
|
||||
(void)rhport;
|
||||
uint8_t const ep_num = tu_edpt_number(ep_addr);
|
||||
tusb_dir_t const dir = tu_edpt_dir(ep_addr);
|
||||
xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
|
||||
uint8_t const ep_idx = xfer->ep_idx;
|
||||
const uint8_t ep_num = tu_edpt_number(ep_addr);
|
||||
const tusb_dir_t dir = tu_edpt_dir(ep_addr);
|
||||
xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
|
||||
const uint8_t ep_idx = xfer->ep_idx;
|
||||
|
||||
uint32_t ep_reg = ep_read(ep_idx) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR bits
|
||||
ep_reg &= USB_EPREG_MASK | EP_STAT_MASK(dir);
|
||||
@ -814,10 +810,10 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
|
||||
void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
|
||||
(void)rhport;
|
||||
|
||||
uint8_t const ep_num = tu_edpt_number(ep_addr);
|
||||
tusb_dir_t const dir = tu_edpt_dir(ep_addr);
|
||||
xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
|
||||
uint8_t const ep_idx = xfer->ep_idx;
|
||||
const uint8_t ep_num = tu_edpt_number(ep_addr);
|
||||
const tusb_dir_t dir = tu_edpt_dir(ep_addr);
|
||||
xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
|
||||
const uint8_t ep_idx = xfer->ep_idx;
|
||||
|
||||
uint32_t ep_reg = ep_read(ep_idx) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR bits
|
||||
ep_reg &= USB_EPREG_MASK | EP_STAT_MASK(dir) | EP_DTOG_MASK(dir);
|
||||
@ -837,7 +833,7 @@ void dcd_int_disable(uint8_t rhport) {
|
||||
fsdev_int_disable(rhport);
|
||||
}
|
||||
|
||||
#if defined(USB_BCDR_DPPU) || defined(SYSCFG_PMC_USB_PU)
|
||||
#if defined(USB_BCDR_DPPU) || defined(SYSCFG_PMC_USB_PU)
|
||||
void dcd_connect(uint8_t rhport) {
|
||||
fsdev_connect(rhport);
|
||||
}
|
||||
@ -845,6 +841,6 @@ void dcd_connect(uint8_t rhport) {
|
||||
void dcd_disconnect(uint8_t rhport) {
|
||||
fsdev_disconnect(rhport);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@ -35,7 +35,6 @@
|
||||
|
||||
#endif
|
||||
|
||||
#define FSDEV_PMA_SIZE (512u)
|
||||
#define FSDEV_USE_SBUF_ISO 0
|
||||
#define FSDEV_REG_BASE (APB1PERIPH_BASE + 0x00005C00UL)
|
||||
#define FSDEV_PMA_BASE (APB1PERIPH_BASE + 0x00006000UL)
|
||||
|
||||
@ -53,7 +53,6 @@
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#define FSDEV_PMA_SIZE (512u)
|
||||
#define FSDEV_USE_SBUF_ISO 0
|
||||
#define FSDEV_REG_BASE (APB1PERIPH_BASE + 0x00005C00UL)
|
||||
#define FSDEV_PMA_BASE (APB1PERIPH_BASE + 0x00006000UL)
|
||||
|
||||
@ -69,179 +69,6 @@ void fsdev_deinit(void) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// PMA read/write
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Write to packet memory area (PMA) from user memory
|
||||
// - Packet memory must be either strictly 16-bit or 32-bit depending on FSDEV_BUS_32BIT
|
||||
// - Uses unaligned for RAM (since M0 cannot access unaligned address)
|
||||
bool fsdev_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t nbytes) {
|
||||
if (nbytes == 0) {
|
||||
return true;
|
||||
}
|
||||
uint32_t n_write = nbytes / FSDEV_BUS_SIZE;
|
||||
|
||||
fsdev_pma_buf_t* pma_buf = PMA_BUF_AT(dst);
|
||||
const uint8_t *src8 = src;
|
||||
|
||||
while (n_write--) {
|
||||
pma_buf->value = fsdevbus_unaligned_read(src8);
|
||||
src8 += FSDEV_BUS_SIZE;
|
||||
pma_buf++;
|
||||
}
|
||||
|
||||
// odd bytes e.g 1 for 16-bit or 1-3 for 32-bit
|
||||
uint16_t odd = nbytes & (FSDEV_BUS_SIZE - 1);
|
||||
if (odd) {
|
||||
fsdev_bus_t temp = 0;
|
||||
for(uint16_t i = 0; i < odd; i++) {
|
||||
temp |= *src8++ << (i * 8);
|
||||
}
|
||||
pma_buf->value = temp;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read from packet memory area (PMA) to user memory.
|
||||
// - Packet memory must be either strictly 16-bit or 32-bit depending on FSDEV_BUS_32BIT
|
||||
// - Uses unaligned for RAM (since M0 cannot access unaligned address)
|
||||
bool fsdev_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t nbytes) {
|
||||
if (nbytes == 0) {
|
||||
return true;
|
||||
}
|
||||
uint32_t n_read = nbytes / FSDEV_BUS_SIZE;
|
||||
|
||||
fsdev_pma_buf_t* pma_buf = PMA_BUF_AT(src);
|
||||
uint8_t *dst8 = (uint8_t *)dst;
|
||||
|
||||
while (n_read--) {
|
||||
fsdevbus_unaligned_write(dst8, (fsdev_bus_t ) pma_buf->value);
|
||||
dst8 += FSDEV_BUS_SIZE;
|
||||
pma_buf++;
|
||||
}
|
||||
|
||||
// odd bytes e.g 1 for 16-bit or 1-3 for 32-bit
|
||||
uint16_t odd = nbytes & (FSDEV_BUS_SIZE - 1);
|
||||
if (odd) {
|
||||
fsdev_bus_t temp = pma_buf->value;
|
||||
while (odd--) {
|
||||
*dst8++ = (uint8_t) (temp & 0xfful);
|
||||
temp >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Write to PMA from FIFO
|
||||
bool fsdev_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes) {
|
||||
if (wNBytes == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Since we copy from a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies
|
||||
tu_fifo_buffer_info_t info;
|
||||
tu_fifo_get_read_info(ff, &info);
|
||||
|
||||
uint16_t cnt_lin = tu_min16(wNBytes, info.linear.len);
|
||||
uint16_t cnt_wrap = tu_min16(wNBytes - cnt_lin, info.wrapped.len);
|
||||
uint16_t const cnt_total = cnt_lin + cnt_wrap;
|
||||
|
||||
// We want to read from the FIFO and write it into the PMA, if LIN part is ODD and has WRAPPED part,
|
||||
// last lin byte will be combined with wrapped part To ensure PMA is always access aligned
|
||||
uint16_t lin_even = cnt_lin & ~(FSDEV_BUS_SIZE - 1);
|
||||
uint16_t lin_odd = cnt_lin & (FSDEV_BUS_SIZE - 1);
|
||||
uint8_t const *src8 = (uint8_t const*) info.linear.ptr;
|
||||
|
||||
// write even linear part
|
||||
fsdev_write_packet_memory(dst, src8, lin_even);
|
||||
dst += lin_even;
|
||||
src8 += lin_even;
|
||||
|
||||
if (lin_odd == 0) {
|
||||
src8 = (uint8_t const*) info.wrapped.ptr;
|
||||
} else {
|
||||
// Combine last linear bytes + first wrapped bytes to form fsdev bus width data
|
||||
fsdev_bus_t temp = 0;
|
||||
uint16_t i;
|
||||
for(i = 0; i < lin_odd; i++) {
|
||||
temp |= *src8++ << (i * 8);
|
||||
}
|
||||
|
||||
src8 = (uint8_t const*) info.wrapped.ptr;
|
||||
for(; i < FSDEV_BUS_SIZE && cnt_wrap > 0; i++, cnt_wrap--) {
|
||||
temp |= *src8++ << (i * 8);
|
||||
}
|
||||
|
||||
fsdev_write_packet_memory(dst, &temp, FSDEV_BUS_SIZE);
|
||||
dst += FSDEV_BUS_SIZE;
|
||||
}
|
||||
|
||||
// write the rest of the wrapped part
|
||||
fsdev_write_packet_memory(dst, src8, cnt_wrap);
|
||||
|
||||
tu_fifo_advance_read_pointer(ff, cnt_total);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read from PMA to FIFO
|
||||
bool fsdev_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes) {
|
||||
if (wNBytes == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Since we copy into a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies
|
||||
// Check for first linear part
|
||||
tu_fifo_buffer_info_t info;
|
||||
tu_fifo_get_write_info(ff, &info); // We want to read from the FIFO
|
||||
|
||||
uint16_t cnt_lin = tu_min16(wNBytes, info.linear.len);
|
||||
uint16_t cnt_wrap = tu_min16(wNBytes - cnt_lin, info.wrapped.len);
|
||||
uint16_t cnt_total = cnt_lin + cnt_wrap;
|
||||
|
||||
// We want to read from the FIFO and write it into the PMA, if LIN part is ODD and has WRAPPED part,
|
||||
// last lin byte will be combined with wrapped part To ensure PMA is always access aligned
|
||||
|
||||
uint16_t lin_even = cnt_lin & ~(FSDEV_BUS_SIZE - 1);
|
||||
uint16_t lin_odd = cnt_lin & (FSDEV_BUS_SIZE - 1);
|
||||
uint8_t *dst8 = (uint8_t *) info.linear.ptr;
|
||||
|
||||
// read even linear part
|
||||
fsdev_read_packet_memory(dst8, src, lin_even);
|
||||
dst8 += lin_even;
|
||||
src += lin_even;
|
||||
|
||||
if (lin_odd == 0) {
|
||||
dst8 = (uint8_t *) info.wrapped.ptr;
|
||||
} else {
|
||||
// Combine last linear bytes + first wrapped bytes to form fsdev bus width data
|
||||
fsdev_bus_t temp;
|
||||
fsdev_read_packet_memory(&temp, src, FSDEV_BUS_SIZE);
|
||||
src += FSDEV_BUS_SIZE;
|
||||
|
||||
uint16_t i;
|
||||
for (i = 0; i < lin_odd; i++) {
|
||||
*dst8++ = (uint8_t) (temp & 0xfful);
|
||||
temp >>= 8;
|
||||
}
|
||||
|
||||
dst8 = (uint8_t *) info.wrapped.ptr;
|
||||
for (; i < FSDEV_BUS_SIZE && cnt_wrap > 0; i++, cnt_wrap--) {
|
||||
*dst8++ = (uint8_t) (temp & 0xfful);
|
||||
temp >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
// read the rest of the wrapped part
|
||||
fsdev_read_packet_memory(dst8, src, cnt_wrap);
|
||||
|
||||
tu_fifo_advance_write_pointer(ff, cnt_total);
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// BTable Helper
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
@ -32,11 +32,11 @@
|
||||
#include "common/tusb_common.h"
|
||||
|
||||
#if CFG_TUD_ENABLED
|
||||
#include "device/dcd.h"
|
||||
#include "device/dcd.h"
|
||||
#endif
|
||||
|
||||
#if CFG_TUH_ENABLED
|
||||
#include "host/hcd.h"
|
||||
#include "host/hcd.h"
|
||||
#endif
|
||||
|
||||
#if defined(TUP_USBIP_FSDEV_STM32)
|
||||
@ -56,41 +56,37 @@ extern "C" {
|
||||
// If sharing with CAN, one can set this to be non-zero to give CAN space where it wants it
|
||||
// Both of these MUST be a multiple of 2, and are in byte units.
|
||||
#ifndef FSDEV_BTABLE_BASE
|
||||
#define FSDEV_BTABLE_BASE 0U
|
||||
#define FSDEV_BTABLE_BASE 0U
|
||||
#endif
|
||||
|
||||
TU_VERIFY_STATIC(FSDEV_BTABLE_BASE % 8 == 0, "BTABLE base must be aligned to 8 bytes");
|
||||
|
||||
// FSDEV_PMA_SIZE is PMA buffer size in bytes.
|
||||
// CFG_TUSB_FSDEV_PMA_SIZE is PMA buffer size in bytes.
|
||||
// - 512-byte devices, access with a stride of two words (use every other 16-bit address)
|
||||
// - 1024-byte devices, access with a stride of one word (use every 16-bit address)
|
||||
// - 2048-byte devices, access with 32-bit address
|
||||
|
||||
// For purposes of accessing the packet
|
||||
#if FSDEV_PMA_SIZE == 512
|
||||
#if CFG_TUSB_FSDEV_PMA_SIZE == 512
|
||||
// 1x16 bit / word access scheme
|
||||
#define FSDEV_PMA_STRIDE 2
|
||||
#define pma_access_scheme TU_ATTR_ALIGNED(4)
|
||||
#elif FSDEV_PMA_SIZE == 1024
|
||||
#elif CFG_TUSB_FSDEV_PMA_SIZE == 1024
|
||||
// 2x16 bit / word access scheme
|
||||
#define FSDEV_PMA_STRIDE 1
|
||||
#define FSDEV_PMA_STRIDE 1
|
||||
#define pma_access_scheme
|
||||
#elif FSDEV_PMA_SIZE == 2048
|
||||
#elif CFG_TUSB_FSDEV_PMA_SIZE == 2048
|
||||
// 32 bit access scheme
|
||||
#define FSDEV_BUS_32BIT
|
||||
#define FSDEV_PMA_STRIDE 1
|
||||
#define FSDEV_PMA_STRIDE 1
|
||||
#define pma_access_scheme
|
||||
#endif
|
||||
|
||||
// The fsdev_bus_t type can be used for both register and PMA access necessities
|
||||
#ifdef FSDEV_BUS_32BIT
|
||||
typedef uint32_t fsdev_bus_t;
|
||||
#define fsdevbus_unaligned_read(_addr) tu_unaligned_read32(_addr)
|
||||
#define fsdevbus_unaligned_write(_addr, _value) tu_unaligned_write32(_addr, _value)
|
||||
typedef uint32_t fsdev_bus_t;
|
||||
#else
|
||||
typedef uint16_t fsdev_bus_t;
|
||||
#define fsdevbus_unaligned_read(_addr) tu_unaligned_read16(_addr)
|
||||
#define fsdevbus_unaligned_write(_addr, _value) tu_unaligned_write16(_addr, _value)
|
||||
typedef uint16_t fsdev_bus_t;
|
||||
#endif
|
||||
|
||||
enum {
|
||||
@ -124,77 +120,77 @@ typedef union {
|
||||
} ep32[FSDEV_EP_COUNT][2];
|
||||
} fsdev_btable_t;
|
||||
|
||||
TU_VERIFY_STATIC(sizeof(fsdev_btable_t) == FSDEV_EP_COUNT*8*FSDEV_PMA_STRIDE, "size is not correct");
|
||||
TU_VERIFY_STATIC(FSDEV_BTABLE_BASE + FSDEV_EP_COUNT*8 <= FSDEV_PMA_SIZE, "BTABLE does not fit in PMA RAM");
|
||||
TU_VERIFY_STATIC(sizeof(fsdev_btable_t) == FSDEV_EP_COUNT * 8 * FSDEV_PMA_STRIDE, "size is not correct");
|
||||
TU_VERIFY_STATIC(FSDEV_BTABLE_BASE + FSDEV_EP_COUNT * 8 <= CFG_TUSB_FSDEV_PMA_SIZE, "BTABLE does not fit in PMA RAM");
|
||||
|
||||
#define FSDEV_BTABLE ((volatile fsdev_btable_t*) (FSDEV_PMA_BASE + FSDEV_PMA_STRIDE*(FSDEV_BTABLE_BASE)))
|
||||
#define FSDEV_BTABLE ((volatile fsdev_btable_t *)(FSDEV_PMA_BASE + FSDEV_PMA_STRIDE * (FSDEV_BTABLE_BASE)))
|
||||
|
||||
typedef struct {
|
||||
volatile pma_access_scheme fsdev_bus_t value;
|
||||
} fsdev_pma_buf_t;
|
||||
|
||||
#define PMA_BUF_AT(_addr) ((fsdev_pma_buf_t*) (FSDEV_PMA_BASE + FSDEV_PMA_STRIDE*(_addr)))
|
||||
#define PMA_BUF_AT(_addr) ((fsdev_pma_buf_t *)(FSDEV_PMA_BASE + FSDEV_PMA_STRIDE * (_addr)))
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Registers Typedef
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// volatile 32-bit aligned
|
||||
#define _va32 volatile TU_ATTR_ALIGNED(4)
|
||||
#define _va32 volatile TU_ATTR_ALIGNED(4)
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
_va32 fsdev_bus_t reg;
|
||||
}ep[FSDEV_EP_COUNT];
|
||||
} ep[FSDEV_EP_COUNT];
|
||||
|
||||
_va32 uint32_t RESERVED7[8]; // Reserved
|
||||
_va32 fsdev_bus_t CNTR; // 40: Control register
|
||||
_va32 fsdev_bus_t ISTR; // 44: Interrupt status register
|
||||
_va32 fsdev_bus_t FNR; // 48: Frame number register
|
||||
_va32 fsdev_bus_t DADDR; // 4C: Device address register
|
||||
_va32 fsdev_bus_t BTABLE; // 50: Buffer Table address register (16-bit only)
|
||||
_va32 fsdev_bus_t LPMCSR; // 54: LPM Control and Status Register (32-bit only)
|
||||
_va32 fsdev_bus_t BCDR; // 58: Battery Charging Detector Register (32-bit only)
|
||||
_va32 uint32_t RESERVED7[8]; // Reserved
|
||||
_va32 fsdev_bus_t CNTR; // 40: Control register
|
||||
_va32 fsdev_bus_t ISTR; // 44: Interrupt status register
|
||||
_va32 fsdev_bus_t FNR; // 48: Frame number register
|
||||
_va32 fsdev_bus_t DADDR; // 4C: Device address register
|
||||
_va32 fsdev_bus_t BTABLE; // 50: Buffer Table address register (16-bit only)
|
||||
_va32 fsdev_bus_t LPMCSR; // 54: LPM Control and Status Register (32-bit only)
|
||||
_va32 fsdev_bus_t BCDR; // 58: Battery Charging Detector Register (32-bit only)
|
||||
} fsdev_regs_t;
|
||||
|
||||
TU_VERIFY_STATIC(offsetof(fsdev_regs_t, CNTR) == 0x40, "Wrong offset");
|
||||
TU_VERIFY_STATIC(sizeof(fsdev_regs_t) == 0x5C, "Size is not correct");
|
||||
|
||||
#define FSDEV_REG ((fsdev_regs_t*) FSDEV_REG_BASE)
|
||||
#define FSDEV_REG ((fsdev_regs_t *)FSDEV_REG_BASE)
|
||||
|
||||
|
||||
#ifndef USB_EPTX_STAT
|
||||
#define USB_EPTX_STAT 0x0030U
|
||||
#define USB_EPTX_STAT 0x0030U
|
||||
#endif
|
||||
|
||||
#ifndef USB_EPRX_STAT
|
||||
#define USB_EPRX_STAT 0x3000U
|
||||
#define USB_EPRX_STAT 0x3000U
|
||||
#endif
|
||||
|
||||
#ifndef USB_EPTX_STAT_Pos
|
||||
#define USB_EPTX_STAT_Pos 4u
|
||||
#define USB_EPTX_STAT_Pos 4u
|
||||
#endif
|
||||
|
||||
#ifndef USB_EP_DTOG_TX_Pos
|
||||
#define USB_EP_DTOG_TX_Pos 6u
|
||||
#define USB_EP_DTOG_TX_Pos 6u
|
||||
#endif
|
||||
|
||||
#ifndef USB_EP_CTR_TX_Pos
|
||||
#define USB_EP_CTR_TX_Pos 7u
|
||||
#define USB_EP_CTR_TX_Pos 7u
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
EP_STAT_DISABLED = 0,
|
||||
EP_STAT_STALL = 1,
|
||||
EP_STAT_NAK = 2,
|
||||
EP_STAT_VALID = 3
|
||||
}ep_stat_t;
|
||||
EP_STAT_STALL = 1,
|
||||
EP_STAT_NAK = 2,
|
||||
EP_STAT_VALID = 3
|
||||
} ep_stat_t;
|
||||
|
||||
#define EP_STAT_MASK(_dir) (3u << (USB_EPTX_STAT_Pos + ((_dir) == TUSB_DIR_IN ? 0 : 8)))
|
||||
#define EP_DTOG_MASK(_dir) (1u << (USB_EP_DTOG_TX_Pos + ((_dir) == TUSB_DIR_IN ? 0 : 8)))
|
||||
#define EP_STAT_MASK(_dir) (3u << (USB_EPTX_STAT_Pos + ((_dir) == TUSB_DIR_IN ? 0 : 8)))
|
||||
#define EP_DTOG_MASK(_dir) (1u << (USB_EP_DTOG_TX_Pos + ((_dir) == TUSB_DIR_IN ? 0 : 8)))
|
||||
|
||||
#define CH_STAT_MASK(_dir) (3u << (USB_EPTX_STAT_Pos + ((_dir) == TUSB_DIR_IN ? 8 : 0)))
|
||||
#define CH_DTOG_MASK(_dir) (1u << (USB_EP_DTOG_TX_Pos + ((_dir) == TUSB_DIR_IN ? 8 : 0)))
|
||||
#define CH_STAT_MASK(_dir) (3u << (USB_EPTX_STAT_Pos + ((_dir) == TUSB_DIR_IN ? 8 : 0)))
|
||||
#define CH_DTOG_MASK(_dir) (1u << (USB_EP_DTOG_TX_Pos + ((_dir) == TUSB_DIR_IN ? 8 : 0)))
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Endpoint Helper
|
||||
@ -211,7 +207,7 @@ TU_ATTR_ALWAYS_INLINE static inline void ep_write(uint32_t ep_id, uint32_t value
|
||||
fsdev_int_disable(0);
|
||||
}
|
||||
|
||||
FSDEV_REG->ep[ep_id].reg = (fsdev_bus_t) value;
|
||||
FSDEV_REG->ep[ep_id].reg = (fsdev_bus_t)value;
|
||||
|
||||
if (need_exclusive) {
|
||||
fsdev_int_enable(0);
|
||||
@ -226,11 +222,11 @@ TU_ATTR_ALWAYS_INLINE static inline void ep_write_clear_ctr(uint32_t ep_id, tusb
|
||||
ep_write(ep_id, reg, false);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void ep_change_status(uint32_t* reg, tusb_dir_t dir, ep_stat_t state) {
|
||||
TU_ATTR_ALWAYS_INLINE static inline void ep_change_status(uint32_t *reg, tusb_dir_t dir, ep_stat_t state) {
|
||||
*reg ^= (state << (USB_EPTX_STAT_Pos + (dir == TUSB_DIR_IN ? 0 : 8)));
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void ep_change_dtog(uint32_t* reg, tusb_dir_t dir, uint8_t state) {
|
||||
TU_ATTR_ALWAYS_INLINE static inline void ep_change_dtog(uint32_t *reg, tusb_dir_t dir, uint8_t state) {
|
||||
*reg ^= (state << (USB_EP_DTOG_TX_Pos + (dir == TUSB_DIR_IN ? 0 : 8)));
|
||||
}
|
||||
|
||||
@ -259,11 +255,11 @@ TU_ATTR_ALWAYS_INLINE static inline void ch_write_clear_ctr(uint32_t ch_id, tusb
|
||||
ep_write(ch_id, reg, false);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void ch_change_status(uint32_t* reg, tusb_dir_t dir, ep_stat_t state) {
|
||||
TU_ATTR_ALWAYS_INLINE static inline void ch_change_status(uint32_t *reg, tusb_dir_t dir, ep_stat_t state) {
|
||||
*reg ^= (state << (USB_EPTX_STAT_Pos + (dir == TUSB_DIR_IN ? 8 : 0)));
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void ch_change_dtog(uint32_t* reg, tusb_dir_t dir, uint8_t state) {
|
||||
TU_ATTR_ALWAYS_INLINE static inline void ch_change_dtog(uint32_t *reg, tusb_dir_t dir, uint8_t state) {
|
||||
*reg ^= (state << (USB_EP_DTOG_TX_Pos + (dir == TUSB_DIR_IN ? 8 : 0)));
|
||||
}
|
||||
|
||||
@ -281,8 +277,8 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t btable_get_addr(uint32_t ep_id, uin
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void btable_set_addr(uint32_t ep_id, uint8_t buf_id, uint16_t addr) {
|
||||
#ifdef FSDEV_BUS_32BIT
|
||||
uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr;
|
||||
count_addr = (count_addr & 0xFFFF0000u) | (addr & 0x0000FFFCu);
|
||||
uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr;
|
||||
count_addr = (count_addr & 0xFFFF0000u) | (addr & 0x0000FFFCu);
|
||||
FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr;
|
||||
#else
|
||||
FSDEV_BTABLE->ep16[ep_id][buf_id].addr = addr;
|
||||
@ -301,12 +297,12 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t btable_get_count(uint32_t ep_id, ui
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void btable_set_count(uint32_t ep_id, uint8_t buf_id, uint16_t byte_count) {
|
||||
#ifdef FSDEV_BUS_32BIT
|
||||
uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr;
|
||||
count_addr = (count_addr & ~0x03FF0000u) | ((byte_count & 0x3FFu) << 16);
|
||||
uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr;
|
||||
count_addr = (count_addr & ~0x03FF0000u) | ((byte_count & 0x3FFu) << 16);
|
||||
FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr;
|
||||
#else
|
||||
uint16_t cnt = FSDEV_BTABLE->ep16[ep_id][buf_id].count;
|
||||
cnt = (cnt & ~0x3FFU) | (byte_count & 0x3FFU);
|
||||
uint16_t cnt = FSDEV_BTABLE->ep16[ep_id][buf_id].count;
|
||||
cnt = (cnt & ~0x3FFU) | (byte_count & 0x3FFU);
|
||||
FSDEV_BTABLE->ep16[ep_id][buf_id].count = cnt;
|
||||
#endif
|
||||
}
|
||||
@ -318,31 +314,11 @@ void fsdev_core_reset(void);
|
||||
void fsdev_deinit(void);
|
||||
|
||||
// Aligned buffer size according to hardware
|
||||
uint16_t pma_align_buffer_size(uint16_t size, uint8_t* blsize, uint8_t* num_block);
|
||||
uint16_t pma_align_buffer_size(uint16_t size, uint8_t *blsize, uint8_t *num_block);
|
||||
|
||||
// Set RX buffer size
|
||||
void btable_set_rx_bufsize(uint32_t ep_id, uint8_t buf_id, uint16_t wCount);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// PMA (Packet Memory Area) Access
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Write to packet memory area (PMA) from user memory
|
||||
// - Packet memory must be either strictly 16-bit or 32-bit depending on FSDEV_BUS_32BIT
|
||||
// - Uses unaligned for RAM (since M0 cannot access unaligned address)
|
||||
bool fsdev_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t nbytes);
|
||||
|
||||
// Read from packet memory area (PMA) to user memory.
|
||||
// - Packet memory must be either strictly 16-bit or 32-bit depending on FSDEV_BUS_32BIT
|
||||
// - Uses unaligned for RAM (since M0 cannot access unaligned address)
|
||||
bool fsdev_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t nbytes);
|
||||
|
||||
// Write to PMA from FIFO
|
||||
bool fsdev_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes);
|
||||
|
||||
// Read from PMA to FIFO
|
||||
bool fsdev_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -32,10 +32,23 @@
|
||||
#ifndef TUSB_FSDEV_STM32_H
|
||||
#define TUSB_FSDEV_STM32_H
|
||||
|
||||
#if CFG_TUSB_MCU == OPT_MCU_STM32F0
|
||||
#if CFG_TUSB_MCU == OPT_MCU_STM32C0
|
||||
#include "stm32c0xx.h"
|
||||
#define FSDEV_HAS_SBUF_ISO 1
|
||||
#define USB USB_DRD_FS
|
||||
#define USB_EP_CTR_RX USB_CHEP_VTRX
|
||||
#define USB_EP_CTR_TX USB_CHEP_VTTX
|
||||
#define USB_EPREG_MASK USB_CHEP_REG_MASK
|
||||
#define USB_CNTR_FRES USB_CNTR_USBRST
|
||||
#define USB_CNTR_RESUME USB_CNTR_L2RES
|
||||
#define USB_ISTR_EP_ID USB_ISTR_IDN
|
||||
#define USB_EPADDR_FIELD USB_CHEP_ADDR
|
||||
#define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
|
||||
#define USB_CNTR_FSUSP USB_CNTR_SUSPEN
|
||||
|
||||
#elif CFG_TUSB_MCU == OPT_MCU_STM32F0
|
||||
#include "stm32f0xx.h"
|
||||
#define FSDEV_PMA_SIZE (1024u)
|
||||
#define FSDEV_REG_BASE USB_BASE
|
||||
#define FSDEV_REG_BASE USB_BASE
|
||||
#define FSDEV_HAS_SBUF_ISO 0
|
||||
// F0x2 models are crystal-less
|
||||
// All have internal D+ pull-up
|
||||
@ -44,29 +57,24 @@
|
||||
|
||||
#elif CFG_TUSB_MCU == OPT_MCU_STM32F1
|
||||
#include "stm32f1xx.h"
|
||||
#define FSDEV_PMA_SIZE (512u)
|
||||
#define FSDEV_HAS_SBUF_ISO 0
|
||||
// NO internal Pull-ups
|
||||
// *B, and *C: 2 x 16 bits/word
|
||||
|
||||
// F1 names this differently from the rest
|
||||
#define USB_CNTR_LPMODE USB_CNTR_LP_MODE
|
||||
#define USB_CNTR_LPMODE USB_CNTR_LP_MODE
|
||||
|
||||
#elif defined(STM32F302xB) || defined(STM32F302xC) || \
|
||||
defined(STM32F303xB) || defined(STM32F303xC) || \
|
||||
defined(STM32F373xC)
|
||||
#elif defined(STM32F302xB) || defined(STM32F302xC) || defined(STM32F303xB) || defined(STM32F303xC) || \
|
||||
defined(STM32F373xC)
|
||||
#include "stm32f3xx.h"
|
||||
#define FSDEV_PMA_SIZE (512u)
|
||||
#define FSDEV_HAS_SBUF_ISO 0
|
||||
// NO internal Pull-ups
|
||||
// *B, and *C: 1 x 16 bits/word
|
||||
// PMA dedicated to USB (no sharing with CAN)
|
||||
|
||||
#elif defined(STM32F302x6) || defined(STM32F302x8) || \
|
||||
defined(STM32F302xD) || defined(STM32F302xE) || \
|
||||
defined(STM32F303xD) || defined(STM32F303xE)
|
||||
#elif defined(STM32F302x6) || defined(STM32F302x8) || defined(STM32F302xD) || defined(STM32F302xE) || \
|
||||
defined(STM32F303xD) || defined(STM32F303xE)
|
||||
#include "stm32f3xx.h"
|
||||
#define FSDEV_PMA_SIZE (1024u)
|
||||
#define FSDEV_HAS_SBUF_ISO 0
|
||||
// NO internal Pull-ups
|
||||
// *6, *8, *D, and *E: 2 x 16 bits/word LPM Support
|
||||
@ -74,114 +82,60 @@
|
||||
|
||||
#elif CFG_TUSB_MCU == OPT_MCU_STM32L0
|
||||
#include "stm32l0xx.h"
|
||||
#define FSDEV_PMA_SIZE (1024u)
|
||||
#define FSDEV_HAS_SBUF_ISO 0
|
||||
|
||||
#elif CFG_TUSB_MCU == OPT_MCU_STM32L1
|
||||
#include "stm32l1xx.h"
|
||||
#define FSDEV_PMA_SIZE (512u)
|
||||
#define FSDEV_HAS_SBUF_ISO 0
|
||||
|
||||
#elif CFG_TUSB_MCU == OPT_MCU_STM32G4
|
||||
#include "stm32g4xx.h"
|
||||
#define FSDEV_PMA_SIZE (1024u)
|
||||
#define FSDEV_HAS_SBUF_ISO 0
|
||||
|
||||
#elif CFG_TUSB_MCU == OPT_MCU_STM32G0
|
||||
#include "stm32g0xx.h"
|
||||
#define FSDEV_PMA_SIZE (2048u)
|
||||
#define FSDEV_HAS_SBUF_ISO 1
|
||||
#define USB USB_DRD_FS
|
||||
|
||||
#define USB_EP_CTR_RX USB_EP_VTRX
|
||||
#define USB_EP_CTR_TX USB_EP_VTTX
|
||||
#define USB_EP_T_FIELD USB_CHEP_UTYPE
|
||||
#define USB_EPREG_MASK USB_CHEP_REG_MASK
|
||||
#define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK
|
||||
#define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK
|
||||
#define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1
|
||||
#define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2
|
||||
#define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1
|
||||
#define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2
|
||||
#define USB_EPRX_STAT USB_CH_RX_VALID
|
||||
#define USB_EPKIND_MASK USB_EP_KIND_MASK
|
||||
#define USB_CNTR_FRES USB_CNTR_USBRST
|
||||
#define USB_CNTR_RESUME USB_CNTR_L2RES
|
||||
#define USB_ISTR_EP_ID USB_ISTR_IDN
|
||||
#define USB_EPADDR_FIELD USB_CHEP_ADDR
|
||||
#define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
|
||||
#define USB_CNTR_FSUSP USB_CNTR_SUSPEN
|
||||
|
||||
#elif CFG_TUSB_MCU == OPT_MCU_STM32C0
|
||||
#include "stm32c0xx.h"
|
||||
#define FSDEV_PMA_SIZE (2048u)
|
||||
#define FSDEV_HAS_SBUF_ISO 1
|
||||
#define USB USB_DRD_FS
|
||||
#define USB_EP_CTR_RX USB_CHEP_VTRX
|
||||
#define USB_EP_CTR_TX USB_CHEP_VTTX
|
||||
#define USB_EPREG_MASK USB_CHEP_REG_MASK
|
||||
#define USB_CNTR_FRES USB_CNTR_USBRST
|
||||
#define USB_CNTR_RESUME USB_CNTR_L2RES
|
||||
#define USB_ISTR_EP_ID USB_ISTR_IDN
|
||||
#define USB_EPADDR_FIELD USB_CHEP_ADDR
|
||||
#define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
|
||||
#define USB_CNTR_FSUSP USB_CNTR_SUSPEN
|
||||
|
||||
#elif CFG_TUSB_MCU == OPT_MCU_STM32H5
|
||||
#include "stm32h5xx.h"
|
||||
#define FSDEV_PMA_SIZE (2048u)
|
||||
#define FSDEV_HAS_SBUF_ISO 1
|
||||
#define USB USB_DRD_FS
|
||||
|
||||
#define USB_EP_CTR_RX USB_EP_VTRX
|
||||
#define USB_EP_CTR_TX USB_EP_VTTX
|
||||
#define USB_EP_T_FIELD USB_CHEP_UTYPE
|
||||
#define USB_EPREG_MASK USB_CHEP_REG_MASK
|
||||
#define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK
|
||||
#define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK
|
||||
#define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1
|
||||
#define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2
|
||||
#define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1
|
||||
#define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2
|
||||
#define USB_EPRX_STAT USB_CH_RX_VALID
|
||||
#define USB_EPKIND_MASK USB_EP_KIND_MASK
|
||||
#define USB_CNTR_FRES USB_CNTR_USBRST
|
||||
#define USB_CNTR_RESUME USB_CNTR_L2RES
|
||||
#define USB_ISTR_EP_ID USB_ISTR_IDN
|
||||
#define USB_EPADDR_FIELD USB_CHEP_ADDR
|
||||
#define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
|
||||
#define USB_CNTR_FSUSP USB_CNTR_SUSPEN
|
||||
|
||||
#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
|
||||
#include "stm32wbxx.h"
|
||||
#define FSDEV_PMA_SIZE (1024u)
|
||||
#define FSDEV_HAS_SBUF_ISO 0
|
||||
/* ST provided header has incorrect value of USB_PMAADDR */
|
||||
#define FSDEV_PMA_BASE USB1_PMAADDR
|
||||
|
||||
#elif CFG_TUSB_MCU == OPT_MCU_STM32L4
|
||||
#include "stm32l4xx.h"
|
||||
#define FSDEV_PMA_SIZE (1024u)
|
||||
#define FSDEV_HAS_SBUF_ISO 0
|
||||
|
||||
#elif CFG_TUSB_MCU == OPT_MCU_STM32L5
|
||||
#include "stm32l5xx.h"
|
||||
#define FSDEV_PMA_SIZE (1024u)
|
||||
#define FSDEV_HAS_SBUF_ISO 0
|
||||
|
||||
#ifndef USB_PMAADDR
|
||||
#define USB_PMAADDR (USB_BASE + (USB_PMAADDR_NS - USB_BASE_NS))
|
||||
#endif
|
||||
|
||||
#elif CFG_TUSB_MCU == OPT_MCU_STM32U5
|
||||
#include "stm32u5xx.h"
|
||||
#define FSDEV_PMA_SIZE (2048u)
|
||||
#define FSDEV_HAS_SBUF_ISO 1
|
||||
#define USB USB_DRD_FS
|
||||
#elif CFG_TUSB_MCU == OPT_MCU_STM32G0
|
||||
#include "stm32g0xx.h"
|
||||
#define FSDEV_HAS_SBUF_ISO 1
|
||||
#define USB USB_DRD_FS
|
||||
|
||||
#define USB_EP_CTR_RX USB_EP_VTRX
|
||||
#define USB_EP_CTR_TX USB_EP_VTTX
|
||||
#define USB_EP_T_FIELD USB_CHEP_UTYPE
|
||||
#define USB_EP_CTR_RX USB_EP_VTRX
|
||||
#define USB_EP_CTR_TX USB_EP_VTTX
|
||||
#define USB_EP_T_FIELD USB_CHEP_UTYPE
|
||||
#define USB_EPREG_MASK USB_CHEP_REG_MASK
|
||||
#define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK
|
||||
#define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK
|
||||
#define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1
|
||||
#define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2
|
||||
#define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1
|
||||
#define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2
|
||||
#define USB_EPRX_STAT USB_CH_RX_VALID
|
||||
#define USB_EPKIND_MASK USB_EP_KIND_MASK
|
||||
#define USB_CNTR_FRES USB_CNTR_USBRST
|
||||
#define USB_CNTR_RESUME USB_CNTR_L2RES
|
||||
#define USB_ISTR_EP_ID USB_ISTR_IDN
|
||||
#define USB_EPADDR_FIELD USB_CHEP_ADDR
|
||||
#define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
|
||||
#define USB_CNTR_FSUSP USB_CNTR_SUSPEN
|
||||
|
||||
#elif CFG_TUSB_MCU == OPT_MCU_STM32G4
|
||||
#include "stm32g4xx.h"
|
||||
#define FSDEV_HAS_SBUF_ISO 0
|
||||
|
||||
#elif CFG_TUSB_MCU == OPT_MCU_STM32H5
|
||||
#include "stm32h5xx.h"
|
||||
#define FSDEV_HAS_SBUF_ISO 1
|
||||
#define USB USB_DRD_FS
|
||||
|
||||
#define USB_EP_CTR_RX USB_EP_VTRX
|
||||
#define USB_EP_CTR_TX USB_EP_VTTX
|
||||
#define USB_EP_T_FIELD USB_CHEP_UTYPE
|
||||
#define USB_EPREG_MASK USB_CHEP_REG_MASK
|
||||
#define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK
|
||||
#define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK
|
||||
@ -200,7 +154,6 @@
|
||||
|
||||
#elif CFG_TUSB_MCU == OPT_MCU_STM32U0
|
||||
#include "stm32u0xx.h"
|
||||
#define FSDEV_PMA_SIZE (1024u)
|
||||
#define FSDEV_BUS_32BIT
|
||||
#define FSDEV_HAS_SBUF_ISO 1
|
||||
#define USB USB_DRD_FS
|
||||
@ -226,10 +179,9 @@
|
||||
|
||||
#elif CFG_TUSB_MCU == OPT_MCU_STM32U3
|
||||
#include "stm32u3xx.h"
|
||||
#define FSDEV_PMA_SIZE (2048u)
|
||||
#define FSDEV_BUS_32BIT
|
||||
#define FSDEV_HAS_SBUF_ISO 1 // This is assumed to work but has not been tested...
|
||||
#define USB USB_DRD_FS
|
||||
#define USB USB_DRD_FS
|
||||
|
||||
#define USB_EP_CTR_RX USB_EP_VTRX
|
||||
#define USB_EP_CTR_TX USB_EP_VTTX
|
||||
@ -240,15 +192,45 @@
|
||||
#define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1
|
||||
#define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2
|
||||
#define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1
|
||||
#define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2
|
||||
#define USB_EPRX_STAT USB_CH_RX_VALID
|
||||
#define USB_EPKIND_MASK USB_EP_KIND_MASK
|
||||
#define USB_CNTR_FRES USB_CNTR_USBRST
|
||||
#define USB_CNTR_RESUME USB_CNTR_L2RES
|
||||
#define USB_ISTR_EP_ID USB_ISTR_IDN
|
||||
#define USB_EPADDR_FIELD USB_CHEP_ADDR
|
||||
#define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
|
||||
#define USB_CNTR_FSUSP USB_CNTR_SUSPEN
|
||||
#define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2
|
||||
#define USB_EPRX_STAT USB_CH_RX_VALID
|
||||
#define USB_EPKIND_MASK USB_EP_KIND_MASK
|
||||
#define USB_CNTR_FRES USB_CNTR_USBRST
|
||||
#define USB_CNTR_RESUME USB_CNTR_L2RES
|
||||
#define USB_ISTR_EP_ID USB_ISTR_IDN
|
||||
#define USB_EPADDR_FIELD USB_CHEP_ADDR
|
||||
#define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
|
||||
#define USB_CNTR_FSUSP USB_CNTR_SUSPEN
|
||||
|
||||
#elif CFG_TUSB_MCU == OPT_MCU_STM32U5
|
||||
#include "stm32u5xx.h"
|
||||
#define FSDEV_HAS_SBUF_ISO 1
|
||||
#define USB USB_DRD_FS
|
||||
|
||||
#define USB_EP_CTR_RX USB_EP_VTRX
|
||||
#define USB_EP_CTR_TX USB_EP_VTTX
|
||||
#define USB_EP_T_FIELD USB_CHEP_UTYPE
|
||||
#define USB_EPREG_MASK USB_CHEP_REG_MASK
|
||||
#define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK
|
||||
#define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK
|
||||
#define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1
|
||||
#define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2
|
||||
#define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1
|
||||
#define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2
|
||||
#define USB_EPRX_STAT USB_CH_RX_VALID
|
||||
#define USB_EPKIND_MASK USB_EP_KIND_MASK
|
||||
#define USB_CNTR_FRES USB_CNTR_USBRST
|
||||
#define USB_CNTR_RESUME USB_CNTR_L2RES
|
||||
#define USB_ISTR_EP_ID USB_ISTR_IDN
|
||||
#define USB_EPADDR_FIELD USB_CHEP_ADDR
|
||||
#define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
|
||||
#define USB_CNTR_FSUSP USB_CNTR_SUSPEN
|
||||
|
||||
#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
|
||||
#include "stm32wbxx.h"
|
||||
#define FSDEV_HAS_SBUF_ISO 0
|
||||
/* ST provided header has incorrect value of USB_PMAADDR */
|
||||
#define FSDEV_PMA_BASE USB1_PMAADDR
|
||||
|
||||
#else
|
||||
#error You are using an untested or unimplemented STM32 variant. Please update the driver.
|
||||
@ -299,7 +281,7 @@
|
||||
// - Enable double buffering on devices with >1KB Packet Memory Area (PMA)
|
||||
// to improve isochronous transfer reliability and performance
|
||||
// - Disable on devices with limited PMA to conserve memory space
|
||||
#if FSDEV_PMA_SIZE > 1024u
|
||||
#if CFG_TUSB_FSDEV_PMA_SIZE > 1024u
|
||||
#define CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP 1
|
||||
#else
|
||||
#define CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP 0
|
||||
|
||||
@ -303,10 +303,12 @@ static void ch_handle_ack(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir) {
|
||||
uint8_t const daddr = (ch_reg & USB_CHEP_DEVADDR_Msk) >> USB_CHEP_DEVADDR_Pos;
|
||||
|
||||
uint8_t ep_id = endpoint_find(daddr, ep_num | (dir == TUSB_DIR_IN ? TUSB_DIR_IN_MASK : 0));
|
||||
if (ep_id == TUSB_INDEX_INVALID_8) return;
|
||||
if (ep_id == TUSB_INDEX_INVALID_8) {
|
||||
return;
|
||||
}
|
||||
|
||||
hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id];
|
||||
hcd_channel_t* channel = &_hcd_data.channel[ch_id];
|
||||
hcd_endpoint_t *edpt = &_hcd_data.edpt[ep_id];
|
||||
hcd_channel_t *channel = &_hcd_data.channel[ch_id];
|
||||
|
||||
if (dir == TUSB_DIR_OUT) {
|
||||
// OUT/TX direction
|
||||
@ -314,7 +316,7 @@ static void ch_handle_ack(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir) {
|
||||
// More data to send
|
||||
uint16_t const len = tu_min16(edpt->buflen - edpt->queued_len, edpt->max_packet_size);
|
||||
uint16_t pma_addr = (uint16_t) btable_get_addr(ch_id, BTABLE_BUF_TX);
|
||||
fsdev_write_packet_memory(pma_addr, &(edpt->buffer[edpt->queued_len]), len);
|
||||
tu_hwfifo_write(PMA_BUF_AT(pma_addr), &(edpt->buffer[edpt->queued_len]), len, NULL);
|
||||
btable_set_count(ch_id, BTABLE_BUF_TX, len);
|
||||
edpt->queued_len += len;
|
||||
channel_write_status(ch_id, ch_reg, TUSB_DIR_OUT, EP_STAT_VALID, false);
|
||||
@ -329,8 +331,7 @@ static void ch_handle_ack(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir) {
|
||||
// IN/RX direction
|
||||
uint16_t const rx_count = channel_get_rx_count(ch_id);
|
||||
uint16_t pma_addr = (uint16_t) btable_get_addr(ch_id, BTABLE_BUF_RX);
|
||||
|
||||
fsdev_read_packet_memory(edpt->buffer + edpt->queued_len, pma_addr, rx_count);
|
||||
tu_hwfifo_read(PMA_BUF_AT(pma_addr), edpt->buffer + edpt->queued_len, rx_count, NULL);
|
||||
edpt->queued_len += rx_count;
|
||||
|
||||
if ((rx_count < edpt->max_packet_size) || (edpt->queued_len >= edpt->buflen)) {
|
||||
@ -740,7 +741,7 @@ static uint32_t hcd_pma_alloc(uint8_t channel, tusb_dir_t dir, uint16_t len) {
|
||||
uint16_t addr = FSDEV_BTABLE_BASE + 8 * FSDEV_EP_COUNT;
|
||||
addr += channel * TUSB_EPSIZE_BULK_FS * 2 + (dir == TUSB_DIR_IN ? TUSB_EPSIZE_BULK_FS : 0);
|
||||
|
||||
TU_ASSERT(addr <= FSDEV_PMA_SIZE, 0xFFFF);
|
||||
TU_ASSERT(addr <= CFG_TUSB_FSDEV_PMA_SIZE, 0xFFFF);
|
||||
|
||||
return addr;
|
||||
}
|
||||
@ -841,8 +842,7 @@ static bool channel_xfer_start(uint8_t ch_id, tusb_dir_t dir) {
|
||||
|
||||
if (dir == TUSB_DIR_OUT) {
|
||||
uint16_t const len = tu_min16(edpt->buflen - edpt->queued_len, edpt->max_packet_size);
|
||||
|
||||
fsdev_write_packet_memory(pma_addr, &(edpt->buffer[edpt->queued_len]), len);
|
||||
tu_hwfifo_write(PMA_BUF_AT(pma_addr), &(edpt->buffer[edpt->queued_len]), len, NULL);
|
||||
btable_set_count(ch_id, BTABLE_BUF_TX, len);
|
||||
|
||||
edpt->queued_len += len;
|
||||
|
||||
@ -98,10 +98,14 @@ TU_ATTR_ALWAYS_INLINE static inline bool edpt_is_enabled(dwc2_dep_t* dep) {
|
||||
return (dep->ctl & EPCTL_EPENA) != 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// DMA
|
||||
//--------------------------------------------------------------------
|
||||
#if CFG_TUD_MEM_DCACHE_ENABLE
|
||||
#if CFG_TUD_DWC2_SLAVE_ENABLE
|
||||
static uint16_t epin_write_tx_fifo(dwc2_regs_t *dwc2, uint8_t epnum);
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// DMA
|
||||
//--------------------------------------------------------------------
|
||||
#if CFG_TUD_MEM_DCACHE_ENABLE
|
||||
bool dcd_dcache_clean(const void* addr, uint32_t data_size) {
|
||||
TU_VERIFY(addr && data_size);
|
||||
return dwc2_dcache_clean(addr, data_size);
|
||||
@ -345,40 +349,6 @@ static void edpt_disable(uint8_t rhport, uint8_t ep_addr, bool stall) {
|
||||
}
|
||||
}
|
||||
|
||||
static uint16_t epin_write_tx_fifo(uint8_t rhport, uint8_t epnum) {
|
||||
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
|
||||
dwc2_dep_t* const epin = &dwc2->ep[0][epnum];
|
||||
xfer_ctl_t* const xfer = XFER_CTL_BASE(epnum, TUSB_DIR_IN);
|
||||
|
||||
dwc2_ep_tsize_t tsiz = {.value = epin->tsiz};
|
||||
const uint16_t remain_packets = tsiz.packet_count;
|
||||
|
||||
uint16_t total_bytes_written = 0;
|
||||
// Process every single packet (only whole packets can be written to fifo)
|
||||
for (uint16_t i = 0; i < remain_packets; i++) {
|
||||
tsiz.value = epin->tsiz;
|
||||
const uint16_t remain_bytes = (uint16_t) tsiz.xfer_size;
|
||||
const uint16_t xact_bytes = tu_min16(remain_bytes, xfer->max_size);
|
||||
|
||||
// Check if dtxfsts has enough space available
|
||||
if (xact_bytes > ((epin->dtxfsts & DTXFSTS_INEPTFSAV_Msk) << 2)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Push packet to Tx-FIFO
|
||||
if (xfer->ff) {
|
||||
volatile uint32_t* tx_fifo = dwc2->fifo[epnum];
|
||||
tu_fifo_read_n_access_mode(xfer->ff, (void *)(uintptr_t)tx_fifo, xact_bytes, TU_FIFO_FIXED_ADDR_RW32);
|
||||
total_bytes_written += xact_bytes;
|
||||
} else {
|
||||
dfifo_write_packet(dwc2, epnum, xfer->buffer, xact_bytes);
|
||||
xfer->buffer += xact_bytes;
|
||||
total_bytes_written += xact_bytes;
|
||||
}
|
||||
}
|
||||
return total_bytes_written;
|
||||
}
|
||||
|
||||
// Since this function returns void, it is not possible to return a boolean success message
|
||||
// We must make sure that this function is not called when the EP is disabled
|
||||
// Must be called from critical section
|
||||
@ -423,6 +393,7 @@ static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uin
|
||||
}
|
||||
}
|
||||
|
||||
#if CFG_TUD_DWC2_DMA_ENABLE
|
||||
const bool is_dma = dma_device_enabled(dwc2);
|
||||
if(is_dma) {
|
||||
if (dir == TUSB_DIR_IN && total_bytes != 0) {
|
||||
@ -434,11 +405,14 @@ static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uin
|
||||
if (epnum == 0) {
|
||||
xfer->buffer += total_bytes;
|
||||
}
|
||||
} else {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
#if CFG_TUD_DWC2_SLAVE_ENABLE
|
||||
dep->diepctl = depctl.value; // enable endpoint
|
||||
|
||||
if (dir == TUSB_DIR_IN && total_bytes != 0) {
|
||||
const uint16_t xferred_bytes = epin_write_tx_fifo(rhport, epnum);
|
||||
const uint16_t xferred_bytes = epin_write_tx_fifo(dwc2, epnum);
|
||||
|
||||
// Enable TXFE interrupt if there are still data to be sent
|
||||
// EP0 only sends one packet at a time, so no need to check for EP0
|
||||
@ -446,6 +420,7 @@ static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uin
|
||||
dwc2->diepempmsk |= (1u << epnum);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -689,9 +664,6 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t to
|
||||
// into the USB buffer!
|
||||
bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t total_bytes, bool is_isr) {
|
||||
(void) is_isr;
|
||||
// USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1
|
||||
TU_ASSERT(ff->item_size == 1);
|
||||
|
||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir);
|
||||
@ -854,6 +826,39 @@ TU_ATTR_ALWAYS_INLINE static inline void print_doepint(uint32_t doepint) {
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_DWC2_SLAVE_ENABLE
|
||||
static uint16_t epin_write_tx_fifo(dwc2_regs_t *dwc2, uint8_t epnum) {
|
||||
dwc2_dep_t *const epin = &dwc2->ep[0][epnum];
|
||||
xfer_ctl_t *const xfer = XFER_CTL_BASE(epnum, TUSB_DIR_IN);
|
||||
|
||||
dwc2_ep_tsize_t tsiz = {.value = epin->tsiz};
|
||||
const uint16_t remain_packets = tsiz.packet_count;
|
||||
|
||||
uint16_t total_bytes_written = 0;
|
||||
// Process every single packet (only whole packets can be written to fifo)
|
||||
for (uint16_t i = 0; i < remain_packets; i++) {
|
||||
tsiz.value = epin->tsiz;
|
||||
const uint16_t remain_bytes = (uint16_t)tsiz.xfer_size;
|
||||
const uint16_t xact_bytes = tu_min16(remain_bytes, xfer->max_size);
|
||||
|
||||
// Check if dtxfsts has enough space available
|
||||
if (xact_bytes > ((epin->dtxfsts & DTXFSTS_INEPTFSAV_Msk) << 2)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Push packet to Tx-FIFO
|
||||
volatile uint32_t *tx_fifo = dwc2->fifo[epnum];
|
||||
if (xfer->ff) {
|
||||
tu_hwfifo_write_from_fifo(tx_fifo, xfer->ff, xact_bytes, NULL);
|
||||
total_bytes_written += xact_bytes;
|
||||
} else {
|
||||
tu_hwfifo_write(tx_fifo, xfer->buffer, xact_bytes, NULL);
|
||||
xfer->buffer += xact_bytes;
|
||||
total_bytes_written += xact_bytes;
|
||||
}
|
||||
}
|
||||
return total_bytes_written;
|
||||
}
|
||||
|
||||
// Process shared receive FIFO, this interrupt is only used in Slave mode
|
||||
static void handle_rxflvl_irq(uint8_t rhport) {
|
||||
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
|
||||
@ -893,9 +898,9 @@ static void handle_rxflvl_irq(uint8_t rhport) {
|
||||
if (byte_count != 0) {
|
||||
// Read packet off RxFIFO
|
||||
if (xfer->ff != NULL) {
|
||||
tu_fifo_write_n_access_mode(xfer->ff, (const void *)(uintptr_t)rx_fifo, byte_count, TU_FIFO_FIXED_ADDR_RW32);
|
||||
tu_hwfifo_read_to_fifo(rx_fifo, xfer->ff, byte_count, NULL);
|
||||
} else {
|
||||
dfifo_read_packet(dwc2, xfer->buffer, byte_count);
|
||||
tu_hwfifo_read(rx_fifo, xfer->buffer, byte_count, NULL);
|
||||
xfer->buffer += byte_count;
|
||||
}
|
||||
}
|
||||
@ -967,7 +972,7 @@ static void handle_epin_slave(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diep
|
||||
// - 64 bytes or
|
||||
// - Half/Empty of TX FIFO size (configured by GAHBCFG.TXFELVL)
|
||||
if (diepint_bm.txfifo_empty && tu_bit_test(dwc2->diepempmsk, epnum)) {
|
||||
epin_write_tx_fifo(rhport, epnum);
|
||||
epin_write_tx_fifo(dwc2, epnum);
|
||||
|
||||
// Turn off TXFE if all bytes are written.
|
||||
dwc2_ep_tsize_t tsiz = {.value = epin->tsiz};
|
||||
|
||||
@ -264,58 +264,4 @@ bool dwc2_core_init(uint8_t rhport, bool is_highspeed, bool is_dma) {
|
||||
//
|
||||
// }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// DFIFO
|
||||
//--------------------------------------------------------------------
|
||||
// Read a single data packet from receive DFIFO
|
||||
void dfifo_read_packet(dwc2_regs_t* dwc2, uint8_t* dst, uint16_t len) {
|
||||
const volatile uint32_t* rx_fifo = dwc2->fifo[0];
|
||||
|
||||
// Reading full available 32 bit words from fifo
|
||||
uint16_t word_count = len >> 2;
|
||||
while (word_count--) {
|
||||
tu_unaligned_write32(dst, *rx_fifo);
|
||||
dst += 4;
|
||||
}
|
||||
|
||||
// Read the remaining 1-3 bytes from fifo
|
||||
const uint8_t bytes_rem = len & 0x03;
|
||||
if (bytes_rem != 0) {
|
||||
const uint32_t tmp = *rx_fifo;
|
||||
dst[0] = tu_u32_byte0(tmp);
|
||||
if (bytes_rem > 1) {
|
||||
dst[1] = tu_u32_byte1(tmp);
|
||||
}
|
||||
if (bytes_rem > 2) {
|
||||
dst[2] = tu_u32_byte2(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write a single data packet to DFIFO
|
||||
void dfifo_write_packet(dwc2_regs_t* dwc2, uint8_t fifo_num, const uint8_t* src, uint16_t len) {
|
||||
volatile uint32_t* tx_fifo = dwc2->fifo[fifo_num];
|
||||
|
||||
// Pushing full available 32 bit words to fifo
|
||||
uint16_t word_count = len >> 2;
|
||||
while (word_count--) {
|
||||
*tx_fifo = tu_unaligned_read32(src);
|
||||
src += 4;
|
||||
}
|
||||
|
||||
// Write the remaining 1-3 bytes into fifo
|
||||
const uint8_t bytes_rem = len & 0x03;
|
||||
if (bytes_rem) {
|
||||
uint32_t tmp_word = src[0];
|
||||
if (bytes_rem > 1) {
|
||||
tmp_word |= (src[1] << 8);
|
||||
}
|
||||
if (bytes_rem > 2) {
|
||||
tmp_word |= (src[2] << 16);
|
||||
}
|
||||
|
||||
*tx_fifo = tmp_word;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -856,7 +856,7 @@ static void handle_rxflvl_irq(uint8_t rhport) {
|
||||
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
|
||||
|
||||
if (byte_count > 0) {
|
||||
dfifo_read_packet(dwc2, edpt->buffer + xfer->xferred_bytes, byte_count);
|
||||
tu_hwfifo_read(dwc2->fifo[0], edpt->buffer + xfer->xferred_bytes, byte_count, NULL);
|
||||
xfer->xferred_bytes += byte_count;
|
||||
xfer->fifo_bytes = byte_count;
|
||||
}
|
||||
@ -907,7 +907,7 @@ static bool handle_txfifo_empty(dwc2_regs_t* dwc2, bool is_periodic) {
|
||||
return true;
|
||||
}
|
||||
|
||||
dfifo_write_packet(dwc2, ch_id, edpt->buffer + xfer->fifo_bytes, xact_bytes);
|
||||
tu_hwfifo_write(dwc2->fifo[ch_id], edpt->buffer + xfer->fifo_bytes, xact_bytes, NULL);
|
||||
xfer->fifo_bytes += xact_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
@ -316,7 +316,7 @@ bool tu_edpt_stream_init(tu_edpt_stream_t *s, bool is_host, bool is_tx, bool ove
|
||||
#endif
|
||||
|
||||
s->is_host = is_host;
|
||||
tu_fifo_config(&s->ff, ff_buf, ff_bufsize, 1, overwritable);
|
||||
tu_fifo_config(&s->ff, ff_buf, ff_bufsize, overwritable);
|
||||
|
||||
#if OSAL_MUTEX_REQUIRED
|
||||
if (ff_buf != NULL && ff_bufsize > 0) {
|
||||
|
||||
@ -273,16 +273,7 @@
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
//------------- DWC2 -------------//
|
||||
// Slave mode for device
|
||||
#ifndef CFG_TUD_DWC2_SLAVE_ENABLE
|
||||
#ifndef CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT
|
||||
#define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT 1
|
||||
#endif
|
||||
|
||||
#define CFG_TUD_DWC2_SLAVE_ENABLE CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT
|
||||
#endif
|
||||
|
||||
// DMA for device
|
||||
// DMA mode for device
|
||||
#ifndef CFG_TUD_DWC2_DMA_ENABLE
|
||||
#ifndef CFG_TUD_DWC2_DMA_ENABLE_DEFAULT
|
||||
#define CFG_TUD_DWC2_DMA_ENABLE_DEFAULT 0
|
||||
@ -291,16 +282,16 @@
|
||||
#define CFG_TUD_DWC2_DMA_ENABLE CFG_TUD_DWC2_DMA_ENABLE_DEFAULT
|
||||
#endif
|
||||
|
||||
// Slave mode for host
|
||||
#ifndef CFG_TUH_DWC2_SLAVE_ENABLE
|
||||
#ifndef CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT
|
||||
#define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT 1
|
||||
// Slave mode for device
|
||||
#ifndef CFG_TUD_DWC2_SLAVE_ENABLE
|
||||
#ifndef CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT
|
||||
#define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE // disabled if DMA is enabled
|
||||
#endif
|
||||
|
||||
#define CFG_TUH_DWC2_SLAVE_ENABLE CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT
|
||||
#define CFG_TUD_DWC2_SLAVE_ENABLE CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT
|
||||
#endif
|
||||
|
||||
// DMA for host
|
||||
// DMA mode for host
|
||||
#ifndef CFG_TUH_DWC2_DMA_ENABLE
|
||||
#ifndef CFG_TUH_DWC2_DMA_ENABLE_DEFAULT
|
||||
#define CFG_TUH_DWC2_DMA_ENABLE_DEFAULT 0
|
||||
@ -309,14 +300,21 @@
|
||||
#define CFG_TUH_DWC2_DMA_ENABLE CFG_TUH_DWC2_DMA_ENABLE_DEFAULT
|
||||
#endif
|
||||
|
||||
#if defined(TUP_USBIP_DWC2)
|
||||
#if CFG_TUD_DWC2_SLAVE_ENABLE && !CFG_TUD_DWC2_DMA_ENABLE
|
||||
#define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
|
||||
// Slave mode for host
|
||||
#ifndef CFG_TUH_DWC2_SLAVE_ENABLE
|
||||
#ifndef CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT
|
||||
#define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_DWC2_DMA_ENABLE // disabled if DMA is enabled
|
||||
#endif
|
||||
|
||||
#if CFG_TUH_DWC2_SLAVE_ENABLE && !CFG_TUH_DWC2_DMA_ENABLE
|
||||
#define CFG_TUH_EDPT_DEDICATED_HWFIFO 1
|
||||
#endif
|
||||
#define CFG_TUH_DWC2_SLAVE_ENABLE CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT
|
||||
#endif
|
||||
|
||||
#if defined(TUP_USBIP_DWC2)
|
||||
#define CFG_TUD_EDPT_DEDICATED_HWFIFO CFG_TUD_DWC2_SLAVE_ENABLE
|
||||
#define CFG_TUH_EDPT_DEDICATED_HWFIFO CFG_TUH_DWC2_SLAVE_ENABLE
|
||||
|
||||
#define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 4 // 32bit access
|
||||
#define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 0 // fixed hwfifo address
|
||||
#endif
|
||||
|
||||
//------------- ChipIdea -------------//
|
||||
@ -357,16 +355,36 @@
|
||||
//------------ FSDEV --------------//
|
||||
#if defined(TUP_USBIP_FSDEV)
|
||||
#define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
|
||||
|
||||
#if CFG_TUSB_FSDEV_PMA_SIZE == 512
|
||||
#define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 2 // 16-bit data
|
||||
#define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 4 // 32-bit address increase
|
||||
#elif CFG_TUSB_FSDEV_PMA_SIZE == 1024
|
||||
#define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 2 // 16-bit data
|
||||
#define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 2 // 16-bit address increase
|
||||
#elif CFG_TUSB_FSDEV_PMA_SIZE == 2048
|
||||
#define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 4 // 32-bit data
|
||||
#define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 4 // 32-bit address increase
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//------------ MUSB --------------//
|
||||
#if defined(TUP_USBIP_MUSB)
|
||||
#define CFG_TUD_EDPT_DEDICATED_HWFIFO 0 // need testing to enable
|
||||
#define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
|
||||
#define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 4 // 32 bit data
|
||||
#define CFG_TUSB_FIFO_HWFIFO_DATA_ODD_16BIT_ACCESS // allow odd 16bit access
|
||||
#define CFG_TUSB_FIFO_HWFIFO_DATA_ODD_8BIT_ACCESS // allow odd 8bit access
|
||||
#define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 0 // fixed hwfifo
|
||||
|
||||
#endif
|
||||
|
||||
//------------ RUSB2 --------------//
|
||||
#if defined(TUP_USBIP_RUSB2)
|
||||
#define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
|
||||
#define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
|
||||
#define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE (2 | (TUD_OPT_HIGH_SPEED ? 4 : 0)) // 16 bit and 32 bit data if highspeed
|
||||
#define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 0
|
||||
#define CFG_TUSB_FIFO_HWFIFO_CUSTOM_WRITE // custom write since rusb2 can change access width 32 -> 16 and can write
|
||||
// odd byte with byte access
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
@ -103,8 +103,9 @@
|
||||
"name": "ra4m1_ek",
|
||||
"uid": "152E163038303131393346E46F26574B",
|
||||
"tests": {
|
||||
"device": true, "host": false, "dual": false,
|
||||
"skip": ["device/cdc_msc", "device/cdc_msc_freertos"]
|
||||
"device": true,
|
||||
"host": false,
|
||||
"dual": false
|
||||
},
|
||||
"comment": "MSC is slow to enumerated #2602",
|
||||
"flasher": {
|
||||
|
||||
@ -113,7 +113,6 @@ add_ceedling_test(
|
||||
${CEEDLING_WORKDIR}/../../src/common/tusb_fifo.c
|
||||
""
|
||||
)
|
||||
target_compile_definitions(test_fifo PRIVATE CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32=1)
|
||||
|
||||
add_ceedling_test(
|
||||
test_usbd
|
||||
|
||||
@ -128,7 +128,9 @@
|
||||
:defines:
|
||||
:test:
|
||||
- _UNITY_TEST_
|
||||
- CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32
|
||||
- CFG_TUD_EDPT_DEDICATED_HWFIFO=1
|
||||
- CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE=6
|
||||
- CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE=0
|
||||
:release: []
|
||||
|
||||
# Enable to inject name of a test as a unique compilation symbol into its respective executable build.
|
||||
|
||||
@ -32,7 +32,7 @@
|
||||
|
||||
#define FIFO_SIZE 64
|
||||
uint8_t tu_ff_buf[FIFO_SIZE * sizeof(uint8_t)];
|
||||
tu_fifo_t tu_ff = TU_FIFO_INIT(tu_ff_buf, FIFO_SIZE, uint8_t, false);
|
||||
tu_fifo_t tu_ff = TU_FIFO_INIT(tu_ff_buf, FIFO_SIZE, false);
|
||||
|
||||
tu_fifo_t *ff = &tu_ff;
|
||||
tu_fifo_buffer_info_t info;
|
||||
@ -40,6 +40,16 @@ tu_fifo_buffer_info_t info;
|
||||
uint8_t test_data[4096];
|
||||
uint8_t rd_buf[FIFO_SIZE];
|
||||
|
||||
static const tu_hwfifo_access_t hwfifo_access_32 = {
|
||||
.data_stride = 4,
|
||||
.param = 0,
|
||||
};
|
||||
|
||||
static const tu_hwfifo_access_t hwfifo_access_16 = {
|
||||
.data_stride = 2,
|
||||
.param = 0,
|
||||
};
|
||||
|
||||
void setUp(void) {
|
||||
tu_fifo_clear(ff);
|
||||
memset(&info, 0, sizeof(tu_fifo_buffer_info_t));
|
||||
@ -68,34 +78,6 @@ void test_normal(void) {
|
||||
}
|
||||
}
|
||||
|
||||
void test_item_size(void) {
|
||||
uint8_t ff4_buf[FIFO_SIZE * sizeof(uint32_t)];
|
||||
tu_fifo_t ff4 = TU_FIFO_INIT(ff4_buf, FIFO_SIZE, uint32_t, false);
|
||||
|
||||
uint32_t data4[2 * FIFO_SIZE];
|
||||
for (uint32_t i = 0; i < sizeof(data4) / 4; i++) {
|
||||
data4[i] = i;
|
||||
}
|
||||
|
||||
// fill up fifo
|
||||
tu_fifo_write_n(&ff4, data4, FIFO_SIZE);
|
||||
|
||||
uint32_t rd_buf4[FIFO_SIZE];
|
||||
uint16_t rd_count;
|
||||
|
||||
// read 0 -> 4
|
||||
rd_count = tu_fifo_read_n(&ff4, rd_buf4, 5);
|
||||
TEST_ASSERT_EQUAL(5, rd_count);
|
||||
TEST_ASSERT_EQUAL_UINT32_ARRAY(data4, rd_buf4, rd_count); // 0 -> 4
|
||||
|
||||
tu_fifo_write_n(&ff4, data4 + FIFO_SIZE, 5);
|
||||
|
||||
// read all 5 -> 68
|
||||
rd_count = tu_fifo_read_n(&ff4, rd_buf4, FIFO_SIZE);
|
||||
TEST_ASSERT_EQUAL(FIFO_SIZE, rd_count);
|
||||
TEST_ASSERT_EQUAL_UINT32_ARRAY(data4 + 5, rd_buf4, rd_count); // 5 -> 68
|
||||
}
|
||||
|
||||
void test_read_n(void) {
|
||||
uint16_t rd_count;
|
||||
|
||||
@ -362,7 +344,7 @@ void test_rd_idx_wrap(void) {
|
||||
uint8_t buf[10];
|
||||
uint8_t dst[10];
|
||||
|
||||
tu_fifo_config(&ff10, buf, 10, 1, 1);
|
||||
tu_fifo_config(&ff10, buf, 10, 1);
|
||||
|
||||
uint16_t n;
|
||||
|
||||
@ -431,7 +413,7 @@ void test_write_n_fixed_addr_rw32_nowrap(void) {
|
||||
|
||||
for (uint8_t n = 1; n <= 8; n++) {
|
||||
tu_fifo_clear(ff);
|
||||
uint16_t written = tu_fifo_write_n_access_mode(ff, (const void *)®, n, TU_FIFO_FIXED_ADDR_RW32);
|
||||
uint16_t written = tu_fifo_write_n_access_mode(ff, (const void *)®, n, &hwfifo_access_32);
|
||||
TEST_ASSERT_EQUAL(n, written);
|
||||
TEST_ASSERT_EQUAL(n, tu_fifo_count(ff));
|
||||
|
||||
@ -453,7 +435,7 @@ void test_write_n_fixed_addr_rw32_wrapped(void) {
|
||||
ff->wr_idx = FIFO_SIZE - 3;
|
||||
ff->rd_idx = FIFO_SIZE - 3;
|
||||
|
||||
uint16_t written = tu_fifo_write_n_access_mode(ff, (const void *)®, n, TU_FIFO_FIXED_ADDR_RW32);
|
||||
uint16_t written = tu_fifo_write_n_access_mode(ff, (const void *)®, n, &hwfifo_access_32);
|
||||
TEST_ASSERT_EQUAL(n, written);
|
||||
TEST_ASSERT_EQUAL(n, tu_fifo_count(ff));
|
||||
|
||||
@ -473,7 +455,7 @@ void test_read_n_fixed_addr_rw32_nowrap(void) {
|
||||
tu_fifo_write_n(ff, pattern, 8);
|
||||
|
||||
uint32_t reg = 0;
|
||||
uint16_t read_cnt = tu_fifo_read_n_access_mode(ff, ®, n, TU_FIFO_FIXED_ADDR_RW32);
|
||||
uint16_t read_cnt = tu_fifo_read_n_access_mode(ff, ®, n, &hwfifo_access_32);
|
||||
TEST_ASSERT_EQUAL(n, read_cnt);
|
||||
TEST_ASSERT_EQUAL(8 - n, tu_fifo_count(ff));
|
||||
|
||||
@ -497,7 +479,7 @@ void test_read_n_fixed_addr_rw32_wrapped(void) {
|
||||
}
|
||||
|
||||
uint32_t reg = 0;
|
||||
uint16_t read_cnt = tu_fifo_read_n_access_mode(ff, ®, n, TU_FIFO_FIXED_ADDR_RW32);
|
||||
uint16_t read_cnt = tu_fifo_read_n_access_mode(ff, ®, n, &hwfifo_access_32);
|
||||
TEST_ASSERT_EQUAL(n, read_cnt);
|
||||
TEST_ASSERT_EQUAL(0, tu_fifo_count(ff));
|
||||
|
||||
@ -505,6 +487,86 @@ void test_read_n_fixed_addr_rw32_wrapped(void) {
|
||||
}
|
||||
}
|
||||
|
||||
void test_write_n_fixed_addr_rw16_nowrap(void) {
|
||||
tu_fifo_clear(ff);
|
||||
|
||||
volatile uint16_t reg = 0x1122;
|
||||
uint8_t expected[6] = {0x22, 0x11, 0x22, 0x11, 0x22, 0x11};
|
||||
|
||||
for (uint8_t n = 1; n <= 6; n++) {
|
||||
tu_fifo_clear(ff);
|
||||
uint16_t written = tu_fifo_write_n_access_mode(ff, (const void *)®, n, &hwfifo_access_16);
|
||||
TEST_ASSERT_EQUAL(n, written);
|
||||
TEST_ASSERT_EQUAL(n, tu_fifo_count(ff));
|
||||
|
||||
uint8_t out[6] = {0};
|
||||
tu_fifo_read_n(ff, out, n);
|
||||
TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, out, n);
|
||||
}
|
||||
}
|
||||
|
||||
void test_write_n_fixed_addr_rw16_wrapped(void) {
|
||||
tu_fifo_clear(ff);
|
||||
|
||||
volatile uint16_t reg = 0xA1B2;
|
||||
uint8_t expected[6] = {0xB2, 0xA1, 0xB2, 0xA1, 0xB2, 0xA1};
|
||||
|
||||
for (uint8_t n = 1; n <= 6; n++) {
|
||||
tu_fifo_clear(ff);
|
||||
// Position the fifo near the end so writes wrap
|
||||
ff->wr_idx = FIFO_SIZE - 3;
|
||||
ff->rd_idx = FIFO_SIZE - 3;
|
||||
|
||||
uint16_t written = tu_fifo_write_n_access_mode(ff, (const void *)®, n, &hwfifo_access_16);
|
||||
TEST_ASSERT_EQUAL(n, written);
|
||||
TEST_ASSERT_EQUAL(n, tu_fifo_count(ff));
|
||||
|
||||
uint8_t out[6] = {0};
|
||||
tu_fifo_read_n(ff, out, n);
|
||||
TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, out, n);
|
||||
}
|
||||
}
|
||||
|
||||
void test_read_n_fixed_addr_rw16_nowrap(void) {
|
||||
uint8_t pattern[6] = {0x10, 0x21, 0x32, 0x43, 0x54, 0x65};
|
||||
uint16_t reg_expected[6] = {0x0010, 0x2110, 0x0032, 0x4332, 0x0054, 0x6554};
|
||||
|
||||
for (uint8_t n = 1; n <= 6; n++) {
|
||||
tu_fifo_clear(ff);
|
||||
tu_fifo_write_n(ff, pattern, 6);
|
||||
|
||||
uint16_t reg = 0;
|
||||
uint16_t read_cnt = tu_fifo_read_n_access_mode(ff, ®, n, &hwfifo_access_16);
|
||||
TEST_ASSERT_EQUAL(n, read_cnt);
|
||||
TEST_ASSERT_EQUAL(6 - n, tu_fifo_count(ff));
|
||||
|
||||
TEST_ASSERT_EQUAL_HEX16(reg_expected[n - 1], reg);
|
||||
}
|
||||
}
|
||||
|
||||
void test_read_n_fixed_addr_rw16_wrapped(void) {
|
||||
uint8_t pattern[6] = {0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5};
|
||||
uint16_t reg_expected[6] = {0x00F0, 0xE1F0, 0x00D2, 0xC3D2, 0x00B4, 0xA5B4};
|
||||
|
||||
for (uint8_t n = 1; n <= 6; n++) {
|
||||
tu_fifo_clear(ff);
|
||||
ff->rd_idx = FIFO_SIZE - 1;
|
||||
ff->wr_idx = (uint16_t)(ff->rd_idx + n);
|
||||
|
||||
for (uint8_t i = 0; i < n; i++) {
|
||||
uint8_t idx = (uint8_t)((ff->rd_idx + i) % FIFO_SIZE);
|
||||
ff->buffer[idx] = pattern[i];
|
||||
}
|
||||
|
||||
uint16_t reg = 0;
|
||||
uint16_t read_cnt = tu_fifo_read_n_access_mode(ff, ®, n, &hwfifo_access_16);
|
||||
TEST_ASSERT_EQUAL(n, read_cnt);
|
||||
TEST_ASSERT_EQUAL(0, tu_fifo_count(ff));
|
||||
|
||||
TEST_ASSERT_EQUAL_HEX16(reg_expected[n - 1], reg);
|
||||
}
|
||||
}
|
||||
|
||||
void test_get_read_info_advanced_cases(void) {
|
||||
tu_fifo_clear(ff);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user