MCP3903 Library

MCP3903 is a six channel Delta-Sigma A/D converter. It features six synchronous sampling differential channels which can be programmed to sample between 16 bit and 24 bit accuracy, the gain for each channel can also be programmatically set from 1 up to 32. It also has an internal low tempco (5ppm/°C) voltage reference, making MCP3903 an excellent choice for digitizing small differential signals from various sensors.

I have created a library for Arduino. It allows you to explore most of the functionalities MCP3903 provides with ease. The library can be downloaded towards the end of this post as usual. And it is also available on GitHub.

MCP3903 communicates with MCU over SPI and for the most part, the communication is pretty straight forward. Unlike many SPI devices for which the sending and receiving of the data happen simultaneously during an SPI.transfer call, sending and receiving data are done in MCP3903 via different commands. In its simplest terms (which covers most of the scenario), the communication (either sending or receiving) packet includes four bytes. The first byte is the control byte, which contains the device address, the register needs to be accessed and whether this command is a read or write. The subsequent three bytes are either read from or send to MCP3903 depending on whether the command is a read or write.

This fixed-width command structure makes programming very easy. For different ADC resolutions (e.g. 16 bit versus 24 bit) the command and data structures are identical. The ADC result would always contain 24 bits, the lower bits are simply filled with zeros when the resolution used is less than 24 bits. Again, this makes programming a lot simpler as we can treat all conversion results as 24 bits regardless of the resolution used.

Of course, when using some special features (e.g. continuous read), the command structure is slightly different than what we have mentioned above, but you can always add in these functions if you want to use them. But 90% of the time the functionalities provided in this library should be sufficient.

There are a couple of things you will need to pay attention to when using MCP3903. First, voltages applied at each differential pairs are limited to ±0.5V (when using a gain of one). While each of the analog inputs can handle up to ±6V without suffering any damage, the measurement results will not be accurate when the voltages fall outside of the linearity range. Second, MCP3903 has a gain of 3 amplifier on each channel, which is independent of the programmable gain settings. If you take a look at the implementation of the library function readADC, you will notice that the result has been scaled down by a factor of 3 to reflect the original measurement value.

Below are a few most used functions. For the full implementation, please refer to the source code linked towards the end of this post.

reset

This function resets MCP3903 to 24 bit operation mode (when no parameter is supplied), or you may specify a predefined OSR (over sampling ratio) factor for the desired bit resolution. Note that the reset does not change other register settings except for the gain setting mentioned earlier. According to the datasheet, a full reset can only be achieved via the RESET pin (pin 27).

setGain

This function changes the gain setting for the given channel. It can take either two parameters or three parameters. When two parameters are supplied, the first parameter is the channel number (0-5), and the second parameter is the desired gain (GAIN_1, GAIN_2, GAIN_4, GAIN_8, GAIN_16, GAIN_32 and GAIN_64). When a third parameter is supplied, the last parameter indicates whether to turn on current boost mode for the channel (1 to turn on boost).

readADC

Returns normalized ([-1,1]) ADC data for the supplied channel. Multiply this result by the reference voltage will yield the measured voltage. Because the value for the internal high stability (5ppm/°C) voltage reference can vary up to ±2%, you will want to measure the reference output with a high precision meter to obtain the reference voltage for your particular ADC first rather than relying on the nominal value to achieve the most accurate result. The nominal value for the internal voltage reference is 2.35V (in my example below, the actual reference voltage is 2.36V).

The following code shows how to read channel 1 results with 24 bit resolution and use a gain of 8. As mentioned earlier, the OSR_256 parameter can be omitted in this case as it is equivalent to the default reset with no parameter.

#include "MCP3903.h"
#include <SPI.h>

MCP3903 mcp3903;

void setup()
{
    SPI.begin();
    Serial.begin(9600);
    
    mcp3903.reset(MCP3903::OSR_256);    
    mcp3903.setGain(1,MCP3903::GAIN_8);
}

void loop()
{
    Serial.println(mcp3903.readADC(1) * 2.36 , 4);
    delay(100);
}

A few features are left out from this library (e.g. phase delay compensation between each pair of channels, pre-scaler settings, continuous read, etc.), but those who are interested can consult the datasheet and add in easily. The schematic below is the recommended design using internal voltage reference, note that the supply voltage for the digital portion of the circuitry is different from the analog portion. According to the datasheet, AVdd should be between 4.5V and 5.5V and DVdd should be between 2.7V and 3.6V.

MCP3903_Test

Here is a picture of my test setup. In the picture below, a small differential voltage is applied to channel 0 via a resistor bridge.
MCP3903_breadboard

Download

MCP3903.tar.gz
GitHub

Be Sociable, Share!

