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

Serial port on the nRF52840 Dongle

Hi I am trying to init the serial on the nRF52840 Dongle but there are some defines missing in the boards/pca10069.h

I run this on the nRF52840 DK and it works fine.

NRF_SERIAL_DRV_UART_CONFIG_DEF(m_uart0_drv_config,
    RX_PIN_NUMBER, TX_PIN_NUMBER,
    RTS_PIN_NUMBER, CTS_PIN_NUMBER,
    NRF_UART_HWFC_ENABLED, NRF_UART_PARITY_EXCLUDED,
    NRF_UART_BAUDRATE_115200,
    UART_DEFAULT_CONFIG_IRQ_PRIORITY);

file: boards/pca10056.h

#define RX_PIN_NUMBER  8
#define TX_PIN_NUMBER  6
#define CTS_PIN_NUMBER 7
#define RTS_PIN_NUMBER 5
#define HWFC           true

Parents Reply
  • Hi,

    I'm interested in doing something similar to the original question here with an nRF52840 Dongle where I'd like to stream data over the dongle's USB connection and read it from a computer via /dev/ttyACMx. I've tried to compile the usbd_cdc_acm example to use as a template but it seems to rely on TX_PIN_NUMBER and RX_PIN_NUMBER constants that aren't defined for pca10059.

    Is this kind of setup possible with pca10059? Is usbd_cdc_acm the right example to use (it doesn't have a pca10059 subfolder)?

Children
  • This works for both my dev board and the dongle.

    #include <stdlib.h>
    
    #include "zboss_api.h"
    #include "sdk_config.h"
    
    #include "app_usbd.h"
    #include "app_usbd_cdc_acm.h"
    #include "app_usbd_serial_num.h"
    //#include "app_usbd_string_desc.h"
    
    #include "boards.h"
    #include "serial_handler.h"
    
    /**
     * @brief Enable power USB detection
     *
     * Configure if example supports USB port connection
     */
    #ifndef USBD_POWER_DETECTION
    #define USBD_POWER_DETECTION true
    #endif
    
    static zb_uint8_t tx = 0;
    
    static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const * p_inst, app_usbd_cdc_acm_user_event_t event);
    static void usbd_user_ev_handler(app_usbd_event_type_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
    
    
    /**
     * @brief CDC_ACM class instance
     * */
    APP_USBD_CDC_ACM_GLOBAL_DEF(serial_uart,
                                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
                                APP_USBD_CDC_COMM_PROTOCOL_NONE
    );
    
    void serial_reset()
    {
        serial_command_hdr_t rts;
        rts.size    = 0xC0C0;
        rts.command = SERIAL_CMD_INVALID;
        app_usbd_cdc_acm_write(&serial_uart, &rts, sizeof(rts) );
    }
    
    void serial_init()
    {
        static const app_usbd_config_t usbd_config = {
            .ev_state_proc = usbd_user_ev_handler
        };
    
        ret_code_t ret;
    
        app_usbd_serial_num_generate();
    
        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(&serial_uart);
        ret = app_usbd_class_append(class_cdc_acm);
        APP_ERROR_CHECK(ret);
    
        EVT_LOG("USBD CDC ACM example started.\n", NULL);
        if (USBD_POWER_DETECTION)
        {
            ret = app_usbd_power_events_enable();
            APP_ERROR_CHECK(ret);
        }
        else
        {
            EVT_LOG("No USB power detection enabled\nStarting USB now\n", NULL);
    
            app_usbd_enable();
            app_usbd_start();
        }
    }
    
    struct _tx_item
    {
        void* p;
        size_t s;
    };
    
    #define TX_MAX 32
    
    static int _tx_pos  = 0;
    static int _tx_next = 0;
    static struct _tx_item tx_queue[ TX_MAX ];
    
    static void __send_it(void* hdr, size_t hdr_size, void* buf, size_t blen )
    {
        zb_uint8_t* t = (zb_uint8_t*)malloc(hdr_size + blen );
        memcpy( t, hdr, hdr_size);
        if( blen > 0 && buf != NULL )
        {
            memcpy( &t[hdr_size], buf, blen );
        }
    
        if (tx_queue[_tx_next].p != NULL) 
        {
            // OOM.....
            PRINT("tx_queue is full !!... dropping packet! %d %d\n",  _tx_pos, _tx_next);
            free(t);
            return;
        }
        tx_queue[_tx_next].p = t;
        tx_queue[_tx_next].s = hdr_size + blen;    
    
        // No on going item send now!
        if( _tx_pos == _tx_next )
        {    
            if( app_usbd_cdc_acm_write(&serial_uart, t, hdr_size + blen ) == NRF_ERROR_INVALID_STATE )
            {           
                // No serial connected, just drop packet!
                tx_queue[_tx_next].p = NULL;
                tx_queue[_tx_next].s = 0;
                free(t);
                return;
            }
        }
        ++_tx_next;
        if( _tx_next >= TX_MAX )
        {
            _tx_next = 0;
        }
    }
    
    
    static cb_command_handler      command_handler     = NULL;
    static cb_port_status_handler  port_status_handler = NULL;
    
    void serial_set_command_handler(cb_command_handler cb)
    {
        command_handler = cb;
    }
    
    void serial_set_port_status_handler(cb_port_status_handler cb)
    {
        port_status_handler = cb;
    }
    
    
    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 char tmp[1024];
        static uint16_t tmp_i     = 0;
        static uint16_t size      = 0;
    
        switch (event)
        {
            case APP_USBD_CDC_ACM_USER_EVT_PORT_OPEN:
            {        
                tmp_i = 2;
                size  = 0;
                tx = 0;
                memset(tmp,0,sizeof(tmp));
                /*Setup first transfer*/
                ret_code_t ret = app_usbd_cdc_acm_read(&serial_uart,
                                                       tmp,
                                                       sizeof(size));
            
                UNUSED_VARIABLE(ret);
                bsp_board_led_on(BSP_BOARD_LED_0);
                if( port_status_handler != NULL ) 
                {
                    port_status_handler( true );
                }
                break;
            }
            case APP_USBD_CDC_ACM_USER_EVT_PORT_CLOSE:
                bsp_board_led_off(BSP_BOARD_LED_0);
                if( port_status_handler != NULL ) 
                {
                    port_status_handler( false );
                }
                break;
            case APP_USBD_CDC_ACM_USER_EVT_TX_DONE:
                free( tx_queue[_tx_pos].p );
                tx_queue[_tx_pos].p = NULL;
                tx_queue[_tx_pos].s = 0;
    
                // We should normaly only go once in this loop, but if there is an
                // error sending its most likly due to disconnected serial and we will
                // loop thrue and flush the queue.
                do
                {
                    ++_tx_pos;
                    if( _tx_pos >= TX_MAX )
                    {
                        _tx_pos = 0;
                    }
                
                    if( _tx_pos != _tx_next )
                    {
                        if( app_usbd_cdc_acm_write(&serial_uart, tx_queue[_tx_pos].p, tx_queue[_tx_pos].s ) == NRF_ERROR_INVALID_STATE )
                        {           
                            PRINT( "Drop from queue packet... %d %d\n", _tx_pos, _tx_next);
                            free(tx_queue[_tx_pos].p);
                            tx_queue[_tx_pos].p = NULL;
                            tx_queue[_tx_pos].s = 0;                        
                        }
                        else
                        {
                            break;
                        }
                     }
                }while( _tx_pos != _tx_next );
    
                break;
            case APP_USBD_CDC_ACM_USER_EVT_RX_DONE:
            {           
                ret_code_t ret;   
                do
                { 
                    //size_t xsize = app_usbd_cdc_acm_rx_size(p_cdc_acm);
                    //EVT_LOG("Bytes waiting: %zd %hu:%hu\n", xsize, tmp_i, size );
                    if( size == 0 )
                    {
                        memcpy(&size, tmp, sizeof(size));
                        ret = app_usbd_cdc_acm_read_any(&serial_uart, &tmp[tmp_i], 1);
                        continue;
                    }
                    if (tmp_i < size) 
                    {
                        ++tmp_i;
                    }
                    if (size == tmp_i) 
                    {
                        if (command_handler != NULL) 
                        {
                            command_handler(tmp);
                        }
    
                        tmp_i = 2;
                        size  = 0;
                        memset(tmp,0,sizeof(tmp));
                        app_usbd_cdc_acm_read(&serial_uart, tmp, sizeof(size));
                        break;
                    }
                    ret = app_usbd_cdc_acm_read_any(&serial_uart, &tmp[tmp_i], 1);
                    if (ret != NRF_SUCCESS) 
                    {
                        break;
                    }
                } while (ret == NRF_SUCCESS);
                break;
            }
            default:
                PRINT("Unhandled usb event: %x\n",event);
                break;
        }
    }
    
    static void usbd_user_ev_handler(app_usbd_event_type_t event)
    {
        switch (event)
        {
            case APP_USBD_EVT_DRV_SUSPEND:
                PRINT("USB_RESUME\n",NULL);
                break;
            case APP_USBD_EVT_DRV_RESUME:
                PRINT("USB_RESUME\n",NULL);
                break;
            case APP_USBD_EVT_STARTED:
                break;
            case APP_USBD_EVT_STOPPED:
                app_usbd_disable();
                bsp_board_leds_off();
                break;
            case APP_USBD_EVT_POWER_DETECTED:
                PRINT("USB power detected\n",NULL);
    
                if (!nrf_drv_usbd_is_enabled())
                {
                    app_usbd_enable();
                }
                break;
            case APP_USBD_EVT_POWER_REMOVED:
                PRINT("USB power removed\n",NULL);
                app_usbd_stop();
                break;
            case APP_USBD_EVT_POWER_READY:
                PRINT("USB ready\n",NULL);
                app_usbd_start();
                break;
            default:
                PRINT("USB unhandled event:%x\n", event);
                break;
        }
    }
    
    void serial_process()
    {
        app_usbd_event_queue_process();
    }

  • Hey Jimmy,

    I'm trying to run this sample on a nr52840 dongle, and I can't seem to find a definition for the rts struct. Any chance you'd know?

  • The struct is not part of Nordic SDK its part of our source. 

    typedef struct serial_command_hdr
    {
        zb_uint16_t size;
        zb_uint8_t command; // serial_command_t
    } serial_command_hdr_t;

  • Running into something similar on the cb_command_handler/cb_port_status_handler. If this is part of a larger framework, let me know.

  • typedef void (*cb_command_handler)(char*);
    void serial_set_command_handler(cb_command_handler cb);
    typedef void (*cb_port_status_handler)(bool);
    void serial_set_port_status_handler(cb_port_status_handler cb);

    -----

    void handle_serial_command(char *tmp)
    {
        serial_command_hdr_t *hdr = (serial_command_hdr_t *)tmp;

Related