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!