USB driver for MK66 MCU (USB-HS device mode)

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

USB driver for MK66 MCU (USB-HS device mode)

Jump to solution
4,568 Views
edwinkaus
Contributor III

I am working on MK66FN2M0VLQ18 MCU in customized board.

I need to enumerate the MCU in USB device mode, I am using SDK_2.0_MK66FNM0xxx18 stack , in that if I use USB_DEVICE_CDC_VCOM the device is enumerated as virtual com port device.

>> Can I achieve 480Mbps(USB-HS) as com Port device.

Or Is there any example to enumerate device as normal Bulk USB device in that I need only control end point, Bulk IN and Bulk OUT endpoint. 

1 Solution
3,318 Views
isaacavila
NXP Employee
NXP Employee

Hello Edwin,

USB callbacks are needed to handle USB communication correctly. After enumeration has been done and setConfiguration command is received from Host, an USB event is received (USB_DEV_EVENT_CONFIG_CHANGED), after this event is received, USB VCOM example calls the USB_Class_CDC_Recv_Data API to receive data from Host:

    else if (event_type == USB_DEV_EVENT_CONFIG_CHANGED)
    {
        /* Schedule buffer for receive */
        USB_Class_CDC_Recv_Data(handle, DIC_BULK_OUT_ENDPOINT, g_curr_recv_buf, g_bulk_out_max_packet_size);
        start_app = TRUE;
    }

Then, program can do other thing and when data is finally received, another event is got: USB_DEV_EVENT_DATA_RECEIVED (it is handled on USB_App_Class_Callback)

