I am finding that the voltage measurement is about .52 volts off when measuring Vdd I have set up a power supply and connected it to external power. My saadc is set up with 14 bit resolution, a gain of 4, an internal reference (.6v). I set oversample to try to improve results, as well. With the usb connected, the saadc is reporting about 2.74 volts and my understanding is the usb is regulated to 3.3 volts. To get the voltage I am dividing the EasyDMA result by 4551.1 (1/6 / .6) * 2^14
My solution is to subtract .52v off the measured voltage. I was trying to get better insight into what is going on by adjusting my power supply and seeing what the reported voltage is. Unfortunately, the USB cable power source conflicts with the external power supply so I cannot use external power to vary the voltage. Attempting to rectify that, I removed the 5V supply from the USB cable but it appears the JLink connection requires the 5V source and JLink failed.
I am looking for help on how to debug the adc and saadc and get around the supply source problem.
I realize that subtracting .52v is not a good way to solve this problem as something fundamental must be wrong. Here is the saadc code and the routine to test the voltage:
static void saadc_init(void){
// Configure SAADC singled-ended channel, Internal reference (0.6V), and 1/6 gain.
NRF_SAADC->CH[0].CONFIG = (SAADC_CH_CONFIG_GAIN_Gain1_6 << 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_5us << SAADC_CH_CONFIG_TACQ_Pos);
(SAADC_CH_CONFIG_BURST_Enabled << SAADC_CH_CONFIG_BURST_Pos);
// Configure the SAADC channel with VDD as positive input, no negative input(single ended).
NRF_SAADC->CH[0].PSELP = SAADC_CH_PSELP_PSELP_VDD << 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;
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;
NRF_SAADC->OVERSAMPLE = SAADC_OVERSAMPLE_OVERSAMPLE_Over8x << SAADC_OVERSAMPLE_OVERSAMPLE_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;
// Calibrate the SAADC
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));
}
static void low_battery_test(){
// 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;
// Convert the result to voltage
// Result = [V(p) - V(n)] * GAIN/REFERENCE * 2^(RESOLUTION)
// Result = (VDD - 0) * ((1/6) / 0.6) * 2^14
// VDD = Result / 4551.1
precise_result = (float)result / 4551.1f;
//trip low battery if voltage is less than 2.5 volts
if(precise_result < BATTERY_LOW-.52){
//update the transmit packet content
batt_low = true;
}
int main(void){
saadc_init();
low_battery_test();
}
