rename nxp_sof_received to nxp_int_sof

implementing freeRTOS integration
change get_period_frame_list from using lst_idx to hostid (fix bug)
adding polling interval supported for interrupt: 1ms, 2ms, 4ms, 8ms
- add interval_ms to get_period_head function
- add bInterval to qhd_init
- add support for sub-frame (less than 8 micro frames) interval
- add bunch of test for interrupt different intervals
This commit is contained in:
hathach 2013-04-21 00:28:25 +07:00
parent a9010c1786
commit 357888a5e5
16 changed files with 416 additions and 113 deletions

View File

@ -85,7 +85,8 @@
</toolChain>
</folderInfo>
<sourceEntries>
<entry excluding="bsp/boards/EA4357|NGX|bsp/lpc13uxx|bsp/lpc11uxx" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
<entry excluding="freertos/freertos/Source/portable|bsp/boards/EA4357|NGX|bsp/lpc13uxx|bsp/lpc11uxx" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="freertos/freertos/Source/portable/GCC/ARM_CM4F"/>
</sourceEntries>
</configuration>
</storageModule>
@ -93,7 +94,6 @@
<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
<storageModule moduleId="scannerConfiguration"/>
</cconfiguration>
<cconfiguration id="com.crt.advproject.config.exe.debug.1239969983.636406670">
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.crt.advproject.config.exe.debug.1239969983.636406670" moduleId="org.eclipse.cdt.core.settings" name="Board EA4357">
@ -179,7 +179,8 @@
</toolChain>
</folderInfo>
<sourceEntries>
<entry excluding="bsp/boards/EA4357|NGX|bsp/lpc13uxx|bsp/lpc11uxx" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
<entry excluding="freertos/freertos/Source/portable|bsp/boards/EA4357|NGX|bsp/lpc13uxx|bsp/lpc11uxx" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="freertos/freertos/Source/portable/GCC/ARM_CM4F"/>
</sourceEntries>
</configuration>
</storageModule>
@ -187,7 +188,6 @@
<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
<storageModule moduleId="scannerConfiguration"/>
</cconfiguration>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">

View File

@ -87,11 +87,12 @@ void test_hcd_init_usbint(void)
TEST_ASSERT_FALSE(regs->usb_int_enable_bit.framelist_rollover);
TEST_ASSERT_FALSE(regs->usb_int_enable_bit.pci_host_system_error);
TEST_ASSERT_FALSE(regs->usb_int_enable_bit.nxp_int_sof);
TEST_ASSERT_FALSE(regs->usb_int_enable_bit.usb);
TEST_ASSERT_TRUE(regs->usb_int_enable_bit.nxp_int_async);
TEST_ASSERT_TRUE(regs->usb_int_enable_bit.nxp_int_period);
TEST_IGNORE_MESSAGE("not use nxp int async/period, use usbint instead");
// TODO to be portable use usbint instead of nxp int async/period
}
}
@ -115,27 +116,46 @@ void test_hcd_init_async_list(void)
}
}
void check_qhd_endpoint_link(ehci_link_t *p_prev, ehci_qhd_t *p_qhd)
{
//------------- period list check -------------//
TEST_ASSERT_EQUAL_HEX((uint32_t) p_qhd, align32(p_prev->address));
TEST_ASSERT_FALSE(p_prev->terminate);
TEST_ASSERT_EQUAL(EHCI_QUEUE_ELEMENT_QHD, p_prev->type);
}
void test_hcd_init_period_list(void)
{
#if EHCI_PERIODIC_LIST
for(uint32_t i=0; i<CONTROLLER_HOST_NUMBER; i++)
{
uint8_t const hostid = i+TEST_CONTROLLER_HOST_START_INDEX;
ehci_registers_t* const regs = get_operational_register(hostid);
ehci_qhd_t * const period_head = get_period_head(hostid);
ehci_link_t * const framelist = get_period_frame_list(hostid);
uint8_t const hostid = i+TEST_CONTROLLER_HOST_START_INDEX;
ehci_registers_t* const regs = get_operational_register(hostid);
ehci_qhd_t * const period_head_arr = get_period_head(hostid, 1);
ehci_link_t * const framelist = get_period_frame_list(hostid);
TEST_ASSERT_EQUAL_HEX( (uint32_t) framelist, regs->periodic_list_base);
for(uint32_t list_idx=0; list_idx < EHCI_FRAMELIST_SIZE; list_idx++)
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+2, period_head_arr+2);
check_qhd_endpoint_link( framelist+6, 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( (ehci_link_t*) (period_head_arr+1), period_head_arr);
check_qhd_endpoint_link( (ehci_link_t*) (period_head_arr+2), period_head_arr);
for(uint32_t i=0; i<3; i++)
{
TEST_ASSERT_EQUAL_HEX( (uint32_t) period_head, align32((uint32_t)framelist[list_idx].address) );
TEST_ASSERT_FALSE(framelist[list_idx].terminate);
TEST_ASSERT_EQUAL(EHCI_QUEUE_ELEMENT_QHD, framelist[list_idx].type);
TEST_ASSERT(period_head_arr[i].interrupt_smask);
TEST_ASSERT(period_head_arr[i].qtd_overlay.halted);
}
TEST_ASSERT(period_head->interrupt_smask)
TEST_ASSERT_TRUE(period_head->next.terminate);
TEST_ASSERT(period_head->qtd_overlay.halted);
TEST_ASSERT_TRUE(period_head_arr[0].next.terminate);
}
#endif
}

View File

@ -252,7 +252,7 @@ void test_register_usbsts(void)
TEST_ASSERT_EQUAL( 3 , BITFIELD_OFFSET_OF_MEMBER(ehci_registers_t, usb_sts_bit, framelist_rollover));
TEST_ASSERT_EQUAL( 4 , BITFIELD_OFFSET_OF_MEMBER(ehci_registers_t, usb_sts_bit, pci_host_system_error));
TEST_ASSERT_EQUAL( 5 , BITFIELD_OFFSET_OF_MEMBER(ehci_registers_t, usb_sts_bit, async_advance));
TEST_ASSERT_EQUAL( 7 , BITFIELD_OFFSET_OF_MEMBER(ehci_registers_t, usb_sts_bit, nxp_sof_received));
TEST_ASSERT_EQUAL( 7 , BITFIELD_OFFSET_OF_MEMBER(ehci_registers_t, usb_sts_bit, nxp_int_sof));
TEST_ASSERT_EQUAL( 12 , BITFIELD_OFFSET_OF_MEMBER(ehci_registers_t, usb_sts_bit, hc_halted));
TEST_ASSERT_EQUAL( 13 , BITFIELD_OFFSET_OF_MEMBER(ehci_registers_t, usb_sts_bit, reclamation));
TEST_ASSERT_EQUAL( 14 , BITFIELD_OFFSET_OF_MEMBER(ehci_registers_t, usb_sts_bit, period_schedule_status));
@ -269,7 +269,7 @@ void test_register_usbint(void)
TEST_ASSERT_EQUAL( 3 , BITFIELD_OFFSET_OF_MEMBER(ehci_registers_t, usb_int_enable_bit, framelist_rollover));
TEST_ASSERT_EQUAL( 4 , BITFIELD_OFFSET_OF_MEMBER(ehci_registers_t, usb_int_enable_bit, pci_host_system_error));
TEST_ASSERT_EQUAL( 5 , BITFIELD_OFFSET_OF_MEMBER(ehci_registers_t, usb_int_enable_bit, async_advance));
TEST_ASSERT_EQUAL( 7 , BITFIELD_OFFSET_OF_MEMBER(ehci_registers_t, usb_int_enable_bit, nxp_sof_received));
TEST_ASSERT_EQUAL( 7 , BITFIELD_OFFSET_OF_MEMBER(ehci_registers_t, usb_int_enable_bit, nxp_int_sof));
TEST_ASSERT_EQUAL( 18 , BITFIELD_OFFSET_OF_MEMBER(ehci_registers_t, usb_int_enable_bit, nxp_int_async));
TEST_ASSERT_EQUAL( 19 , BITFIELD_OFFSET_OF_MEMBER(ehci_registers_t, usb_int_enable_bit, nxp_int_period));

