Arduino Nano BLE 33/Sense nRF52840 ADC sampling is interrupted by Bluetooth

Hi,
I use Arduino Nano BLE 33/Sense (as Bluetooth Periperal) to sample a full rectified sine voltage wave and real-time send it through bluetooth, then bluetooth central (Such as: pad) can show the waveform realtime. In this project,I find an important issue.

To get high ADC sampling rate, I can’t use AnalogRead() which is too slow for my project. Instead, I code based on the sketch which Klaus_K provided in the post [Increase the ADC sample rate]. Thanks to Klaus_K!

However, I find a critial issue:
When I don’t connect Bluetooth, nRF52840 ADC works fine,I can achieve high accuracy based on the ADC sampling data. I plot it by using a Python script based on the data which a PC computer receive from Serial port of Arduino Nano BLE 33/Sense. Refer to Fig 1, it is a standard full-rectified sine wave (x axis: sample numbers; y axis: ADC value read by Arduino Nano BLE 33/Sense). Great! But when I connect Bluetooth, the wavform received from Bluetooth Central is distorted. It can not be achieve any accuracy for later computation at all. I dig into the code line by line. Eventually, I find if I just use BLE.begin(), the nRF52840 ADC sampling is interrupted, refer to Fig 2. Notice: the actual input waveform to Arduino Nano BLE A0 is good, refer to Fig 3, just the internal ADC sampling seems to be interrupted.

My questions are:

  1. is there any configuration wrong in the sketch for this application? (If I am lucky, I hope Klaus_K can be aware of this blog and help to review the codes configuration for ADC.)
  2. Is there any thing wrong (or conflict) with ArduinoBLE library and mbed library when both libraries are used?
  3. Is Arduino Nano BLE 33/Sense support ADC sampling and real-time Bluetooth commuincation? (I had been stopped by this issue for a couple of weeks. I am thinking If this issue can’t be solved, I have to use two Arduino Nano BLE boards: one Arduino Nano BLE 33/Sense as ADC, the other one for Bluetooth communication for this project, but certainly, this is not a beautiful design. I really want to make both ADC sampling and Bluetooth in one Arduino Nano BLE 33/Sense )

I really appreciate if anyone can help me out in this issue.

I provide code below. You can just comment/uncomment “if(BLE.begin()) { Serial.println( "Bluetooth initialized successfully!");}” to deplicate this issue.

To duplicate this issue, I proivde minimum code below. Again, I make a little change based on Klaus_K’s code. For the hardware connection, I use a circuit to convert a sine wave(the project require a input frequency: 30 ~ 300Hz, amplitude: +/-2.5V) to fully recified waveform, then input to A0 of Arduino Nano BLE 33. You can duplicate Fig 1 and Fig2 by using 30Hz Sine waveform. I also attach a 100Hz Sine waveform waveform. It seems ADC is interrupted by some action with higher priority, refer to Fig 4. I try to increase ADC priority: by change NVIC_setPriority(SAADC_IRQn, 1UL) to NVIC_setPriority(SAADC_IRQn, 0UL), however it doesn’t help. It seems Bluetotooth has higher priority, forecly disable any other interrupt(?). Notice; please do not use DC voltage to A0 to duplicate this issue, you won’t find this issue since DC voltage still can be plotted to a straight line even the ADC is interuppted.
OK. Any help, I really appreciate!!!

/*

  This experimental code shows how to control the nRF52840 SAADC using a Timer and PPI.

  The SAADC uses EasyDMA to copy each sample into a variable in memory.

  The ADC samples pin A0.

  Note:

  - the maximum sampling rate is 200kSamples/s

  - only one sample per second it printed

  - this code has not been tested with a debugger, some samples might be lost due to mbedOS (needs further testing)

  - this code will likely not work when using analogRead() on other pins

  

  The circuit:

  - Arduino Nano 33 BLE/ BLE Sense board.

  This example code is in the public domain.

*/

// make some change on the original experimental codes to demonstrate the ADC interrupted issue by Bluetooth,2022/01/17 9:55AM

#include "mbed.h"

#include <ArduinoBLE.h>

#define SAMPLES_PER_SECOND  20000

#define PPI_CHANNEL         (7)

#define ADC_BUFFER_SIZE     1

volatile nrf_saadc_value_t adcBuffer[ADC_BUFFER_SIZE];

volatile bool adcFlag = false;

volatile uint32_t sampleCounter = 0;

void setup()

{

  Serial.begin( 115200 );

  while ( !Serial );

  Serial.println( "Arduino Nano 33 BLE (mbedOS) example: Timer -> PPI -> SAADC" );

  if(BLE.begin())

  {

    Serial.println( "Bluetooth initialized successfully!");

  }

  initADC();

  initTimer4();

  initPPI();

}

void loop()

