Hello All,

Sometimes the Internal ADC is not enough. Like when you need more resolution
or high speed. The internal ADC of AVR generally has the following specifications.

  • 15K samples per second
  • 10 bit resolution.

If you need more than that you need an external ADC. You may also need external
ADCs if you have already used the internal ones. This tutorial will guide you
how to install an external ADC with AVR MCU and write a test program to get
data from it.

A very common external ADC is from Microchip
the MCP3204.
It has the following configuration.

  • 100K samples per second. (More than 6 times faster than AVRs inbuilt)
  • 12 bit resolution (4 times more detailed)
  • 4 input channels (MCP3208
    has 8 channels).
  • SPI Bus Compatible.

Basic SPI Tutorial

These ADCs are SPI Bus based which is a serial bus. So the number of pins in
IC is very low. Total of 4 lines are required to interface it with AVR MCU.

  1. MISO (Master In Slave Out)
  2. MOSI (Master Out Slave In)
  3. SCK (Serial Clock)
  4. CS (Chip Select)

As you know in synchronous serial communication their is a clock line (SCK
in case of SPI) which synchronizes the transfer. Please read the article :-

The clock is always controlled by the MASTER. In our case the AVR MCU is the
MASTER and the MCP3204 is a slave on the bus. SPI is full duplex, that means
data can be sent and received simultaneously

SPI Transfer.

A SPI transfer is initiated by the MASTER pulling the CS line low. The CS line
sits at HIGH during idle state. Now master can write to the bus in 8bit (or
1 byte) chunks. One most important thing to note about SPI is that for every
byte MASTER writes to SLAVE the MASTER receives one byte in return. So the only
transaction possible is exchange of data. Their is no separate Read and Write
commands their is only one command and that is Write. So in C language you will
write something like this

data_in=SPIWrite(data_out);

here data_in and data_out are 8 bit C variables
(unsigned char).

data_in is the data read from the SLAVE.

data_out is the data you want to send to the SLAVE.

So when you just want to read data do some thing like this

data_in=SPIWrite(any_junk_value); //any_junk_value is a DON'T Care data byte

And when you Only want to write data to the slave you write

SPIWrite(data_out); // The Compiler just ignores the return value

The MCP3204 12 bit SPI ADC Chip.

The PIN out of MCP3204 is shown below.

MCP3204 SPI ADC Pin Configuration

MCP3204 SPI ADC Pin Configuration

  1. CH0 : Analog Input Channel 0
  2. CH1 : Analog Input Channel 1
  3. CH2 : Analog Input Channel 2
  4. CH3 : Analog Input Channel 3
  5. N/C : Not Connected.
  6. N/C : Not Connected.
  7. DGND : Digital Ground.
  8. CS: Chip Select.
  9. Din : Connected to AVRs MOSI
  10. Dout : Connected to AVRs MISO
  11. CLK : Connected to AVRs SCK
  12. Agnd : Analog Ground
  13. Vref : Reference Voltage. (Don’t know what is Vref then See: Using
    the Analog To Digital Converter.
    )
  14. Vdd : Positive supply (5v).

SPI Transaction

The SPI Packet for one ADC Conversion is made up of 3 bytes. The complete transaction
is shown below.

MCP3204 SPI ADC Pin Configuration

Byte I

In this byte the Master Writes a bit sequence as shown below

’0′ ’0′ ’0′ ’0′ ’0′ ’1′ ‘S’ ‘D2′

Where S is the bit which selects between differential and single ended operation.
In our example we need single ended operation and for that this bit must be
1.

Byte II

In this byte MASTER Writes the following sequence

‘D1′ ‘D0′ ‘X’ ‘X’ ‘X’ ‘X’ ‘X ‘X’

Where D2,D1,D0 selects the input channel.

  D2 D1 D0
Channel 0
0
0
0
Channel 1
0
0
1
Channel 2
0
1
0
Channel 3
0
1
1
Channel 4
1
0
0
Channel 5
1
0
1
Channel 6
1
1
0
Channel 7
1
1
1

Note: Channel Number 4 to 7 are only available in MCP3208.

And the slave return the following sequence

‘?’ ‘?’ ‘?’ ‘N’ ‘B11′ ‘B10′ ‘B9′ ‘B8′

Where ‘?’ is Unknown bit and may be 0 or 1