View File

@ -59,7 +59,7 @@ uint8_t dev_addr;
uint8_t hostid;
ehci_registers_t * regs;
ehci_qhd_t *async_head;
ehci_qhd_t *period_head;
ehci_qhd_t *period_head_arr;
void setUp(void)
{
@ -84,7 +84,7 @@ void setUp(void)
regs = get_operational_register(hostid);
async_head = get_async_head( hostid );
period_head = get_period_head( hostid );
period_head_arr = get_period_head( hostid, 1 );
regs->usb_sts = 0; // hcd_init clear usb_sts by writing 1s
}

View File

@ -54,7 +54,12 @@ uint8_t const hub_port = 2;
uint8_t dev_addr;
uint8_t hostid;
ehci_qhd_t *period_head;
ehci_qhd_t *period_head_arr;
ehci_qhd_t *p_int_qhd;
pipe_handle_t pipe_hdl;
uint8_t count_set_bits(uint8_t x);
//--------------------------------------------------------------------+
// Setup/Teardown + helper declare
@ -76,7 +81,9 @@ void setUp(void)
usbh_devices[i].speed = TUSB_SPEED_HIGH;
}
period_head = get_period_head( hostid );
period_head_arr = get_period_head( hostid, 1 );
p_int_qhd = NULL;
memclr_(&pipe_hdl, sizeof(pipe_handle_t));
}
void tearDown(void)
@ -107,6 +114,7 @@ void verify_open_qhd(ehci_qhd_t *p_qhd, uint8_t endpoint_addr, uint16_t max_pack
TEST_ASSERT_NULL(p_qhd->p_qtd_list_tail);
}
//--------------------------------------------------------------------+
// PIPE OPEN
//--------------------------------------------------------------------+
@ -117,7 +125,7 @@ tusb_descriptor_endpoint_t const desc_ept_interrupt_out =
.bEndpointAddress = 0x02,
.bmAttributes = { .xfer = TUSB_XFER_INTERRUPT },
.wMaxPacketSize = 16,
.bInterval = 1
.bInterval = 4
};
void verify_int_qhd(ehci_qhd_t *p_qhd, tusb_descriptor_endpoint_t const * desc_endpoint, uint8_t class_code)
{
@ -127,40 +135,148 @@ void verify_int_qhd(ehci_qhd_t *p_qhd, tusb_descriptor_endpoint_t const * desc_e
TEST_ASSERT_FALSE(p_qhd->data_toggle_control);
TEST_ASSERT_FALSE(p_qhd->non_hs_control_endpoint);
// TEST_ASSERT_EQUAL(desc_endpoint->bInterval); TDD highspeed bulk/control OUT
TEST_ASSERT_EQUAL(desc_endpoint->bEndpointAddress & 0x80 ? EHCI_PID_IN : EHCI_PID_OUT, p_qhd->pid_non_control);
}
void check_int_endpoint_link(ehci_qhd_t *p_prev, ehci_qhd_t *p_qhd)
{
//------------- period list check -------------//
TEST_ASSERT_EQUAL_HEX((uint32_t) p_qhd, align32(period_head->next.address));
TEST_ASSERT_FALSE(period_head->next.terminate);
TEST_ASSERT_EQUAL(EHCI_QUEUE_ELEMENT_QHD, period_head->next.type);
TEST_ASSERT_EQUAL_HEX((uint32_t) p_qhd, align32(p_prev->next.address));
TEST_ASSERT_FALSE(p_prev->next.terminate);
TEST_ASSERT_EQUAL(EHCI_QUEUE_ELEMENT_QHD, p_prev->next.type);
}
void test_open_interrupt_qhd_hs(void)
{
ehci_qhd_t *p_qhd;
pipe_handle_t pipe_hdl;
//------------- Code Under TEST -------------//
pipe_hdl = hcd_pipe_open(dev_addr, &desc_ept_interrupt_out, TUSB_CLASS_HID);
TEST_ASSERT_EQUAL(dev_addr, pipe_hdl.dev_addr);
TEST_ASSERT_EQUAL(TUSB_XFER_INTERRUPT, pipe_hdl.xfer_type);
p_qhd = &ehci_data.device[ pipe_hdl.dev_addr-1].qhd[ pipe_hdl.index ];
p_int_qhd = &ehci_data.device[ pipe_hdl.dev_addr-1].qhd[ pipe_hdl.index ];
verify_int_qhd(p_qhd, &desc_ept_interrupt_out, TUSB_CLASS_HID);
verify_int_qhd(p_int_qhd, &desc_ept_interrupt_out, TUSB_CLASS_HID);
TEST_ASSERT_EQUAL(0xFF, p_qhd->interrupt_smask);
// TEST_ASSERT_EQUAL(0, p_qhd->non_hs_interrupt_cmask);
TEST_ASSERT_EQUAL(0, p_int_qhd->non_hs_interrupt_cmask);
}
void test_open_interrupt_hs_interval_1(void)
{
tusb_descriptor_endpoint_t int_edp_interval = desc_ept_interrupt_out;
int_edp_interval.bInterval = 1;
//------------- Code Under TEST -------------//
pipe_hdl = hcd_pipe_open(dev_addr, &int_edp_interval, TUSB_CLASS_HID);
p_int_qhd = &ehci_data.device[ pipe_hdl.dev_addr-1].qhd[ pipe_hdl.index ];
TEST_ASSERT_EQUAL(0 , p_int_qhd->interval_ms);
TEST_ASSERT_EQUAL(BIN8(11111111) , p_int_qhd->interrupt_smask);
check_int_endpoint_link(period_head_arr, p_int_qhd);
}
void test_open_interrupt_hs_interval_2(void)
{
tusb_descriptor_endpoint_t int_edp_interval = desc_ept_interrupt_out;
int_edp_interval.bInterval = 2;
//------------- Code Under TEST -------------//
pipe_hdl = hcd_pipe_open(dev_addr, &int_edp_interval, TUSB_CLASS_HID);
p_int_qhd = &ehci_data.device[ pipe_hdl.dev_addr-1].qhd[ pipe_hdl.index ];
TEST_ASSERT_EQUAL(0 , p_int_qhd->interval_ms);
TEST_ASSERT_EQUAL(4 , count_set_bits(p_int_qhd->interrupt_smask)); // either 10101010 or 01010101
check_int_endpoint_link(period_head_arr, p_int_qhd);
}
void test_open_interrupt_hs_interval_3(void)
{
tusb_descriptor_endpoint_t int_edp_interval = desc_ept_interrupt_out;
int_edp_interval.bInterval = 3;
//------------- Code Under TEST -------------//
pipe_hdl = hcd_pipe_open(dev_addr, &int_edp_interval, TUSB_CLASS_HID);
p_int_qhd = &ehci_data.device[ pipe_hdl.dev_addr-1].qhd[ pipe_hdl.index ];
TEST_ASSERT_EQUAL(0, p_int_qhd->interval_ms);
TEST_ASSERT_EQUAL(2, count_set_bits(p_int_qhd->interrupt_smask) );
check_int_endpoint_link(period_head_arr, p_int_qhd);
}
void test_open_interrupt_hs_interval_4(void)
{
tusb_descriptor_endpoint_t int_edp_interval = desc_ept_interrupt_out;
int_edp_interval.bInterval = 4;
//------------- Code Under TEST -------------//
pipe_hdl = hcd_pipe_open(dev_addr, &int_edp_interval, TUSB_CLASS_HID);
p_int_qhd = &ehci_data.device[ pipe_hdl.dev_addr-1].qhd[ pipe_hdl.index ];
TEST_ASSERT_EQUAL(1, p_int_qhd->interval_ms);
TEST_ASSERT_EQUAL(1, count_set_bits(p_int_qhd->interrupt_smask) );
check_int_endpoint_link(period_head_arr, p_int_qhd);
}
void test_open_interrupt_hs_interval_5(void)
{
tusb_descriptor_endpoint_t int_edp_interval = desc_ept_interrupt_out;
int_edp_interval.bInterval = 5;
//------------- Code Under TEST -------------//
pipe_hdl = hcd_pipe_open(dev_addr, &int_edp_interval, TUSB_CLASS_HID);
p_int_qhd = &ehci_data.device[ pipe_hdl.dev_addr-1].qhd[ pipe_hdl.index ];
TEST_ASSERT_EQUAL(2, p_int_qhd->interval_ms);
TEST_ASSERT_EQUAL(1, count_set_bits(p_int_qhd->interrupt_smask) );
check_int_endpoint_link( get_period_head(hostid, 2), p_int_qhd );
}
void test_open_interrupt_hs_interval_6(void)
{
tusb_descriptor_endpoint_t int_edp_interval = desc_ept_interrupt_out;
int_edp_interval.bInterval = 6;
//------------- Code Under TEST -------------//
pipe_hdl = hcd_pipe_open(dev_addr, &int_edp_interval, TUSB_CLASS_HID);
p_int_qhd = &ehci_data.device[ pipe_hdl.dev_addr-1].qhd[ pipe_hdl.index ];
TEST_ASSERT_EQUAL(4, p_int_qhd->interval_ms);
TEST_ASSERT_EQUAL(1, count_set_bits(p_int_qhd->interrupt_smask) );
check_int_endpoint_link( get_period_head(hostid, 4), p_int_qhd);
}
void test_open_interrupt_hs_interval_7(void)
{
tusb_descriptor_endpoint_t int_edp_interval = desc_ept_interrupt_out;
int_edp_interval.bInterval = 7;
//------------- Code Under TEST -------------//
pipe_hdl = hcd_pipe_open(dev_addr, &int_edp_interval, TUSB_CLASS_HID);
p_int_qhd = &ehci_data.device[ pipe_hdl.dev_addr-1].qhd[ pipe_hdl.index ];
TEST_ASSERT_EQUAL(8, p_int_qhd->interval_ms);
TEST_ASSERT_EQUAL(1, count_set_bits(p_int_qhd->interrupt_smask) );
check_int_endpoint_link( get_period_head(hostid, 8), p_int_qhd);
}
void test_open_interrupt_hs_interval_8(void)
{
tusb_descriptor_endpoint_t int_edp_interval = desc_ept_interrupt_out;
int_edp_interval.bInterval = 8;
//------------- Code Under TEST -------------//
pipe_hdl = hcd_pipe_open(dev_addr, &int_edp_interval, TUSB_CLASS_HID);
p_int_qhd = &ehci_data.device[ pipe_hdl.dev_addr-1].qhd[ pipe_hdl.index ];
TEST_ASSERT_EQUAL(16, p_int_qhd->interval_ms);
TEST_ASSERT_EQUAL(1, count_set_bits(p_int_qhd->interrupt_smask) );
check_int_endpoint_link( get_period_head(hostid, 16), p_int_qhd);
check_int_endpoint_link( get_period_head(hostid, 8) , p_int_qhd);
}
void test_open_interrupt_qhd_non_hs(void)
{
ehci_qhd_t *p_qhd;
pipe_handle_t pipe_hdl;
usbh_devices[dev_addr].speed = TUSB_SPEED_FULL;
//------------- Code Under TEST -------------//
@ -169,12 +285,29 @@ void test_open_interrupt_qhd_non_hs(void)
TEST_ASSERT_EQUAL(dev_addr, pipe_hdl.dev_addr);
TEST_ASSERT_EQUAL(TUSB_XFER_INTERRUPT, pipe_hdl.xfer_type);
p_qhd = &ehci_data.device[ pipe_hdl.dev_addr-1].qhd[ pipe_hdl.index ];
p_int_qhd = &ehci_data.device[ pipe_hdl.dev_addr-1].qhd[ pipe_hdl.index ];
verify_int_qhd(p_qhd, &desc_ept_interrupt_out, TUSB_CLASS_HID);
verify_int_qhd(p_int_qhd, &desc_ept_interrupt_out, TUSB_CLASS_HID);
TEST_ASSERT_EQUAL(1, p_qhd->interrupt_smask);
TEST_ASSERT_EQUAL(0x1c, p_qhd->non_hs_interrupt_cmask);
TEST_ASSERT_EQUAL(desc_ept_interrupt_out.bInterval, p_int_qhd->interval_ms);
TEST_ASSERT_EQUAL(1, p_int_qhd->interrupt_smask);
TEST_ASSERT_EQUAL(0x1c, p_int_qhd->non_hs_interrupt_cmask);
}
void test_open_interrupt_qhd_non_hs_9(void)
{
tusb_descriptor_endpoint_t int_edp_interval = desc_ept_interrupt_out;
int_edp_interval.bInterval = 32;
usbh_devices[dev_addr].speed = TUSB_SPEED_FULL;
//------------- Code Under TEST -------------//
pipe_hdl = hcd_pipe_open(dev_addr, &int_edp_interval, TUSB_CLASS_HID);
p_int_qhd = &ehci_data.device[ pipe_hdl.dev_addr-1].qhd[ pipe_hdl.index ];
TEST_ASSERT_EQUAL(int_edp_interval.bInterval, p_int_qhd->interval_ms);
check_int_endpoint_link( get_period_head(hostid, 32), p_int_qhd);
check_int_endpoint_link( get_period_head(hostid, 8) , p_int_qhd);
}
//--------------------------------------------------------------------+
@ -182,17 +315,28 @@ void test_open_interrupt_qhd_non_hs(void)
//--------------------------------------------------------------------+
void test_interrupt_close(void)
{
ehci_qhd_t *p_qhd;
pipe_handle_t pipe_hdl;
pipe_hdl = hcd_pipe_open(dev_addr, &desc_ept_interrupt_out, TUSB_CLASS_HID);
p_qhd = qhd_get_from_pipe_handle(pipe_hdl);
p_int_qhd = qhd_get_from_pipe_handle(pipe_hdl);
//------------- Code Under TEST -------------//
hcd_pipe_close(pipe_hdl);
TEST_ASSERT(p_qhd->is_removing);
TEST_ASSERT( align32(period_head->next.address) != (uint32_t) p_qhd );
TEST_ASSERT_EQUAL_HEX( (uint32_t) period_head, align32(p_qhd->next.address ) );
TEST_ASSERT_EQUAL(EHCI_QUEUE_ELEMENT_QHD, p_qhd->next.type);
TEST_ASSERT(p_int_qhd->is_removing);
TEST_ASSERT( align32(period_head_arr->next.address) != (uint32_t) p_int_qhd );
TEST_ASSERT_EQUAL_HEX( (uint32_t) period_head_arr, 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;
for (uint8_t i=0; i<8; i++)
{
if ( x & BIT_(i) )
{
++result;
}
}
return result;
}

View File

@ -56,7 +56,7 @@ uint8_t hostid;
uint8_t xfer_data [100];
uint8_t data2[100];
ehci_qhd_t *period_head;
ehci_qhd_t *period_head_arr;
ehci_qhd_t *p_qhd_interrupt;
pipe_handle_t pipe_hdl_interrupt;
@ -67,7 +67,7 @@ tusb_descriptor_endpoint_t const desc_ept_interrupt_in =
.bEndpointAddress = 0x81,
.bmAttributes = { .xfer = TUSB_XFER_INTERRUPT },
.wMaxPacketSize = 8,
.bInterval = 0
.bInterval = 2
};
tusb_descriptor_endpoint_t const desc_ept_interupt_out =
@ -77,7 +77,7 @@ tusb_descriptor_endpoint_t const desc_ept_interupt_out =
.bEndpointAddress = 0x01,
.bmAttributes = { .xfer = TUSB_XFER_INTERRUPT },
.wMaxPacketSize = 64,
.bInterval = 0
.bInterval = 3
};
//--------------------------------------------------------------------+
@ -103,7 +103,7 @@ void setUp(void)
usbh_devices[i].speed = TUSB_SPEED_HIGH;
}
period_head = get_period_head( hostid );
period_head_arr = get_period_head( hostid, 1 );
pipe_hdl_interrupt = hcd_pipe_open(dev_addr, &desc_ept_interrupt_in, TUSB_CLASS_HID);
TEST_ASSERT_EQUAL(dev_addr, pipe_hdl_interrupt.dev_addr);
@ -186,22 +186,49 @@ void test_interrupt_xfer_double(void)
TEST_ASSERT_TRUE(p_tail->int_on_complete);
}
void test_interrupt_xfer_complete_isr(void)
void check_qhd_after_complete(ehci_qhd_t *p_qhd)
{
TEST_ASSERT_TRUE(p_qhd->qtd_overlay.next.terminate);
TEST_ASSERT_NULL(p_qhd->p_qtd_list_head);
TEST_ASSERT_NULL(p_qhd->p_qtd_list_tail);
}
void test_interrupt_xfer_complete_isr_interval_less_than_1ms(void)
{
hcd_pipe_xfer(pipe_hdl_interrupt, xfer_data, sizeof(xfer_data), false);
hcd_pipe_xfer(pipe_hdl_interrupt, data2, sizeof(data2), true);
usbh_isr_Expect(pipe_hdl_interrupt, TUSB_CLASS_HID, TUSB_EVENT_XFER_COMPLETE);
ehci_qtd_t* p_head = p_qhd_interrupt->p_qtd_list_head;
ehci_qtd_t* p_tail = p_qhd_interrupt->p_qtd_list_tail;
usbh_isr_Expect(pipe_hdl_interrupt, TUSB_CLASS_HID, TUSB_EVENT_XFER_COMPLETE);
//------------- Code Under Test -------------//
ehci_controller_run(hostid);
TEST_ASSERT_TRUE(p_qhd_interrupt->qtd_overlay.next.terminate);
check_qhd_after_complete(p_qhd_interrupt);
TEST_ASSERT_FALSE(p_head->used);
TEST_ASSERT_FALSE(p_tail->used);
TEST_ASSERT_NULL(p_qhd_interrupt->p_qtd_list_head);
TEST_ASSERT_NULL(p_qhd_interrupt->p_qtd_list_tail);
}
void test_interrupt_xfer_complete_isr_interval_2ms(void)
{
tusb_descriptor_endpoint_t desc_endpoint_2ms = desc_ept_interrupt_in;
desc_endpoint_2ms.bInterval = 5;
pipe_handle_t pipe_hdl_2ms = hcd_pipe_open(dev_addr, &desc_endpoint_2ms, TUSB_CLASS_HID);
ehci_qhd_t * p_qhd_2ms = &ehci_data.device[ dev_addr -1].qhd[ pipe_hdl_2ms.index ];
hcd_pipe_xfer(pipe_hdl_2ms, xfer_data, sizeof(xfer_data), false);
ehci_qtd_t* p_head = p_qhd_2ms->p_qtd_list_head;
ehci_qtd_t* p_tail = p_qhd_2ms->p_qtd_list_tail;
//------------- Code Under Test -------------//
ehci_controller_run(hostid);
check_qhd_after_complete(p_qhd_2ms);
TEST_ASSERT_FALSE(p_head->used);
TEST_ASSERT_FALSE(p_tail->used);
}

