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

Stuck application when implementing UART

Hi,

I have PCA10028 board, and I'm trying to implement UART send/receive. I've searched for the problem here but could not find a solution for it.

My uart init function is(most of the code is copy/paste):

static void uart_init(void)
{
    uint32_t				err_code;
		
		app_uart_comm_params_t params;
    memset(&params, 0, sizeof(params));
    
    params.baud_rate = UART_BAUDRATE_BAUDRATE_Baud115200;
    params.tx_pin_no = TX_PIN_NUMBER;
    params.rx_pin_no = RX_PIN_NUMBER;
    params.use_parity = false;
    params.flow_control = APP_UART_FLOW_CONTROL_DISABLED;
    
    static uint8_t rx_buffer[UART_RX_BUFFER_SIZE];
    static uint8_t tx_buffer[UART_TX_BUFFER_SIZE];
    app_uart_buffers_t buffers;
    buffers.rx_buf = rx_buffer;
    buffers.rx_buf_size = UART_RX_BUFFER_SIZE;
    buffers.tx_buf = tx_buffer;
    buffers.tx_buf_size = UART_TX_BUFFER_SIZE;
    
    err_code = app_uart_init(&params, &buffers, uart_event_handle, APP_IRQ_PRIORITY_LOW, NULL);
    APP_ERROR_CHECK(err_code);
}

This is event handler:

void uart_event_handle(app_uart_evt_t * p_event)
{
    static uint8_t data_array[BLE_MAX_DATA_LEN];
    static uint8_t index = 0;
    uint32_t       err_code;

    switch (p_event->evt_type)
    {
        case APP_UART_DATA_READY:
            UNUSED_VARIABLE(app_uart_get(&data_array[index]));
            index++;

            if ((data_array[index - 1] == '\n') || (index >= (BLE_MAX_DATA_LEN)))
            {
								// TODO: Check sending of data here
                //err_code = ble_nus_string_send(&m_nus, data_array, index);
                if (err_code != NRF_ERROR_INVALID_STATE)
                {
                    APP_ERROR_CHECK(err_code);
                }
                
                index = 0;
            }
            break;

        case APP_UART_COMMUNICATION_ERROR:
            APP_ERROR_HANDLER(p_event->data.error_communication);
            break;

        case APP_UART_FIFO_ERROR:
            APP_ERROR_HANDLER(p_event->data.error_code);
            break;

        default:
            break;
    }
}

And this is my write function:

void app_uart_put_string(const char* s)
{
    uint8_t len = strlen(s);
    for (uint8_t i = 0; i < len; i++)
    {
	while (app_uart_put(s[i]) != NRF_SUCCESS);
        //err_code = app_uart_put(s[i]);
        //APP_ERROR_CHECK(err_code);
    }
}

When this is used: err_code = app_uart_put(s[i]); APP_ERROR_CHECK(err_code); and while (app_uart_put(s[i]) != NRF_SUCCESS) is omitted, this function sends continuously bytes which are not in the char* s. If I send 1 byte it sends it normally and I can see it on the terminal, but when I try to send 2 bytes it sends gibberish continuously.

So I've searched for solution and found: while (app_uart_put(s[i]) != NRF_SUCCESS).

Unfortunately, I've used it and now my PCA board is stuck. I can't flash the new code, can't debug, can't erase with nrfjprog --eraseall and can't erase it in nRFgo Studio. It's not recognized at all.

1.) How can I "unstuck" my board? 2.) Is there an implementation of UART which works? I need a simple sending and receiving of bytes over UART, at higer speeds (baud 115200 or above). I've also found fifo implementation but can't get it to send or receive. I use S110.

Thank you!

