Uart corrupted when scanning with many advertisers in range

Hello,

There seems to be a bug with scanning for many Bluetooth advertisements while simultaneously sending  data over uart in Nrf sdk v17. 

I have tried to work around this issue by using the nrfx_uart/uarte library, and slowing the scanning rate. Both of these changes did not fix the issue, just made it take longer to show up. Also originally I was using nrf sdk v16, upgrading to v17 made the issue better but still shows up.

At the bottom of this post is a reproducible project that shows this bug.

If the code is programmed and the python script is pointing to the com port of the device, you will see that thereis a wild inconsistency with the data recieved.

If lines 166 and 167 are commented out (the nrf_ble_scan_start) and start the script again, the script will show that every 100 bytes received are in the same pattern

Note: this only seems to happen when there are a lot of advertisers around.

Can you please help find a solution to this problem?

Thanks

#include "nrfx_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "nrf_pwr_mgmt.h"
#include "nrf_sdh.h"
#include "nrf_sdh_ble.h"
#include "nrf_ble_scan.h"
#include <nrfx.h>

#include "nrf_uarte.h"
#include "nrf_gpio.h"


#define APP_BLE_CONN_CFG_TAG 1

struct uart_config_t {
	uint32_t            pseltxd; ///< TXD pin number.
	uint32_t            pselrxd; ///< RXD pin number.
	uint32_t            pselcts; ///< CTS pin number.
	uint32_t            pselrts; ///< RTS pin number.
	void *              p_context; ///< Context passed to interrupt handler.
	nrf_uarte_hwfc_t     hwfc; ///< Flow control configuration.
	nrf_uarte_parity_t   parity; ///< Parity configuration.
	nrf_uarte_baudrate_t baudrate; ///< Baudrate.
	uint8_t             interrupt_priority; ///< Interrupt priority.
} ;

static nrf_ble_scan_t m_scan;
NRF_UARTE_Type * p_uart = NRF_UARTE0;
static void send_uart_payload();
static void ble_evt(ble_evt_t const * p_evt, void * p_context);
NRF_SDH_BLE_OBSERVER(m_ble_observer, 1, ble_evt, 0);
#define UART_PAYLOAD_SIZE 100
static uint8_t pl[UART_PAYLOAD_SIZE] = { 0 };

static void ble_evt(ble_evt_t const * p_evt, void * p_context) {
	if (p_evt->header.evt_id == BLE_GAP_EVT_ADV_REPORT) {
		ble_gap_evt_adv_report_t const * p_adv_report = &p_evt->evt.gap_evt.params.adv_report;
		NRFX_LOG_INFO("ADV");
	}
	send_uart_payload();
	nrf_ble_scan_on_ble_evt(p_evt, &m_scan);
	
}

static void init_softdevice() {
	ret_code_t err_code = nrf_sdh_enable_request();
	APP_ERROR_CHECK(err_code);
}

static void init_bluetooth() {
		
	uint32_t ram_start = 0;
	ret_code_t err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
	APP_ERROR_CHECK(err_code);
	
	err_code = nrf_sdh_ble_enable(&ram_start);
	APP_ERROR_CHECK(err_code);
}

static void send_uart_payload() {
	nrf_uarte_tx_buffer_set(p_uart, pl, UART_PAYLOAD_SIZE);
	nrf_uarte_task_trigger(p_uart, NRF_UARTE_TASK_STARTTX);
}

void nrfx_uarte_0_irq_handler(void) {
	if (nrf_uarte_int_enable_check(p_uart, NRF_UARTE_INT_ERROR_MASK) && nrf_uarte_event_check(p_uart, NRF_UARTE_EVENT_ERROR)) {
		nrf_uarte_event_clear(p_uart, NRF_UARTE_EVENT_ERROR);
		nrf_uarte_int_disable(p_uart, NRF_UARTE_INT_RXDRDY_MASK | NRF_UARTE_INT_ERROR_MASK);
		NRFX_LOG_ERROR("uart error!");
	}
	
	if (nrf_uarte_event_check(p_uart, NRF_UARTE_EVENT_ENDTX)) {
		nrf_uarte_event_clear(p_uart, NRF_UARTE_EVENT_ENDTX);
		nrf_uarte_event_clear(p_uart, NRF_UARTE_EVENT_TXSTOPPED);
		send_uart_payload();
	}
}
static void init_scanner() {
	nrf_ble_scan_init_t init_scan = { 
			.connect_if_match = false,
		.conn_cfg_tag = APP_BLE_CONN_CFG_TAG
	};

	ret_code_t err_code = nrf_ble_scan_init(&m_scan, &init_scan, 0);
	APP_ERROR_CHECK(err_code);
	
	m_scan.scan_params.interval =  MSEC_TO_UNITS(100, UNIT_0_625_MS);
	m_scan.scan_params.window =  MSEC_TO_UNITS(100, UNIT_0_625_MS);
	m_scan.scan_params.timeout =  MSEC_TO_UNITS(0, UNIT_10_MS);
}

