AVR Embedded Tutorial - SPI MCP4922

From Free Pascal wiki

Deutsch (de) English (en)

Control an MCP4922 12 bit DAC via SPI

This code is for an Atmega328 / Arduino with a 16MHz clock and an SPI compatible MCP4922 Digital/Analog Converter (DAC).

The following functions are described in other tutorials:

  • GPIO - Output/Input - How do I access the GPIO on the AVR.
  • SPI - use of the hardware SPI interface.

This example shows how to control the MCP4922 DAC via SPI.

Functions for the 74HC595 shift register

Constants

Pins which are required at PORTB for SPI.

 type
   TSPIGPIO = bitpacked record
     p0, p1, SlaveSelect, MOSI, MISO, Clock, p6, p7 : boolean;
   end;

 var
   SPI_PORT : TSPIGPIO absolute PORTB;
   SPI_DDR  : TSPIGPIO absolute DDRB;

Initialize SPI

 procedure SPIInit;
 begin
   // Setup SPI port for output
   SPI_DDR.MOSI        := True;
   SPI_DDR.Clock       := True;
   SPI_DDR.SlaveSelect := True;

   SPCR := (1 shl SPE) or (0 shl SPIE) or (0 shl DORD) or (1 shl MSTR) or (0 shl CPOL) or (0 shl CPHA) or (%01 shl SPR);
   SPSR := 1 shl SPI2X;  // SCK x 2 on 1 MHz
 end;

Write SPI

 procedure SPIWrite(p : PByte; len : byte);
 var
   i : byte;
 begin
   SPI_Port.SlaveSelect := False;

   for i := len - 1 downto 0 do
     begin
       SPDR := p[i];
       
       while(SPSR and (1 shl SPIF)) = 0 do
         begin
         end;
   end;

   SPI_Port.SlaveSelect := True;
 end;

MCP4922 functions

Bit assignments for the MCP4922:

Bit Name Description
15 A/B: DACA or DACB Selection bit 0 = Write to DACA
1 = Write to DACB
14 BUF: Vref Input Buffer Controlbit 0 = Unbuffered
1 = Buffered
13 GA:Output Gain Selection bit 0 = 2x (VOUT = 2 * VREF * D / 4096)
1 = 1x (VOUT = VREF * D / 4096)
12 SHDN: Output Shutdown Control bit 0 = Shutdown the selected DAC channel. Analog output is not available at the channel that was shut down. VOUT pin is connected to 500 kOhm(typical)
1 = Active mode operation. VOUT is available.
11:0 D11:D0: DAC Input Data bits. Bit x is ignored.

Send to DAC

 procedure MCP4922sendValue(Value : UInt16; Channel : Byte);
 type
   TADC = bitpacked record
     Value : 0..4095;  // bits 0-11
     ShutDown,         // bit 12
     Gain,             // bit 13
     VRef,             // bit 14
     DAC : 0..1;       // bit 15
   end;

 begin
   with TADC(Value) do 
     begin
       ShutDown := 1;
       Gain     := 1;
       VRef     := 0;
       Dac      := Channel;
   end;

   SPIWrite(@Value, 2);
 end;

Example program

This example shows the output of two analog values ​​from the DAC. Two LEDs connected to the DAC flash alternately with a very smooth transition.

Constants and variables

A counting variable that counts up to 4095.

 var
   z : Int16 ;

Main program

Alternately write a value in DAC 0 & 1.

 begin
   // initialize SPI.
   SPIInit; 

   repeat
     for z := 0 to 4095 do 
       begin
         MCP4922sendValue(4095 - z, 0);
         MCP4922sendValue(z, 1);
       end;
   until 1 = 2;
 end.

See also