nRF5 SDK is not maintained anymore
More Info: Consider nRF Connect SDK for new designs
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

Problem on combining ADC, GPIO, and BLE

Hello all!

I'm using nRF52-DK to develop program which is controlled by smartphone (BLE) and do ADC&GPIO in the circuit.

GPIO acts like this: High-Low-High-Low.... it changes its state every 24 us. Let's say pin number of GPIO is P.20.

ADC reads the voltage of P.20 every 12us. Of course, ADC pin is not P.20(it is P.04) but I connected two by wires.

I send a message to nRF52-DK from smartphone by BLE to trigger those functions.

So, if it works ideally, The ADC result should be: High, High, Low, Low, High, High, Low, Low,.... -> result[4k+1] should be high.

However, it does not: Sometimes, High-High-Low-High-High-Low-Low... like this. So result[4k+1] is high, but often low.

The below picture shows that result: result[4k+1].

But, when I turned off the BLE, it works well.

Can anyone give me an idea how to solve this?

Here is part of my codes.

I just added things that I think important for this problem.

#define TIMER_1_TIMEOUT_US_1      12
#define TIMER_1_TIMEOUT_US_2      24
#define TIMER_1_TIMEOUT_US_3      36
#define TIMER_1_TIMEOUT_US_4      48

#define TIMER_ADC_TIMEOUT_US_1     12 
#define TIMER_ADC_TIMEOUT_US_2     24 
#define TIMER_ADC_TIMEOUT_US_3     36 
#define TIMER_ADC_TIMEOUT_US_4     48 

#define MUX_INPUT_0 2 // LSB PA.02
#define MUX_INPUT_1 28
#define MUX_INPUT_2 20
#define MUX_INPUT_3 18 // MSB PA.18
#define MUX_OUTPUT  NRF_SAADC_INPUT_AIN2 // PA04

static const nrf_drv_timer_t m_timer_1 = NRF_DRV_TIMER_INSTANCE(1); 
static const nrf_drv_timer_t m_timer_2 = NRF_DRV_TIMER_INSTANCE(2);   

static void timer_init(void)
{
	ret_code_t err_code;

	nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
	timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32;

	err_code = nrf_drv_timer_init(&m_timer_1, &timer_cfg, timer_handler);
	APP_ERROR_CHECK(err_code);
	err_code = nrf_drv_timer_init(&m_timer_2, &timer_cfg, timer_handler);
	APP_ERROR_CHECK(err_code);

        uint32_t ticks_input_adc0 = nrf_drv_timer_us_to_ticks(&m_timer_2, TIMER_ADC_TIMEOUT_US_1); //220602
        uint32_t ticks_input_adc1 = nrf_drv_timer_us_to_ticks(&m_timer_2, TIMER_ADC_TIMEOUT_US_2); //220602
        uint32_t ticks_input_adc2 = nrf_drv_timer_us_to_ticks(&m_timer_2, TIMER_ADC_TIMEOUT_US_3); //220602
        uint32_t ticks_input_adc3 = nrf_drv_timer_us_to_ticks(&m_timer_2, TIMER_ADC_TIMEOUT_US_4); //220602

	uint32_t ticks_input0 = nrf_drv_timer_us_to_ticks(&m_timer_1, TIMER_1_TIMEOUT_US_1); //220602
	uint32_t ticks_input1 = nrf_drv_timer_us_to_ticks(&m_timer_1, TIMER_1_TIMEOUT_US_2); //220602
	uint32_t ticks_input2 = nrf_drv_timer_us_to_ticks(&m_timer_1, TIMER_1_TIMEOUT_US_3); //220602
	uint32_t ticks_input3 = nrf_drv_timer_us_to_ticks(&m_timer_1, TIMER_1_TIMEOUT_US_4); //220602

        nrf_drv_timer_compare(&m_timer_2, NRF_TIMER_CC_CHANNEL0, ticks_input_adc0, false); //220602
        nrf_drv_timer_compare(&m_timer_2, NRF_TIMER_CC_CHANNEL1, ticks_input_adc1, false); //220602
        nrf_drv_timer_compare(&m_timer_2, NRF_TIMER_CC_CHANNEL2, ticks_input_adc2, false); //220602
        nrf_drv_timer_extended_compare(&m_timer_2, NRF_TIMER_CC_CHANNEL3, ticks_input_adc3, NRF_TIMER_SHORT_COMPARE3_CLEAR_MASK, false); //220602

	nrf_drv_timer_compare(&m_timer_1, NRF_TIMER_CC_CHANNEL0, ticks_input0, false); //220602
        nrf_drv_timer_compare(&m_timer_1, NRF_TIMER_CC_CHANNEL1, ticks_input1, false); //220602
        nrf_drv_timer_compare(&m_timer_1, NRF_TIMER_CC_CHANNEL2, ticks_input2, false); //220602
        nrf_drv_timer_extended_compare(&m_timer_1, NRF_TIMER_CC_CHANNEL3, ticks_input3, NRF_TIMER_SHORT_COMPARE3_CLEAR_MASK, false);//220602
}