View File

@ -54,7 +54,7 @@ uint8_t const hub_port = 2;
uint8_t dev_addr;
uint8_t hostid;
ehci_qhd_t *period_head;
ehci_qhd_t *period_head_arr;
//--------------------------------------------------------------------+
// Setup/Teardown + helper declare
//--------------------------------------------------------------------+
@ -75,7 +75,7 @@ void setUp(void)
usbh_devices[i].speed = TUSB_SPEED_HIGH;
}
period_head = get_period_head( hostid );
period_head_arr = get_period_head( hostid, 1 );
}
void tearDown(void)

View File

@ -123,7 +123,7 @@ void ehci_controller_run(uint8_t hostid)
complete_all_qtd_in_list((ehci_qhd_t*) regs->async_list_base);
//------------- Period List -------------//
complete_all_qtd_in_list( get_period_head(hostid) );
complete_all_qtd_in_list( get_period_head(hostid, 1) );
regs->usb_sts = EHCI_INT_MASK_NXP_ASYNC | EHCI_INT_MASK_NXP_PERIODIC;
hcd_isr(hostid);

View File

@ -64,9 +64,9 @@ void ehci_controller_device_plug(uint8_t hostid, tusb_speed_t speed);
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 list_idx);
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);
ehci_qhd_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);

