This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

USB COM CDC on android

Hi everyone!

I have recently implemented USB CDC on a custom NRF52840 device with SDK 15.0 and got it to work with Windows, Mac, and Linux OS. However, when I try it on an Android device I can't seem to get it to connect and send/receive any data. I can see the device by using any USB serial terminal application available on play store, such as,  Serial terminal or USB Serial terminal. The device appears in the list and can see the correct PID/VID, but as I establish a connection with the device I receive an error that the controlTransfer failed, can't seem to find anything about this error somewhere when searching on android forums.

My question is whether I have to do anything in the software to enable the device to communicate with an Android device? It is working without any problems on all other operative systems that I have tried on but not on Android devices. Have also tried different adapters and three different Android devices and all show the same error. 

I really appreciate any help I could get

Best regards

Hadi

  • UPDATE:

    I tested the original USBD CDC ACM example and seem to work, but the application that I have made does not work with Android. When comparing the two applications, the only difference in the code is that I had not added nrf_drv_clock_init, app_usbd_power_events_enable, and some of the defines related to nrf power are set to 0. I tried to add these and change the defines but the application fail during init of the usbd

    When calling nrf_drv_clock_init, I get <error> app: Fatal error

    If I am using a softdevice should I still call nrf_Drv_clock_init?

    I have also these configurations in sdk config, could this be the cause of the application failing?

    // <0=> NRF_CLOCK_LF_SRC_RC 
    // <1=> NRF_CLOCK_LF_SRC_XTAL 
    // <2=> NRF_CLOCK_LF_SRC_SYNTH 
    
    #ifndef NRF_SDH_CLOCK_LF_SRC
    #define NRF_SDH_CLOCK_LF_SRC 1
    #endif
    
    // <o> NRF_SDH_CLOCK_LF_RC_CTIV - SoftDevice calibration timer interval. 
    #ifndef NRF_SDH_CLOCK_LF_RC_CTIV
    #define NRF_SDH_CLOCK_LF_RC_CTIV 0
    #endif
    
    // <o> NRF_SDH_CLOCK_LF_RC_TEMP_CTIV - SoftDevice calibration timer interval under constant temperature. 
    // <i> How often (in number of calibration intervals) the RC oscillator shall be calibrated
    // <i>  if the temperature has not changed.
    
    #ifndef NRF_SDH_CLOCK_LF_RC_TEMP_CTIV
    #define NRF_SDH_CLOCK_LF_RC_TEMP_CTIV 0
    #endif
    
    // <o> NRF_SDH_CLOCK_LF_ACCURACY  - External clock accuracy used in the LL to compute timing.
     
    // <0=> NRF_CLOCK_LF_ACCURACY_250_PPM 
    // <1=> NRF_CLOCK_LF_ACCURACY_500_PPM 
    // <2=> NRF_CLOCK_LF_ACCURACY_150_PPM 
    // <3=> NRF_CLOCK_LF_ACCURACY_100_PPM 
    // <4=> NRF_CLOCK_LF_ACCURACY_75_PPM 
    // <5=> NRF_CLOCK_LF_ACCURACY_50_PPM 
    // <6=> NRF_CLOCK_LF_ACCURACY_30_PPM 
    // <7=> NRF_CLOCK_LF_ACCURACY_20_PPM 
    // <8=> NRF_CLOCK_LF_ACCURACY_10_PPM 
    // <9=> NRF_CLOCK_LF_ACCURACY_5_PPM 
    // <10=> NRF_CLOCK_LF_ACCURACY_2_PPM 
    // <11=> NRF_CLOCK_LF_ACCURACY_1_PPM 
    
    #ifndef NRF_SDH_CLOCK_LF_ACCURACY
    #define NRF_SDH_CLOCK_LF_ACCURACY 7
    #endif

  • If I am using a softdevice should I still call nrf_Drv_clock_init?

    The driver nrf_drv_clock should handle that fine, as long as you have the SOFTDEVICE_PRESENT preprocessor define. My guess is that you are getting the NRF_ERROR_MODULE_ALREADY_INITIALIZED error. If you want BLE+USBD CDC ACM, you should take a look at the usbd_ble_uart example. (PS; If you are on SDK 15.0, take look at this post.)

    When calling nrf_drv_clock_init, I get <error> app: Fatal error

    Add DEBUG as preprocessor define, and the error-code should be printed instead. If you are using SES, you only need to set the build configuration to "Debug".

  • Thank you for your help!

    Yes exactly, sorry forgot to mention that we are using BLE+Composite(CDC+HID) together.

    PS; If you are on SDK 15.0, take look at this post.)

    I looked in the file and it seems that this is already changed to 0x20 as it should be.

    I have added the preprocessor flag to my makefile and compiled it but do not get the fatal error print anymore, but seem like it still is stuck at the same place as it is not continuing. 

    UPDATE:

    Tried with segger instead and get the following error in nrf_drv_power (DEADBEEF):

    <error> app: ERROR 3735928559 [Unknown error code] at /home/dek/bitbucket/nRF52_DK/sdk/nRF5_SDK_15.0.0_a53641a/integration/nrfx/legacy/nrf_drv_power.c:352
    PC at: 0x0003A403
    <error> app: End of error report
    

    Seem like it is failing on this step according to the error above: ASSERT(m_initialized); /* This module has to be enabled first */

    Seem like the error is triggered when changing the values in sdk_config, it is not triggered from nrf_drv_clock or app_usbd_power_events_enable fucntion call. Am I missing something when changing the POWER_ENABLE, APP_USBD_CONFIG_POWER_EVENTS_PROCESS, etc.. in sdk_config???

    UPDATE 2:

    Further debugging with segger shows that the application fails at this step:

    sdh_state_observer_notify(NRF_SDH_EVT_STATE_ENABLED);

    Is it RAM that has to be increased?

    /* Linker script to configure memory regions.  */
    
    SEARCH_DIR(.)
    GROUP(-lgcc -lc -lnosys)
    
    MEMORY
    {
      FLASH (rx) : ORIGIN = 0x26000, LENGTH = 0xda000
      RAM (rwx) :  ORIGIN = 0x20005290, LENGTH = 0x10000
    }
    
    SECTIONS
    {
    }
    
    SECTIONS
    {
      . = ALIGN(4);
      .mem_section_dummy_ram :
      {
      }
      .cli_sorted_cmd_ptrs :
      {
        PROVIDE(__start_cli_sorted_cmd_ptrs = .);
        KEEP(*(.cli_sorted_cmd_ptrs))
        PROVIDE(__stop_cli_sorted_cmd_ptrs = .);
      } > RAM
      .fs_data :
      {
        PROVIDE(__start_fs_data = .);
        KEEP(*(.fs_data))
        PROVIDE(__stop_fs_data = .);
      } > RAM
      .log_dynamic_data :
      {
        PROVIDE(__start_log_dynamic_data = .);
        KEEP(*(SORT(.log_dynamic_data*)))
        PROVIDE(__stop_log_dynamic_data = .);
      } > RAM
    
    } INSERT AFTER .data;
    
    SECTIONS
    {
      .mem_section_dummy_rom :
      {
      }
      .sdh_ble_observers :
      {
        PROVIDE(__start_sdh_ble_observers = .);
        KEEP(*(SORT(.sdh_ble_observers*)))
        PROVIDE(__stop_sdh_ble_observers = .);
      } > FLASH
      .sdh_soc_observers :
      {
        PROVIDE(__start_sdh_soc_observers = .);
        KEEP(*(SORT(.sdh_soc_observers*)))
        PROVIDE(__stop_sdh_soc_observers = .);
      } > FLASH
      .sdh_state_observers :
      {
        PROVIDE(__start_sdh_state_observers = .);
        KEEP(*(SORT(.sdh_state_observers*)))
        PROVIDE(__stop_sdh_state_observers = .);
      } > FLASH
      .sdh_stack_observers :
      {
        PROVIDE(__start_sdh_stack_observers = .);
        KEEP(*(SORT(.sdh_stack_observers*)))
        PROVIDE(__stop_sdh_stack_observers = .);
      } > FLASH
      .sdh_req_observers :
      {
        PROVIDE(__start_sdh_req_observers = .);
        KEEP(*(SORT(.sdh_req_observers*)))
        PROVIDE(__stop_sdh_req_observers = .);
      } > FLASH
        .nrf_queue :
      {
        PROVIDE(__start_nrf_queue = .);
        KEEP(*(.nrf_queue))
        PROVIDE(__stop_nrf_queue = .);
      } > FLASH
        .nrf_balloc :
      {
        PROVIDE(__start_nrf_balloc = .);
        KEEP(*(.nrf_balloc))
        PROVIDE(__stop_nrf_balloc = .);
      } > FLASH
        .cli_command :
      {
        PROVIDE(__start_cli_command = .);
        KEEP(*(.cli_command))
        PROVIDE(__stop_cli_command = .);
      } > FLASH
      .crypto_data :
      {
        PROVIDE(__start_crypto_data = .);
        KEEP(*(SORT(.crypto_data*)))
        PROVIDE(__stop_crypto_data = .);
      } > FLASH
      .pwr_mgmt_data :
      {
        PROVIDE(__start_pwr_mgmt_data = .);
        KEEP(*(SORT(.pwr_mgmt_data*)))
        PROVIDE(__stop_pwr_mgmt_data = .);
      } > FLASH
      .log_const_data :
      {
        PROVIDE(__start_log_const_data = .);
        KEEP(*(SORT(.log_const_data*)))
        PROVIDE(__stop_log_const_data = .);
      } > FLASH
    
    } INSERT AFTER .text
    
    INCLUDE "nrf_common.ld"

  • Hi,

    I have went further with debugging the application and can't seem to get it to work. I have a question regarding  how to get it to communicate with an Android device.

    Do I need to init nrf_drv_clock and enable power event handler in order to connect to device on android? 

    Currently I run these two functions after I have initialized usbd_init:

    app_usbd_enable();
    app_usbd_start();

    But the custom board can't connect to my android device

    UPDATE:

    I found the problem !

    Somehow the defined interface for the HID and CDC was not valid, had to change them to:

    /**
     * @brief USB cdc interfaces
     */
    
    #define CDC_ACM_COMM_INTERFACE  0
    #define CDC_ACM_COMM_EPIN       NRF_DRV_USBD_EPIN2
    
    #define CDC_ACM_DATA_INTERFACE  1
    #define CDC_ACM_DATA_EPIN       NRF_DRV_USBD_EPIN1
    #define CDC_ACM_DATA_EPOUT      NRF_DRV_USBD_EPOUT1
    
    /**
     * @brief USB composite interfaces
     */
    #define APP_USBD_INTERFACE_KBD   3
    #define HID_COMM_EPIN NRF_DRV_USBD_EPIN3

    /Hadi

Related