static void ppi_init(void)
{
	ret_code_t err_code;

	/* ppi driver initialization */
	err_code = nrf_drv_ppi_init();
	APP_ERROR_CHECK(err_code);

	/* ppi channel allocation */
	err_code = nrf_drv_ppi_channel_alloc(&ppi_channel_0);
	APP_ERROR_CHECK(err_code);
	err_code = nrf_drv_ppi_channel_alloc(&ppi_channel_1);
	APP_ERROR_CHECK(err_code);
	err_code = nrf_drv_ppi_channel_alloc(&ppi_channel_2);
	APP_ERROR_CHECK(err_code);
	err_code = nrf_drv_ppi_channel_alloc(&ppi_channel_3);
	APP_ERROR_CHECK(err_code); //220602

	err_code = nrf_drv_ppi_channel_alloc(&ppi_channel_a0);
	APP_ERROR_CHECK(err_code);
	err_code = nrf_drv_ppi_channel_alloc(&ppi_channel_a1);
	APP_ERROR_CHECK(err_code); 
	err_code = nrf_drv_ppi_channel_alloc(&ppi_channel_a2);
	APP_ERROR_CHECK(err_code);
	err_code = nrf_drv_ppi_channel_alloc(&ppi_channel_a3);
	APP_ERROR_CHECK(err_code); //220602

}

static void mux_input_gpio_init(void)
{
	ret_code_t err_code;

	/* gpiote driver initialization */
	err_code = nrf_drv_gpiote_init(); // already initialized by button module
	APP_ERROR_CHECK(err_code);

	/* configure gpio for output that would server the input of the external chip to select the channel */
	nrf_drv_gpiote_out_config_t config_low = GPIOTE_CONFIG_OUT_TASK_TOGGLE(false);
	nrf_drv_gpiote_out_config_t config_high = GPIOTE_CONFIG_OUT_TASK_TOGGLE(true);
	err_code = nrf_drv_gpiote_out_init(MUX_INPUT_0, &config_low);
	APP_ERROR_CHECK(err_code);

	err_code = nrf_drv_gpiote_out_init(MUX_INPUT_1, &config_high);
	APP_ERROR_CHECK(err_code);

	err_code = nrf_drv_gpiote_out_init(MUX_INPUT_2, &config_low);
	APP_ERROR_CHECK(err_code);

	err_code = nrf_drv_gpiote_out_init(MUX_INPUT_3, &config_low);
	APP_ERROR_CHECK(err_code);

}

static void saadc_sampling_event_init(void)
{
	ret_code_t err_code;

        uint32_t timer_compare_event_addr_0 = nrf_drv_timer_event_address_get(&m_timer_2, NRF_TIMER_EVENT_COMPARE0); 
	uint32_t saadc_sample_task_addr_0 = nrf_drv_saadc_sample_task_get();

        uint32_t timer_compare_event_addr_1 = nrf_drv_timer_event_address_get(&m_timer_2, NRF_TIMER_EVENT_COMPARE1); 
	uint32_t saadc_sample_task_addr_1 = nrf_drv_saadc_sample_task_get();

        uint32_t timer_compare_event_addr_2 = nrf_drv_timer_event_address_get(&m_timer_2, NRF_TIMER_EVENT_COMPARE2); 
	uint32_t saadc_sample_task_addr_2 = nrf_drv_saadc_sample_task_get();

        uint32_t timer_compare_event_addr_3 = nrf_drv_timer_event_address_get(&m_timer_2, NRF_TIMER_EVENT_COMPARE3); 
	uint32_t saadc_sample_task_addr_3 = nrf_drv_saadc_sample_task_get();

        err_code = nrf_drv_ppi_channel_assign(ppi_channel_a0, timer_compare_event_addr_0, saadc_sample_task_addr_0);
	APP_ERROR_CHECK(err_code);

	err_code = nrf_drv_ppi_channel_assign(ppi_channel_a1, timer_compare_event_addr_1, saadc_sample_task_addr_1);
	APP_ERROR_CHECK(err_code); 

        err_code = nrf_drv_ppi_channel_assign(ppi_channel_a2, timer_compare_event_addr_2, saadc_sample_task_addr_2);
	APP_ERROR_CHECK(err_code);

	err_code = nrf_drv_ppi_channel_assign(ppi_channel_a3, timer_compare_event_addr_3, saadc_sample_task_addr_3);
	APP_ERROR_CHECK(err_code);  //220602
}