Regards, Mladen

  • Managed to "unstuck" PCA(removed UART connections to FTDI chip and I could erase it.)

    UART still not working properly.

  • Hi. I have tried your code and both:

    for (uint8_t i = 0; i < len; i++)
    {
        //while (app_uart_put(s[i]) != NRF_SUCCESS);
        err_code = app_uart_put(s[i]);
        APP_ERROR_CHECK(err_code);
    }
    

    and

    for (uint8_t i = 0; i < len; i++)
    {
        while (app_uart_put(s[i]) != NRF_SUCCESS);
        //err_code = app_uart_put(s[i]);
        //APP_ERROR_CHECK(err_code);
    }
    

    seem to work fine. How have you defined UART_RX_BUFFER_SIZE, UART_TX_BUFFER_SIZE and BLE_MAX_DATA_LEN? Maybe you can post your main.c file?

  • Yes, I did define them. Here is entire main.c file:

    #define ENABLE_DEBUG_LOG_SUPPORT
    
    #include <stdint.h>
    #include <string.h>
    #include "nordic_common.h"
    #include "nrf.h"
    #include "app_error.h"
    #include "nrf_gpio.h"
    #include "nrf51_bitfields.h"
    #include "ble.h"
    #include "ble_hci.h"
    #include "ble_srv_common.h"
    #include "ble_advdata.h"
    #include "ble_advertising.h"
    #include "ble_conn_params.h"
    #include "app_scheduler.h"
    #include "softdevice_handler.h"
    #include "app_timer_appsh.h"
    #include "bsp.h"
    #include "app_uart.h"
    #include "ble_alps.h"
    
    #define IS_SRVC_CHANGED_CHARACT_PRESENT 0                                           /**< Include or not the service_changed characteristic. if not enabled, the server's database cannot be changed for the lifetime of the device*/
    
    #define WAKEUP_BUTTON_ID                0                                           /**< Button used to wake up the application. */
    
    #define LED_FOR_TOGGLE									BSP_LED_2
    
    #define DEVICE_NAME                     "Test Device 04N"                           /**< Name of device. Will be included in the advertising data. */
    
    #define APP_ADV_INTERVAL                64                                          /**< The advertising interval (in units of 0.625 ms. This value corresponds to 40 ms). */
    #define APP_ADV_TIMEOUT_IN_SECONDS      180                                         /**< The advertising timeout (in units of seconds). */
    
    // YOUR_JOB: Modify these according to requirements.
    #define APP_TIMER_PRESCALER             0                                           /**< Value of the RTC1 PRESCALER register. */
    #define APP_TIMER_MAX_TIMERS            (2 + BSP_APP_TIMERS_NUMBER)                 /**< Maximum number of simultaneously created timers. */
    #define APP_TIMER_OP_QUEUE_SIZE         4                                           /**< Size of timer operation queues. */
    
    #define MIN_CONN_INTERVAL               MSEC_TO_UNITS(8, UNIT_1_25_MS)              /**< Minimum acceptable connection interval (0.5 seconds = 500). */
    #define MAX_CONN_INTERVAL               MSEC_TO_UNITS(8, UNIT_1_25_MS)              /**< Maximum acceptable connection interval (1 second = 1000). */
    #define SLAVE_LATENCY                   0                                           /**< Slave latency. */
    #define CONN_SUP_TIMEOUT                MSEC_TO_UNITS(4000, UNIT_10_MS)             /**< Connection supervisory timeout (4 seconds). */
    #define FIRST_CONN_PARAMS_UPDATE_DELAY  APP_TIMER_TICKS(5000, APP_TIMER_PRESCALER)  /**< Time from initiating event (connect or start of notification) to first time sd_ble_gap_conn_param_update is called (5 seconds). */
    #define NEXT_CONN_PARAMS_UPDATE_DELAY   APP_TIMER_TICKS(30000, APP_TIMER_PRESCALER) /**< Time between each call to sd_ble_gap_conn_param_update after the first call (30 seconds). */
    #define MAX_CONN_PARAMS_UPDATE_COUNT    3                                           /**< Number of attempts before giving up the connection parameter negotiation. */
    
    #define SEC_PARAM_BOND                  1                                           /**< Perform bonding. */
    #define SEC_PARAM_MITM                  0                                           /**< Man In The Middle protection not required. */
    #define SEC_PARAM_IO_CAPABILITIES       BLE_GAP_IO_CAPS_NONE                        /**< No I/O capabilities. */
    #define SEC_PARAM_OOB                   0                                           /**< Out Of Band data not available. */
    #define SEC_PARAM_MIN_KEY_SIZE          7                                           /**< Minimum encryption key size. */
    #define SEC_PARAM_MAX_KEY_SIZE          16                                          /**< Maximum encryption key size. */
    
    #define BUTTON_DETECTION_DELAY          APP_TIMER_TICKS(50, APP_TIMER_PRESCALER)    /**< Delay from a GPIOTE event until a button is reported as pushed (in number of timer ticks). */
    
    #define UART_TX_BUFFER_SIZE                256                                      /**< UART TX buffer size. */
    #define UART_RX_BUFFER_SIZE                256                                      /**< UART RX buffer size. */
    #define BLE_MAX_DATA_LEN (GATT_MTU_SIZE_DEFAULT - 3)																/**< Maximum length of data (in bytes) that can be transmitted to the peer by the Nordic UART service module. */
    
    #define DEAD_BEEF                       0xDEADBEEF                                  /**< Value used as error code on stack dump, can be used to identify stack location on stack unwind. */
    
    // YOUR_JOB: Modify these according to requirements (e.g. if other event types are to pass through
    //           the scheduler).
    #define SCHED_MAX_EVENT_DATA_SIZE       sizeof(app_timer_event_t)                   /**< Maximum size of scheduler events. Note that scheduler BLE stack events do not contain any data, as the events are being pulled from the stack in the event handler. */
    #define SCHED_QUEUE_SIZE                10                                          /**< Maximum number of events in the scheduler queue. */
    
    static ble_gap_sec_params_t             m_sec_params;                               /**< Security requirements for this application. */
    static uint16_t                         m_conn_handle = BLE_CONN_HANDLE_INVALID;    /**< Handle of the current connection. */
    
    static ble_alps_t                       m_alps;
    
    void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)
    {
        app_error_handler(DEAD_BEEF, line_num, p_file_name);
    }
    
    static void timers_init(void)
    {
        // Initialize timer module, making it use the scheduler
        APP_TIMER_APPSH_INIT(APP_TIMER_PRESCALER, APP_TIMER_MAX_TIMERS, APP_TIMER_OP_QUEUE_SIZE, true);
    
        /* YOUR_JOB: Create any timers to be used by the application.
                     Below is an example of how to create a timer.
                     For every new timer needed, increase the value of the macro APP_TIMER_MAX_TIMERS by
                     one.
        err_code = app_timer_create(&m_app_timer_id, APP_TIMER_MODE_REPEATED, timer_timeout_handler);
        APP_ERROR_CHECK(err_code); */
    }
    
    static void gap_params_init(void)
    {
        uint32_t                err_code;
        ble_gap_conn_params_t   gap_conn_params;
        ble_gap_conn_sec_mode_t sec_mode;
    
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
    
        err_code = sd_ble_gap_device_name_set(&sec_mode,
                                              (const uint8_t *)DEVICE_NAME,
                                              strlen(DEVICE_NAME));
        APP_ERROR_CHECK(err_code);
    
        /* YOUR_JOB: Use an appearance value matching the application's use case.
        err_code = sd_ble_gap_appearance_set(BLE_APPEARANCE_);
        APP_ERROR_CHECK(err_code); */
    
        memset(&gap_conn_params, 0, sizeof(gap_conn_params));
    
        gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;
        gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;
        gap_conn_params.slave_latency     = SLAVE_LATENCY;
        gap_conn_params.conn_sup_timeout  = CONN_SUP_TIMEOUT;
    
        err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
        APP_ERROR_CHECK(err_code);
    }
    
    static void data_write_handler(ble_alps_t* p_alps, uint8_t* p_data, uint16_t length)
    {
        uint32_t       err_code;
    
        err_code = ble_alps_send(&m_alps, p_data, length);
    		if (err_code != NRF_ERROR_INVALID_STATE)
    		{
    				APP_ERROR_CHECK(err_code);
    		}  
    }
    
    static void services_init(void)
    {
        // YOUR_JOB: Add code to initialize the services used by the application.
    		uint32_t err_code;
        ble_alps_init_t init;
        
        init.data_write_handler = data_write_handler;
        
        err_code = ble_alps_init(&m_alps, &init);
        APP_ERROR_CHECK(err_code);
    }
    
    static void sec_params_init(void)
    {
        m_sec_params.bond         = SEC_PARAM_BOND;
        m_sec_params.mitm         = SEC_PARAM_MITM;
        m_sec_params.io_caps      = SEC_PARAM_IO_CAPABILITIES;
        m_sec_params.oob          = SEC_PARAM_OOB;
        m_sec_params.min_key_size = SEC_PARAM_MIN_KEY_SIZE;
        m_sec_params.max_key_size = SEC_PARAM_MAX_KEY_SIZE;
    }
    
    static void on_conn_params_evt(ble_conn_params_evt_t * p_evt)
    {
        uint32_t err_code;
    
        if(p_evt->evt_type == BLE_CONN_PARAMS_EVT_FAILED)
        {
            err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
            APP_ERROR_CHECK(err_code);
        }
    }
    
    static void conn_params_error_handler(uint32_t nrf_error)
    {
        APP_ERROR_HANDLER(nrf_error);
    }
    
    static void conn_params_init(void)
    {
        uint32_t               err_code;
        ble_conn_params_init_t cp_init;
    
        memset(&cp_init, 0, sizeof(cp_init));
    
        cp_init.p_conn_params                  = NULL;
        cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
        cp_init.next_conn_params_update_delay  = NEXT_CONN_PARAMS_UPDATE_DELAY;
        cp_init.max_conn_params_update_count   = MAX_CONN_PARAMS_UPDATE_COUNT;
        cp_init.start_on_notify_cccd_handle    = BLE_GATT_HANDLE_INVALID;
        cp_init.disconnect_on_fail             = false;
        cp_init.evt_handler                    = on_conn_params_evt;
        cp_init.error_handler                  = conn_params_error_handler;
    
        err_code = ble_conn_params_init(&cp_init);
        APP_ERROR_CHECK(err_code);
    }
    
    static void timers_start(void)
    {
        /* YOUR_JOB: Start your timers. below is an example of how to start a timer.
        uint32_t err_code;
    
        err_code = app_timer_start(m_app_timer_id, TIMER_INTERVAL, NULL);
        APP_ERROR_CHECK(err_code); */
    }
    
    static void sleep_mode_enter(void)
    {
        uint32_t err_code = bsp_indication_set(BSP_INDICATE_IDLE);
        APP_ERROR_CHECK(err_code);
    
        // Go to system-off mode (this function will not return; wakeup will cause a reset).
        err_code = sd_power_system_off();
        APP_ERROR_CHECK(err_code);
    }
    
    static void on_adv_evt(ble_adv_evt_t ble_adv_evt)
    {
        uint32_t err_code;
    
        switch (ble_adv_evt)
        {
            case BLE_ADV_EVT_FAST:
                err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
                APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_ADV_EVT_IDLE:
                sleep_mode_enter();
                break;
    
            default:
                break;
        }
    }
    
    static void on_ble_evt(ble_evt_t * p_ble_evt)
    {
        uint32_t                         err_code;
        static ble_gap_evt_auth_status_t m_auth_status;
        bool                             master_id_matches;
        ble_gap_sec_kdist_t *            p_distributed_keys;
        ble_gap_enc_info_t *             p_enc_info;
        ble_gap_irk_t *                  p_id_info;
        ble_gap_sign_info_t *            p_sign_info;
    
        static ble_gap_enc_key_t         m_enc_key;           /**< Encryption Key (Encryption Info and Master ID). */
        static ble_gap_id_key_t          m_id_key;            /**< Identity Key (IRK and address). */
        static ble_gap_sign_info_t       m_sign_key;          /**< Signing Key (Connection Signature Resolving Key). */
        static ble_gap_sec_keyset_t      m_keys = {.keys_periph = {&m_enc_key, &m_id_key, &m_sign_key}};
    
        switch (p_ble_evt->header.evt_id)
        {
            case BLE_GAP_EVT_CONNECTED:
                err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
                APP_ERROR_CHECK(err_code);
                m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
    
                /* YOUR_JOB: Uncomment this part if you are using the app_button module to handle button
                             events (assuming that the button events are only needed in connected
                             state). If this is uncommented out here,
                                1. Make sure that app_button_disable() is called when handling
                                   BLE_GAP_EVT_DISCONNECTED below.
                                2. Make sure the app_button module is initialized.
                err_code = app_button_enable();
                APP_ERROR_CHECK(err_code);
                */
    				
    						err_code = app_button_enable();
    				
                break;
    
            case BLE_GAP_EVT_DISCONNECTED:
                m_conn_handle = BLE_CONN_HANDLE_INVALID;
    
                /* YOUR_JOB: Uncomment this part if you are using the app_button module to handle button
                             events. This should be done to save power when not connected
                             to a peer.
                err_code = app_button_disable();
                APP_ERROR_CHECK(err_code);
                */
                break;
    
            case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
                err_code = sd_ble_gap_sec_params_reply(m_conn_handle,
                                                       BLE_GAP_SEC_STATUS_SUCCESS,
                                                       &m_sec_params,
                                                       &m_keys);
                APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_GATTS_EVT_SYS_ATTR_MISSING:
                err_code = sd_ble_gatts_sys_attr_set(m_conn_handle,
                                                     NULL,
                                                     0,
                                                     BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS | BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS);
                APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_GAP_EVT_AUTH_STATUS:
                m_auth_status = p_ble_evt->evt.gap_evt.params.auth_status;
                break;
    
            case BLE_GAP_EVT_SEC_INFO_REQUEST:
                master_id_matches  = memcmp(&p_ble_evt->evt.gap_evt.params.sec_info_request.master_id,
                                            &m_enc_key.master_id,
                                            sizeof(ble_gap_master_id_t)) == 0;
                p_distributed_keys = &m_auth_status.kdist_periph;
    
                p_enc_info  = (p_distributed_keys->enc  && master_id_matches) ? &m_enc_key.enc_info : NULL;
                p_id_info   = (p_distributed_keys->id   && master_id_matches) ? &m_id_key.id_info   : NULL;
                p_sign_info = (p_distributed_keys->sign && master_id_matches) ? &m_sign_key         : NULL;
    
                err_code = sd_ble_gap_sec_info_reply(m_conn_handle, p_enc_info, p_id_info, p_sign_info);
                    APP_ERROR_CHECK(err_code);
                break;
    
            default:
                // No implementation needed.
                break;
        }
    }
    
    static void ble_evt_dispatch(ble_evt_t * p_ble_evt)
    {
        on_ble_evt(p_ble_evt);
        ble_conn_params_on_ble_evt(p_ble_evt);
        ble_advertising_on_ble_evt(p_ble_evt);
    		//ble_lbs_on_ble_evt(&m_lbs, p_ble_evt);
    		ble_alps_on_ble_evt(&m_alps, p_ble_evt);
    }
    
    static void sys_evt_dispatch(uint32_t sys_evt)
    {
        ble_advertising_on_sys_evt(sys_evt);
    }
    
    
    static void ble_stack_init(void)
    {
        uint32_t err_code;
    
        // Initialize the SoftDevice handler module.
        //SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, NULL);
    		SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_SYNTH_250_PPM, false);
    
    #if defined(S110) || defined(S130)
        // Enable BLE stack 
        ble_enable_params_t ble_enable_params;
        memset(&ble_enable_params, 0, sizeof(ble_enable_params));
    #ifdef S130
        ble_enable_params.gatts_enable_params.attr_tab_size   = BLE_GATTS_ATTR_TAB_SIZE_DEFAULT;
    #endif
        ble_enable_params.gatts_enable_params.service_changed = IS_SRVC_CHANGED_CHARACT_PRESENT;
        err_code = sd_ble_enable(&ble_enable_params);
        APP_ERROR_CHECK(err_code);
    #endif
        
        // Register with the SoftDevice handler module for BLE events.
        err_code = softdevice_ble_evt_handler_set(ble_evt_dispatch);
        APP_ERROR_CHECK(err_code);
        
        // Register with the SoftDevice handler module for BLE events.
        err_code = softdevice_sys_evt_handler_set(sys_evt_dispatch);
        APP_ERROR_CHECK(err_code);
    }
    
    void uart_event_handle(app_uart_evt_t * p_event)
    {
        uint8_t					value;
        uint32_t				err_code;
    
        switch (p_event->evt_type)
        {
            case APP_UART_DATA_READY:
    						err_code = app_uart_get(&value);
                APP_ERROR_CHECK(err_code);
                err_code = app_uart_put(value);
                APP_ERROR_CHECK(err_code);
                break;
    
            case APP_UART_COMMUNICATION_ERROR:
                APP_ERROR_HANDLER(p_event->data.error_communication);
                break;
    
            case APP_UART_FIFO_ERROR:
                APP_ERROR_HANDLER(p_event->data.error_code);
                break;
    
            default:
                break;
        }
    }
    
    static void uart_init(void)
    {
        uint32_t				err_code;
    		
    		app_uart_comm_params_t params;
        memset(&params, 0, sizeof(params));
        
        params.baud_rate = UART_BAUDRATE_BAUDRATE_Baud115200;
        params.tx_pin_no = TX_PIN_NUMBER;
        params.rx_pin_no = RX_PIN_NUMBER;
        params.use_parity = false;
        params.flow_control = APP_UART_FLOW_CONTROL_DISABLED;
        
        static uint8_t rx_buffer[UART_RX_BUFFER_SIZE];
        static uint8_t tx_buffer[UART_TX_BUFFER_SIZE];
        app_uart_buffers_t buffers;
        buffers.rx_buf = rx_buffer;
        buffers.rx_buf_size = UART_RX_BUFFER_SIZE;
        buffers.tx_buf = tx_buffer;
        buffers.tx_buf_size = UART_TX_BUFFER_SIZE;
        
        err_code = app_uart_init(&params, &buffers, uart_event_handle, APP_IRQ_PRIORITY_LOW, NULL);
        APP_ERROR_CHECK(err_code);
    }
    /**@snippet [UART Initialization] */
    
    static void advertising_init(void)
    {
        uint32_t      err_code;
        ble_advdata_t advdata;
    
        // Build advertising data struct to pass into @ref ble_advertising_init.
        memset(&advdata, 0, sizeof(advdata));
    
        advdata.name_type               = BLE_ADVDATA_FULL_NAME;
        advdata.include_appearance      = true;
        advdata.flags                   = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
        advdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
        advdata.uuids_complete.p_uuids  = m_adv_uuids;
    
        ble_adv_modes_config_t options = {0};
        options.ble_adv_fast_enabled  = BLE_ADV_FAST_ENABLED;
        options.ble_adv_fast_interval = APP_ADV_INTERVAL;
        options.ble_adv_fast_timeout  = APP_ADV_TIMEOUT_IN_SECONDS;
    
        err_code = ble_advertising_init(&advdata, NULL, &options, on_adv_evt, NULL);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for the Event Scheduler initialization.
     */
    static void scheduler_init(void)
    {
        APP_SCHED_INIT(SCHED_MAX_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);
    }
    
    static void power_manage(void)
    {
        uint32_t err_code = sd_app_evt_wait();
        APP_ERROR_CHECK(err_code);
    }
    
    void app_uart_put_string(const char* s)
    {
    		uint32_t err_code;
        uint8_t len = strlen(s);
        for (uint8_t i = 0; i < len; i++)
        {
            err_code = app_uart_put(s[i]);
            APP_ERROR_CHECK(err_code);
        }
    }
    
    int main(void)
    {
        uint32_t err_code;
      
    		nrf_gpio_cfg_output(LED_FOR_TOGGLE);
    	
        // Initialize
    		buttons_init();
        timers_init();
        ble_stack_init();
        bsp_module_init();
        scheduler_init();
        gap_params_init();
        advertising_init();
    		uart_init();
        services_init();
        conn_params_init();
        sec_params_init();
    	
    		app_uart_put_string("Sx");
    
        // Start execution
        timers_start();
        err_code = ble_advertising_start(BLE_ADV_MODE_FAST);
        APP_ERROR_CHECK(err_code);
        // Enter main loop
        for (;;)
        {
            app_sched_execute();
            power_manage();
        }
    }
    
  • Hi,

    When you run this code:

    for (uint8_t i = 0; i < len; i++)
    {
        err_code = app_uart_put(s[i]);
        APP_ERROR_CHECK(err_code);
    }
    

    app_uart_put() will return the error code NRF_ERROR_NO_MEM after you have transmitted your first byte. I.e. you are putting bytes in the buffer too fast and the UART doesn't have the time to process all of them. When err_code is then passed on to APP_ERROR_CHECK() you will end up in the function app_error_handler() defined in app_error.c. Finally, since you (probably) didn't have DEBUG defined in your project the error handler will do a system reset of your chip. This is why it looked like the UART was spewing out an endless stream of bytes, while in reality it transmitted just one byte, but then the code was reset and this continued in an endless loop.

    This code works however:

    for (uint8_t i = 0; i < len; i++)
    {
        while (app_uart_put(s[i]) != NRF_SUCCESS);
    }
    

    because this code puts a byte in the TX buffer and waits for the byte to be transmitted before it loads the buffer with another byte. The code is not ideal, however, since it will wait literally forever and block your code if something goes wrong in app_uart_put().

    Your solution should be to use the app_uart_fifo.c driver instead of the simpler app_uart.c driver. Then you can use the first code and the driver will handle the buffer issue.

    EDIT There is an example in "your_SDK_folder\examples\peripheral\uart" using the fifo drivers. To use it in your own project you will need to add the following .c-files to your project driver and library folder:

    image description

    Just right click on e.g. nRF_Drivers and click "Add existing files...", navigate to "your_SDK_folder\components\drivers_nrf\uart", and add the file you need. Make sure to delete app_uart.c from the library folder if it is present. You should use app_uart.c or app_uart_fifo.c.

  • Can you please tell me where can I find this driver? I mean, is there an example with app_uart_fifo driver which sends and receives multiple bytes?

    Thank you!

    Edit: Awesome! This helps a lot!

Related