I'm sorry, maybe it's me, but your SAADC documentation leaves much to be desired, as I was easily able to implement getting readings from a single analog input (non-blocking), but not multiple inputs. Your documentation doesn't seem to explain what I need to do and why so I can implement what I need. I want to have 4 analog inputs convert when I call nrfx_saadc_sample() in the main loop of my program (non-blocking), and I shouldn't need a timer and PPI (because I didn't need either for a single channel, right? And, the documentation for that routine says that calling it samples all enabled channels). What I did get from the documentation and from the examples, it seems that you have to call the following:
- nrf_drv_saadc_init() to define the address of the callback handler.
- nrfx_saadc_channel_init() for each channel, with one channel assigned to each analog input.
- nrfx_saadc_buffer_convert() for each channel, to give it the number of samples to read and provide the address of where to store those samples in the order you defined the channels.
- call nrfx_saadc_sample() repetitively at regular intervals
- the callback will be called for each channel.
The result is that I never get through the third step. I'm attaching the file that I'm trying to do this through. When I tried to run this, I got a NRFX_ERROR_BUSY so I decided to wait, but the farther I got, the longer I waited until it went on forever. Please tell me what I'm doing wrong, why, and what I need to do it right (i.e. please tell me what I'm missing in my understanding and what I need to know to get this to work).
Thank you so much ahead of time, as you guys have always come through for me, and maybe someone else will be able to learn from this.
// SAADC - Successive Approximation Analog to Digital Converter Driver
#include "saadc.h"
#include "nrf_drv_saadc.h"
#include "nrf_wdt.h"
#include "nrf_drv_wdt.h"
// Voltage Reference
// 8 bit = approx 0.01289 = 12.89 millivolts
// 10 bit = approx 0.003226 = 3.226 millivolts
// 12 bit = approx 0.00080566 = 0.80566 Millivolts = 805.66 Micro volts 4096
// 14 bit = approx 0.00020141 = 0.20141 Millivolts = 201.41 Micro Volts
#define PIU_CURRENT_NOISE_OFFSET 14 // Include this because we're reading negative voltages
// Samples are needed to be stored in a buffer, we define the length here
#define SAADC_SAMPLES_IN_BUFFER 4
extern nrfx_wdt_channel_id m_channel_id;
typedef enum
{
SAADC_CH_VDIFF = 0,
SAADC_CH_5V_MON = 1,
SAADC_CH_12V_MON = 2,
SAADC_CH_24V_MON = 3,
SAADC_CHANNELS = 4
} eSAADCChannel;
// Save the sample returned, last one is average
static nrf_saadc_value_t m_buffer[SAADC_CHANNELS][SAADC_SAMPLES_IN_BUFFER];
// Value to return to host.c
static nrf_saadc_value_t adc_value[SAADC_CHANNELS];
// Handle the events once the samples are received in the buffer
void saadc_callback_handler(nrf_drv_saadc_evt_t const * p_event)
{
nrf_saadc_value_t adc_average = 0;
eSAADCChannel channel;
// check if the sampling is done and we are ready to take these samples for processing
if (p_event -> type == NRFX_SAADC_EVT_DONE)
{
ret_code_t err_code; // a variable to hold errors code
// Take the samples in the buffer in the form of 2's complement and convert them to 16-bit interger values
err_code = nrfx_saadc_buffer_convert(p_event->data.done.p_buffer, SAADC_SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(err_code); // check for errors
// Determine which channel we're dealing with, so we know where to put the return value
if (p_event->data.done.p_buffer == m_buffer[SAADC_CH_VDIFF])
channel = SAADC_CH_VDIFF;
else if (p_event->data.done.p_buffer == m_buffer[SAADC_CH_5V_MON])
channel = SAADC_CH_5V_MON;
else if (p_event->data.done.p_buffer == m_buffer[SAADC_CH_12V_MON])
channel = SAADC_CH_12V_MON;
else if (p_event->data.done.p_buffer == m_buffer[SAADC_CH_24V_MON])
channel = SAADC_CH_24V_MON;
else
return; // We didn't find which channel we're dealing with
// Store the value for returning
for (int i = 0; i < SAADC_SAMPLES_IN_BUFFER; ++i)
adc_average += p_event->data.done.p_buffer[i] + 9;
adc_value[channel] = adc_average >> 2; // We know SAADC_SAMPLES_IN_BUFFER is 4
}
}
// Initialize the Successive Approximation Analog to Digital Converter Driver
void SaadcInit(void)
{
ret_code_t err_code; // variable to store the error code
nrf_saadc_channel_config_t channel0_config = NRFX_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN2);
nrf_saadc_channel_config_t channel1_config = NRFX_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN3);
nrf_saadc_channel_config_t channel2_config = NRFX_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN7);
nrf_saadc_channel_config_t channel3_config = NRFX_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN6);
// Initialize adc module (NULL is for configurations) configured via CMSIS Configuration wizard
err_code = nrf_drv_saadc_init(NULL, saadc_callback_handler);
APP_ERROR_CHECK(err_code);
// allocate the channels along with the configurations
err_code = nrfx_saadc_channel_init(SAADC_CH_VDIFF, &channel0_config);
APP_ERROR_CHECK(err_code);
err_code = nrfx_saadc_channel_init(SAADC_CH_5V_MON, &channel1_config);
APP_ERROR_CHECK(err_code);
err_code = nrfx_saadc_channel_init(SAADC_CH_12V_MON, &channel2_config);
APP_ERROR_CHECK(err_code);
err_code = nrfx_saadc_channel_init(SAADC_CH_24V_MON, &channel3_config);
APP_ERROR_CHECK(err_code);
// allocate buffer where the values will be stored once sampled
do
{
err_code = nrfx_saadc_buffer_convert(m_buffer[SAADC_CH_VDIFF], SAADC_SAMPLES_IN_BUFFER);
nrfx_wdt_channel_feed(m_channel_id);
} while (err_code == NRFX_ERROR_BUSY);
APP_ERROR_CHECK(err_code);
do
{
err_code = nrfx_saadc_buffer_convert(m_buffer[SAADC_CH_5V_MON], SAADC_SAMPLES_IN_BUFFER);
nrfx_wdt_channel_feed(m_channel_id);
} while (err_code == NRFX_ERROR_BUSY);
APP_ERROR_CHECK(err_code);
do
{
err_code = nrfx_saadc_buffer_convert(m_buffer[SAADC_CH_12V_MON], SAADC_SAMPLES_IN_BUFFER);
nrfx_wdt_channel_feed(m_channel_id);
} while (err_code == NRFX_ERROR_BUSY);
APP_ERROR_CHECK(err_code);
do
{
err_code = nrfx_saadc_buffer_convert(m_buffer[SAADC_CH_24V_MON], SAADC_SAMPLES_IN_BUFFER);
nrfx_wdt_channel_feed(m_channel_id);
} while (err_code == NRFX_ERROR_BUSY);
APP_ERROR_CHECK(err_code);
}
void UpdateSaadc(void) // Call this regularly and repeditively through the main loop
{
nrfx_saadc_sample(); // FYI: The error busy is ignored because it will do nothing
}
uint16_t GetHostPIUCurrent(void)
{
return (adc_value[SAADC_CH_VDIFF] >= 0) ? adc_value[SAADC_CH_VDIFF] : 0; // + PIU_CURRENT_NOISE_OFFSET???
}