rocketnumbernine

Andrew's Project Blog: Hardware, Software, Stuff I find Interesting

MC3201 ADC being used with SPI

The Serial Peripheral Interface - SPI - allows digital devices to communicate using only 4 wires, additional devices can be added to the same 'bus' with the addition of only a single selection wire for each device.

There are many integrated circuits and other devices that can be controlled via SPI, this entry details a simple experiment with a MCP3201 12-bit Analogue to Digital Converter.

Background

Each end of a SPI connection is acting in one of two roles - Master or Slave. The master is responsible for initiating and controlling the communication.

SPI Master/Slave Connections

The basic mode of operation is very simple: When the master wishes to initiate transfer of data:

  1. It sets the SS (Slave Select - often called CS - chip select) pin low to tell the slave that communication is about to start
  2. The master writes a bit of information onto the MOSI (Master Out Slave In) wire (sets it to 0 or 1) and the slave does the same on the MISO wire (either of these can be omitted if the data transfer is one way)
  3. As the master ticks the clock line SCLK it will read the value of MISO (Master In Slave Out) wire (which the Slave has written) and the slave will read the value of the MOSI wire (whether the data is sampled as the clock rises or falls depends on which mode is in operation)
  4. The process is repeated from (b), transferring a bit of data on each pulse of the clock until all data is transferred

The above can be implemented in software using normal I/O pins but nearly all AVR microcontrollers have hardware support, thus to transfer a byte is simply a matter of doing:

1
2
3
4
5
SPDR = 0x2A; // set byte to send (0x2A)
// loop until SPI flag is set to signal
//  data has been transferred.
while(!(SPIR & _bv(SPI)));
// byte received from slave is now in SPDR register

In master mode any I/O pin on the MCU can be used as chip select to tell the slave that it is being selected. In slave mode the SS pin will be lowered to indicate that this device is being selected. The I/O pins used for SPI vary across the AVR family, for example the pins for the AT90/ATmega/ATtiny are shown below along with the Arduino mappings.

MCU/DeviceSSSCKMOSIMISO
AT90USB82/162 PB0PB1PB2PB3
ATmega48/88/168/328 PB2PB5PB3PB4
ATtiny8--PA6PA5
Arduino10131112

Setup

Although the pins may be different, setup is fairly consistent across all (as well as the spec sheets for individual MCUs AVR SPI support is described in AVR151: Setup And Use of The SPI)

SPI is configured using by setting the SPI Control Register (SPCR) with the following bits:

  • Enable - (SPE) - 1 to enable SPI
  • Master/Slave - (MSTR) - whether the MCU is acting as a master or slave.
  • Clock Divisor - (SPR0, SPR1, SPXI2 in SPSR) indicates the frequency of the clock, represented as a divisor of the MCU clock
  • SPI timing mode (CPOL, CPHA) - controls if data is output to the MISO and read on the rising or falling edge of SCK
  • Data Order - (DORD) - whether MSB or LSB is transmitted first.
  • Enable Interrupt (SPIE) - whether an interrupt should be raised on successful transfer of data.

To simplify setup I created a basic helper library (currently just for master mode) with a setup function that takes a timing mode, data order, interrupt, and master clock/slave spec arguments, and #defines for the values - spi.h, spi.c.

Following shows some simple SPI interaction with the MCU acting as master with a simple device.

SPI to a 12 bit A/D convertor

The picture below shows a Microchip Technology MCP3201 12 Analogue to Digital converter connected to the SPI pins of an MCU. Although most AVRs have an ADC (the AT90USB162 doesn't)- the MCP3201 offers higher precision than the 10-bits in most.

Testing SPI interaction between a AT90USB162 (in a teensy board) and an MC3201 ADC

Control of the MCP3201 D/A converter is fairly straightforward and detailed in the (datasheet. When the microcontroller sets the ^CS pin to low the chip samples the input to IN+ (a potentiometer provides the input in the circuit above) sends the digital representation on Dout line as the CLK line is pulsed by the master. The MCP3201 is a read only device MOSI is not used.

From the datasheet we see the clock frequency can be a max of 1.6MHz at 5V - using a divider of 16 (assuming 16MHz Microcontroller clock) for SPI will give us a safe 1MHz clock frequency. The device is agnostic about whether operating with leading or trailing clock (can be used in any SPI timing mode). The only tricky part is that the 12 bits will be delivered in 2 bytes (most significant bit first), which will have to be recomposed into a single value - see figure 6.1 of the datasheet. The following samples the value and displays the value of the top 3 bits by lighting one of the 8 LEDs on the port B.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <avr/io.h>
#include <util/delay.h>
#include <spi.h>

#define SELECT_ADC PORTB &= ~(1<<PB4)
#define DESELECT_ADC PORTB |= (1<<PB4)

unsigned short read_adc(void)
{
  // select ADC wait 100 microseconds then read two bytes
  SELECT_ADC;
  _delay_us(100);
  unsigned char one = send_spi(0xFF);
  _delay_us(100);
  unsigned char two = send_spi(0xFF);
  DESELECT_ADC;
  // 12 bits of ADC value is bottom 5 bits of first
  // byte and top 7 bits of second, move into 16 bit int
  return ((0x1F & one) << 7) | (two >> 1);
}

int main(void)
{
  DDRB |= (1<<PB4); // chip select for ADC
  // use port D for LEDs
  DDRD = 0xFF;
  PORTD = 0x00;

  // make sure ADC is unselected and setup spi
  DESELECT_ADC;
  setup_spi(SPI_MODE_0, SPI_MSB, SPI_NO_INTERRUPT, SPI_MSTR_CLK16);

  while (1) {
    unsigned int num = read_adc();
    PORTD = (1<< (num >> 9)); // use the top 3 bytes to turn on LED
    _delay_ms(1);
  }  
}

Updated 2010/02/24:

SPI library code moved to Google Code

References

It looks like your browser doesn't support javascript so comments won't work

Tags/Categories: AVR, SPI, Serial, MCP3201, DAC, at90usb162, atmega328, howto

Contact
andrew @ rocketnumbernine.com
Feed-icon16x16 Subscribe to RSS
phatIO
Checkout phatIO an IO device that looks like a USB filesystem

Set a pin to 5V by saving "1" to its control file, set it back to 0V by saving "0".
Control LCD and LED displays by writing the data to display to a file.
Communicate with TWI, and SPI and other devices by writing data to a file.
Videos, reference and more at phatIO
Share with others: