Problem Using ADC in Differential Mode

Hi, I have a SARA N211 AFF and I want to use it to read some sound datas coming from the Grove Sound Sensor.
I saw the schematic of the sensor and I understood that the output analog signal is bipolar (so it can be both positive and negative, with respect to the ground).
Consequently, I need to set the ADC in Differential Mode (as I read in the SAMD21 User guide " If the positive input may go below the negative input, creating some negative results, the differential mode should be used in order to get correct results").
So I set the ADC in DIFFMODE by writing the corresponding register, and I started looking at the serial plotter and at the serial monitor. What I notice is that the ADC’s output value only becomes 0 or 65535, so it seems not to work (I also wrote the RESSEL bit to ensure a 12-bit resolution conversion).
In addition, I didn’t modified the MUXNEG selection (by default it is set at internal ground), because I think that I’m on the right way, i.e. my ADC positive input (that comes from the sound sensor) can also be negative, so it can be lower than the ADC negative input (internal ground), and this thing should be ok for the DIFFMODE configuration.


Could you explain a bit more about how you have setup the ADC.

Also, what function are you using to read the ADC value. If the value range is 0…65535, this indicates that the return value is an unsigned 16bit integer.

Sure @GabrielNotman.

I set up the ADC in the following way:
ADC->CTRLB.bit.RESSEL = 0x0; //12-bit mode
ADC->REFCTRL.bit.REFSEL = 0x01; // Ref = VDDANA/1,48 = 2,23 V

To read the ADC value, I use the analogRead() function by default on Arduino. By reading these registers on the Serial Monitor, I noticed that after using this function to read values from ADC, the setup that I wrote above doesn’t change, so it seems that the analogRead function doesn’t affect the registers.

I also tried to change the MUXPOS and MUXNEG bits to give an external ground reference to the ADC.

By the way, here is what I think about this problem:
I have an analog signal that could assume both positive and negative values (with reference to the ground), as a normal sinusoidal wave with offset = 0 V.
This analog signal goes to the ADC and I want that the negative half part of the wave doesn’t go lost.
I think that a differential mode is not what I really need for this measurement, because is ok to have the negative input of the ADC connected to the internal ground (as it is in single ended default mode), while the positive input of the ADC oscillates around -1 V and +1 V, for example.
Bu, as I said before, I read on the SAMD21 user guide that if the positive input may go below the negative one, the differential mode should be used. For this reason I’m going on that way.

Sorry for my english, I hope I managed to explain my situation in the best way possible


The code for the built in Arduino ADC functions can be found in ‘wiring_analog.c’:

I believe the MUXPOS is already setup for the correct positive input, but you also are required to set MUXNEG when in differential mode.
See p.806:

I’ve not actually ever measured a negative readings. However, I believe that the data is found in the ADC->RESULT register, in some form.

This application note with ASF might be useful:

Also, if you have access to ASF you could try loading that example and have a peek at how they configure things for differential mode.

@GabrielNotman Thank you very much for your help!

Thanks again for your support @GabrielNotman, I would like to ask a suggestion about my project.
As I wrote in my first post, the goal is to collect sound data from the sensor mentioned.
For example, I need to store all the samples during 1s and then elaborate them in some ways.
Let’s focus on the first part, the storing of the samples in 1s (whose number should depend on the ADC sampling frequency), or the storing of a pre-determined number of samples.

I was thinking about an interrupt-based way: by enabling the RESULT READY INTERRUPT (in the INTENSET register), every time that a new conversion is finished the INT RES RDY bit (in the INTFLAG register) will be ‘1’ and so I can execute the ADC Handler (after having enabled the interrupt reception in the NVIC configuration).
My idea is to fill a buffer array and increment a counter variable in the ADC Handler, every time that it is called, so after each new conversion.
Consequently, I should manage to keep track of how many samples I’m storing in the buffer array (in this case I will control the number of samples, instead of the duration of the interval during which I read datas, I suppose).
After, for example 1000 values read and copied to the buffer’s entries, with an If statement in the ADC Handler I could stop the conversion of new values by disabling the ADC (or its Free Running Mode).

Could that work?


I would recommend having a look at setting up the system using the DMAC (Direct Memory Access Controller) which is effectively designed to do exactly what you want (copy results to a location in memory, and then increment the memory address for the next write). A DMA approach would probably allow more efficient operation and possibly higher sample rates. If you don’t require a specifically high sample rate, then you could probably do it in a software via a interrupt routine.

Also with regards to controlling the sample timing, there are two ways. First you can control the whole ADC sample rate by adjusting the feed clocks and prescalars. The other approach would be to figure out how you can trigger the start of a new sample and then link that to some periodic timer.

Unfortunately I can’t provide any specific examples as I haven’t actually used these modes myself. As before, I would recommend you look at the examples from Microchip as they have written the official drivers for their ASF development setup.

I found a code that uses the DMAC to copy results to the SRAM memory, as you suggested me to do.

Thank you very much @GabrielNotman!