Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

[NRF5 SDK] Usbd_cdc_acm : port not reappear after device reboot

Hi,

I have setup a device with usbd_cdc_acm to communicate with a computer throw usb port.

First, when the device boot up and the usbd init, all works fine and the device appear in the device manager and I can communicate with it (COM12).

However, during the life cycle of my board, I need to reboot it for some reason from the firmware code. The reboot works correctly but after the usbd initialization, the device don't appear anymore on my computer and I'm not able to communicate with it throw the usb serial port. To make the device reappear, I need to power down and then power up my board.

So how can I properly reopen the serial port ?

My code for usbd_cdc_acm :

#include "usbd_controller.h"

#include "app_usbd.h"
#include "app_usbd_core.h"
#include "app_usbd_cdc_acm.h"
#include "app_usbd_serial_num.h"
#include "app_usbd_string_desc.h"

#include "nrf_log.h"
#include "serial_process.h"

static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const * p_inst, app_usbd_cdc_acm_user_event_t event);

#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

APP_USBD_CDC_ACM_GLOBAL_DEF(m_app_cdc_acm,
                            cdc_acm_user_ev_handler,
                            CDC_ACM_COMM_INTERFACE,
                            CDC_ACM_DATA_INTERFACE,
                            CDC_ACM_COMM_EPIN,
                            CDC_ACM_DATA_EPIN,
                            CDC_ACM_DATA_EPOUT,
                            APP_USBD_CDC_COMM_PROTOCOL_AT_V250
);

#define READ_SIZE 1
static char m_rx_buffer[READ_SIZE];
static char m_tx_buffer[NRF_DRV_USBD_EPSIZE];

static void cdc_acm_user_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);

  static int cmd_receive = 0;
  static uint8_t byte_receive = 0;

  switch (event)
  {
    case APP_USBD_CDC_ACM_USER_EVT_PORT_OPEN:
    {
      ret_code_t ret = app_usbd_cdc_acm_read(&m_app_cdc_acm, m_rx_buffer, READ_SIZE);
      UNUSED_VARIABLE(ret);
      break;
    }
    case APP_USBD_CDC_ACM_USER_EVT_PORT_CLOSE:
      break;
    case APP_USBD_CDC_ACM_USER_EVT_TX_DONE:
      break;
    case APP_USBD_CDC_ACM_USER_EVT_RX_DONE:
    {
      ret_code_t ret;
    
      do
      {
        do
        {
          ret = app_usbd_cdc_acm_read(&m_app_cdc_acm, m_rx_buffer, READ_SIZE);
        } while (ret == NRF_SUCCESS);

        memcpy(m_tx_buffer,m_rx_buffer,READ_SIZE);
        serial_receive_byte(m_tx_buffer[0]);
      } while(app_usbd_cdc_acm_bytes_stored(p_cdc_acm) > 0);

      break;
    }
    default:
      break;
  }
}

static void usbd_user_ev_handler(app_usbd_event_type_t event)
{
  switch (event)
  {
    case APP_USBD_EVT_DRV_SUSPEND:
      break;
    case APP_USBD_EVT_DRV_RESUME:
      break;
    case APP_USBD_EVT_STARTED:
      break;
    case APP_USBD_EVT_STOPPED:
      app_usbd_disable();
      break;
    case APP_USBD_EVT_POWER_DETECTED:
      if (!nrf_drv_usbd_is_enabled())
      {
        app_usbd_enable();
      }
      break;
    case APP_USBD_EVT_POWER_REMOVED:
      app_usbd_stop();
      break;
    case APP_USBD_EVT_POWER_READY:
      app_usbd_start();
      break;
    default:
        break;
  }
}

void usbd_init(void)
{
  static const app_usbd_config_t usbd_config = {
    .ev_state_proc = usbd_user_ev_handler
  };

  app_usbd_init(&usbd_config);

  app_usbd_class_inst_t const * class_cdc_acm = app_usbd_cdc_acm_class_inst_get(&m_app_cdc_acm);
  app_usbd_class_append(class_cdc_acm);

  app_usbd_enable();
  app_usbd_start();
  NRF_LOG_INFO("Usbd initialized");
}

void process_usbd_queue(void)
{
  while (app_usbd_event_queue_process()) {}
}

void send_usbd_datas(uint8_t* datas, uint16_t length)
{
  app_usbd_class_inst_t const * class_cdc_acm = app_usbd_cdc_acm_class_inst_get(&m_app_cdc_acm);
  app_usbd_cdc_acm_write(class_cdc_acm, datas, length);
}

My main :

#include <stdint.h>
#include <string.h>
#include "nrf.h"
#include "nordic_common.h"

#include "app_timer.h"
#include "app_scheduler.h"
#include "app_util_platform.h"

#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"

#include "serial/usbd_controller.h"

APP_TIMER_DEF(m_process_timer);

// Initialize the nrf log module
static void log_init(void)
{
    ret_code_t err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);
    NRF_LOG_DEFAULT_BACKENDS_INIT();
}

// Initialize the usb connection
static void usb_init(void)
{
  usbd_init();
}

// Handle the idle state (main loop)
static void idle_state_handle(void)
{
    UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
}

// App timer process execution
static void timer_process(void * p_context)
{
  
}

// Application main function
int main(void)
{
    // Initialize logs
    log_init();

    // Initialize timer and power manager
    app_timer_init();
    nrf_drv_clock_init();
    nrf_drv_clock_lfclk_request(NULL);

    // Initialize uart and serial
    usb_init();

    // Start timer
    app_timer_create(&m_process_timer, APP_TIMER_MODE_REPEATED, timer_process);
    app_timer_start(m_process_timer, APP_TIMER_TICKS(100), NULL);

    // Enter main loop
    for (;;)
    {
      (void)process_usbd_queue();
      (void)idle_state_handle();
    }
}

Regards

Used sdk version : 17.0.2

Related