static void apply_uart_config(const struct uart_config_t* p_config) {
	if (p_config->pseltxd != NRF_UARTE_PSEL_DISCONNECTED) {
		nrf_gpio_pin_set(p_config->pseltxd);
		nrf_gpio_cfg_output(p_config->pseltxd);
	}
	if (p_config->pselrxd != NRF_UARTE_PSEL_DISCONNECTED) {
		nrf_gpio_cfg_input(p_config->pselrxd, NRF_GPIO_PIN_NOPULL);
	}
	nrf_uarte_baudrate_set(p_uart, p_config->baudrate);
	nrf_uarte_configure(p_uart, p_config->parity, p_config->hwfc);
	nrf_uarte_txrx_pins_set(p_uart, p_config->pseltxd, p_config->pselrxd);
	if (p_config->hwfc == NRF_UARTE_HWFC_ENABLED) {
		if (p_config->pselcts != NRF_UARTE_PSEL_DISCONNECTED) {
			nrf_gpio_cfg_input(p_config->pselcts, NRF_GPIO_PIN_NOPULL);
		}
		if (p_config->pselrts != NRF_UARTE_PSEL_DISCONNECTED) {
			nrf_gpio_pin_set(p_config->pselrts);
			nrf_gpio_cfg_output(p_config->pselrts);
		}
		nrf_uarte_hwfc_pins_set(p_uart, p_config->pselrts, p_config->pselcts);
	}
}
static void init_uart() {
	struct uart_config_t config = { 
		.pseltxd = 6,
		.pselrxd = 5, 
		.pselcts = NRF_UARTE_PSEL_DISCONNECTED, 
		.pselrts = NRF_UARTE_PSEL_DISCONNECTED,
		.p_context = NULL,
		.hwfc = NRF_UARTE_HWFC_DISABLED,
		.parity = NRF_UARTE_PARITY_EXCLUDED,
		.baudrate = NRF_UARTE_BAUDRATE_9600,
		.interrupt_priority = NRFX_UART_DEFAULT_CONFIG_IRQ_PRIORITY, 
	};
	apply_uart_config(&config);
	
	nrf_uarte_event_clear(p_uart, NRF_UARTE_EVENT_TXDRDY);
	nrf_uarte_event_clear(p_uart, NRF_UARTE_EVENT_RXTO);
	nrf_uarte_int_enable(p_uart,
		NRF_UARTE_INT_TXDRDY_MASK |  NRF_UARTE_INT_RXTO_MASK | NRF_UARTE_INT_ERROR_MASK);
	NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_uart),
		config.interrupt_priority);
	NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_uart));
	
	nrf_uarte_enable(p_uart);
}

int main() {
	ret_code_t err_code = NRF_LOG_INIT(NULL);
	APP_ERROR_CHECK(err_code);

	NRF_LOG_DEFAULT_BACKENDS_INIT();
	
	err_code = nrf_pwr_mgmt_init();
	APP_ERROR_CHECK(err_code);
	
	NRFX_LOG_INFO("Test started.");
	
	memset(pl, 0xAB, UART_PAYLOAD_SIZE);
	for (uint16_t i = 0; i < UART_PAYLOAD_SIZE; i++) {
		if (i % 2 == 0) {
			pl[i] = 0xAB;
		} else {
			pl[i] = 0xCD;
		}
	}
	
	init_softdevice();
	init_bluetooth();
	init_scanner();
	init_uart();
	send_uart_payload();
	
	err_code = nrf_ble_scan_start(&m_scan);
	APP_ERROR_CHECK(err_code);
	
	for (;;) {
		if (!NRF_LOG_PROCESS()) {
			nrf_pwr_mgmt_run();
		}
	}
	return 0;
}

import serial

def main():
    with serial.Serial('COM17', baudrate=9600) as s:
        while True:
            p = []
            while len(p) < 100:
                p += s.read(100 - len(p))
            print(''.join(map('{:X}'.format, p)))


if __name__ == "__main__":
    main()

Parents
  • Bug is here:

    static void send_uart_payload() {
    	uint8_t pl[30] = { 0 };
    	nrfx_uart_tx(&uart, pl, 30);
    }
    

    The "pl" resides on the stack, and I am pretty sure nrf_uart_tx() is non-blocking. That allows other calls - like later advertisements - to overwrite the stack memory location of pl variable during UART transmission.

    First order fix is quite simple:

    static void send_uart_payload() {
    	static uint8_t pl[30] = { 0 }; /* <-- static here */
    	nrfx_uart_tx(&uart, pl, 30);
    }
    

    But in the long run you may need to switch to some kind of FIFO or a blocking UART function.

  • Hello,

    If lines 166 and 167 are commented out (the nrf_ble_scan_start) and start the script again, you will see that thereis a wild inconsistency with the data recieved.

    Is it not the other way around? Your subject lines says the data is corrupted during scanning? Anyway. Could you with the help of a debugger halt the CPU and try to inspect the UART TX buffer 'pl' when when the garbled data is being sent?  I'm wondering if the data in the buffer is corrupt or not.

    Also, from your picture it looks like the device recovers and starts sending the correct pattern after a while. Could be that it recovers because of a reset?

    Best regards,

    Vidar

  • Sorry, yes the problem happens when scanning. I have updated the post.

    I have been trying to find a work around for this issue for about a week so I have done a lot of debugging around it.

    1) The uart buffers not corrupted when the broken data is received.

    2) the module is not resetting.

Reply Children
No Data
Related