Introduction
NXP i.MXRT106x has two USB2.0 OTG instance. And the RT1060 EVK has both of the USB interface on the board. But the RT1060 SDK only has single USB host example. Although RT1060’s USB host stack support multiple devices, but we still need a USB HUB when user want to connect two device. This article will show you how to make both USB instance as host.
RT1060 SDK has single host examples which support multiple devices, like host_hid_mouse_keyboard_bm. But this application don’t use these examples. Instead, MCUXpresso Config Tools is used to build the demo from beginning. The config tool is a very powerful tool which can configure clock, pin and peripherals, especially the USB. In this application demo, it can save 95% coding work.
Hardware and software tools
RT1060 EVK
MCUXpresso 11.4.0
MIMXRT1060 SDK 2.9.1
Step 1
This project will support USB HID mouse and USB CDC. First, create an empty project named MIMXRT1062_usb_host_dual_port. When select SDK components, select “USB host CDC” and “”USB host HID” in Middleware label. IDE will select other necessary component automatically.
After creating the empty project, clock should be configured first. Both of the USB PHY need 480M clock.
Step 2
Next step is to configure USB host in peripheral config tool. Due to the limitation of config tool, only one host instance of the USB component is allowed. In this project, CDC VCOM is added first.
Step 3
After these settings, click “Update Code” in control bar. This will turn all the configurations into code and merge into project.
Then click the “copy to clipboard” button. This will copy the host task call function. Paste it in the forever while loop in the project’s main(). Besides that, it also need to add BOARD_InitBootPeripherals() function call in main().
At this point, USB VCOM is ready. The tool will not only copy the file and configure USB, but also create basic implementation framework. If compile and download the project to RT1060 EVK, it can enumerate a USB CDC VCOM device on USB1. If characters are send from CDC device, the project can send it out to DAPLink UART port so that you can see the character on a terminal interface in computer.
Step 4
To get USB HID mouse code, it need to create another USB HID project. The workflow is similar to the first project. Here is the screenshot of the USB HID configuration.
Click “Update code”, the HID mouse code will be generated. The config tool generate two files, usb_host_interface_0_hid_mouse.c and usb_host_interface_0_hid_mouse. Copy them to the “source” folder in dual host project.
Step 5
Next step is to modify some USB macro definitions.
<usb_host_config.h>
#define USB_HOST_CONFIG_EHCI 2 /*means there are two host instance*/
#define USB_HOST_CONFIG_MAX_HOST 2 /*The USB driver can support two ehci*/
#define USB_HOST_CONFIG_HID (1U) /*for mouse*/
Next step is merge usb_host_app.c. The project initialize USB hardware and software in USB_HostApplicationInit().
usb_status_t USB_HostApplicationInit(void)
{
usb_status_t status;
USB_HostClockInit(kUSB_ControllerEhci0);
USB_HostClockInit(kUSB_ControllerEhci1);
#if ((defined FSL_FEATURE_SOC_SYSMPU_COUNT) && (FSL_FEATURE_SOC_SYSMPU_COUNT))
SYSMPU_Enable(SYSMPU, 0);
#endif /* FSL_FEATURE_SOC_SYSMPU_COUNT */
status = USB_HostInit(kUSB_ControllerEhci0, &g_HostHandle[0], USB_HostEvent);
status = USB_HostInit(kUSB_ControllerEhci1, &g_HostHandle[1], USB_HostEvent); /*each usb instance have a g_HostHandle*/
if (status != kStatus_USB_Success)
{
return status;
} else {
USB_HostInterface0CicVcomInit();
USB_HostInterface0HidMouseInit();
}
USB_HostIsrEnable();
return status;
}
In USB_HostIsrEnable(), add code to enable USB2 interrupt.
irqNumber = usbHOSTEhciIrq[1];
NVIC_SetPriority((IRQn_Type)irqNumber, USB_HOST_INTERRUPT_PRIORITY);
EnableIRQ((IRQn_Type)irqNumber);
Then add and modify USB interrupt handler.
void USB_OTG1_IRQHandler(void)
{
USB_HostEhciIsrFunction(g_HostHandle[0]);
}
void USB_OTG2_IRQHandler(void)
{
USB_HostEhciIsrFunction(g_HostHandle[1]);
}
Since both USB instance share the USB stack, When USB event come, all the event will call USB_HostEvent() in usb_host_app.c. HID code should also be merged into this function.
static usb_status_t USB_HostEvent(usb_device_handle deviceHandle,
usb_host_configuration_handle
configurationHandle,
uint32_t eventCode)
{
usb_status_t status1;
usb_status_t status2;
usb_status_t status = kStatus_USB_Success;
/* Used to prevent from multiple processing of one interface;
* e.g. when class/subclass/protocol is the same then one interface on a device is processed only by one interface on host */
uint8_t processedInterfaces[USB_HOST_CONFIG_CONFIGURATION_MAX_INTERFACE] = {0};
switch (eventCode & 0x0000FFFFU)
{
case kUSB_HostEventAttach:
status1 = USB_HostInterface0CicVcomEvent(deviceHandle,
configurationHandle, eventCode, processedInterfaces);
status2 = USB_HostInterface0HidMouseEvent(deviceHandle,
configurationHandle, eventCode, processedInterfaces);
if ((status1 == kStatus_USB_NotSupported) && (status2 ==
kStatus_USB_NotSupported))
{
status = kStatus_USB_NotSupported;
}
break;
case kUSB_HostEventNotSupported:
usb_echo("Device not supported.\r\n");
break;
case kUSB_HostEventEnumerationDone:
status1 = USB_HostInterface0CicVcomEvent(deviceHandle,
configurationHandle, eventCode, processedInterfaces);
status2 = USB_HostInterface0HidMouseEvent(deviceHandle,
configurationHandle, eventCode, processedInterfaces);
if ((status1 != kStatus_USB_Success) && (status2 != kStatus_USB_Success))
{
status = kStatus_USB_Error;
}
break;
case kUSB_HostEventDetach:
status1 = USB_HostInterface0CicVcomEvent(deviceHandle,
configurationHandle, eventCode, processedInterfaces);
status2 = USB_HostInterface0HidMouseEvent(deviceHandle,
configurationHandle, eventCode, processedInterfaces);
if ((status1 != kStatus_USB_Success) && (status2 !=
kStatus_USB_Success))
{
status = kStatus_USB_Error;
}
break;
case kUSB_HostEventEnumerationFail:
usb_echo("Enumeration failed\r\n");
break;
default:
break;
}
return status;
}
USB_HostTasks() is used to deal with all the USB messages in the main loop. At last, HID work should also be added in this function.
void USB_HostTasks(void)
{
USB_HostTaskFn(g_HostHandle[0]);
USB_HostTaskFn(g_HostHandle[1]);
USB_HostInterface0CicVcomTask();
USB_HostInterface0HidMouseTask();
}
After all these steps, the dual USB function is ready. User can insert USB mouse and USB CDC device into any of the two USB port simultaneously.
Conclusion
All the RT/LPC/Kinetis devices with two OTG or HOST can support dual USB host. With the help of MCUXpresso Config Tool, it is easy to implement this function.
Hello @jingpan ,
Customer trying to use USB examp0le to set the USB#1 as host and USB#2 as device. While selecting the components in the Step 1, choose FreeRTOS instead of bare metal. In step 2 while choosing the preset its showing only the HID keyboard(baremetal) option and there is no option to choose the preset with the FreeRTOS support. Is it designed that way? How do to change to support FreeRTOS?
Also, while selecting the clock in step 1, when I enable the clock for USBPHY2_CLK, it gets set to 24 MHz. Is that ok?
Appreciate your advice.
Regards,
Audrey
Hi Jing,
When we follow the above steps to set up, there is a prompt: Only one host instance of the USB component is allowed in the configuration. There may be a problem with the setting somewhere. And the attachment of "rt1060_dual_usb_host.zip" is not complete. Can you help to update a completed example code? Thanks,
Claire
Hello,
I would like to implement the presented solution on MIMXRT1060-EVKB Board. In MIMXRT1060-EVKB Board User Manual, Rev. 0, 7 January 2022 I found this table:
I run few examples from SDK. I also I used Config Tool to manually add USB Host (USB1 or USB2). n all cases I can plug USB device only tothe J47 socket (and the device is powered). But when I plug device in socket J48 it is not working - it is not powered.
How can I enable 5V to the J48 socket and use this socket as USB Host?