{

  static uint32_t previousMillis = 0;

  if ( adcFlag )

  {

    adcFlag = false;

    // if ( sampleCounter >= SAMPLES_PER_SECOND )

    if ( sampleCounter >= 1 )

    {

      // uint32_t sampleCount = sampleCounter;

      // uint32_t currentMillis = millis();

      // uint32_t runTime = currentMillis - previousMillis;

      // Serial.print( "Samples: " );

      // Serial.print( sampleCount );

      // Serial.print( " run time: " );

      // Serial.print( runTime );

      // Serial.print( " ms A0: " );

      Serial.println( adcBuffer[0] );

      // previousMillis = currentMillis;

      sampleCounter = 0;

    }

  }

}

extern "C" void SAADC_IRQHandler_v( void )

{

  if ( NRF_SAADC->EVENTS_END != 0 )

  {

    NRF_SAADC->EVENTS_END = 0;

    adcFlag = true;

    sampleCounter++;

  }

}

void initADC()

{

  nrf_saadc_disable();

  NRF_SAADC->RESOLUTION = NRF_SAADC_RESOLUTION_12BIT;

  // P0.04 - AIN2 -> Pin A0

  NRF_SAADC->CH[2].CONFIG = ( SAADC_CH_CONFIG_GAIN_Gain1_4    << SAADC_CH_CONFIG_GAIN_Pos ) |

                            ( SAADC_CH_CONFIG_MODE_SE         << SAADC_CH_CONFIG_MODE_Pos ) |

                            ( SAADC_CH_CONFIG_REFSEL_VDD1_4   << SAADC_CH_CONFIG_REFSEL_Pos ) |

                            ( SAADC_CH_CONFIG_RESN_Bypass     << SAADC_CH_CONFIG_RESN_Pos ) |

                            ( SAADC_CH_CONFIG_RESP_Bypass     << SAADC_CH_CONFIG_RESP_Pos ) |

                            ( SAADC_CH_CONFIG_TACQ_3us        << SAADC_CH_CONFIG_TACQ_Pos );

  NRF_SAADC->CH[2].PSELP = SAADC_CH_PSELP_PSELP_AnalogInput2 << SAADC_CH_PSELP_PSELP_Pos;

  NRF_SAADC->CH[2].PSELN = SAADC_CH_PSELN_PSELN_NC << SAADC_CH_PSELN_PSELN_Pos;

  NRF_SAADC->RESULT.MAXCNT = ADC_BUFFER_SIZE;

  NRF_SAADC->RESULT.PTR = ( uint32_t )&adcBuffer;

  NRF_SAADC->EVENTS_END = 0;

  nrf_saadc_int_enable( NRF_SAADC_INT_END );

  NVIC_SetPriority( SAADC_IRQn, 1UL );

  NVIC_EnableIRQ( SAADC_IRQn );

  nrf_saadc_enable();

  NRF_SAADC->TASKS_CALIBRATEOFFSET = 1;

  while ( NRF_SAADC->EVENTS_CALIBRATEDONE == 0 );

  NRF_SAADC->EVENTS_CALIBRATEDONE = 0;

  while ( NRF_SAADC->STATUS == ( SAADC_STATUS_STATUS_Busy << SAADC_STATUS_STATUS_Pos ) );

}

void initTimer4()

{

  NRF_TIMER4->MODE = TIMER_MODE_MODE_Timer;

  NRF_TIMER4->BITMODE = TIMER_BITMODE_BITMODE_16Bit;

  NRF_TIMER4->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos;

  NRF_TIMER4->PRESCALER = 0;

  NRF_TIMER4->CC[0] = 16000000 / SAMPLES_PER_SECOND; // Needs prescaler set to 0 (1:1) 16MHz clock

  NRF_TIMER4->TASKS_START = 1;

}

void initPPI()

{

  NRF_PPI->CH[PPI_CHANNEL].EEP = ( uint32_t )&NRF_TIMER4->EVENTS_COMPARE[0];

  NRF_PPI->CH[PPI_CHANNEL].TEP = ( uint32_t )&NRF_SAADC->TASKS_START;

  NRF_PPI->FORK[PPI_CHANNEL].TEP = ( uint32_t )&NRF_SAADC->TASKS_SAMPLE;

  NRF_PPI->CHENSET = ( 1UL << PPI_CHANNEL );

}

Fig 1. Singal Generator: 30Hz,+/-2.5V Sine waveform, after full rectified circuit, 60Hz full rectified sine wave to A0. Comment BLE.begin() in codes.


Fig 2. Singal Generator: 30Hz,+/-2.5V Sine waveform, after full rectified circuit, 60Hz full rectified sine wave to A0. Uncomment BLE.begin() in codes.

Fig 3. the actual waveform catched by oscilloscope. Blue waveform: 30Hz,+/-2.5V Sine waveform. Green waveform: 60Hz full rectified sine wave to Arduino A0

Fig 4.Singal Generator: 100Hz,+/-2.5V Sine waveform, after full rectified circuit, 200Hz full rectified sine wave to A0. Uncomment BLE.begin() in codes. The inerrupt seems periodic.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.