Enabling Oversampling on the nRF52840

Hi, this is follow-up to @Klaus_K excellent post

As I read through the nRF52840 documentation, I saw the possibility of ADC-Oversampling done by the Microcontroller on its own, and fiddling around a bit, I found out, how to do it ... and wanted to share it here:

So, you need to set the Oversampling to the desired value e.g. 4x Oversampling here:

NRF_SAADC->OVERSAMPLE = SAADC_OVERSAMPLE_OVERSAMPLE_Over4x << SAADC_OVERSAMPLE_OVERSAMPLE_Pos;

And enable the Oversampling ich each Chanel-Config by enabling the Burst (see the line with SAADC_CH_CONFIG_BURST_Enabled):

  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_BURST_Enabled << SAADC_CH_CONFIG_BURST_Pos) |
                            (SAADC_CH_CONFIG_TACQ_3us << SAADC_CH_CONFIG_TACQ_Pos);

Doing these two minor changes, you have suddenly the ADC giving you the average of 4 ADC samples -- but, of course, you need to be careful, that you are not pushing the ADC over its limots ...
for example if you want to have 16kHz sampling rate, using a 4x Oversampling results into 64kHz real sampling rate, which is still feasable, higher Oversampling and/or sampling rate might not work, however.

So, to be more complete, the init-routine as code (please refer to the linked code of Klaus_K for a complete example):

void initADC() {
  nrf_saadc_disable();

  NRF_SAADC->RESOLUTION = NRF_SAADC_RESOLUTION_12BIT;
  NRF_SAADC->OVERSAMPLE = SAADC_OVERSAMPLE_OVERSAMPLE_Over4x << SAADC_OVERSAMPLE_OVERSAMPLE_Pos;

  // 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_BURST_Enabled << SAADC_CH_CONFIG_BURST_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;

  // P0.05 - AIN3 -> Pin A1
  NRF_SAADC->CH[3].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_BURST_Enabled << SAADC_CH_CONFIG_BURST_Pos) |
                            (SAADC_CH_CONFIG_TACQ_3us << SAADC_CH_CONFIG_TACQ_Pos);

  NRF_SAADC->CH[3].PSELP = SAADC_CH_PSELP_PSELP_AnalogInput3 << SAADC_CH_PSELP_PSELP_Pos;
  NRF_SAADC->CH[3].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, 0UL);  // ### investigate this. This needs to be higher than the mbed priority
  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))
    ;
}

Oh, still a important side-notice:
The 5V->3.3V of the NANO 33 BLE is somewat suboptimal, resulting in a really noisy 3.3V.
Better cut open the 3.3V jumper on the back, and supply stable 3.3V of your own at the +3V3-Pin.
However, by cuting it open, the USB-Port ceases to work. So, solder a switch of some sort (jumper cables e.g.) to reenable it to be able to flash the Arduino.
Only do it, if you know, what you are doing!

you generally don't need oversampling enabled - some plugins that do it automatically turn off oversampling at 96khz. I've found plugins to sound better at 96khz so tend to work at that sample rate all the time and not worry about oversampling. Other people work at 48khz and oversample plugins only as needed.

moderator edit: spam removed

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