Hello,
To preface, this project was redirected to me and I have very little experience using SoCs. Happy to provide any additional information and apologies for issues in post quality.
We are currently using the onboard SAADC of the nrf52832 as a way to convert the voltage outputs of a TI OPT101 photodiode into digital values for physiological measurements. In this scenario, we tend to measure in very low light settings, caring less about high sampling rates and more for longer acquisition times (~500 us). Moreover, the SoC is controlled by a master module, which sends triggers on when to acquire data. Reading the ADC (as in the code snippet posted below) should only occur when such a trigger is received and only one readout is performed at a time.
When this project was handed to me, it was using an example configuration for a one-channel, single-ended input performing single task measurements. Here is our acquisition code when it was handed to me (minor edits have been made since, but general flow remains the same):
int32_t readADC(int analog_pin, uint8_t gain) { volatile int16_t result = 0; // the adc outputs signed 16-bit volatile float precise_result = 0; volatile int32_t sumSamples = 0; // Configure SAADC singled-ended channel, Internal reference (0.6V) and 1/6 // gain. NRF_SAADC->CH[0].CONFIG = (gain << SAADC_CH_CONFIG_GAIN_Pos) | (SAADC_CH_CONFIG_MODE_SE << SAADC_CH_CONFIG_MODE_Pos) | (SAADC_CH_CONFIG_REFSEL_Internal << 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); // Configure the SAADC channel with Analog input as positive input, no // negative input(single ended). NRF_SAADC->CH[0].PSELP = (analog_pin + 1) << SAADC_CH_PSELP_PSELP_Pos; NRF_SAADC->CH[0].PSELN = SAADC_CH_PSELN_PSELN_NC << SAADC_CH_PSELN_PSELN_Pos; // Configure the SAADC resolution. NRF_SAADC->RESOLUTION = SAADC_RESOLUTION_VAL_14bit << SAADC_RESOLUTION_VAL_Pos; // Configure result to be put in RAM at the location of "result" variable. NRF_SAADC->RESULT.MAXCNT = 1; // This would increase for multiple channels NRF_SAADC->RESULT.PTR = (uint32_t)&result; // No automatic sampling, will trigger with TASKS_SAMPLE. NRF_SAADC->SAMPLERATE = SAADC_SAMPLERATE_MODE_Task << SAADC_SAMPLERATE_MODE_Pos; // Enable SAADC (would capture analog pins if they were used in CH[0].PSELP) NRF_SAADC->ENABLE = SAADC_ENABLE_ENABLE_Enabled << SAADC_ENABLE_ENABLE_Pos; // Take multiple samples. for (int i = 0; i < SAMPLES_TO_READ; i++) { // Start the SAADC and wait for the started event. NRF_SAADC->TASKS_START = 1; while (NRF_SAADC->EVENTS_STARTED == 0) ; NRF_SAADC->EVENTS_STARTED = 0; // Do a SAADC sample, will put the result in the configured RAM buffer. NRF_SAADC->TASKS_SAMPLE = 1; while (NRF_SAADC->EVENTS_END == 0) ; NRF_SAADC->EVENTS_END = 0; sumSamples = sumSamples + result; } sumSamples = sumSamples / SAMPLES_TO_READ; //sumSamples = sumSamples; NRF_SAADC->TASKS_STOP = 1; while (NRF_SAADC->EVENTS_STOPPED == 0) ; NRF_SAADC->EVENTS_STOPPED = 0; return sumSamples; //return result; // result only stored a single measurement. Instead, return sumSamples }
In my reading, I saw that the SAADC supports up to 40 us acquisition times, and even that is well below our target range. Is there a way to define additional acquisition times that would suit our needs?
Thank you very much for any feedback and assistance.