diff --git a/demos/bsp/boards/board_ea4357.c b/demos/bsp/boards/board_ea4357.c index b1ce827b..58939c24 100644 --- a/demos/bsp/boards/board_ea4357.c +++ b/demos/bsp/boards/board_ea4357.c @@ -53,55 +53,55 @@ static const struct { // MIC2555 1YML = 0101111, 0YML = 0101101 #define MIC255_ADDR BIN8(0101111) -static uint8_t mic255_regs_read(uint8_t regs_addr) -{ - uint8_t value; +//static uint8_t mic255_regs_read(uint8_t regs_addr) +//{ +// uint8_t value; +// +// ASSERT( SUCCESS == I2C_MasterTransferData( +// LPC_I2C0, +// & (I2C_M_SETUP_Type) +// { +// .sl_addr7bit = MIC255_ADDR, +// .retransmissions_max = 3, +// +// .tx_data = ®s_addr, +// .tx_length = 1, +// +// .rx_data = &value, +// .rx_length = 1 +// }, +// I2C_TRANSFER_POLLING), 0xFF); +// +// return value; +//} - ASSERT( SUCCESS == I2C_MasterTransferData( - LPC_I2C0, - & (I2C_M_SETUP_Type) - { - .sl_addr7bit = MIC255_ADDR, - .retransmissions_max = 3, - - .tx_data = ®s_addr, - .tx_length = 1, - - .rx_data = &value, - .rx_length = 1 - }, - I2C_TRANSFER_POLLING), 0xFF); - - return value; -} - -static bool mic255_regs_write(uint8_t regs_addr, uint8_t data) -{ - uint8_t xfer_data[2] = { regs_addr, data} ; - - ASSERT( SUCCESS == I2C_MasterTransferData( - LPC_I2C0, - & (I2C_M_SETUP_Type) - { - .sl_addr7bit = MIC255_ADDR, - .retransmissions_max = 3, - - .tx_data = xfer_data, - .tx_length = 2, - }, - I2C_TRANSFER_POLLING), false); - - return true; -} +//static bool mic255_regs_write(uint8_t regs_addr, uint8_t data) +//{ +// uint8_t xfer_data[2] = { regs_addr, data} ; +// +// ASSERT( SUCCESS == I2C_MasterTransferData( +// LPC_I2C0, +// & (I2C_M_SETUP_Type) +// { +// .sl_addr7bit = MIC255_ADDR, +// .retransmissions_max = 3, +// +// .tx_data = xfer_data, +// .tx_length = 2, +// }, +// I2C_TRANSFER_POLLING), false); +// +// return true; +//} -static uint16_t mic255_get_vendorid(void) -{ - uint8_t vendor_low = mic255_regs_read(0); - uint8_t vendor_high = mic255_regs_read(1); - - return (vendor_high << 8) | vendor_low; -} +//static uint16_t mic255_get_vendorid(void) +//{ +// uint8_t vendor_low = mic255_regs_read(0); +// uint8_t vendor_high = mic255_regs_read(1); +// +// return (vendor_high << 8) | vendor_low; +//} void board_init(void) { diff --git a/tests/test/host/ehci/test_ehci_init.c b/tests/test/host/ehci/test_ehci_init.c index a68b0b17..823fa08c 100644 --- a/tests/test/host/ehci/test_ehci_init.c +++ b/tests/test/host/ehci/test_ehci_init.c @@ -107,7 +107,7 @@ void test_hcd_init_async_list(void) TEST_ASSERT_EQUAL_HEX(async_head, regs->async_list_base); - TEST_ASSERT_EQUAL_HEX(async_head, align32(async_head) ); + TEST_ASSERT_EQUAL_HEX(async_head, align32( (uint32_t) async_head) ); TEST_ASSERT_EQUAL(EHCI_QUEUE_ELEMENT_QHD, async_head->next.type); TEST_ASSERT_FALSE(async_head->next.terminate); @@ -136,20 +136,21 @@ void test_hcd_init_period_list(void) TEST_ASSERT_EQUAL_HEX( (uint32_t) framelist, regs->periodic_list_base); - check_qhd_endpoint_link( framelist+1, period_head_arr+1); - check_qhd_endpoint_link( framelist+3, period_head_arr+1); - check_qhd_endpoint_link( framelist+5, period_head_arr+1); - check_qhd_endpoint_link( framelist+7, period_head_arr+1); + check_qhd_endpoint_link( framelist+0, period_head_arr+1); + check_qhd_endpoint_link( framelist+2, period_head_arr+1); + check_qhd_endpoint_link( framelist+4, period_head_arr+1); + check_qhd_endpoint_link( framelist+6, period_head_arr+1); - check_qhd_endpoint_link( framelist+2, period_head_arr+2); - check_qhd_endpoint_link( framelist+6, period_head_arr+2); + check_qhd_endpoint_link( framelist+1, period_head_arr+2); + check_qhd_endpoint_link( framelist+5, period_head_arr+2); - check_qhd_endpoint_link( framelist, period_head_arr); - check_qhd_endpoint_link( framelist+4, period_head_arr); + check_qhd_endpoint_link( framelist+3, period_head_arr+3); + check_qhd_endpoint_link( framelist+7, period_head_arr); check_qhd_endpoint_link( (ehci_link_t*) (period_head_arr+1), period_head_arr); check_qhd_endpoint_link( (ehci_link_t*) (period_head_arr+2), period_head_arr); + check_qhd_endpoint_link( (ehci_link_t*) (period_head_arr+3), period_head_arr); - for(uint32_t i=0; i<3; i++) + for(uint32_t i=0; i<4; i++) { TEST_ASSERT(period_head_arr[i].interrupt_smask); TEST_ASSERT(period_head_arr[i].qtd_overlay.halted); diff --git a/tests/test/host/ehci/test_pipe_interrupt_open.c b/tests/test/host/ehci/test_pipe_interrupt_open.c index d7f14f48..020b8d03 100644 --- a/tests/test/host/ehci/test_pipe_interrupt_open.c +++ b/tests/test/host/ehci/test_pipe_interrupt_open.c @@ -263,7 +263,7 @@ void test_open_interrupt_hs_interval_7(void) void test_open_interrupt_hs_interval_8(void) { tusb_descriptor_endpoint_t int_edp_interval = desc_ept_interrupt_out; - int_edp_interval.bInterval = 8; + int_edp_interval.bInterval = 16; //------------- Code Under TEST -------------// pipe_hdl = hcd_pipe_open(dev_addr, &int_edp_interval, TUSB_CLASS_HID); @@ -327,6 +327,23 @@ void test_interrupt_close(void) TEST_ASSERT_EQUAL(EHCI_QUEUE_ELEMENT_QHD, p_int_qhd->next.type); } +void test_interrupt_256ms_close(void) +{ + tusb_descriptor_endpoint_t int_edp_interval = desc_ept_interrupt_out; + int_edp_interval.bInterval = 9; + + pipe_hdl = hcd_pipe_open(dev_addr, &int_edp_interval, TUSB_CLASS_HID); + p_int_qhd = qhd_get_from_pipe_handle(pipe_hdl); + + //------------- Code Under TEST -------------// + hcd_pipe_close(pipe_hdl); + + TEST_ASSERT(p_int_qhd->is_removing); + TEST_ASSERT( align32(get_period_head(hostid, 8)->address) != (uint32_t) p_int_qhd ); + TEST_ASSERT_EQUAL_HEX( (uint32_t) get_period_head(hostid, 8), align32(p_int_qhd->next.address ) ); + TEST_ASSERT_EQUAL(EHCI_QUEUE_ELEMENT_QHD, p_int_qhd->next.type); +} + uint8_t count_set_bits(uint8_t x) { uint8_t result = 0; diff --git a/tests/test/support/ehci_controller.c b/tests/test/support/ehci_controller.c index d785109a..14a13f82 100644 --- a/tests/test/support/ehci_controller.c +++ b/tests/test/support/ehci_controller.c @@ -88,42 +88,58 @@ void ehci_controller_control_xfer_proceed(uint8_t dev_addr, uint8_t p_data[]) hcd_isr( usbh_devices[dev_addr].core_id ); } -bool complete_all_qtd_in_list(ehci_qhd_t *head) +void complete_qtd_in_qhd(ehci_qhd_t *p_qhd) +{ + if ( !p_qhd->qtd_overlay.halted ) + { + while(!p_qhd->qtd_overlay.next.terminate) + { + ehci_qtd_t* p_qtd = (ehci_qtd_t*) align32(p_qhd->qtd_overlay.next.address); + p_qtd->active = 0; + p_qhd->qtd_overlay = *p_qtd; + } + } +} + +bool complete_all_qtd_in_async(ehci_qhd_t *head) { ehci_qhd_t *p_qhd = head; do { - if ( !p_qhd->qtd_overlay.halted ) - { - while(!p_qhd->qtd_overlay.next.terminate) - { - ehci_qtd_t* p_qtd = (ehci_qtd_t*) align32(p_qhd->qtd_overlay.next.address); - p_qtd->active = 0; - p_qhd->qtd_overlay = *p_qtd; - } - } - if (!p_qhd->next.terminate) - { - p_qhd = (ehci_qhd_t*) align32(p_qhd->next.address); - } - else - { - break; - } + complete_qtd_in_qhd(p_qhd); + p_qhd = (ehci_qhd_t*) align32(p_qhd->next.address); }while(p_qhd != head); // stop if loop around return true; } +bool complete_all_qtd_in_period(ehci_link_t *head) +{ + while(!head->terminate) + { + uint32_t queue_type = head->type; + head = (ehci_link_t*) align32(head->address); + + if ( queue_type == EHCI_QUEUE_ELEMENT_QHD) + { + complete_qtd_in_qhd( (ehci_qhd_t*) head ); + } + } + return true; +} + void ehci_controller_run(uint8_t hostid) { //------------- Async List -------------// ehci_registers_t* const regs = get_operational_register(hostid); - complete_all_qtd_in_list((ehci_qhd_t*) regs->async_list_base); + complete_all_qtd_in_async((ehci_qhd_t*) regs->async_list_base); //------------- Period List -------------// - complete_all_qtd_in_list( get_period_head(hostid, 1) ); + for(uint8_t i=1; i <= EHCI_FRAMELIST_SIZE; i *= 2) + { + complete_all_qtd_in_period( get_period_head(hostid, i) ); + } regs->usb_sts = EHCI_INT_MASK_NXP_ASYNC | EHCI_INT_MASK_NXP_PERIODIC; hcd_isr(hostid); diff --git a/tests/test/support/ehci_controller.h b/tests/test/support/ehci_controller.h index 5b820676..32a0d4cd 100644 --- a/tests/test/support/ehci_controller.h +++ b/tests/test/support/ehci_controller.h @@ -66,7 +66,7 @@ void ehci_controller_device_unplug(uint8_t hostid); ehci_registers_t* get_operational_register(uint8_t hostid); ehci_link_t* get_period_frame_list(uint8_t hostid); ehci_qhd_t* get_async_head(uint8_t hostid); -ehci_qhd_t* get_period_head(uint8_t hostid, uint8_t interval_ms); +ehci_link_t* get_period_head(uint8_t hostid, uint8_t interval_ms); ehci_qhd_t* get_control_qhd(uint8_t dev_addr); ehci_qtd_t* get_control_qtds(uint8_t dev_addr); ehci_qhd_t* qhd_get_from_pipe_handle(pipe_handle_t pipe_hdl); diff --git a/tinyusb/host/ehci/ehci.c b/tinyusb/host/ehci/ehci.c index df234b29..8557ccd9 100644 --- a/tinyusb/host/ehci/ehci.c +++ b/tinyusb/host/ehci/ehci.c @@ -98,8 +98,8 @@ static inline void qtd_remove_1st_from_qhd(ehci_qhd_t *p_qhd) ATTR_ALW static void qtd_init(ehci_qtd_t* p_qtd, uint32_t data_ptr, uint16_t total_bytes); static inline void list_insert(ehci_link_t *current, ehci_link_t *new, uint8_t new_type) ATTR_ALWAYS_INLINE; -static ehci_qhd_t* list_find_previous_qhd(ehci_qhd_t* p_head, ehci_qhd_t* p_qhd); -static tusb_error_t list_remove_qhd(ehci_qhd_t* p_head, ehci_qhd_t* p_qhd_remove); +static ehci_link_t* list_find_previous_item(ehci_link_t* p_head, ehci_link_t* p_current); +static tusb_error_t list_remove_qhd(ehci_link_t* p_head, ehci_link_t* p_remove); static tusb_error_t hcd_controller_init(uint8_t hostid) ATTR_WARN_UNUSED_RESULT; @@ -181,7 +181,7 @@ static tusb_error_t hcd_controller_init(uint8_t hostid) //------------- Periodic List -------------// // Build the polling interval tree with 1 ms, 2 ms, 4 ms and 8 ms (framesize) only - for(uint32_t i=0; i<3; i++) + for(uint32_t i=0; i<4; i++) { ehci_data.period_head_arr[ hostid_to_data_idx(hostid) ][i].interrupt_smask = 1; // queue head in period list must have smask non-zero ehci_data.period_head_arr[ hostid_to_data_idx(hostid) ][i].qtd_overlay.halted = 1; // dummy node, always inactive @@ -189,12 +189,10 @@ static tusb_error_t hcd_controller_init(uint8_t hostid) ehci_link_t * const framelist = get_period_frame_list(hostid); ehci_link_t * const period_1ms = get_period_head(hostid, 1); - ehci_link_t * const period_2ms = get_period_head(hostid, 2); - ehci_link_t * const period_4ms = get_period_head(hostid, 4); - - // 1, 3, 5, 7 etc --> period_head_arr[2] (4ms) - // 2, 6 --> period_head_arr[2] - // 0, 4, + period_head_arr[1] + period_head_arr[2] --> period_head_arr[0] + // all links --> period_head_arr[0] (1ms) + // 0, 2, 4, 6 etc --> period_head_arr[1] (2ms) + // 1, 5 --> period_head_arr[2] (4ms) + // 3 --> period_head_arr[3] (8ms) // TODO EHCI_FRAMELIST_SIZE with other size than 8 for(uint32_t i=0; iterminate = 1; regs->periodic_list_base = (uint32_t) framelist; @@ -336,7 +336,8 @@ tusb_error_t hcd_pipe_control_close(uint8_t dev_addr) if (dev_addr != 0) { - ASSERT_STATUS( list_remove_qhd(get_async_head( usbh_devices[dev_addr].core_id ), p_qhd) ); + ASSERT_STATUS( list_remove_qhd( (ehci_link_t*) get_async_head( usbh_devices[dev_addr].core_id ), + (ehci_link_t*) p_qhd) ); } return TUSB_ERROR_NONE; @@ -419,11 +420,13 @@ tusb_error_t hcd_pipe_close(pipe_handle_t pipe_hdl) if ( pipe_hdl.xfer_type == TUSB_XFER_BULK ) { ASSERT_STATUS( list_remove_qhd( - get_async_head( usbh_devices[pipe_hdl.dev_addr].core_id ), p_qhd) ); + (ehci_link_t*) get_async_head( usbh_devices[pipe_hdl.dev_addr].core_id ), + (ehci_link_t*) p_qhd) ); }else { ASSERT_STATUS( list_remove_qhd( - get_period_head( usbh_devices[pipe_hdl.dev_addr].core_id, 1 ), p_qhd) ); + get_period_head( usbh_devices[pipe_hdl.dev_addr].core_id, p_qhd->interval_ms ), + (ehci_link_t*) p_qhd) ); } return TUSB_ERROR_NONE; @@ -517,7 +520,7 @@ void async_list_process_isr(ehci_qhd_t * const async_head) } p_qhd = (ehci_qhd_t*) align32(p_qhd->next.address); max_loop++; - }while(p_qhd != async_head && max_loop <= EHCI_MAX_QHD); // async list traversal, stop if loop around + }while(p_qhd != async_head && max_loop < EHCI_MAX_QHD); // async list traversal, stop if loop around // TODO abstract max loop guard for async } @@ -697,15 +700,10 @@ STATIC_ INLINE_ ehci_qhd_t* get_async_head(uint8_t hostid) STATIC_ INLINE_ ehci_link_t* get_period_head(uint8_t hostid, uint8_t interval_ms) { - if (interval_ms < 8) - { - return (ehci_link_t*) (ehci_data.period_head_arr[ hostid_to_data_idx(hostid) ] + + return (ehci_link_t*) (ehci_data.period_head_arr[ hostid_to_data_idx(hostid) ] + (interval_ms < 2 ? 0 : - interval_ms < 4 ? 1 : 2)); - }else - { - return get_period_frame_list(hostid); - } + interval_ms < 4 ? 1 : + interval_ms < EHCI_FRAMELIST_SIZE ? 2 : 3)); } STATIC_ INLINE_ ehci_qhd_t* get_control_qhd(uint8_t dev_addr) @@ -811,7 +809,7 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, uint16_t max_packet_si (interval == 2) ? BIN8(10101010) : BIN8(01000100); }else { - p_qhd->interval_ms = ( 1 << (interval-4) ); + p_qhd->interval_ms = (uint8_t) min16_of( 1 << (interval-4), 255 ); p_qhd->interrupt_smask = BIT_(interval % 8); } }else @@ -872,27 +870,31 @@ static inline void list_insert(ehci_link_t *current, ehci_link_t *new, uint8_t n current->address = ((uint32_t) new) | (new_type << 1); } -static ehci_qhd_t* list_find_previous_qhd(ehci_qhd_t* p_head, ehci_qhd_t* p_qhd) +static ehci_link_t* list_find_previous_item(ehci_link_t* p_head, ehci_link_t* p_current) { - ehci_qhd_t *p_prev_qhd = p_head; - while( (align32(p_prev_qhd->next.address) != (uint32_t) p_head) && (align32(p_prev_qhd->next.address) != (uint32_t) p_qhd) ) + ehci_link_t *p_prev = p_head; + uint32_t max_loop = 0; + while( (align32(p_prev->address) != (uint32_t) p_head) && + (align32(p_prev->address) != (uint32_t) p_current) && + !p_prev->terminate && + max_loop < EHCI_MAX_QHD) { - p_prev_qhd = (ehci_qhd_t*) align32(p_prev_qhd->next.address); + p_prev = (ehci_link_t*) align32(p_prev->address); + max_loop++; } - return align32(p_prev_qhd->next.address) != (uint32_t) p_head ? p_prev_qhd : NULL; + return (align32(p_prev->address) != (uint32_t) p_head) ? p_prev : NULL; } -static tusb_error_t list_remove_qhd(ehci_qhd_t* p_head, ehci_qhd_t* p_qhd_remove) +static tusb_error_t list_remove_qhd(ehci_link_t* p_head, ehci_link_t* p_remove) { - ehci_qhd_t *p_prev_qhd = list_find_previous_qhd(p_head, p_qhd_remove); + ehci_link_t *p_prev = list_find_previous_item(p_head, p_remove); - ASSERT_PTR(p_prev_qhd, TUSB_ERROR_INVALID_PARA); + ASSERT_PTR(p_prev, TUSB_ERROR_INVALID_PARA); - p_prev_qhd->next.address = p_qhd_remove->next.address; + p_prev->address = p_remove->address; // EHCI 4.8.2 link the removing queue head to async/period head (which always reachable by Host Controller) - p_qhd_remove->next.address = (uint32_t) p_head; - p_qhd_remove->next.type = EHCI_QUEUE_ELEMENT_QHD; + p_remove->address = ((uint32_t) p_head) | (EHCI_QUEUE_ELEMENT_QHD << 1); return TUSB_ERROR_NONE; } diff --git a/tinyusb/host/ehci/ehci.h b/tinyusb/host/ehci/ehci.h index 5f7cfcc1..a0fa9873 100644 --- a/tinyusb/host/ehci/ehci.h +++ b/tinyusb/host/ehci/ehci.h @@ -449,8 +449,8 @@ typedef struct { #if EHCI_PERIODIC_LIST // for NXP ECHI, only implement 1 ms & 2 ms & 4 ms, 8 ms (framelist) - // [0] : 1ms, [1] : 2ms, [2] : 4ms - ehci_qhd_t period_head_arr[CONTROLLER_HOST_NUMBER][3]; + // [0] : 1ms, [1] : 2ms, [2] : 4ms, [3] : 8 ms + ehci_qhd_t period_head_arr[CONTROLLER_HOST_NUMBER][4]; #endif //------------- Data for Address 0 (use async head as its queue head) -------------//