static void setup_mux_input_channel_selection(void)
{
	ret_code_t err_code;

	uint32_t compare_evt_addr_0, compare_evt_addr_1, compare_evt_addr_2, compare_evt_addr_3;
	uint32_t gpiote_task_addr_0, gpiote_task_addr_1, gpiote_task_addr_2, gpiote_task_addr_3;

	//setup timer compare events and gpiote task
	compare_evt_addr_0 = nrf_drv_timer_event_address_get(&m_timer_1, NRF_TIMER_EVENT_COMPARE0);
	gpiote_task_addr_0 = nrf_drv_gpiote_out_task_addr_get(MUX_INPUT_2); //12us: M2 high

	compare_evt_addr_1 = nrf_drv_timer_event_address_get(&m_timer_1, NRF_TIMER_EVENT_COMPARE1);
	gpiote_task_addr_1 = nrf_drv_gpiote_out_task_addr_get(MUX_INPUT_3); //24us: M3 high

	compare_evt_addr_2 = nrf_drv_timer_event_address_get(&m_timer_1, NRF_TIMER_EVENT_COMPARE2);
	gpiote_task_addr_2 = nrf_drv_gpiote_out_task_addr_get(MUX_INPUT_2); //36us: M2 low

	compare_evt_addr_3 = nrf_drv_timer_event_address_get(&m_timer_1, NRF_TIMER_EVENT_COMPARE3);
	gpiote_task_addr_3 = nrf_drv_gpiote_out_task_addr_get(MUX_INPUT_3); //48us: M3 low //220602
        

        //link task and event via ppi channels 
	err_code = nrf_drv_ppi_channel_assign(ppi_channel_0, compare_evt_addr_0, gpiote_task_addr_0);
	APP_ERROR_CHECK(err_code);

	err_code = nrf_drv_ppi_channel_assign(ppi_channel_1, compare_evt_addr_1, gpiote_task_addr_1);
	APP_ERROR_CHECK(err_code);

	err_code = nrf_drv_ppi_channel_assign(ppi_channel_2, compare_evt_addr_2, gpiote_task_addr_2);
	APP_ERROR_CHECK(err_code);

	err_code = nrf_drv_ppi_channel_assign(ppi_channel_3, compare_evt_addr_3, gpiote_task_addr_3);
	APP_ERROR_CHECK(err_code); //220602
        

	//enable ppi channels 
	err_code = nrf_drv_ppi_channel_enable(ppi_channel_0);
	APP_ERROR_CHECK(err_code);

	err_code = nrf_drv_ppi_channel_enable(ppi_channel_1);
	APP_ERROR_CHECK(err_code);

	err_code = nrf_drv_ppi_channel_enable(ppi_channel_2);
	APP_ERROR_CHECK(err_code);

	err_code = nrf_drv_ppi_channel_enable(ppi_channel_3);
	APP_ERROR_CHECK(err_code); //220602

}

static void start_mux_input_selection(void)
{
	nrf_drv_gpiote_out_task_enable(MUX_INPUT_0);
	nrf_drv_gpiote_out_task_enable(MUX_INPUT_1);
	nrf_drv_gpiote_out_task_enable(MUX_INPUT_2);
	nrf_drv_gpiote_out_task_enable(MUX_INPUT_3);
}

void saadc_sampling_event_enable(void)
{
        ret_code_t err_code;

        err_code = nrf_drv_ppi_channel_enable(ppi_channel_a0);
	APP_ERROR_CHECK(err_code);

	err_code = nrf_drv_ppi_channel_enable(ppi_channel_a1);
	APP_ERROR_CHECK(err_code); 

        err_code = nrf_drv_ppi_channel_enable(ppi_channel_a2);
	APP_ERROR_CHECK(err_code);

	err_code = nrf_drv_ppi_channel_enable(ppi_channel_a3);
	APP_ERROR_CHECK(err_code);  //220602

}

void saadc_init(void)
{
	ret_code_t err_code;
	nrf_saadc_channel_config_t channel_config =
		NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(MUX_OUTPUT);

	err_code = nrf_drv_saadc_init(NULL, saadc_callback);
	APP_ERROR_CHECK(err_code);

	err_code = nrf_drv_saadc_channel_init(0, &channel_config);
	APP_ERROR_CHECK(err_code);

	err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool2[0], SAMPLES_IN_BUFFER-2); 
        APP_ERROR_CHECK(err_code);

	err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool2[1], SAMPLES_IN_BUFFER-2); 
        APP_ERROR_CHECK(err_code);
}

Thank you all.

  • Hi,

    As you only see this when BLE is in use I assume this is related to SoftDevice interrupts, which have high priority. You can refer to the SoftDevice specification to see for how long the SoftDevice can block the application (Bluetooth Low Energy processor usage patterns). If this causes problems then there are several potential ways around it:

    • If the SAADC sampling happens for a not too long time, provide a long ADC buffer so that the CPU is only needed to start sampling and process the samples after all samples are collected (I see you already trigger sampling and toggle the GPIOs using a timer and PPI, so that does not involve the CPU).
    • If you do not need to do the time critical operations continuously, you could consider doing it in timeslots. During that time, you will not get interrupted by the SoftDevice.
  • Wow Thanks, Thorsrud!!

    I accepted your first suggestion.

    I increased the ADC buffer size, and it was really helpful.

    Also, I increased the connection interval, and it makes perfect operation.

    Thank you again,.

Related