‘N’ is Null bit and is always 0

Byte III

In this byte the Master writes a DON’T CARE Byte to slave. You can write any
value it does not matters.

In the same time Slave returns bits B7 to B0 of conversion.

So Bit B11 to B0 forms the 12bit result of Analog to Digital Conversion. Following
Code Example demonstrate the complete transaction.


/********************************************************************

Requests the ADC to perform conversion and send the result.

Arguments:
      uint8_t ch : Channel Number
      For MCP3204 ch is between 0-3 (Total 4 channels)
      For MCP3208 ch is between 0-7 (Total 8 channels)

Return Value:(TYPE uint16_t, i.e a 16bit unsigned int)
      The digital equivalent of analog input on selected channel.

      Since the ADCs are 12 bit the return value is between
      0-4095 (Including both)

********************************************************************/
uint16_t ReadADCEx(uint8_t ch)
{
   uint8_t byte,data_high,data_low;

   byte=0b00000110;

   if(ch>3)
      byte|=0b00000001;

   CS_LOW();

   SPIWrite(byte);

   byte=ch<<6;

   data_high=SPIWrite(byte);

   data_high&=0b00001111;

   data_low=SPIWrite(0xFF);

   CS_HIGH();

   return ((data_high<<8)|data_low);
}


Example Program

The following program reads the ADC result from MCP3204 and displays it in
the LCD module. See the following article from more information about LCD interface
routines.


/******************************************************************************
                        

Sample Program to Test "External SPI ADC Interface" libraries. The Simple job 
performed by this program is as follows:-

*to connect with external SPI ADC
*ask it to convert a analog value to digital on any channel say channel 0
*read the converted value
*display it in LCD Module


Hardware:
   ATmega32 running @ 16MHz
   FUSE HIGH = 0xC9 LOW=0xFF

   MCP320X Connected to SPI Port

   CS PIN of MCP320X Connected to PD7 (Can be chaned by editing spi.h)

   16x2 LCD Module Connected as
      * RS  -> PD3
      * R/W    -> PD6
      * E      -> PB4

      * D4  -> PB0
      * D5  -> PB1
      * D6  -> PB2
      * D7  -> PB3


                                     NOTICE
                           --------
NO PART OF THIS WORK CAN BE COPIED, DISTRIBUTED OR PUBLISHED WITHOUT A
WRITTEN PERMISSION FROM EXTREME ELECTRONICS INDIA. THE LIBRARY, NOR ANY PART
OF IT CAN BE USED IN COMMERCIAL APPLICATIONS. IT IS INTENDED TO BE USED FOR
HOBBY, LEARNING AND EDUCATIONAL PURPOSE ONLY. IF YOU WANT TO USE THEM IN 
COMMERCIAL APPLICATION PLEASE WRITE TO THE AUTHOR.


WRITTEN BY:
AVINASH GUPTA
me@avinashgupta.com

*******************************************************************************/

#include <avr/io.h>

#include "lcd.h"

#include "adc_ex.h"

void main()
{
   //Initialize LCD Module
   LCDInit(LS_ULINE);

   //Initialize External ADC Module
   InitADCEx();

   //A varriable to hold the converted value.

   uint16_t result;

   while(1)
   {
      //Read Channel Number 0
      result=ReadADCEx(0);

      //Display
      LCDWriteStringXY(0,0,"MCP3204 ADC Test");
      LCDWriteStringXY(0,1,"result = ");

      LCDWriteIntXY(9,1,result,5);
   }

}


The complete AVR Studio Project with all relevant support files is available
for download. The project composed of the following files

  • adc_ex.c : Support file for MCP3204 ADC
  • spi.c : Core SPI Communication library. adc_ex.c makes use of these SPI
    Functions.
  • lcd.c : Core LCD Interface Routines.
  • SPIADC.c : The main example file making use of functions in above files.

Hardware for Interfacing MCP3204 with AVR ATmega32

Fuse bits must be set so as to enable external crystal and disable JTAG. Example
LOW FUSE = FF and HIGH FUSE = C9

After running the demo rotate the POT(RV1) and see the value change in LCD
Module. If display is not visible adjust POT(RV2).

mcp3204 spi adc schematic

Interfacing MCP3204 SPI ADC with AVR ATmega32

Downloads