View File

@ -37,8 +37,8 @@
#include "unity.h"
#include "errors.h"
#include "freeRTOS.h"
#include "osal_freeRTOS.h"
//#include "freeRTOS.h"
//#include "osal_freeRTOS.h"
//#include "mock_task.h"
//#include "queue.h"
//#include "mock_portmacro.h"

View File

@ -121,6 +121,12 @@ static inline uint8_t min8_of(uint8_t x, uint8_t y)
return (x < y) ? x : y;
}
static inline uint16_t min16_of(uint16_t x, uint16_t y) ATTR_ALWAYS_INLINE ATTR_CONST;
static inline uint16_t min16_of(uint16_t x, uint16_t y)
{
return (x < y) ? x : y;
}
static inline uint32_t min32_of(uint32_t x, uint32_t y) ATTR_ALWAYS_INLINE ATTR_CONST;
static inline uint32_t min32_of(uint32_t x, uint32_t y)
{

View File

@ -59,10 +59,13 @@
STATIC_ ehci_data_t ehci_data TUSB_CFG_ATTR_USBRAM;
#if EHCI_PERIODIC_LIST
#if (TUSB_CFG_CONTROLLER0_MODE & TUSB_MODE_HOST)
STATIC_ ehci_link_t period_frame_list0[EHCI_FRAMELIST_SIZE] ATTR_ALIGNED(4096) TUSB_CFG_ATTR_USBRAM;
STATIC_ASSERT( ALIGN_OF(period_frame_list0) == 4096, "Period Framelist must be 4k alginment"); // validation
#endif
#if CONTROLLER_HOST_NUMBER > 1
#if (TUSB_CFG_CONTROLLER1_MODE & TUSB_MODE_HOST)
STATIC_ ehci_link_t period_frame_list1[EHCI_FRAMELIST_SIZE] ATTR_ALIGNED(4096) TUSB_CFG_ATTR_USBRAM;
STATIC_ASSERT( ALIGN_OF(period_frame_list1) == 4096, "Period Framelist must be 4k alginment"); // validation
#endif
@ -75,11 +78,11 @@ STATIC_ ehci_data_t ehci_data TUSB_CFG_ATTR_USBRAM;
// PROTOTYPE
//--------------------------------------------------------------------+
STATIC_ INLINE_ ehci_registers_t* get_operational_register(uint8_t hostid) ATTR_PURE ATTR_ALWAYS_INLINE ATTR_WARN_UNUSED_RESULT;
STATIC_ INLINE_ ehci_link_t* get_period_frame_list(uint8_t list_idx) ATTR_PURE ATTR_ALWAYS_INLINE ATTR_WARN_UNUSED_RESULT;
STATIC_ INLINE_ ehci_link_t* get_period_frame_list(uint8_t hostid) ATTR_PURE ATTR_ALWAYS_INLINE ATTR_WARN_UNUSED_RESULT;
STATIC_ INLINE_ uint8_t hostid_to_data_idx(uint8_t hostid) ATTR_ALWAYS_INLINE ATTR_CONST ATTR_WARN_UNUSED_RESULT;
STATIC_ INLINE_ ehci_qhd_t* get_async_head(uint8_t hostid) ATTR_ALWAYS_INLINE ATTR_PURE ATTR_WARN_UNUSED_RESULT;
STATIC_ INLINE_ ehci_qhd_t* get_period_head(uint8_t hostid) ATTR_ALWAYS_INLINE ATTR_PURE ATTR_WARN_UNUSED_RESULT;
STATIC_ INLINE_ ehci_qhd_t* get_async_head(uint8_t hostid) ATTR_ALWAYS_INLINE ATTR_PURE ATTR_WARN_UNUSED_RESULT;
STATIC_ INLINE_ ehci_link_t* get_period_head(uint8_t hostid, uint8_t interval_ms) ATTR_ALWAYS_INLINE ATTR_PURE ATTR_WARN_UNUSED_RESULT;
STATIC_ INLINE_ ehci_qhd_t* get_control_qhd(uint8_t dev_addr) ATTR_ALWAYS_INLINE ATTR_PURE ATTR_WARN_UNUSED_RESULT;
STATIC_ INLINE_ ehci_qtd_t* get_control_qtds(uint8_t dev_addr) ATTR_ALWAYS_INLINE ATTR_PURE ATTR_WARN_UNUSED_RESULT;
@ -87,7 +90,7 @@ STATIC_ INLINE_ ehci_qtd_t* get_control_qtds(uint8_t dev_addr) ATTR_ALWAYS_INLIN
static inline uint8_t qhd_get_index(ehci_qhd_t * p_qhd) ATTR_ALWAYS_INLINE ATTR_PURE;
static inline ehci_qhd_t* qhd_find_free (uint8_t dev_addr) ATTR_PURE ATTR_ALWAYS_INLINE;
STATIC_ INLINE_ ehci_qhd_t* qhd_get_from_pipe_handle(pipe_handle_t pipe_hdl) ATTR_PURE ATTR_ALWAYS_INLINE;
static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, uint16_t max_packet_size, uint8_t endpoint_addr, uint8_t xfer_type);
static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, uint16_t max_packet_size, uint8_t endpoint_addr, uint8_t xfer_type, uint8_t interval);
STATIC_ INLINE_ ehci_qtd_t* qtd_find_free(uint8_t dev_addr) ATTR_PURE ATTR_ALWAYS_INLINE;
static inline void qtd_insert_to_qhd(ehci_qhd_t *p_qhd, ehci_qtd_t *p_qtd_new) ATTR_ALWAYS_INLINE;
@ -174,22 +177,45 @@ static tusb_error_t hcd_controller_init(uint8_t hostid)
regs->async_list_base = (uint32_t) async_head;
//------------- Periodic List -------------//
#if EHCI_PERIODIC_LIST
ehci_link_t * const framelist = get_period_frame_list(hostid);
ehci_qhd_t * const period_head = get_period_head(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++)
{
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
}
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]
// TODO EHCI_FRAMELIST_SIZE with other size than 8
for(uint32_t i=0; i<EHCI_FRAMELIST_SIZE; i++)
{
framelist[i].address = (uint32_t) period_head;
framelist[i].address = (uint32_t) period_1ms;
framelist[i].type = EHCI_QUEUE_ELEMENT_QHD;
}
period_head->interrupt_smask = 1; // queue head in period list must have smask non-zero
period_head->next.terminate = 1;
period_head->qtd_overlay.halted = 1; // dummy node, always inactive
for(uint32_t i=1; i<EHCI_FRAMELIST_SIZE; i+=2)
{
list_insert(framelist + i, period_2ms, EHCI_QUEUE_ELEMENT_QHD);
}
regs->periodic_list_base = (uint32_t) framelist;
for(uint32_t i=2; i<EHCI_FRAMELIST_SIZE; i+=4)
{
list_insert(framelist + i, period_4ms, EHCI_QUEUE_ELEMENT_QHD);
}
period_1ms->terminate = 1;
regs->periodic_list_base = (uint32_t) framelist;
#else
regs->periodic_list_base = 0;
#endif
@ -201,7 +227,7 @@ static tusb_error_t hcd_controller_init(uint8_t hostid)
regs->usb_cmd |= BIT_(EHCI_USBCMD_POS_RUN_STOP) | BIT_(EHCI_USBCMD_POS_ASYNC_ENABLE)
#if EHCI_PERIODIC_LIST
| BIT_(EHCI_USBCMD_POS_PERIOD_ENABLE)
| BIT_(EHCI_USBCMD_POS_PERIOD_ENABLE) // TODO enable period list only there is int/iso endpoint
#endif
| ((EHCI_CFG_FRAMELIST_SIZE_BITS & BIN8(011)) << EHCI_USBCMD_POS_FRAMELIST_SZIE)
| ((EHCI_CFG_FRAMELIST_SIZE_BITS >> 2) << EHCI_USBCMD_POS_NXP_FRAMELIST_SIZE_MSB);
@ -247,7 +273,7 @@ tusb_error_t hcd_pipe_control_open(uint8_t dev_addr, uint8_t max_packet_size)
{
ehci_qhd_t * const p_qhd = get_control_qhd(dev_addr);
qhd_init(p_qhd, dev_addr, max_packet_size, 0, TUSB_XFER_CONTROL);
qhd_init(p_qhd, dev_addr, max_packet_size, 0, TUSB_XFER_CONTROL, 1); // TODO binterval of control is ignored
if (dev_addr != 0)
{
@ -331,23 +357,22 @@ pipe_handle_t hcd_pipe_open(uint8_t dev_addr, tusb_descriptor_endpoint_t const *
ehci_qhd_t * const p_qhd = qhd_find_free(dev_addr);
ASSERT_PTR(p_qhd, null_handle);
qhd_init(p_qhd, dev_addr, p_endpoint_desc->wMaxPacketSize.size, p_endpoint_desc->bEndpointAddress, p_endpoint_desc->bmAttributes.xfer);
qhd_init( p_qhd, dev_addr, p_endpoint_desc->wMaxPacketSize.size, p_endpoint_desc->bEndpointAddress,
p_endpoint_desc->bmAttributes.xfer, p_endpoint_desc->bInterval );
p_qhd->class_code = class_code;
ehci_qhd_t * list_head;
ehci_link_t * list_head;
if (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_BULK)
{
// TODO might need to to disable async list first
list_head = get_async_head(usbh_devices[dev_addr].core_id);
list_head = (ehci_link_t*) get_async_head(usbh_devices[dev_addr].core_id);
}else if (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_INTERRUPT)
{
// TODO might need to to disable period list first
list_head = get_period_head(usbh_devices[dev_addr].core_id);
list_head = get_period_head(usbh_devices[dev_addr].core_id, p_qhd->interval_ms);
}
//------------- insert to async/period list -------------//
list_insert( (ehci_link_t*) list_head,
//------------- insert to async/period list TODO might need to disable async/period list -------------//
list_insert( list_head,
(ehci_link_t*) p_qhd, EHCI_QUEUE_ELEMENT_QHD);
return (pipe_handle_t) { .dev_addr = dev_addr, .xfer_type = p_endpoint_desc->bmAttributes.xfer, .index = qhd_get_index(p_qhd) };
@ -398,7 +423,7 @@ tusb_error_t hcd_pipe_close(pipe_handle_t pipe_hdl)
}else
{
ASSERT_STATUS( list_remove_qhd(
get_period_head( usbh_devices[pipe_hdl.dev_addr].core_id ), p_qhd) );
get_period_head( usbh_devices[pipe_hdl.dev_addr].core_id, 1 ), p_qhd) );
}
return TUSB_ERROR_NONE;
@ -618,9 +643,10 @@ void hcd_isr(uint8_t hostid)
if (int_status & EHCI_INT_MASK_NXP_PERIODIC)
{
period_list_process_isr( get_period_head(hostid) );
period_list_process_isr( get_period_head(hostid, 1) );
}
//------------- There is some removed async previously -------------//
if (int_status & EHCI_INT_MASK_ASYNC_ADVANCE) // need to place after EHCI_INT_MASK_NXP_ASYNC
{
async_advance_isr( get_async_head(hostid) );
@ -635,13 +661,22 @@ STATIC_ INLINE_ ehci_registers_t* get_operational_register(uint8_t hostid)
return (ehci_registers_t*) (hostid ? (&LPC_USB1->USBCMD_H) : (&LPC_USB0->USBCMD_H) );
}
STATIC_ INLINE_ ehci_link_t* get_period_frame_list(uint8_t list_idx)
STATIC_ INLINE_ ehci_link_t* get_period_frame_list(uint8_t hostid)
{
#if CONTROLLER_HOST_NUMBER > 1
return list_idx ? period_frame_list1 : period_frame_list0; // TODO more than 2 controller
#else
return period_frame_list0;
switch(hostid)
{
#if (TUSB_CFG_CONTROLLER0_MODE & TUSB_MODE_HOST)
case 0:
return period_frame_list0;
#endif
#if (TUSB_CFG_CONTROLLER0_MODE & TUSB_MODE_HOST)
case 1:
return period_frame_list1;
#endif
}
return NULL;
}
STATIC_ INLINE_ uint8_t hostid_to_data_idx(uint8_t hostid)
@ -660,9 +695,17 @@ STATIC_ INLINE_ ehci_qhd_t* get_async_head(uint8_t hostid)
return &ehci_data.async_head[ hostid_to_data_idx(hostid) ];
}
STATIC_ INLINE_ ehci_qhd_t* get_period_head(uint8_t hostid)
STATIC_ INLINE_ ehci_link_t* get_period_head(uint8_t hostid, uint8_t interval_ms)
{
return &ehci_data.period_head[ hostid_to_data_idx(hostid) ];
if (interval_ms < 8)
{
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);
}
}
STATIC_ INLINE_ ehci_qhd_t* get_control_qhd(uint8_t dev_addr)
@ -737,7 +780,7 @@ static inline void qtd_insert_to_qhd(ehci_qhd_t *p_qhd, ehci_qtd_t *p_qtd_new)
}
}
static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, uint16_t max_packet_size, uint8_t endpoint_addr, uint8_t xfer_type)
static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, uint16_t max_packet_size, uint8_t endpoint_addr, uint8_t xfer_type, uint8_t interval)
{
// address 0 uses async head, which always on the list --> cannot be cleared (ehci halted otherwise)
if (dev_addr != 0)
@ -752,16 +795,33 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, uint16_t max_packet_si
p_qhd->data_toggle_control = (xfer_type == TUSB_XFER_CONTROL) ? 1 : 0;
p_qhd->head_list_flag = (dev_addr == 0) ? 1 : 0; // addr0's endpoint is the static asyn list head
p_qhd->max_package_size = max_packet_size;
p_qhd->non_hs_control_endpoint = ((TUSB_XFER_CONTROL == xfer_type) && (usbh_devices[dev_addr].speed != TUSB_SPEED_HIGH) ) ? 1 : 0;
p_qhd->non_hs_control_endpoint = ((TUSB_XFER_CONTROL == xfer_type) && (p_qhd->endpoint_speed != TUSB_SPEED_HIGH)) ? 1 : 0;
p_qhd->nak_count_reload = 0;
// Bulk/Control -> smask = cmask = 0
if (TUSB_XFER_INTERRUPT == xfer_type)
{
// Highspeed: schedule every uframe (1 us interval); Full/Low: schedule only 1st frame
p_qhd->interrupt_smask = (TUSB_SPEED_HIGH == usbh_devices[dev_addr].speed) ? 0xFF : 0x01;
// Highspeed: ignored by Host Controller, Full/Low: 4.12.2.1 (EHCI) case 1 schedule complete split at 2,3,4 uframe
p_qhd->non_hs_interrupt_cmask = BIN8(11100);
if (TUSB_SPEED_HIGH == p_qhd->endpoint_speed)
{
ASSERT_INT_WITHIN(1, 16, interval, (void) 0);
if ( interval < 4) // sub milisecond interval
{
p_qhd->interval_ms = 0;
p_qhd->interrupt_smask = (interval == 1) ? BIN8(11111111) :
(interval == 2) ? BIN8(10101010) : BIN8(01000100);
}else
{
p_qhd->interval_ms = ( 1 << (interval-4) );
p_qhd->interrupt_smask = BIT_(interval % 8);
}
}else
{
ASSERT( 0 != interval, (void) 0);
// Full/Low: 4.12.2.1 (EHCI) case 1 schedule start split at 1 us & complete split at 2,3,4 uframes
p_qhd->interrupt_smask = 0x01;
p_qhd->non_hs_interrupt_cmask = BIN8(11100);
p_qhd->interval_ms = interval;
}
}else
{
p_qhd->interrupt_smask = p_qhd->non_hs_interrupt_cmask = 0;
@ -830,7 +890,7 @@ static tusb_error_t list_remove_qhd(ehci_qhd_t* p_head, ehci_qhd_t* p_qhd_remove
ASSERT_PTR(p_prev_qhd, TUSB_ERROR_INVALID_PARA);
p_prev_qhd->next.address = p_qhd_remove->next.address;
// EHCI 4.8.2 link the removing queue head to async_head (which always on the async list)
// 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;

View File

@ -196,10 +196,11 @@ typedef struct {
uint8_t pid_non_control;
uint8_t class_code;
uint8_t interval_ms; // polling interval in frames (or milisecond)
uint8_t reserved[3];
ehci_qtd_t *p_qtd_list_head; // head of the scheduled TD list
ehci_qtd_t *p_qtd_list_tail; // tail of the scheduled TD list
uint32_t reserved_2;
}ATTR_ALIGNED(32) ehci_qhd_t;
/// Highspeed Isochronous Transfer Descriptor (section 3.3)
@ -305,7 +306,7 @@ enum ehci_interrupt_mask_{
EHCI_INT_MASK_FRAMELIST_ROLLOVER = BIT_(3),
EHCI_INT_MASK_PCI_HOST_SYSTEM_ERROR = BIT_(4),
EHCI_INT_MASK_ASYNC_ADVANCE = BIT_(5),
EHCI_INT_MASK_SOF_RECEIVED = BIT_(7),
EHCI_INT_MASK_NXP_SOF = BIT_(7),
EHCI_INT_MASK_NXP_ASYNC = BIT_(18),
EHCI_INT_MASK_NXP_PERIODIC = BIT_(19),
@ -313,7 +314,7 @@ enum ehci_interrupt_mask_{
EHCI_INT_MASK_ALL =
EHCI_INT_MASK_USB | EHCI_INT_MASK_ERROR | EHCI_INT_MASK_PORT_CHANGE |
EHCI_INT_MASK_FRAMELIST_ROLLOVER | EHCI_INT_MASK_PCI_HOST_SYSTEM_ERROR |
EHCI_INT_MASK_ASYNC_ADVANCE | EHCI_INT_MASK_SOF_RECEIVED |
EHCI_INT_MASK_ASYNC_ADVANCE | EHCI_INT_MASK_NXP_SOF |
EHCI_INT_MASK_NXP_ASYNC | EHCI_INT_MASK_NXP_PERIODIC
};
@ -368,7 +369,7 @@ typedef volatile struct {
uint32_t pci_host_system_error : 1 ; ///< R/WC (not used by NXP) The Host Controller sets this bit to 1 when a serious error occurs during a host system access involving the Host Controller module. In a PCI system, conditions that set this bit to 1 include PCI Parity error, PCI Master Abort, and PCI Target Abort. When this error occurs, the Host Controller clears the Run/Stop bit in the Command register to prevent further execution of the scheduled TDs.
uint32_t async_advance : 1 ; ///< R/WC 0=Default. System software can force the host controller to issue an interrupt the next time the host controller advances the asynchronous schedule by writing a one to the Interrupt on Async Advance Doorbell bit in the USBCMD register. This status bit indicates the assertion of that interrupt source.
uint32_t : 1 ; ///< These bits are reserved and should be set to zero.
uint32_t nxp_sof_received : 1 ; ///< R/WC NXP customized: this bit will be set every 125us and can be used by host controller driver as a time base.
uint32_t nxp_int_sof : 1 ; ///< R/WC NXP customized: this bit will be set every 125us and can be used by host controller driver as a time base.
uint32_t : 4 ; ///< These bits are reserved and should be set to zero.
uint32_t hc_halted : 1 ; ///< Read-Only 1=Default. This bit is a zero whenever the Run/Stop bit is a one. The Host Controller sets this bit to one after it has stopped executing as a result of the Run/Stop bit being set to 0, either by software or by the Host Controller hardware (e.g. internal error).
uint32_t reclamation : 1 ; ///< Read-Only 0=Default. This is a read-only status bit, which is used to detect an empty asynchronous schedule. The operational model of empty schedule detection is described in Section 4.8.3. The valid transitions for this bit are described in Section 4.8.6.
@ -392,7 +393,7 @@ typedef volatile struct {
uint32_t pci_host_system_error : 1 ; ///< (not used by NXP) When this bit is a one, and the Host System Error Statusbit in the USBSTS register is a one, the host controller will issue an interrupt. The interrupt is acknowledged by software clearing the Host System Error bit.
uint32_t async_advance : 1 ; ///< When this bit is a one, and the Interrupt on Async Advancebit in the USBSTS register is a one, the host controller will issue an interrupt at the next interrupt threshold. The interrupt is acknowledged by software clearing the Interrupt on Async Advancebit.
uint32_t : 1 ; ///< reserved
uint32_t nxp_sof_received : 1 ; ///< NXP customized: if this bit is one and the SRI bit in the USBSTS register is one, the host controller will issue an interrupt. In host mode, the SRI bit will be set every 125 micro sec and can be used by the host controller as a time base. The interrupt is acknowledged by software clearing the SRI bit in the USBSTS register.
uint32_t nxp_int_sof : 1 ; ///< NXP customized: if this bit is one and the SRI bit in the USBSTS register is one, the host controller will issue an interrupt. In host mode, the SRI bit will be set every 125 micro sec and can be used by the host controller as a time base. The interrupt is acknowledged by software clearing the SRI bit in the USBSTS register.
uint32_t : 10 ; ///< reserved
uint32_t nxp_int_async : 1 ; ///< NXP customized: When this bit is a one, and the USBHSTASYNCINT bit in the USBSTS register is a one, the host controller will issue an interrupt at the next interrupt threshold. The interrupt is acknowledged by software clearing the USBHSTASYNCINT bit.
uint32_t nxp_int_period : 1 ; ///< NXP customized: When this bit is a one, and the USBHSTPERINT bit in the USBSTS register is a one, the host controller will issue an interrupt at the next interrupt threshold. The interrupt is acknowledged by software clearing the USBHSTPERINT bit.
@ -445,7 +446,12 @@ typedef volatile struct {
typedef struct {
//------------- Static Async/Period List Head, Each for one controller -------------//
ehci_qhd_t async_head[CONTROLLER_HOST_NUMBER]; /// head qhd of async list, also is used as control endpoint for address 0
ehci_qhd_t period_head[CONTROLLER_HOST_NUMBER];
#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];
#endif
//------------- Data for Address 0 (use async head as its queue head) -------------//
ehci_qtd_t addr0_qtd[3];

View File

@ -87,6 +87,7 @@ static host_class_driver_t const usbh_class_drivers[TUSB_CLASS_MAX_CONSEC_NUMBER
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
usbh_device_info_t usbh_devices[TUSB_CFG_HOST_DEVICE_MAX+1] TUSB_CFG_ATTR_USBRAM; // including zero-address
OSAL_TASK_DECLARE(usbh_enumeration_task);
//------------- Enumeration Task Data -------------//
OSAL_TASK_DEF(enum_task, usbh_enumeration_task, 128, OSAL_PRIO_HIGH);

View File

@ -71,16 +71,55 @@ extern "C" {
//--------------------------------------------------------------------+
// TASK API
//--------------------------------------------------------------------+
#define OSAL_TASK_DECLARE(task_name) \
void task_name(void *p_task_para)
typedef struct {
signed portCHAR const * name;
pdTASK_CODE code;
unsigned portSHORT stack_depth;
unsigned portBASE_TYPE prio;
} osal_task_t;
#define OSAL_TASK_DEF(task_name, task_code, task_stack_depth, task_prio) \
osal_task_t task_name = {\
.name = #task_name , \
.code = task_code , \
.stack_depth = task_stack_depth , \
.prio = task_prio \
};
#define OSAL_TASK_LOOP_BEGIN \
while(1) {
#define OSAL_TASK_LOOP_END \
}
//------------- Sub Task -------------//
#define OSAL_SUBTASK_BEGIN
#define OSAL_SUBTASK_END
//------------- Task Assert -------------//
#define TASK_RESTART
// TODO FreeRTOS TASK_ASSERT need to omit do while to get continue statement works.
#define _TASK_ASSERT_ERROR_HANDLER(error, func_call) \
func_call; TASK_RESTART;
#define TASK_ASSERT(condition)
#define TASK_ASSERT_STATUS(sts)
#define TASK_ASSERT_WITH_HANDLER(condition, func_call) \
ASSERT_DEFINE_WITH_HANDLER(_TASK_ASSERT_ERROR_HANDLER, func_call, ,\
condition, TUSB_ERROR_OSAL_TASK_FAILED, "%s", "evaluated to false")
//------------- Sub Task Assert -------------// TODO replace directly by TASK ASSERT
#define SUBTASK_ASSERT_STATUS(...) TASK_ASSERT_STATUS(__VA_ARGS__)
#define SUBTASK_ASSERT_STATUS_WITH_HANDLER(...) TASK_ASSERT_STATUS_WITH_HANDLER(__VA_ARGS__)
#define SUBTASK_ASSERT(...) TASK_ASSERT(__VA_ARGS__)
#define SUBTASK_ASSERT_WITH_HANDLER(...) TASK_ASSERT_WITH_HANDLER(__VA_ARGS__)
//--------------------------------------------------------------------+
// Semaphore API
//--------------------------------------------------------------------+

View File

@ -145,7 +145,7 @@ static inline volatile uint32_t osal_tick_get(void)
ASSERT_DEFINE_WITH_HANDLER(_TASK_ASSERT_ERROR_HANDLER, func_call, ,\
condition, TUSB_ERROR_OSAL_TASK_FAILED, "%s", "evaluated to false")
//------------- Sub Task Assert -------------//
//------------- Sub Task Assert -------------// TODO replace directly by TASK ASSERT
#define SUBTASK_ASSERT_STATUS(...) TASK_ASSERT_STATUS(__VA_ARGS__)
#define SUBTASK_ASSERT_STATUS_WITH_HANDLER(...) TASK_ASSERT_STATUS_WITH_HANDLER(__VA_ARGS__)
#define SUBTASK_ASSERT(...) TASK_ASSERT(__VA_ARGS__)