This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

NRF52840 USB CDC Serial is missing first character when SOF = 2 and QUEUE_EN = 0 only

Hi,

The following code has been working fine since it was taken from the examples (NRF52840).

#include <stdint.h>
#include <string.h>
#include "nordic_common.h"
#include "nrf.h"
// #include "ble_hci.h"
// #include "ble_advdata.h"
// #include "ble_advertising.h"
// #include "ble_conn_params.h"
#include "nrf_sdh.h"
#include "nrf_sdh_soc.h"
#include "nrf_sdh_ble.h"
// #include "nrf_ble_gatt.h"
#include "app_timer.h"
// #include "ble_nus.h"
#include "app_uart.h"
#include "app_util_platform.h"
//#include "bsp_btn_ble.h"

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

#include "nrf_drv_usbd.h"
#include "nrf_drv_clock.h"
#include "nrf_gpio.h"
#include "nrf_delay.h"
#include "nrf_drv_power.h"

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


//#define LED_BLE_NUS_CONN (BSP_BOARD_LED_0)
//#define LED_BLE_NUS_RX   (BSP_BOARD_LED_1)
//#define LED_CDC_ACM_CONN (BSP_BOARD_LED_2)
//#define LED_CDC_ACM_RX   (BSP_BOARD_LED_3)

#define RECV_BUF_LEN 256

//#define ENDLINE_STRING "\r\n"



// BLE DEFINES START
#define APP_BLE_CONN_CFG_TAG            1                                           /**< A tag identifying the SoftDevice BLE configuration. */

#define APP_FEATURE_NOT_SUPPORTED       BLE_GATT_STATUS_ATTERR_APP_BEGIN + 2        /**< Reply when unsupported features are requested. */


#define DEAD_BEEF                       0xDEADBEEF                                  /**< Value used as error code on stack dump. Can be used to identify stack location on stack unwind. */


uint32_t buffer_available_idx = 0;


//#define LED_1          NRF_GPIO_PIN_MAP(0,13)
//#define LED_2          NRF_GPIO_PIN_MAP(0,14)


void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)
{
    app_error_handler(DEAD_BEEF, line_num, p_file_name);
}


// USB DEFINES START
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

static char m_cdc_data_array[RECV_BUF_LEN] = {0};

/** @brief CDC_ACM class instance */
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);

// USB DEFINES END
// USB CODE START
static bool m_usb_connected = false;


/** @brief User event handler @ref app_usbd_cdc_acm_user_ev_handler_t */
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);

    switch (event)
    {
        case APP_USBD_CDC_ACM_USER_EVT_PORT_OPEN:
        {
            /*Set up the first transfer*/
            ret_code_t ret = app_usbd_cdc_acm_read(&m_app_cdc_acm, m_cdc_data_array, 1); // necessary it seems
            break;
        }

        case APP_USBD_CDC_ACM_USER_EVT_PORT_CLOSE:
            //NRF_LOG_INFO("CDC ACM port closed");
            //nrf_gpio_pin_write(LED_1,1);
            break;

        case APP_USBD_CDC_ACM_USER_EVT_TX_DONE:
            app_usbd_cdc_acm_read_any(&m_app_cdc_acm, m_cdc_data_array, 1);

            break;

        case APP_USBD_CDC_ACM_USER_EVT_RX_DONE:
        {
            ret_code_t ret;

            do{
                    ret = app_usbd_cdc_acm_read(&m_app_cdc_acm, &m_cdc_data_array[buffer_available_idx++], 1);  
            }while (ret == NRF_SUCCESS);

            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:
            //NRF_LOG_INFO("USB power detected");

            if (!nrf_drv_usbd_is_enabled())
            {
                app_usbd_enable();
            }
            break;

        case APP_USBD_EVT_POWER_REMOVED:
        {

            m_usb_connected = false;
            app_usbd_stop();
        }
            break;

        case APP_USBD_EVT_POWER_READY:
        {

            m_usb_connected = true;
            app_usbd_start();
        }
            break;

        default:
            break;
    }
}


void usb_cdc_write123(char *str, uint16_t len){
    ret_code_t ret = app_usbd_cdc_acm_write(&m_app_cdc_acm, str,len);
}

void INIT_usb_cdc(){
            
    ret_code_t ret;
    static const app_usbd_config_t usbd_config = {
        .ev_state_proc = usbd_user_ev_handler
    };


    app_usbd_serial_num_generate();

    ret = nrf_drv_clock_init();
    APP_ERROR_CHECK(ret);

    //NRF_LOG_INFO("USBD BLE UART example started.");

    ret = app_usbd_init(&usbd_config);
    APP_ERROR_CHECK(ret);

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


            // SOFT DEVICE SHIAT
            ret_code_t err_code;
            err_code = nrf_sdh_enable_request();
            APP_ERROR_CHECK(err_code);
            // Configure the BLE stack using the default settings.
            // Fetch the start address of the application RAM.
            uint32_t ram_start = 0;
            err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
            APP_ERROR_CHECK(err_code);

            // Enable BLE stack.
            err_code = nrf_sdh_ble_enable(&ram_start);
            APP_ERROR_CHECK(err_code);

    ret = app_usbd_power_events_enable();
    APP_ERROR_CHECK(ret);
}

uint32_t usb_cdc_available(){
    return buffer_available_idx;
}

uint8_t usb_cdc_read(){
        char temp_buf[RECV_BUF_LEN] = {0};
        uint8_t bytey = m_cdc_data_array[0]; // if empty it will be \0
        memcpy(temp_buf, (m_cdc_data_array+1), RECV_BUF_LEN-1);
        memcpy(m_cdc_data_array, temp_buf, RECV_BUF_LEN);
        if (buffer_available_idx > 0)
            buffer_available_idx--;
        if (buffer_available_idx == 0)
            memset(m_cdc_data_array, 0, RECV_BUF_LEN);
        return bytey;
}

void SVC_usb_cdc(){
        // removed since we are using the interrupt method now
        // //while (app_usbd_event_queue_process())
        // //{
        //     /* Nothing to do */
        // //}
}

We wanted to remove the  app_usbd_event_queue_process() so we enabled these 2 options in the sdk_config.h (config file was also from the example)

APP_USBD_CONFIG_EVENT_QUEUE_ENABLE = 0
APP_USBD_CONFIG_SOF_HANDLING_MODE = 2

We now have 2 issues with the above code:

- One appeared immediately after turning ON the interrupt mode 2 and queue = 0. The first character was being lost on any size transmission. We tried many solutions but no result. The first received character always gets eaten. 

- The second issue is that some characters are being lost on more frequent, repetitive prints. We are happy to do more analysis for the second issue. We hope we can start by fixing issue 1.

Finally should we want to return back to using app_usbd_event_queue_process() if there is no solution, what are the implications when we want to go to sleep? Can we get awaken by a USB event and then service the queue? Any caveats? Is the interrupt way with no queue, better? 

Thanks!

Parents Reply Children
No Data
Related