Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

Add CDC class to the USB Device Example

I am developing a USB keyboard + mouse using a NRF52833. I have use the USB Device Example from nRF5 SDK v17.1.0. I chose this example because my project is in C++ and had problems compiling the USB HID Composite Example regarding to "designator order for field 'app_usbd_hid_inst_t::p_hid_methods' does not match declaration order in 'app_usbd_hid_inst_t'".

I have implemented the keyboard + mouse HID to my project since the original example only works as a mouse. Now I need to add the CDC class to have a serial com port, any suggestions or examples on how to do it?

  • Update. I have been able to compile the USB HID Composite Example in C++ and the computer correctly recognizes it as keyboard + mouse. Now I need to add CDC class to have serial port as well.

  • Hi,

     

    driverGuy said:
    Update. I have been able to compile the USB HID Composite Example in C++ and the computer correctly recognizes it as keyboard + mouse. Now I need to add CDC class to have serial port as well.

    That is good news.

     

    Unfortunately, we do not have any example that combines CDC_ACM directly with other usb classes, but the project that you are currently working with has two HID classes in one project.

    You'll have to perform similar steps as done in this sample to add the usbd_cdc_acm into your project.

     

    Kind regards,

    Håkon

  • I was able to add the CDC class with the USB device library from SDK 17.1.0 it works fine.

    Now I need some way to send the USB reports to the computer myself since the functions provided by the API only allow me to send single letters. Is there any way of doing this?

    With the legacy USB driver I used the nrfx_usbd_ep_transfer() function and everything worked fine.

  • I am not sure what you mean by sending single letters. Both _read and _write functions have the ability to provide a size.

    To send data from the device to the host, you can use the function "app_usbd_cdc_acm_write()".

    For reading, you can use the function "app_usbd_cdc_acm_read()"

     

    Kind regards,

    Håkon

  • I'm sorry, I think I didn't express myself well, I was referring to sending the USB HID report of the keyboard as I did with the legacy driver, anyway I was able to solve the problem.

    Now I am having problems with the CDC class, it does not receive the first Byte. I've seen this problem come up several times on the forum but I still can't fix it. This is my code, I am using the nRF5 SDK v17.1.0:

    void usb_cdc_ev_handler(app_usbd_class_inst_t const *p_inst, app_usbd_cdc_acm_user_event_t event)
    {
        app_usbd_cdc_acm_t const * p_cdc_acm = app_usbd_cdc_acm_class_get(p_inst);
    
        switch (event)
        {
            case APP_USBD_CDC_ACM_USER_EVT_PORT_OPEN:
                NRF_LOG_INFO("USB serial port open");
    
                uint32_t n = app_usbd_cdc_acm_bytes_stored(p_cdc_acm);
                NRF_LOG_INFO("Bytes waiting: %d", n);
                NRF_LOG_FLUSH();
    
                /*
                    Setup first transfer.
                    If it does not do this, no Bytes can be received later.
                */
                app_usbd_cdc_acm_read(&serial_cdc_class, serial_rx_buffer, 1);
                break;
    
            case APP_USBD_CDC_ACM_USER_EVT_PORT_CLOSE:
                NRF_LOG_INFO("USB serial port close");
                NRF_LOG_FLUSH();
                break;
    
            case APP_USBD_CDC_ACM_USER_EVT_TX_DONE:
                /*NRF_LOG_INFO("Tx done");
                NRF_LOG_FLUSH();*/
                break;
    
            case APP_USBD_CDC_ACM_USER_EVT_RX_DONE:
                {     
                    NRF_LOG_INFO(" ");                          
                    NRF_LOG_INFO("---- New Rx ----------------------");
                    
                    uint32_t n = app_usbd_cdc_acm_bytes_stored(p_cdc_acm);
                    NRF_LOG_INFO("Bytes waiting: %d", n);
                    NRF_LOG_INFO("----");
                    
                    ret_code_t ret;
                    num_bytes = 0;
                    do
                    {
                        n = app_usbd_cdc_acm_rx_size(p_cdc_acm);
                        NRF_LOG_INFO("app_usbd_cdc_acm_rx_size() = %d", n);
     
                        ret = app_usbd_cdc_acm_read(&serial_cdc_class, &serial_rx_buffer[num_bytes], 1);
                        /*
                            ret = 0   -> NRF_SUCCESS
                            ret = 146 -> NRF_ERROR_IO_PENDING
                        */
                        char _ret[30];
                        if (ret == NRF_SUCCESS)
                        {
                            strcpy(_ret, "NRF_SUCCESS");
                        }
                        else if (ret == NRF_ERROR_IO_PENDING)
                        {
                            strcpy(_ret, "NRF_ERROR_IO_PENDING");
                        }
                        else if (ret == NRF_ERROR_BUSY)
                        {
                            strcpy(_ret, "NRF_ERROR_BUSY");
                        }
                        else
                        {
                            strcpy(_ret, "OTHER");
                        }
                        NRF_LOG_INFO("ret = %d -> %s", ret, _ret);
                        NRF_LOG_INFO("serial_rx_buffer[%d] = (int)%d -> (char)%c", num_bytes, serial_rx_buffer[num_bytes], serial_rx_buffer[num_bytes]);
                        NRF_LOG_INFO("----");
                        NRF_LOG_FLUSH();
    
                        num_bytes++;
                    } while (ret == NRF_SUCCESS);  // Fetch data until internal buffer is empty.
                }
                break;
    
            default:
                break;
        }
    }

    And this is the log screen when I send "123" from another serial terminal:

    <info> app: USB serial port open
    
    <info> app: Bytes waiting: 0
    
    <info> app:  
    
    <info> app: ---- New Rx ----------------------
    
    <info> app: Bytes waiting: 2
    
    <info> app: ----
    
    <info> app: app_usbd_cdc_acm_rx_size() = 1
    
    <info> app: ret = 0 -> NRF_SUCCESS
    
    <info> app: serial_rx_buffer[0] = (int)50 -> (char)2
    
    <info> app: ----
    
    <info> app: app_usbd_cdc_acm_rx_size() = 1
    
    <info> app: ret = 0 -> NRF_SUCCESS
    
    <info> app: serial_rx_buffer[1] = (int)51 -> (char)3
    
    <info> app: ----
    
    <info> app: app_usbd_cdc_acm_rx_size() = 1
    
    <info> app: ret = 146 -> NRF_ERROR_IO_PENDING
    
    <info> app: serial_rx_buffer[2] = (int)0 -> (char)
    
    <info> app:  
    
    <info> app: ---- New Rx ----------------------
    
    <info> app: Bytes waiting: 2
    
    <info> app: ----
    
    <info> app: app_usbd_cdc_acm_rx_size() = 1
    
    <info> app: ret = 0 -> NRF_SUCCESS
    
    <info> app: serial_rx_buffer[0] = (int)50 -> (char)2
    
    <info> app: ----
    
    <info> app: app_usbd_cdc_acm_rx_size() = 1
    
    <info> app: ret = 0 -> NRF_SUCCESS
    
    <info> app: serial_rx_buffer[1] = (int)51 -> (char)3
    
    <info> app: ----
    
    <info> app: app_usbd_cdc_acm_rx_size() = 1
    
    <info> app: ret = 146 -> NRF_ERROR_IO_PENDING
    
    <info> app: serial_rx_buffer[2] = (int)49 -> (char)1
    
    <info> app: ----
    
    <info> app:  
    
    <info> app: ---- New Rx ----------------------
    
    <info> app: Bytes waiting: 2
    
    <info> app: ----
    
    <info> app: app_usbd_cdc_acm_rx_size() = 1
    
    <info> app: ret = 0 -> NRF_SUCCESS
    
    <info> app: serial_rx_buffer[0] = (int)50 -> (char)2
    
    <info> app: ----
    
    <info> app: app_usbd_cdc_acm_rx_size() = 1
    
    <info> app: ret = 0 -> NRF_SUCCESS
    
    <info> app: serial_rx_buffer[1] = (int)51 -> (char)3
    
    <info> app: ----
    
    <info> app: app_usbd_cdc_acm_rx_size() = 1
    
    <info> app: ret = 146 -> NRF_ERROR_IO_PENDING
    
    <info> app: serial_rx_buffer[2] = (int)49 -> (char)1
    
    <info> app: ----

    You can see that on the first try it only receives "23" and then the null character when ret == NRF_ERROR_IO_PENDING.
    On subsequent attempts it always receive "231".

    It's weird that the app_usbd_cdc_acm_bytes_stored() function always returns 2 Bytes when actually I'm sending 3 Bytes.

    I have also tried with app_usbd_cdc_acm_read_any() getting the same result.

Related