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.
- MISO (Master In Slave Out)
- MOSI (Master Out Slave In)
- SCK (Serial Clock)
- 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 |
- CH0 : Analog Input Channel 0
- CH1 : Analog Input Channel 1
- CH2 : Analog Input Channel 2
- CH3 : Analog Input Channel 3
- N/C : Not Connected.
- N/C : Not Connected.
- DGND : Digital Ground.
- CS: Chip Select.
- Din : Connected to AVRs MOSI
- Dout : Connected to AVRs MISO
- CLK : Connected to AVRs SCK
- Agnd : Analog Ground
- Vref : Reference Voltage. (Don't know what is Vref then See: Using the Analog To Digital Converter. )
- 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).
Interfacing MCP3204 SPI ADC with AVR ATmega32 |
Downloads




hi can u please upload a c programming to interface mcp3204 with Philips 80c51. its urgent as i require for my project
@Lokesh
Sure why not! Just pay me US$500.
thank u..the amount u asked inspired me to write the program myself and its working really good…
Nice post. Found it really helpful.
Can you please explain the purpose of the following lines in the code a bit clearly?? Please sir
byte=ch<<6
data_high&=0b00001111
data_low=SPIWrite(0xFF)
Outstanding tutorial! I have it working using the 10bit version ADC MCP3004 and I can’t seem to work out the scaling of the ADCs. They still go to 4095. Can you provide clue?
This has been profoundly helpful! Keep it up!