How to transfer data through EPOUT2 in usbd-custom-hid-ep example

Hi,

The example that I use is from here.

I have to use the USB interface to send and receive data between the host PC and the nRF52840 chip.

In the example, I can only send the data from the chip to the computer through EPIN2, but can not send the data from the computer to the chip through EPOUT2.

 • send the data from the chip to the computer

   Press Button 2 → send the data through EPIN2 → SUCCESS (the array that the chip sent shows on the Python terminal, and "transfer complete" shows on PUTTY)

     

 • send the data from the computer to the chip

   Input the data (I use RTT Viewer to send the data. But when I input the string, it shows the warning messages.) → FAIL

       

What should I do to let the data transfer successfully?

What function should I add to call the NRF_DRV_USBD_EVT_EPTRANSFER event to let the receive_custom_data() function work? 

static void usbd_event_handler(nrf_drv_usbd_evt_t const * const p_event)
{
    switch (p_event->type)
    {
    ...
    case NRF_DRV_USBD_EVT_EPTRANSFER:
        if (NRF_DRV_USBD_EPIN2 == p_event->data.eptransfer.ep)
        {
            NRF_LOG_INFO("EP2IN transfer complete");
        }
        else if (NRF_DRV_USBD_EPOUT2 == p_event->data.eptransfer.ep)
        {
            NRF_LOG_INFO("EP2OUT transfer complete");
            receive_custom_data();
        }
        ...
        break;
    ...
}

Parents
  • Hi 

    Would you be able to share your python script with me so I can test it on my end? 

    Have you tried to send exactly 64 bytes to see if that works? 
    As far as I recall I only tested the example with 64 byte packets, it might need some modifications to support any packet size. 

    Best regards
    Torbjørn

  • Hi Torbjørn,

    Would you be able to share your python script with me so I can test it on my end? 

    Sure! This is my pyUSB code.

    import usb.core
    import usb.util
    
    import threading
    
    def write_data(dev, ep):
        while True:
            try:
                to_board = input("")
                to_board = to_board + "\n"
                dev.write(ep.bEndpointAddress, to_board.encode())
                #dev.write(ep.bEndpointAddress, "abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz abcdefghi\n")
            except usb.core.USBError as e:
                data = None
                if e.args == ('Operation timed out',):
                    continue
    
    def read_data(dev, ep):
        while True:
            try:
                data = dev.read(ep.bEndpointAddress, ep.wMaxPacketSize)
                print(data)
            except usb.core.USBError as e:
                data = None
                if e.args == ('Operation timed out',):
                    continue
    
    def main():
        device = usb.core.find(idVendor=0x1915, idProduct=0x520B)
        '''
        for device in device:
            print(device)
        '''
        # use the first/default configuration
        device.set_configuration()
        # endpoint
        endpoint_in = device[0][(1,0)][0]
        endpoint_out = device[0][(1,0)][1]
        print(endpoint_in)
        print(endpoint_out)
        
        thread_r = threading.Thread(target=read_data, args = (device, endpoint_in))
        thread_r.start()
    
        thread_w = threading.Thread(target=write_data, args = (device, endpoint_out))
        thread_w.start()
        
    if __name__ == '__main__':
      main()
    

    Have you tried to send exactly 64 bytes to see if that works? 
    As far as I recall I only tested the example with 64 byte packets

    I didn't try it before getting your suggestion.

    Thanks to your suggestion, I tried sending 64-byte packets, then it works.

    it might need some modifications to support any packet size. 

    I need to modify the packet size so that the chip could receive the data from the computer regardless of the packet size.

    When the chip read the char '\n', then it has to transfer the packet through EPOUT2.

    But I can not find where the chip receives the packet to make the NRF_DRV_USBD_EVT_EPTRANSFER event called.

    So... Now I have another question: "Where should I modify the packet size in this example?"

    Best regards,

    Ning

  • Hi Ning

    What is the problem of just sending two 64 byte payloads and assembling them to a single 128 byte payload on the receiving side?

    You shouldn't need to change the USB libraries to implement this. 

    Best regards
    Torbjørn

  • Hi Torbjørn,

    Sorry for the late reply due to some peresonal reasons.

    You shouldn't need to change the USB libraries to implement this

    OK. I got it. Thank you so much for the answer.

    Recently I encountered a problem when testing the speed, when I transfer data through pyUSB, I could only get a 64,000 bits per second data rate, but I cannot reach the 64,000 bytes per second data rate of HID full speed.

    How could I get a higher data rate?

    Or...Will this problem improve if I use ISO EP instead? Because ISO EP can receive more bytes at one time, I think the data rate may be higher because of this reason.

    Best regards,

    Ning

  • Hi Ning

    This sounds like an issue with the bInterval setting in the endpoint descriptor, as shown here

    In my example this was set to 8, which will limit the polling interval to 8ms. 

    If you set this to 1 instead you should be able to send a packet every millisecond.

    Best regards
    Torbjørn

  • Hi Torbjørn,

    If you set this to 1 instead you should be able to send a packet every millisecond.

    After I set this parameter to 1, I could get the same speed as HID full speed(64,000 bytes per second).

    Thanks for the answer. It is helpful.

    Because HID defines the (interrupt) endpoint polling rate in the endpoint descriptor, the minimum is 1 ms. I can't change the parameter to less than 1 ms to get a higher data rate.

    So I searched online to confirm if I could use this example to get a higher data rate than HID full speed.

    Then I found this page. The questioner mentioned that he read in another post in the forum said the USB examples could achieve 8,184 Mbps. (I think he means 8.184Mbps.)

    Could the program that I used achieve such a high data rate? Or it can be higher than HID full speed is fine. (More than 2 Mbps is better.)

    What method should I use to achieve it?

    Best regards,

    Ning

  • Hi Ning

    You should be able to get a higher speed if you use a different USB class, such as CDC or MSC. 

    We have done some testing internally to evaluate the transfer speed using these classes, and got the following results:

    MSC write zeros to an empty drive (Linux): 513 kB/s (4104 kbit/s)

    CDC ACM binary file transfer (Linux): 323 kB/s (2584 kbit/s)
    CDC ACM binary file transfer (Windows): 215 kB/s (1720 kbit/s)

    I don't know where the 8Mbps number comes from, but keep in mind that if you use an isochronous endpoint you are not guaranteed to have all the data come through, and you would have to accept a certain amount of packet loss. 

    Best regards
    Torbjørn

Reply
  • Hi Ning

    You should be able to get a higher speed if you use a different USB class, such as CDC or MSC. 

    We have done some testing internally to evaluate the transfer speed using these classes, and got the following results:

    MSC write zeros to an empty drive (Linux): 513 kB/s (4104 kbit/s)

    CDC ACM binary file transfer (Linux): 323 kB/s (2584 kbit/s)
    CDC ACM binary file transfer (Windows): 215 kB/s (1720 kbit/s)

    I don't know where the 8Mbps number comes from, but keep in mind that if you use an isochronous endpoint you are not guaranteed to have all the data come through, and you would have to accept a certain amount of packet loss. 

    Best regards
    Torbjørn

Children
  • Hi Torbjørn,

    You should be able to get a higher speed if you use a different USB class, such as CDC or MSC. 

    I'd used CDC and PySerial(in Python) before. But I want to transfer the data through the endpoint directly but not through the virtual COM port. So I tried to use HID and PyUSB(in Python) to implement my project.

    if you use an isochronous endpoint you are not guaranteed to have all the data come through, and you would have to accept a certain amount of packet loss. 

    If reliability is not considered, is it possible to use an isochronous endpoint to get a higher data rate than CDC?

    Best regards,

    Ning

  • Hi Ning

    425Ning said:
    If reliability is not considered, is it possible to use an isochronous endpoint to get a higher data rate than CDC?

    Isochronous endpoints essentially give you a guaranteed and stable data rate, but without the guarantee that all the packets are received. The main use case for this is audio or video streaming where it is more important to keep latency low and throughput stable, rather than make sure that all the data is successfully transmitted. 

    Our examples only use isochronous endpoints for CD quality audio, so we haven't really tried to push the data rates to the limit. 

    Best regards
    Torbjørn

Related