case USB_DEV_EVENT_DATA_RECEIVED:
        {
        if ((start_app == TRUE) && (start_transactions == TRUE))
        {
            g_recv_size = *size;

            if (!g_recv_size)
            {
                /* Schedule buffer for next receive event */
                USB_Class_CDC_Recv_Data(handle, DIC_BULK_OUT_ENDPOINT, g_curr_recv_buf, g_bulk_out_max_packet_size);
            }
        }

Here you can get data from Host and process it.

On the other hand, for sending data, you can call USB_Class_CDC_Send_Data function in your main application and once data has been sent correctly, a new event is called (USB_DEV_EVENT_SEND_COMPLETE).

You have to be sure to complete any event (receive or send data) before calling a new receive/send API. In case that these procedures are not completed an you trigger a new request, these requests will be enqueued and, if more than 12 requests are enqueued, USB application will crash (there is only 12 spaces for these requests). So, be sure to complete every request before triggering a new one (reception needs to be completed before a new receive API is called, same for transmission, it needs to be completed before a new Send API is used).

Hope this helps!

Regards,
Isaac

View solution in original post

19 Replies
3,318 Views
isaacavila
NXP Employee
NXP Employee

Hello Edwin,

There is no a generic USB example that uses Bulk IN/OUT endpoints. (There is only a generic USB_HID_example for interrupt endpoints) You can use this VCOM example that uses one Interrupt endpoint (for configuring settings as line coding for the virtual com), one bulk out and one bulk in for receiving/sending data from/to USB host instead.


Also, as you already noticed, K66 includes an USB HS module and USB protocol defines its maximum transfer speed as 480 Mbps. Just remember that VCOM uses BULK endpoints that do not reserve guaranteed bandwith (as for Isochronous endpoints for example)

Hope this helps!

Regards,

Isaac

0 Kudos
Reply
3,318 Views
edwinkaus
Contributor III

Hai isaacavila.,

Thank you for your reply.

If I use VCOM example as per your suggestion USB speed will restricted to USB port bandwidth (which is not upto 480MBps), I want customize this example so that I can send & receive data through available Bulk end points and need to get USB-HS speed. and it should get enumerate as USB port device.

0 Kudos
Reply
3,318 Views
edwinkaus
Contributor III

Hi., 

correction in last reply:-  it shouldn't get enumerate as USB port device

0 Kudos
Reply
3,318 Views
isaacavila
NXP Employee
NXP Employee

Hello Edwin,

VCOM example in FRDM-K66F is configured to use High Speed mode so this can be detected as High-Speed Virtual COM (obviously, USB Host must support HS mode).

If you look at USB's initialization function, you will find this call:

if (kStatus_USB_Success != USB_DeviceClassInit(CONTROLLER_ID, &s_cdcAcmConfigList, &s_cdcVcom.deviceHandle))

CONTROLLER_ID is a macro that  defines the USB controller (KHCI, EHCI) used to configure the module. In this case, EHCI is used (Enhanced Host Controller Interface, which is the specification for USB 2.0 that defines USB High Speed):

#define CONTROLLER_ID kUSB_ControllerEhci0

So K66 is using its USB HS module and it can be detected as High speed device (HS VCOM device).

I hope this can help you!

Regards,
Isaac

3,318 Views
edwinkaus
Contributor III

Hai.,

Thank you reply.,

Here in APPTASK  s_recvSize is monitoring to know about data arriving, If some data sent from PC , does receive function automatically called??, or else Is there any receive status flag available.  

0 Kudos
Reply
3,318 Views
isaacavila
NXP Employee
NXP Employee

Hello Edwin,

It is managed by callbacks. You can refer to this post where it explains a little bit about how the VCOM example is built: https://community.nxp.com/thread/359149 

Hope this helps!

Regards,
Isaac

0 Kudos
Reply
3,318 Views
edwinkaus
Contributor III

Hello  isaacavila ..,

I am not using APPTASK function and also not required to implement VCOM call back functions, After enumeration has been done , I want schedule USB device to receive data from PC and need to process that message.

Could you please tell me how do receive some data from PC and sending data to PC. I need to use use simple receive & send function in main function. While sending data I can use send function directly that is not the issue, But if some data has sent from PC which event will occur first and how do I monitor that receiving status, and how to receive the data from endpoint to our buffer.

Hope you got my problem and help me soon. 

Regards,

Karthik

0 Kudos
Reply
3,319 Views
isaacavila
NXP Employee
NXP Employee

Hello Edwin,

USB callbacks are needed to handle USB communication correctly. After enumeration has been done and setConfiguration command is received from Host, an USB event is received (USB_DEV_EVENT_CONFIG_CHANGED), after this event is received, USB VCOM example calls the USB_Class_CDC_Recv_Data API to receive data from Host:

    else if (event_type == USB_DEV_EVENT_CONFIG_CHANGED)
    {
        /* Schedule buffer for receive */
        USB_Class_CDC_Recv_Data(handle, DIC_BULK_OUT_ENDPOINT, g_curr_recv_buf, g_bulk_out_max_packet_size);
        start_app = TRUE;
    }

Then, program can do other thing and when data is finally received, another event is got: USB_DEV_EVENT_DATA_RECEIVED (it is handled on USB_App_Class_Callback)

case USB_DEV_EVENT_DATA_RECEIVED:
        {
        if ((start_app == TRUE) && (start_transactions == TRUE))
        {
            g_recv_size = *size;

            if (!g_recv_size)
            {
                /* Schedule buffer for next receive event */
                USB_Class_CDC_Recv_Data(handle, DIC_BULK_OUT_ENDPOINT, g_curr_recv_buf, g_bulk_out_max_packet_size);
            }
        }

Here you can get data from Host and process it.

On the other hand, for sending data, you can call USB_Class_CDC_Send_Data function in your main application and once data has been sent correctly, a new event is called (USB_DEV_EVENT_SEND_COMPLETE).

You have to be sure to complete any event (receive or send data) before calling a new receive/send API. In case that these procedures are not completed an you trigger a new request, these requests will be enqueued and, if more than 12 requests are enqueued, USB application will crash (there is only 12 spaces for these requests). So, be sure to complete every request before triggering a new one (reception needs to be completed before a new receive API is called, same for transmission, it needs to be completed before a new Send API is used).

Hope this helps!

Regards,
Isaac

3,318 Views
edwinkaus
Contributor III

Helloisaacavila ..,

I used USB_VCOM example to analyze the code flow. 

Now I have customized the USB_moss storage (usb_device_msc_ramdisk) example as per our requirement.(It has two Bulk endpoints)

> configuration descriptors modified as

                                       #define USB_DEVICE_CLASS (0x00U)
                                       #define USB_DEVICE_SUBCLASS (0x00U)
                                       #define USB_DEVICE_PROTOCOL (0x00U)  

The device is has enumerated successfully with our customized PC side driver.

 once enumeration has been done and setConfiguration command is received from Host, there I am calling receive function,

 case kUSB_DeviceEventSetConfiguration:
            if (param)
               {
                   g_msc.attach = 1;
                   g_msc.currentConfiguration = *temp8;
                   if (USB_MSC_CONFIGURE_INDEX == (*temp8))
                      {
                                /* Schedule buffer for receive */ 
                          error = USB_DeviceRecvRequest(handle,USB_MSC_BULK_OUT_ENDPOINT,s_currRecvBuf,HS_MSC_BULK_IN_PACKET_SIZE);
                 if (kStatus_USB_Success != error)
                      { 
                         usb_echo("kUSB_Device receive error!");
                           }
                        }
                      }  

The receive request also placed successfully.

If I send some data from PC , its not receiving. I think once data has received kUSB_DeviceMscEventWriteResponse event should come, but not getting that event also.

suggest If any other modification has to be done.

Regards.,

Edwin

0 Kudos
Reply
3,318 Views
isaacavila
NXP Employee
NXP Employee

Hello Edwin,

How are your device being detected? How do you send data to device? are you able to use any USB analyzer to see if data is being sent correctly?

Regards

Isaac

0 Kudos
Reply
3,318 Views
edwinkaus
Contributor III

Hello  isaacavila.,

Sorry I got mistake that USB_DeviceRecvRequest has been placed successfully , but this function returns error. 

It detecting as USB bulk device, I am using USB analyzer(USBLYZER) to check device details, As per analyzer one control end point & two Bulk(IN & OUT) are available of size 512kb, also device got enumerated.

Now the issue is  USB_DeviceRecvRequest function returns error, This function i am calling from set configuration event.

 

Is there any functions available to send/receive data from PC. 

As per my studies 

usb_status_t USB_DeviceMscSend(usb_device_msc_struct_t *mscHandle)

usb_status_t USB_DeviceMscRecv(usb_device_msc_struct_t *mscHandle)

If I call this function , receive Request would placed with end point 0(control endpoint). 

 

Give me some clarity whether can I use this function with some modification, if so What what are things to modify.

Thank you..,

Regards .,

Edwin 

0 Kudos
Reply
3,318 Views
isaacavila
NXP Employee
NXP Employee

Hello Edwin,

I refered about how is your device being detected in your PC, as a Mass Storage disk or did you modify device descriptor?

When USB stack is initialized, it also intialize the device's class. This device class defines different protocols for every subclass (for MSD, there are different protocols that support different commands to communicate with device). Among these functions, a send/receive request is performed depending on the command (please check the usb_device_msc_ufi.c, USB_DeviceMscUfiThirteenCasesCheck function). After that, callback will receive the events:   kUSB_DeviceMscEventReadResponse, kUSB_DeviceMscEventWriteResponse, kUSB_DeviceMscEventWriteRequest, kUSB_DeviceMscEventReadRequest, etc. In summary,  MSD class calls the usb_status_t USB_DeviceMscRecv(usb_device_msc_struct_t *mscHandle);
usb_status_t USB_DeviceMscSend(usb_device_msc_struct_t *mscHandle);

functions to request/send data to host.

If you are receiving an error when you request for sending/receiving data, then probably you are trying to send/receive "raw" data and you are not properly following what MSD class specifies. what error are you receving from the USB_DeviceRecvRequest?

If you look at VCOM example (that also uses Bulk endpoints) you will see the  USB_DeviceCdcAcmRecv function that is used to request data from host.

I hope this can help you!

Regards,
isaac

0 Kudos
Reply
3,318 Views
edwinkaus
Contributor III

Hello  isaac.,

Yes I have modified device descriptors, its was not detecting as Mass storage disk.

Is there any modification has to be done in device class initialization, I got stuck here 

I am getting kStatus_USB_Error error.

0 Kudos
Reply
3,318 Views
isaacavila
NXP Employee
NXP Employee

Hello Edwin,

When USB is initialized, the USB_DeviceClassInit receives an strucute that makes reference to class being used:

    if (kStatus_USB_Success != USB_DeviceClassInit(CONTROLLER_ID, &msc_config_list, &g_msc.deviceHandle))

msc_config_list includes a g_UsbDeviceMscConfig structure:

/* USB device class information */
usb_device_class_config_struct_t msc_config[1] = {{
    USB_DeviceMscCallback, 0, &g_UsbDeviceMscConfig,
}};
/* USB device class configuraion information */
usb_device_class_config_list_struct_t msc_config_list = {
    msc_config, USB_DeviceCallback, 1,
};

And this structure has reference to MSD class:

usb_device_class_struct_t g_UsbDeviceMscConfig = {
    g_UsbDeviceMscInterfaceList, /* The interface list of the msc */
    kUSB_DeviceClassTypeMsc,     /* The msc class type */
    USB_CONFIGURE_COUNT,         /* The configuration count */
};

Error that you are seeing comes from USB_DeviceEhciTransfer function and this error can be caused by two conditions:

    if (0U == ehciState->qh[index].endpointStatusUnion.endpointStatusBitmap.isOpened)
    {
        return kStatus_USB_Error;
    }
    /* Return error when ehci is doing reset */
    if (ehciState->isResetting)
    {
        return kStatus_USB_Error;
    }

Have you tried to use an USB analyzer and check USB transactions?

I would expect that USB VCOM example could be easier to modify rather than USB MSD.

Regards,

Isaac

0 Kudos
Reply
3,318 Views
edwinkaus
Contributor III

Haii Isaac

Yea I tried to send some data , but it showing transaction failed.

Yes I can use USB VCOM example it has two bulk end points & one interrupt endpoint, but in my application its only needed two bulk endpoint.

Anyhow that is not problem I can proceed with USB VCOM example only, But before that I have to clarify somethings

In USB VCOM example

#define HS_CDC_VCOM_BULK_IN_PACKET_SIZE (64)
#define FS_CDC_VCOM_BULK_IN_PACKET_SIZE (64)
#define HS_CDC_VCOM_BULK_OUT_PACKET_SIZE (64)
#define FS_CDC_VCOM_BULK_OUT_PACKET_SIZE (64)

they have defined both FS & HS parameters as same size, Why they have taken same value, Can't we expect high speed with USB COM port device. What is maximum data rate we can get in USB VCOM example.

>> And Is there any data rate difference in USB moss storage & USB VCOM examples.

One more thing I have observed is Bulk end point size is 512Kb when I used USB moss storage example, but for USB VCOM example Bulk end point size is 64Kb which is same as USB full speed device. That is why I am in confusion.

Could You please track me how to proceed with. Either I can use USB moss storage example or else USB VCOM example.

Thank you.,

Regards.,

Edwin 
 

0 Kudos
Reply
3,318 Views
isaacavila
NXP Employee
NXP Employee

Hello Edwin,

VCOM uses bulk endpoints (as well as MSD) for sending/receiving data. For FS, bulk has a maximum packet size of 64 bytes, on HS, it can be up to 512 bytes. In this example, it is set to 64 but you can be set to 512 as well.

I hope this can help you!

Regards,

Isaac

3,318 Views
edwinkaus
Contributor III

Hello  isaacavila.,

As per discussion with our superior , they are not agreeing to use USB VCOM example.

>>Anyhow I have to use USB Mass storage example only, or otherwise Can please provide If any Custom class device example with only two bulk end point. 

In USB Mass storage example other then Descriptor changes nothing else to be change, because enumeration process is same for all the class device(except descriptor we have to pass),Also getting enumerated successfully. 

          usb_status_t USB_DeviceMscRecv(usb_device_msc_struct_t *mscHandle); 

                  What parameter I need pass while calling this function(*mscHandle?)

I am calling this function as : USB_DeviceMscRecv((usb_device_msc_struct_t*)(g_msc.mscHandle));

Is this the Correct way of calling this function.

Once I have Call this function , Receive request has successfully placed and return value is also "kStatus_USB_Success". But internally It calls the receive request on Endpoint 0(control endpoint), If I change this into Endpoint 3(Bulk out endpoint) its returning "kStatus_USB_Error".

How do I modify USB_DeviceMscRecv function so that I can call this function with Bulk out endpoint parameter.?

Thank you 

Regards 

Edwin

0 Kudos
Reply
3,318 Views
isaacavila
NXP Employee
NXP Employee

Hello Edwin,

USB_DeviceMscRecv function needs to receive an usb_device_msc_struct_t pointer which has information about the disk, such as Lba number, Lba length, logical unit number and other MSC-specific information, you you need to pass this information.

Edwin, it is important to understand that MSC does not work as if "disk can request/send data to host whenever it wants". The mass storage device's only task is to STORE BLOCKS OF DATA RECEIVED FROM HOST and SEND BLOCKS OF DATA REQUESTED BY HOST. In this case, there is no a "request receive" API for MSD, there is a function (callback) that is called everytime a request is received from host:

usb_status_t USB_DeviceMscCallback(class_handle_t handle, uint32_t event, void *param)
{
    usb_status_t error = kStatus_USB_Error;
    usb_device_lba_information_struct_t *lbaInformationStructure;
    usb_device_lba_app_struct_t *lbaData;

    switch (event)
    {
        case kUSB_DeviceMscEventReadResponse:
            lbaData = (usb_device_lba_app_struct_t *)param;
            break;
        case kUSB_DeviceMscEventWriteResponse:
            lbaData = (usb_device_lba_app_struct_t *)param;
            break;
        case kUSB_DeviceMscEventWriteRequest:
            lbaData = (usb_device_lba_app_struct_t *)param;
            /*offset is the write start address get from write command, refer to class driver*/
            lbaData->buffer = g_msc.storageDisk + lbaData->offset;
            break;
        case kUSB_DeviceMscEventReadRequest:
            lbaData = (usb_device_lba_app_struct_t *)param;
            /*offset is the read start address get from read command, refer to class driver*/
            lbaData->buffer = g_msc.storageDisk + lbaData->offset;
            break;
        case kUSB_DeviceMscEventGetLbaInformation:
            lbaInformationStructure = (usb_device_lba_information_struct_t *)param;
            lbaInformationStructure->lengthOfEachLba = LENGTH_OF_EACH_LBA;
            lbaInformationStructure->totalLbaNumberSupports = TOTAL_LOGICAL_ADDRESS_BLOCKS_NORMAL;
            lbaInformationStructure->logicalUnitNumberSupported = LOGICAL_UNIT_SUPPORTED;
            lbaInformationStructure->bulkInBufferSize = DISK_SIZE_NORMAL;
            lbaInformationStructure->bulkOutBufferSize = DISK_SIZE_NORMAL;
            break;
        case kUSB_DeviceMscEventFormatComplete:
            break;
        case kUSB_DeviceMscEventRemovalRequest:
            break;
        default:
            break;
    }
    return error;
}

And internally, in the MSC class's firmware, everything is already designed to attend this requests and exchange information as defined in MSC specifications:

MSC transactions.jpg

So, that is why you cannot find an API to request data being a MSD.

I recommended you to use VCOM example which has APIs to send/received data to/from Host. If you do not want to use this class VCOM (although VCOM uses 3 endpoints, INT endpoint is used to detect some changes on device's configuration, but you can exchange data using both IN and OUT bulk endpoints), you will need to create your vendor specific class and also create a driver from Host's point of view in order to implement the logic to exchange data between host and device.

I hope this can help you!

Regards,

Isaac

3,318 Views
edwinkaus
Contributor III

Hello isaacavila.,

Thank you so much for the help, Now I got clear picture on code flow. I will get back to you for any further issues. 

Regards

Edwin.,

0 Kudos
Reply