19 Comments

  1. Sergio says:

    Hi, first of all great job making the library!

    I’m planning to use the MCP3903 with Arduino UNO and the library will be a great help!

    Just a few questions: In the circuit you connect the 4MHz oscillator to OSC1 and OSC2, what are the values of the C4 and C5 caps? It seems like 33uF but I’m not sure

    And I can’t see very clear the part of the board with transistor and caps, connected to pins 27 / 28, what are these for? Are you making the 3.3V from 5V?

    Thanks in advance!

    • kwong says:

      Hi Sergio,

      C4 and C5 are load capacitors, in my circuit they are both 33pF. In general their value depends on the crystal you use, but typical values range from 20 to 60 pFs.

      That isn’t a transistor, it’s a 3.3V voltage regulator.

      • Sergio says:

        Great!

        I was planning to use the Arduino built-in 3.3V for DVDD, but maybe would be more elegant to use a regulator.

        As soon as my chip comes I will start playing XD

        Thank you!

  2. jaytar says:

    I followed your schematic, but I keep getting zeros from the ADC. Did a similar problem occur for you?
    (The readADC()-Method returns 0.00).
    Thanks in advance!

    • kwong says:

      I don’t recall running into this particular problem. Assuming you are reading from the correct channel, the only thing I’d double check is to make sure that the oscillator is working on MCP3903. and the MOSI pins are connected correctly (in this case you need to use pin 10 as CS).

      • jaytar says:

        I’m really stuck. Actually, I rewrote the entire SPI library (in order to add some delays, needed for my crappy scope to catch the bits) – but although the Arduino sends everything correctly, monitoring the SDO output shows exactly the same signal as on SDI (apart from some strange noise). I tried every register (Channels + Config registers). I tried it both with Arduino Due (3.3V logic) and Arduino Micro (5V logic).
        This behavior doesn’t even change when I remove power supply from the Chip.
        Anyone who can help me? Thanks a lot!

      • AR says:

        I am having the same problem (getting 0.00). I also tried mcp3903 on Raspberry pi using my own program but still I got 0.00.
        Is there any solution to this problem?

        Is there any library for interfacing MCP3903 with Raspberry pi ?

  3. Chris says:

    Is the 4 mHz oscillator required, or does the MCP3903 have an internal oscillator?

  4. Abhinav says:

    Hi

    We have used this ADC (MCP 3903) with our PIC32MX series board and we are reading it for a Load measurement application. Now what I want to achieve is to have 1 in 10000 stable counts but we are finding it hard to achieve.

    Can you suggest how to get stable data.

    Abhinav

  5. jose says:

    Hola yo tambien estoy teniendo el mismo problema. Sólo con sigue ceros a la salida. ¿Cuál puede ser el fallo?

  6. Marko says:

    Hi everybody!
    First of all thanks for the good post. I have one simple question regarding the MCP3903.
    I’m measuring only positive voltage, so CHn- are all connected to GND. If I understand the datasheet correctly, the maximum Vref+ = 2.9V which mean: (-2.9V/3)<input voltage range<(+2.9V/3) or in my case: 0V<input range<(+2.9V/3)? So I can only measure voltage range up to 0.97V and with 23-bit resolution (because 1MSB is lost due to positive input signal)?
    BR, Marko

  7. Vinayak Joshi says:

    Hi, I interfaced the MCP3903 to an arduino Due with the help of your library and a few modifications making use of bitbanged SPI.

    I am using this ADC to measure the anguler position of a motor via a potentiometer. The problem that I am facing is that the signal from the ADC keeps varying, right upto the 12th bit. I wanted 23bit resolution, but due to this variation, I am having only as good as 8 bit resolution. Can you tell me what I may have done wrong, or whether, the ADC just works that way.

    NOTE i have set the gain to 1 and OSR to 256, using internal refrence,

  8. Peteorito says:

    Hi
    A chic library!! Thanks for all! At first i had some problem because i haven`t read the datasheet and inputs are [-1,1] . I have made a resistor divided for reading one sensor that has a +5v output!!
    :)

  9. Bogdan says:

    If someone know the formulae for ADC when using 16bit AC signal, it will be of great help.

  10. Hi Kerry,
    last days i build up my MSP3903. Thank you for your library. I was a great help to make the first steps on this great chip. In your library there is no hint of your Copyright. Is your library CC/GNU? If yes, wich conditions you have declared?

    Best regards

    Jennifer

  11. Emerson says:

    Good morning.
    I am trying to test MCP3903 out using your program.
    My setup uses a voltage regulator with a potentiometer as an input, It goes from 0 up to times the reference voltage (2V), the problem is whenever the voltage goes negative the serial plotter jumps to 1700 V and I can’t seem to grasp why.

Leave a Reply to AR