complete enumeration

This commit is contained in:
hathach 2023-08-24 16:27:12 +07:00
parent 2c237b1ae4
commit 3ed5d6c372
No known key found for this signature in database
GPG Key ID: F5D50C6D51D17CBA
2 changed files with 47 additions and 26 deletions

View File

@ -105,6 +105,10 @@ void max3421e_int_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) {
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// API: SPI transfer with MAX3421E, must be implemented by application // API: SPI transfer with MAX3421E, must be implemented by application
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
void tuh_max3421e_int_api(uint8_t rhport, bool enabled) {
(void) rhport;
nrfx_gpiote_trigger_enable(MAX3241E_INTR_PIN, enabled);
}
void tuh_max3421_spi_cs_api(uint8_t rhport, bool active) { void tuh_max3421_spi_cs_api(uint8_t rhport, bool active) {
(void) rhport; (void) rhport;
@ -241,7 +245,6 @@ void board_init(void) {
in_config.pull = NRF_GPIO_PIN_PULLUP; in_config.pull = NRF_GPIO_PIN_PULLUP;
nrfx_gpiote_in_init(MAX3241E_INTR_PIN, &in_config, max3421e_int_handler); nrfx_gpiote_in_init(MAX3241E_INTR_PIN, &in_config, max3421e_int_handler);
nrfx_gpiote_in_event_enable(MAX3241E_INTR_PIN, true);
#endif #endif
} }

View File

@ -166,6 +166,7 @@ enum {
typedef struct { typedef struct {
uint8_t xfer_type; uint8_t xfer_type;
uint8_t data_toggle; uint8_t data_toggle;
uint8_t xfer_complete;
uint16_t packet_size; uint16_t packet_size;
uint16_t total_len; uint16_t total_len;
@ -244,7 +245,6 @@ static void reg_write(uint8_t reg, uint8_t data) {
// HIRQ register since we are in full-duplex mode // HIRQ register since we are in full-duplex mode
_hcd_data.hirq = rx_buf[0]; _hcd_data.hirq = rx_buf[0];
TU_LOG3_HEX(_hcd_data.hirq);
} }
static uint8_t reg_read(uint8_t reg) { static uint8_t reg_read(uint8_t reg) {
@ -473,6 +473,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf
ep->buf = buffer; ep->buf = buffer;
ep->total_len = buflen; ep->total_len = buflen;
ep->xferred_len = 0; ep->xferred_len = 0;
ep->xfer_complete = 0;
peraddr_write(daddr); peraddr_write(daddr);
@ -595,34 +596,19 @@ static void handle_xfer_done(uint8_t rhport) {
// more to transfer // more to transfer
} }
} else { } else {
// IN transfer // IN transfer: fifo data is already received in RCVDAV IRQ
hcd_ep_t *ep = &_hcd_data.ep[ep_num][1]; hcd_ep_t *ep = &_hcd_data.ep[ep_num][1];
uint8_t xact_len;
if ( xfer_type & HXFR_HS ) { if ( xfer_type & HXFR_HS ) {
xact_len = 0; ep->xfer_complete = 1;
} else {
// RCVDAV_IRQ can trigger 2 times (dual buffered)
while ( _hcd_data.hirq & HIRQ_RCVDAV_IRQ ) {
uint8_t rcvbc = reg_read(RCVBC_ADDR);
xact_len = (uint8_t) tu_min16(rcvbc, ep->total_len - ep->xferred_len);
if ( xact_len ) {
fifo_read(ep->buf, xact_len);
ep->buf += xact_len;
ep->xferred_len += xact_len;
}
// ack RCVDVAV IRQ
reg_write(HIRQ_ADDR, HIRQ_RCVDAV_IRQ);
_hcd_data.hirq = reg_read(HIRQ_ADDR);
}
} }
// short packet or all bytes transferred // short packet or all bytes transferred
if ( xact_len < ep->packet_size || ep->xferred_len >= ep->total_len ) { if ( ep->xfer_complete ) {
hcd_event_xfer_complete(_hcd_data.peraddr, TUSB_DIR_IN_MASK | ep_num, ep->xferred_len, xfer_result, true); hcd_event_xfer_complete(_hcd_data.peraddr, TUSB_DIR_IN_MASK | ep_num, ep->xferred_len, xfer_result, true);
}else { }else {
// more to transfer // more to transfer
hxfr_write(_hcd_data.hxfr);
} }
} }
} }
@ -655,7 +641,7 @@ void hcd_int_handler(uint8_t rhport) {
uint8_t hirq = reg_read(HIRQ_ADDR) & _hcd_data.hien; uint8_t hirq = reg_read(HIRQ_ADDR) & _hcd_data.hien;
if (!hirq) return; if (!hirq) return;
print_hirq(hirq); // print_hirq(hirq);
if (hirq & HIRQ_FRAME_IRQ) { if (hirq & HIRQ_FRAME_IRQ) {
_hcd_data.frame_count++; _hcd_data.frame_count++;
@ -671,12 +657,44 @@ void hcd_int_handler(uint8_t rhport) {
} }
} }
if (hirq & HIRQ_HXFRDN_IRQ) { // queue more transfer in handle_xfer_done() can cause hirq to be set again while external IRQ may not catch and/or
handle_xfer_done(rhport); // not call this handler again. So we need to loop until all IRQ are cleared
while ( hirq & (HIRQ_RCVDAV_IRQ | HIRQ_HXFRDN_IRQ) ) {
if ( hirq & HIRQ_RCVDAV_IRQ ) {
uint8_t ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK;
hcd_ep_t *ep = &_hcd_data.ep[ep_num][1];
uint8_t xact_len;
// RCVDAV_IRQ can trigger 2 times (dual buffered)
while ( hirq & HIRQ_RCVDAV_IRQ ) {
uint8_t rcvbc = reg_read(RCVBC_ADDR);
xact_len = (uint8_t) tu_min16(rcvbc, ep->total_len - ep->xferred_len);
if ( xact_len ) {
fifo_read(ep->buf, xact_len);
ep->buf += xact_len;
ep->xferred_len += xact_len;
}
// ack RCVDVAV IRQ
reg_write(HIRQ_ADDR, HIRQ_RCVDAV_IRQ);
hirq = reg_read(HIRQ_ADDR);
}
if ( xact_len < ep->packet_size || ep->xferred_len >= ep->total_len ) {
ep->xfer_complete = 1;
}
}
if ( hirq & HIRQ_HXFRDN_IRQ ) {
reg_write(HIRQ_ADDR, HIRQ_HXFRDN_IRQ);
handle_xfer_done(rhport);
}
hirq = reg_read(HIRQ_ADDR);
} }
// clear all interrupt except SNDBAV_IRQ and RCVDAV_IRQ must be clear after pulling data from FIFO // clear all interrupt except SNDBAV_IRQ (never clear by us). Note RCVDAV_IRQ, HXFRDN_IRQ already clear while processing
hirq &= ~ (HIRQ_SNDBAV_IRQ | HIRQ_RCVDAV_IRQ); hirq &= ~HIRQ_SNDBAV_IRQ;
if ( hirq ) { if ( hirq ) {
reg_write(HIRQ_ADDR, hirq); reg_write(HIRQ_ADDR, hirq);
} }