refactor: add hxfr per endpoint

This commit is contained in:
hathach 2024-04-02 14:28:41 +07:00
parent bd2210b812
commit e802fe0677
No known key found for this signature in database
GPG Key ID: 26FAB84F615C3C52
2 changed files with 52 additions and 61 deletions

View File

@ -184,17 +184,21 @@ enum {
typedef struct { typedef struct {
uint8_t daddr; uint8_t daddr;
union { ;
struct TU_ATTR_PACKED { struct TU_ATTR_PACKED {
uint8_t state : 4; uint8_t ep_num : 4;
uint8_t is_setup : 1; // also bit 4 in HXFR reg (smaller code, no shift necessary) uint8_t is_setup : 1;
uint8_t ep_dir : 1; // also bit 5 in HXFR reg (smaller code, no shift necessary) uint8_t is_out : 1;
uint8_t is_iso : 1; // also bit 6 in HXFR reg (smaller code, no shift necessary) uint8_t is_iso : 1;
uint8_t data_toggle : 1; }hxfr_bm;
uint8_t hxfr;
}; };
struct TU_ATTR_PACKED { struct TU_ATTR_PACKED {
uint8_t ep_num : 4; uint8_t state : 4;
uint16_t packet_size : 12; uint8_t data_toggle : 1;
uint16_t packet_size : 11;
}; };
uint16_t total_len; uint16_t total_len;
@ -370,10 +374,11 @@ TU_ATTR_ALWAYS_INLINE static inline void sndbc_write(uint8_t rhport, uint8_t dat
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
static max3421_ep_t* find_ep_not_addr0(uint8_t daddr, uint8_t ep_num, uint8_t ep_dir) { static max3421_ep_t* find_ep_not_addr0(uint8_t daddr, uint8_t ep_num, uint8_t ep_dir) {
uint8_t const is_out = 1-ep_dir;
for(size_t i=1; i<CFG_TUH_MAX3421_ENDPOINT_TOTAL; i++) { for(size_t i=1; i<CFG_TUH_MAX3421_ENDPOINT_TOTAL; i++) {
max3421_ep_t* ep = &_hcd_data.ep[i]; max3421_ep_t* ep = &_hcd_data.ep[i];
// for control endpoint, skip direction check // control endpoint is bi-direction (skip check)
if (daddr == ep->daddr && ep_num == ep->ep_num && (ep_dir == ep->ep_dir || ep_num == 0)) { if (daddr == ep->daddr && ep_num == ep->hxfr_bm.ep_num && (ep_num == 0 || is_out == ep->hxfr_bm.is_out)) {
return ep; return ep;
} }
} }
@ -577,7 +582,6 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
// Open an endpoint // Open an endpoint
bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * ep_desc) { bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * ep_desc) {
(void) rhport; (void) rhport;
(void) daddr;
uint8_t const ep_num = tu_edpt_number(ep_desc->bEndpointAddress); uint8_t const ep_num = tu_edpt_number(ep_desc->bEndpointAddress);
tusb_dir_t const ep_dir = tu_edpt_dir(ep_desc->bEndpointAddress); tusb_dir_t const ep_dir = tu_edpt_dir(ep_desc->bEndpointAddress);
@ -589,12 +593,9 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * e
ep = allocate_ep(); ep = allocate_ep();
TU_ASSERT(ep); TU_ASSERT(ep);
ep->daddr = daddr; ep->daddr = daddr;
ep->ep_num = (uint8_t) (ep_num & 0x0f); ep->hxfr_bm.ep_num = (uint8_t) (ep_num & 0x0f);
ep->ep_dir = (ep_dir == TUSB_DIR_IN) ? 1 : 0; ep->hxfr_bm.is_out = (ep_dir == TUSB_DIR_OUT) ? 1 : 0;
} ep->hxfr_bm.is_iso = (TUSB_XFER_ISOCHRONOUS == ep_desc->bmAttributes.xfer) ? 1 : 0;
if ( TUSB_XFER_ISOCHRONOUS == ep_desc->bmAttributes.xfer ) {
ep->is_iso = 1;
} }
ep->packet_size = (uint16_t) (tu_edpt_packet_size(ep_desc) & 0x7ff); ep->packet_size = (uint16_t) (tu_edpt_packet_size(ep_desc) & 0x7ff);
@ -602,7 +603,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * e
return true; return true;
} }
void xact_out(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) { static void xact_out(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
// Page 12: Programming BULK-OUT Transfers // Page 12: Programming BULK-OUT Transfers
// TODO double buffered // TODO double buffered
if (switch_ep) { if (switch_ep) {
@ -618,12 +619,10 @@ void xact_out(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
fifo_write(rhport, SNDFIFO_ADDR, ep->buf, xact_len, in_isr); fifo_write(rhport, SNDFIFO_ADDR, ep->buf, xact_len, in_isr);
} }
sndbc_write(rhport, xact_len, in_isr); sndbc_write(rhport, xact_len, in_isr);
hxfr_write(rhport, ep->hxfr, in_isr);
uint8_t const hxfr = (uint8_t ) (ep->ep_num | HXFR_OUT_NIN | (ep->is_iso ? HXFR_ISO : 0));
hxfr_write(rhport, hxfr, in_isr);
} }
void xact_in(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) { static void xact_in(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
// Page 13: Programming BULK-IN Transfers // Page 13: Programming BULK-IN Transfers
if (switch_ep) { if (switch_ep) {
peraddr_write(rhport, ep->daddr, in_isr); peraddr_write(rhport, ep->daddr, in_isr);
@ -632,34 +631,36 @@ void xact_in(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
reg_write(rhport, HCTL_ADDR, hctl, in_isr); reg_write(rhport, HCTL_ADDR, hctl, in_isr);
} }
uint8_t const hxfr = (uint8_t) (ep->ep_num | (ep->is_iso ? HXFR_ISO : 0)); hxfr_write(rhport, ep->hxfr, in_isr);
hxfr_write(rhport, hxfr, in_isr);
} }
TU_ATTR_ALWAYS_INLINE static inline static void xact_setup(uint8_t rhport, max3421_ep_t *ep, bool in_isr) {
void xact_inout(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
if (ep->ep_num == 0 ) {
// setup
if (ep->is_setup) {
peraddr_write(rhport, ep->daddr, in_isr); peraddr_write(rhport, ep->daddr, in_isr);
fifo_write(rhport, SUDFIFO_ADDR, ep->buf, 8, in_isr); fifo_write(rhport, SUDFIFO_ADDR, ep->buf, 8, in_isr);
hxfr_write(rhport, HXFR_SETUP, in_isr); hxfr_write(rhport, HXFR_SETUP, in_isr);
}
static void xact_generic(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
if (ep->hxfr_bm.ep_num == 0 ) {
// setup
if (ep->hxfr_bm.is_setup) {
xact_setup(rhport, ep, in_isr);
return; return;
} }
// status // status
if (ep->buf == NULL || ep->total_len == 0) { if (ep->buf == NULL || ep->total_len == 0) {
uint8_t const hxfr = HXFR_HS | (ep->ep_dir ? 0 : HXFR_OUT_NIN); uint8_t const hxfr = HXFR_HS | (ep->hxfr_bm.is_out ? HXFR_OUT_NIN : 0);
peraddr_write(rhport, ep->daddr, in_isr); peraddr_write(rhport, ep->daddr, in_isr);
hxfr_write(rhport, hxfr, in_isr); hxfr_write(rhport, hxfr, in_isr);
return; return;
} }
} }
if (ep->ep_dir) { if (ep->hxfr_bm.is_out) {
xact_in(rhport, ep, switch_ep, in_isr);
}else {
xact_out(rhport, ep, switch_ep, in_isr); xact_out(rhport, ep, switch_ep, in_isr);
}else {
xact_in(rhport, ep, switch_ep, in_isr);
} }
} }
@ -672,7 +673,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf
TU_VERIFY(ep); TU_VERIFY(ep);
// control transfer can switch direction // control transfer can switch direction
ep->ep_dir = ep_dir ? 1u : 0u; ep->hxfr_bm.is_out = ep_dir ? 0u : 1u;
ep->buf = buffer; ep->buf = buffer;
ep->total_len = buflen; ep->total_len = buflen;
@ -680,13 +681,13 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf
ep->state = EP_STATE_ATTEMPT_1; ep->state = EP_STATE_ATTEMPT_1;
if (ep_num == 0) { if (ep_num == 0) {
ep->is_setup = 0; ep->hxfr_bm.is_setup = 0;
ep->data_toggle = 1; ep->data_toggle = 1;
} }
// carry out transfer if not busy // carry out transfer if not busy
if (!atomic_flag_test_and_set(&_hcd_data.busy)) { if (!atomic_flag_test_and_set(&_hcd_data.busy)) {
xact_inout(rhport, ep, true, false); xact_generic(rhport, ep, true, false);
} }
return true; return true;
@ -709,8 +710,8 @@ bool hcd_setup_send(uint8_t rhport, uint8_t daddr, uint8_t const setup_packet[8]
max3421_ep_t* ep = find_opened_ep(daddr, 0, 0); max3421_ep_t* ep = find_opened_ep(daddr, 0, 0);
TU_ASSERT(ep); TU_ASSERT(ep);
ep->ep_dir = 0; ep->hxfr_bm.is_out = 1;
ep->is_setup = 1; ep->hxfr_bm.is_setup = 1;
ep->buf = (uint8_t*)(uintptr_t) setup_packet; ep->buf = (uint8_t*)(uintptr_t) setup_packet;
ep->total_len = 8; ep->total_len = 8;
ep->xferred_len = 0; ep->xferred_len = 0;
@ -718,7 +719,7 @@ bool hcd_setup_send(uint8_t rhport, uint8_t daddr, uint8_t const setup_packet[8]
// carry out transfer if not busy // carry out transfer if not busy
if (!atomic_flag_test_and_set(&_hcd_data.busy)) { if (!atomic_flag_test_and_set(&_hcd_data.busy)) {
xact_inout(rhport, ep, true, false); xact_setup(rhport, ep, false);
} }
return true; return true;
@ -783,10 +784,11 @@ static void handle_connect_irq(uint8_t rhport, bool in_isr) {
} }
static void xfer_complete_isr(uint8_t rhport, max3421_ep_t *ep, xfer_result_t result, uint8_t hrsl, bool in_isr) { static void xfer_complete_isr(uint8_t rhport, max3421_ep_t *ep, xfer_result_t result, uint8_t hrsl, bool in_isr) {
uint8_t const ep_addr = tu_edpt_addr(ep->ep_num, ep->ep_dir); uint8_t const ep_dir = 1-ep->hxfr_bm.is_out;
uint8_t const ep_addr = tu_edpt_addr(ep->hxfr_bm.ep_num, ep_dir);
// save data toggle // save data toggle
if (ep->ep_dir) { if (ep_dir) {
ep->data_toggle = (hrsl & HRSL_RCVTOGRD) ? 1u : 0u; ep->data_toggle = (hrsl & HRSL_RCVTOGRD) ? 1u : 0u;
}else { }else {
ep->data_toggle = (hrsl & HRSL_SNDTOGRD) ? 1u : 0u; ep->data_toggle = (hrsl & HRSL_SNDTOGRD) ? 1u : 0u;
@ -798,7 +800,7 @@ static void xfer_complete_isr(uint8_t rhport, max3421_ep_t *ep, xfer_result_t re
// Find next pending endpoint // Find next pending endpoint
max3421_ep_t * next_ep = find_next_pending_ep(ep); max3421_ep_t * next_ep = find_next_pending_ep(ep);
if (next_ep) { if (next_ep) {
xact_inout(rhport, next_ep, true, in_isr); xact_generic(rhport, next_ep, true, in_isr);
}else { }else {
// no more pending // no more pending
atomic_flag_clear(&_hcd_data.busy); atomic_flag_clear(&_hcd_data.busy);
@ -841,7 +843,7 @@ static void handle_xfer_done(uint8_t rhport, bool in_isr) {
hxfr_write(rhport, _hcd_data.hxfr, in_isr); hxfr_write(rhport, _hcd_data.hxfr, in_isr);
} else if (next_ep) { } else if (next_ep) {
// switch to next pending endpoint TODO could have issue with double buffered if not clear previously out data // switch to next pending endpoint TODO could have issue with double buffered if not clear previously out data
xact_inout(rhport, next_ep, true, in_isr); xact_generic(rhport, next_ep, true, in_isr);
} else { } else {
// no more pending in this frame -> clear busy // no more pending in this frame -> clear busy
atomic_flag_clear(&_hcd_data.busy); atomic_flag_clear(&_hcd_data.busy);
@ -945,7 +947,7 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
// start usb transfer if not busy // start usb transfer if not busy
if (ep_retry != NULL && !atomic_flag_test_and_set(&_hcd_data.busy)) { if (ep_retry != NULL && !atomic_flag_test_and_set(&_hcd_data.busy)) {
xact_inout(rhport, ep_retry, true, in_isr); xact_generic(rhport, ep_retry, true, in_isr);
} }
} }

View File

@ -34,7 +34,7 @@
#define TUSB_VERSION_MAJOR 0 #define TUSB_VERSION_MAJOR 0
#define TUSB_VERSION_MINOR 16 #define TUSB_VERSION_MINOR 16
#define TUSB_VERSION_REVISION 0 #define TUSB_VERSION_REVISION 0
#define TUSB_VERSION_BUILD 1 #define TUSB_VERSION_BUILD 2
#define TUSB_VERSION_NUMBER (TUSB_VERSION_MAJOR << 24 | TUSB_VERSION_MINOR << 16 | TUSB_VERSION_REVISION << 8 | TUSB_VERSION_BUILD) #define TUSB_VERSION_NUMBER (TUSB_VERSION_MAJOR << 24 | TUSB_VERSION_MINOR << 16 | TUSB_VERSION_REVISION << 8 | TUSB_VERSION_BUILD)
#define TUSB_VERSION_STRING TU_STRING(TUSB_VERSION_MAJOR) "." TU_STRING(TUSB_VERSION_MINOR) "." TU_STRING(TUSB_VERSION_REVISION) #define TUSB_VERSION_STRING TU_STRING(TUSB_VERSION_MAJOR) "." TU_STRING(TUSB_VERSION_MINOR) "." TU_STRING(TUSB_VERSION_REVISION)
@ -529,17 +529,6 @@
#define CFG_TUH_MAX3421 0 #define CFG_TUH_MAX3421 0
#endif #endif
// MAX3421 Host max. transfer attempts per frame (except control and iso)
// retry quantity = (CFG_TUH_MAX3421_MAX_ATTEMPS_PER_FRAME - 1)
// 0 = endless retries. is default to keep compatibility
// => this may overload MCU with permanently repeating NAK interrupts
// => possible increased USB traffic, increased latencies, reduced data throughput
// a usual attempt quantity is 3 (reference: the book "USB Complete" by Jan Axelson)
#ifndef CFG_TUH_MAX3421_MAX_ATTEMPTS_PER_FRAME
#define CFG_TUH_MAX3421_MAX_ATTEMPTS_PER_FRAME 0
#endif
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// TypeC Options (Default) // TypeC Options (Default)
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+