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

Issues with writing my own project that communicates with a computer over USB.

Hi,

I've been trying to combine the spi_slave and USB_CDC_ADM examples so that I can pipe data from a spi_master all the way to my host machine. In my cobbled together project, the SPI transactions are working, but the USB isn't being properly sensed by my machine. I keep seeing this in my device manager:

The USB_CDC_ADM example works just fine though.

Any ideas on what I'm messing up? Thank you!

Parents
  • Hi Rye, 

    Could you check what's the issue with the nRF52 USB Product (right click and click properties)
    I would suggest to comment out the SPI functionality part by part until you see the USB work again, this way we can track down what caused the issue. 


  • Okay, the problem was that I wasn't running app_usbd_event_queue_process() to actually process any USB events. I must have accidentally forgotten to copy it over. I have a new issue though. 

    I've set up two dev kits, a SPI master & a SPI slave. The Master sends a message "comes_from_spi_mstr" to the slave, which then pipes it to my desktop via USB. What's weird is that the message makes its way to my computer (I see "comes_from_spi_mstr" on computer from the USB's COM port)... but when I print the SPI's rx buffer through the logger it comes up empty.

    Here are photos to show what's happening:

    SPI logger output:

    USB output:

    Any idea why it's not coming up in the logger, despite being there (as shown by making its way all the way through the USB).

    Thanks,

    Ryan

  • Hi, 
    Please post your code, and state which SDK you are using. 
    Please track down on how you pass the data from SPI to USB.

  • Hi Hung,

    I've attached my main.c and sdkconfig.h. I'm using nRF5 SDK v16.0.0.

    As fare as how data is being passed from the SPI to the USB, I'm just taking the SPI_rx buffer and sprintf-ing it into the USB_tx buffer (corresponding lines copied below):

            size_t size = sprintf(m_tx_buffer, "Hello USB CDC demo: %s\r\n", (uint32_t)spi_rx_buf);
            app_usbd_cdc_acm_write(&m_app_cdc_acm, m_tx_buffer, size);

     

    /**
     * Copyright (c) 2017 - 2019, Nordic Semiconductor ASA
     *
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     *
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     *
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     *
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     *
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */
    #include <stdint.h>
    #include <stdbool.h>
    #include <stddef.h>
    #include <stdio.h>
    
    #include "nrf.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"
    
    #include "boards.h"
    #include "bsp.h"
    #include "bsp_cli.h"
    #include "nrf_cli.h"
    #include "nrf_cli_uart.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #include "sdk_config.h"
    #include "nrf_drv_spis.h"
    #include <string.h>
    
    
    #if NRF_CLI_ENABLED
    /**
     * @brief CLI interface over UART
     */
    NRF_CLI_UART_DEF(m_cli_uart_transport, 0, 64, 16);
    NRF_CLI_DEF(m_cli_uart,
                "uart_cli:~$ ",
                &m_cli_uart_transport.transport,
                '\r',
                4);
    #endif
    
    /**@file
     * @defgroup usbd_cdc_acm_example main.c
     * @{
     * @ingroup usbd_cdc_acm_example
     * @brief USBD CDC ACM example
     *
     */
    
    #define LED_USB_RESUME      (BSP_BOARD_LED_0)
    #define LED_CDC_ACM_OPEN    (BSP_BOARD_LED_1)
    #define LED_CDC_ACM_RX      (BSP_BOARD_LED_2)
    #define LED_CDC_ACM_TX      (BSP_BOARD_LED_3)
    
    #define BTN_CDC_DATA_SEND       0
    #define BTN_CDC_NOTIFY_SEND     1
    
    #define BTN_CDC_DATA_KEY_RELEASE        (bsp_event_t)(BSP_EVENT_KEY_LAST + 1)
    
    /**
     * @brief Enable power USB detection
     *
     * Configure if example supports USB port connection
     */
    #ifndef USBD_POWER_DETECTION
    #define USBD_POWER_DETECTION true
    #endif
    
    
    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
    
    
    /**
     * @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
    );
    
    #define READ_SIZE 1
    
    static char m_rx_buffer[READ_SIZE];
    static char m_tx_buffer[NRF_DRV_USBD_EPSIZE];
    static bool m_send_flag = 0;
    
    #define SPIS_INSTANCE 1 /**< SPIS instance index. */
    static const nrf_drv_spis_t spis = NRF_DRV_SPIS_INSTANCE(SPIS_INSTANCE);/**< SPIS instance. */
    
    #define TEST_STRING "666"
    static uint8_t       spi_tx_buf[] = TEST_STRING;           /**< TX buffer. */
    static uint8_t       spi_rx_buf[sizeof(TEST_STRING) + 1];    /**< RX buffer. */
    static uint32_t      spi_packet_buffer;
    static const uint8_t spi_length = sizeof(spi_tx_buf);        /**< Transfer length. */
    
    static volatile bool spis_xfer_done; /**< Flag used to indicate that SPIS instance completed the transfer. */
    
    /**
     * @brief SPIS user event handler.
     *
     * @param event
     */
    void spis_event_handler(nrf_drv_spis_event_t event)
    {
        if (event.evt_type == NRF_DRV_SPIS_XFER_DONE)
        {
            spis_xfer_done = true;
            spi_packet_buffer = (uint32_t)spi_rx_buf;
            NRF_LOG_INFO(" Transfer completed. Received: %s",(uint32_t)spi_rx_buf);
            bsp_board_led_invert(BSP_BOARD_LED_0);
    
            size_t size = sprintf(m_tx_buffer, "Hello USB CDC demo: %s\r\n", (uint32_t)spi_rx_buf);
            app_usbd_cdc_acm_write(&m_app_cdc_acm, m_tx_buffer, size);
    
            //memset(spi_rx_buf, 0, spi_length);
            //APP_ERROR_CHECK(nrf_drv_spis_buffers_set(&spis, spi_tx_buf, spi_length, spi_rx_buf, spi_length));
        }
    }
    
    /**
     * @brief User event handler @ref app_usbd_cdc_acm_user_ev_handler_t (headphones)
     * */
    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:
            {
                bsp_board_led_on(LED_CDC_ACM_OPEN);
    
                /*Setup first transfer*/
                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:
                bsp_board_led_off(LED_CDC_ACM_OPEN);
                break;
            case APP_USBD_CDC_ACM_USER_EVT_TX_DONE:
                bsp_board_led_invert(LED_CDC_ACM_TX);
                break;
            case APP_USBD_CDC_ACM_USER_EVT_RX_DONE:
            {
                ret_code_t ret;
                NRF_LOG_INFO("Bytes waiting: %d", app_usbd_cdc_acm_bytes_stored(p_cdc_acm));
                do
                {
                    /*Get amount of data transfered*/
                    size_t size = app_usbd_cdc_acm_rx_size(p_cdc_acm);
                    NRF_LOG_INFO("RX: size: %lu char: %lu", size, m_rx_buffer[0]);
    
                    /* Fetch data until internal buffer is empty */
                    ret = app_usbd_cdc_acm_read(&m_app_cdc_acm,
                                                m_rx_buffer,
                                                READ_SIZE);
                } while (ret == NRF_SUCCESS);
    
                bsp_board_led_invert(LED_CDC_ACM_RX);
                break;
            }
            default:
                break;
        }
    }
    
    static void usbd_user_ev_handler(app_usbd_event_type_t event)
    {
        switch (event)
        {
            case APP_USBD_EVT_DRV_SUSPEND:
                bsp_board_led_off(LED_USB_RESUME);
                break;
            case APP_USBD_EVT_DRV_RESUME:
                bsp_board_led_on(LED_USB_RESUME);
                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:
                NRF_LOG_INFO("USB power detected");
    
                if (!nrf_drv_usbd_is_enabled())
                {
                    app_usbd_enable();
                }
                break;
            case APP_USBD_EVT_POWER_REMOVED:
                NRF_LOG_INFO("USB power removed");
                app_usbd_stop();
                break;
            case APP_USBD_EVT_POWER_READY:
                NRF_LOG_INFO("USB ready");
                app_usbd_start();
                break;
            default:
                break;
        }
    }
    
    static void bsp_event_callback(bsp_event_t ev)
    {
        ret_code_t ret;
        switch ((unsigned int)ev)
        {
            case CONCAT_2(BSP_EVENT_KEY_, BTN_CDC_DATA_SEND):
            {
                m_send_flag = 1;
                break;
            }
            
            case BTN_CDC_DATA_KEY_RELEASE :
            {
                m_send_flag = 0;
                break;
            }
    
            case CONCAT_2(BSP_EVENT_KEY_, BTN_CDC_NOTIFY_SEND):
            {
                ret = app_usbd_cdc_acm_serial_state_notify(&m_app_cdc_acm,
                                                           APP_USBD_CDC_ACM_SERIAL_STATE_BREAK,
                                                           false);
                UNUSED_VARIABLE(ret);
                break;
            }
    
            default:
                return; // no implementation needed
        }
    }
    
    static void init_bsp(void)
    {
        ret_code_t ret;
        ret = bsp_init(BSP_INIT_BUTTONS, bsp_event_callback);
        APP_ERROR_CHECK(ret);
        
        UNUSED_RETURN_VALUE(bsp_event_to_button_action_assign(BTN_CDC_DATA_SEND,
                                                              BSP_BUTTON_ACTION_RELEASE,
                                                              BTN_CDC_DATA_KEY_RELEASE));
        
        /* Configure LEDs */
        bsp_board_init(BSP_INIT_LEDS);
    }
    
    #if NRF_CLI_ENABLED
    static void init_cli(void)
    {
        ret_code_t ret;
        ret = bsp_cli_init(bsp_event_callback);
        APP_ERROR_CHECK(ret);
        nrf_drv_uart_config_t uart_config = NRF_DRV_UART_DEFAULT_CONFIG;
        uart_config.pseltxd = TX_PIN_NUMBER;
        uart_config.pselrxd = RX_PIN_NUMBER;
        uart_config.hwfc    = NRF_UART_HWFC_DISABLED;
        ret = nrf_cli_init(&m_cli_uart, &uart_config, true, true, NRF_LOG_SEVERITY_INFO);
        APP_ERROR_CHECK(ret);
        ret = nrf_cli_start(&m_cli_uart);
        APP_ERROR_CHECK(ret);
    }
    #endif
    
    int main(void)
    {
    
        NRF_POWER->TASKS_CONSTLAT = 1;
    
    
        ret_code_t ret;
        static const app_usbd_config_t usbd_config = {
            .ev_state_proc = usbd_user_ev_handler
        };
    
        ret = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(ret);
    
        ret = nrf_drv_clock_init();
        APP_ERROR_CHECK(ret);
        
        nrf_drv_clock_lfclk_request(NULL);
    
        while(!nrf_drv_clock_lfclk_is_running())
        {
            /* Just waiting */
        }
    
        ret = app_timer_init();
        APP_ERROR_CHECK(ret);
    
        init_bsp();
    #if NRF_CLI_ENABLED
        init_cli();
    #endif
    
        app_usbd_serial_num_generate();
    
        ret = app_usbd_init(&usbd_config);
        APP_ERROR_CHECK(ret);
        NRF_LOG_INFO("USB setup completed. Beginning SPI setup...");
    
        nrf_drv_spis_config_t spis_config = NRF_DRV_SPIS_DEFAULT_CONFIG;
        spis_config.csn_pin               = APP_SPIS_CS_PIN;
        spis_config.miso_pin              = APP_SPIS_MISO_PIN;
        spis_config.mosi_pin              = APP_SPIS_MOSI_PIN;
        spis_config.sck_pin               = APP_SPIS_SCK_PIN;
    
        APP_ERROR_CHECK(nrf_drv_spis_init(&spis, &spis_config, spis_event_handler));    
        memset(spi_rx_buf, 0, spi_length);
        spis_xfer_done = false;
        APP_ERROR_CHECK(nrf_drv_spis_buffers_set(&spis, spi_tx_buf, spi_length, spi_rx_buf, spi_length));
        bsp_board_led_invert(BSP_BOARD_LED_3); // Just so I know it gets past this point
    
        NRF_LOG_INFO("SPI setup completed. Beginning USB starup...");
        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);
    
        if (USBD_POWER_DETECTION)
        {
            ret = app_usbd_power_events_enable();
            APP_ERROR_CHECK(ret);
        }
        else
        {
            NRF_LOG_INFO("No USB power detection enabled\r\nStarting USB now");
    
            app_usbd_enable();
            app_usbd_start();
        }
    
        while (true)
        {
            app_usbd_event_queue_process(); // need to manually clear USB queue??
            
            if(m_send_flag)
            {
                static int  frame_counter;
    
                size_t size = sprintf(m_tx_buffer, "Hello USB CDC demo: %s\r\n", (uint32_t)spi_rx_buf);
                m_send_flag = 0;
    
                ret = app_usbd_cdc_acm_write(&m_app_cdc_acm, m_tx_buffer, size);
                //if (ret == NRF_SUCCESS)
                //{
                //    ++frame_counter;
                //}
            }
    
            if (spis_xfer_done)
            {
            // If you're in this loop then that means spi interrupt was fired and flag has been set. We're okay to reset everything and wait for the next spi transfer
    
            NRF_LOG_FLUSH();
            // bsp_board_led_invert(BSP_BOARD_LED_1);
            memset(spi_rx_buf, 0, spi_length);
            spis_xfer_done = false;
            APP_ERROR_CHECK(nrf_drv_spis_buffers_set(&spis, spi_tx_buf, spi_length, spi_rx_buf, spi_length));
    
    
            }
            
    #if NRF_CLI_ENABLED
            nrf_cli_process(&m_cli_uart);
    #endif
    
            UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
            /* Sleep CPU only if there was no interrupt since last loop processing */
            __WFE();
        }
    }
    
    /** @} */
    
    6685.sdk_config.h

  • I don't think using the buffer as a string is a good idea here. A char array can be a string if the end of the array has a NULL character '/0' which you don't have. 

    To copy from one array to another array you can use memcpy instead.

    What I can see is that your  rx buffer is only 4 bytes, I dont know how you can get "comes_from_spi_mastr" as in the log. 

    Please get familiar with debugging, try to put a break point and view the buffer to see what you have there. 

Reply
  • I don't think using the buffer as a string is a good idea here. A char array can be a string if the end of the array has a NULL character '/0' which you don't have. 

    To copy from one array to another array you can use memcpy instead.

    What I can see is that your  rx buffer is only 4 bytes, I dont know how you can get "comes_from_spi_mastr" as in the log. 

    Please get familiar with debugging, try to put a break point and view the buffer to see what you have there. 

Children
  • Yea, that gave me some other issues. Since I really only care about the bits, I've switched to calculating a 32 bit value from the rx_buff and outputting that. While this fixed some string related null character handling, I'm still outputting nothing over the LOG and the actual (expected) number over USB, so I wonder if there's an order of operations issue. I'll step through with the debugger.

    Thanks for your help!

Related