mirror of
https://github.com/hathach/tinyusb.git
synced 2025-03-29 10:20:57 +00:00
fix ep tx with double buffered
This commit is contained in:
parent
bd039c8d37
commit
f38c460433
@ -123,7 +123,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align4k (uint32_t value) { retur
|
|||||||
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_offset4k(uint32_t value) { return (value & 0xFFFUL); }
|
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_offset4k(uint32_t value) { return (value & 0xFFFUL); }
|
||||||
|
|
||||||
//------------- Mathematics -------------//
|
//------------- Mathematics -------------//
|
||||||
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_abs(int32_t value) { return (uint32_t)((value < 0) ? (-value) : value); }
|
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_div_ceil(uint32_t v, uint32_t d) { return (v + d -1)/d; }
|
||||||
|
|
||||||
/// inclusive range checking TODO remove
|
/// inclusive range checking TODO remove
|
||||||
TU_ATTR_ALWAYS_INLINE static inline bool tu_within(uint32_t lower, uint32_t value, uint32_t upper)
|
TU_ATTR_ALWAYS_INLINE static inline bool tu_within(uint32_t lower, uint32_t value, uint32_t upper)
|
||||||
|
@ -64,40 +64,30 @@ static struct hw_endpoint *hw_endpoint_get_by_addr(uint8_t ep_addr)
|
|||||||
|
|
||||||
static void _hw_endpoint_alloc(struct hw_endpoint *ep)
|
static void _hw_endpoint_alloc(struct hw_endpoint *ep)
|
||||||
{
|
{
|
||||||
uint16_t size = tu_min16(64, ep->wMaxPacketSize);
|
// size must be multiple of 64
|
||||||
|
uint16_t size = tu_div_ceil(ep->wMaxPacketSize, 64) * 64u;
|
||||||
|
|
||||||
// Assumes single buffered for now
|
// double buffered for non-ISO endpoint
|
||||||
ep->hw_data_buf = next_buffer_ptr;
|
if ( ep->transfer_type != TUSB_XFER_ISOCHRONOUS ) size *= 2u;
|
||||||
next_buffer_ptr += size;
|
|
||||||
|
|
||||||
// Bits 0-5 are ignored by the controller so make sure these are 0
|
ep->hw_data_buf = next_buffer_ptr;
|
||||||
if ((uintptr_t)next_buffer_ptr & 0b111111u)
|
next_buffer_ptr += size;
|
||||||
{
|
|
||||||
// Round up to the next 64
|
|
||||||
uint32_t fixptr = (uintptr_t)next_buffer_ptr;
|
|
||||||
fixptr &= ~0b111111u;
|
|
||||||
fixptr += 64;
|
|
||||||
pico_info("Rounding non 64 byte boundary buffer up from %x to %x\n", (uintptr_t)next_buffer_ptr, fixptr);
|
|
||||||
next_buffer_ptr = (uint8_t*)fixptr;
|
|
||||||
}
|
|
||||||
assert(((uintptr_t)next_buffer_ptr & 0b111111u) == 0);
|
|
||||||
uint dpram_offset = hw_data_offset(ep->hw_data_buf);
|
|
||||||
assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX);
|
|
||||||
|
|
||||||
pico_info("Alloced %d bytes at offset 0x%x (0x%p) for ep %d %s\n",
|
assert(((uintptr_t )next_buffer_ptr & 0b111111u) == 0);
|
||||||
size,
|
uint dpram_offset = hw_data_offset(ep->hw_data_buf);
|
||||||
dpram_offset,
|
assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX);
|
||||||
ep->hw_data_buf,
|
|
||||||
tu_edpt_number(ep->ep_addr),
|
|
||||||
ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
|
|
||||||
|
|
||||||
// Fill in endpoint control register with buffer offset
|
pico_info("Alloced %d bytes at offset 0x%x (0x%p) for ep %d %s\n",
|
||||||
uint32_t reg = EP_CTRL_ENABLE_BITS
|
size,
|
||||||
| EP_CTRL_INTERRUPT_PER_BUFFER
|
dpram_offset,
|
||||||
| (ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB)
|
ep->hw_data_buf,
|
||||||
| dpram_offset;
|
tu_edpt_number(ep->ep_addr),
|
||||||
|
ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
|
||||||
|
|
||||||
*ep->endpoint_control = reg;
|
// Fill in endpoint control register with buffer offset
|
||||||
|
uint32_t const reg = EP_CTRL_ENABLE_BITS | (ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | dpram_offset;
|
||||||
|
|
||||||
|
*ep->endpoint_control = reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type)
|
static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type)
|
||||||
|
@ -108,7 +108,8 @@ void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_m
|
|||||||
*ep->buffer_control = value;
|
*ep->buffer_control = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t compute_buffer_control(struct hw_endpoint *ep, uint8_t buf_id)
|
// prepare buffer, return buffer control
|
||||||
|
static uint32_t prepare_ep_buffer(struct hw_endpoint *ep, uint8_t buf_id)
|
||||||
{
|
{
|
||||||
uint16_t const buflen = tu_min16(ep->remaining_len, ep->wMaxPacketSize);
|
uint16_t const buflen = tu_min16(ep->remaining_len, ep->wMaxPacketSize);
|
||||||
ep->remaining_len -= buflen;
|
ep->remaining_len -= buflen;
|
||||||
@ -122,14 +123,13 @@ static uint32_t compute_buffer_control(struct hw_endpoint *ep, uint8_t buf_id)
|
|||||||
if ( !ep->rx )
|
if ( !ep->rx )
|
||||||
{
|
{
|
||||||
// Copy data from user buffer to hw buffer
|
// Copy data from user buffer to hw buffer
|
||||||
memcpy(ep->hw_data_buf, ep->user_buf, buflen);
|
memcpy(ep->hw_data_buf + buf_id*64, ep->user_buf, buflen);
|
||||||
ep->user_buf += buflen;
|
ep->user_buf += buflen;
|
||||||
|
|
||||||
// Mark as full
|
// Mark as full
|
||||||
buf_ctrl |= USB_BUF_CTRL_FULL;
|
buf_ctrl |= USB_BUF_CTRL_FULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TUSB_OPT_HOST_ENABLED
|
|
||||||
// Is this the last buffer? Only really matters for host mode. Will trigger
|
// Is this the last buffer? Only really matters for host mode. Will trigger
|
||||||
// the trans complete irq but also stop it polling. We only really care about
|
// the trans complete irq but also stop it polling. We only really care about
|
||||||
// trans complete for setup packets being sent
|
// trans complete for setup packets being sent
|
||||||
@ -137,7 +137,6 @@ static uint32_t compute_buffer_control(struct hw_endpoint *ep, uint8_t buf_id)
|
|||||||
{
|
{
|
||||||
buf_ctrl |= USB_BUF_CTRL_LAST;
|
buf_ctrl |= USB_BUF_CTRL_LAST;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
if (buf_id) buf_ctrl = buf_ctrl << 16;
|
if (buf_id) buf_ctrl = buf_ctrl << 16;
|
||||||
|
|
||||||
@ -150,14 +149,14 @@ static void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep)
|
|||||||
uint32_t ep_ctrl = *ep->endpoint_control;
|
uint32_t ep_ctrl = *ep->endpoint_control;
|
||||||
|
|
||||||
// always compute buffer 0
|
// always compute buffer 0
|
||||||
uint32_t buf_ctrl = compute_buffer_control(ep, 0);
|
uint32_t buf_ctrl = prepare_ep_buffer(ep, 0);
|
||||||
|
|
||||||
if(ep->remaining_len)
|
if(ep->remaining_len)
|
||||||
{
|
{
|
||||||
// Use buffer 1 (double buffered) if there is still data
|
// Use buffer 1 (double buffered) if there is still data
|
||||||
// TODO: Isochronous for buffer1 bit-field is different than CBI (control bulk, interrupt)
|
// TODO: Isochronous for buffer1 bit-field is different than CBI (control bulk, interrupt)
|
||||||
|
|
||||||
buf_ctrl |= compute_buffer_control(ep, 1);
|
buf_ctrl |= prepare_ep_buffer(ep, 1);
|
||||||
|
|
||||||
// Set endpoint control double buffered bit if needed
|
// Set endpoint control double buffered bit if needed
|
||||||
ep_ctrl &= ~EP_CTRL_INTERRUPT_PER_BUFFER;
|
ep_ctrl &= ~EP_CTRL_INTERRUPT_PER_BUFFER;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user