CPE 329: Digital-to-Analog ConversionInterfacing the ATmega 328 and the Ardunio Uno to a DAC. Revisions Created by John Oliver 10.12.2010 Edited by John Oliver 03.20.2012 Objective Understand how to use a digital-to-analog converter and how to interface it to an ATmega328 microcontroller. Introduction This document will discuss digital-to-analog converters (DAC) and walk-through the setup of a DAC with the ATmega328. In particular, this document uses a National Semiconductor DAC121S101, 12-bit D/A converter, which are found on Digilent Inc.’s DA-2 PMOD board. Other devices that use SPI communication protocols will follow a similar procedure, and will be discussed later. This document assumes you have completed the ATmega SPI tutorial (the previous assignment). A DAC is a device that converts a digital (usually binary) code to an analog signal (current, voltage, or electric charge). An analog-to-digital converter (ADC) performs the reverse operation. Signals are easily stored and transmitted in digital form, but a DAC is needed for the signal to be recognized by human senses or other non-digital systems. Digital-to-analog conversion can degrade a signal, so be careful about choosing the DAC with the correct properties (not a problem in CPE 329, but can be challenging when you are working in industry). Due to cost and the need for matched components, DACs are almost exclusively manufactured on integrated circuits (ICs). There are many DAC architectures which have different advantages and disadvantages. The suitability of a particular DAC for an application is determined by a variety of measurements including speed and resolution. The two most common DAC types are DACs built with a pulse-width modulator method, and oversampling/interpolating DACs such as the delta-sigma DAC. Experiment We will use the ATmega as an SPI master - the microcontroller will initiate all communications with the DAC. Reminder, the SPI for the ATmega328 is muxed with the pins of PORTB. The PMOD board has 5 connections of use to use, and should be connected to the ATmega328 as shown below: ATmega328 PMOD DA-2 1 we first need to make !SS active (go low). SYNC 2.waiting in a busy loop until the byte transfer has been completed. Assignment: 2 . Alternatively. SCK GND VDD Once the connections have been made. but we need to write 12b of data to the DAC. we need to perform a write. you can setup the SPI to generate an interrupt when the byte has been transferred. the program falls into two phases. then put the high-byte of our 12b value into the SPI's data register SPDR. In this example. We wait for the low-byte to be transferred. SPI initialization and writing data to the SPI. So each write is actually going to be comprised to two different writes to the DAC.PB2 (SS) PB3 (MOSI) PB5 (SCK) GND VDD 1. To initialize the SPI. The DAC expects the following configurations for the SPI Control Register: SPCR DORD MSTR CPOL CPHA SPR1 SPR0 0 MSB transmitted first 1 Master enabled 0 active high clock 1 sample on falling edge 0 freq / 4 0 It is also good practice to clear the SPI status register before using the SPI: SPSR SPIF WCOL SPI2X 0 clear pending interrupt 0 clear write collision flag 0 regular rate SCK Please familiarize yourself with the different control and status bits for the SPI prior to doing the lab by reading the SPI register description in the data sheet. we need to make sure that we setup the SPI in a configuration that will operate well with the DAC. DINA 4. we need to program the ATmega to write values to the DAC. disable the slave select and we are done! The example code at the end of this document demonstrates this communications process. we will poll the status register to see when this byte has been transmitted . Once the high-byte has been transferred. Similar to the previous tutorial on the SPI. Now that initialization is done. The SPI on the ATmega328 is an 8b SPI port. To perform writes to the DAC. we can then proceed to the lowbyte. Submit an electronic document via Polylearn that has your names. Create a triangle wave using a minimum of 10 different points per period of the triangle wave. 3. Re-write the example program to create a squarewave that has a 1V peak-to-peak with a 1V DC offset with the same period. The code below creates a square wave that is about 1. 2.1. void Transmit_SPI_Master(int Data).66 V DC offset with a 20 uS period. #define F_CPU 16000000 #define MOSI 3 #define SCK 5 #define SS 2 #include <avr/io. //define internal CLK speed // PB pin 3 // PB pin 5 // PB pin 2 3 . Get a scope capture of the output of the DAC.h> void Initialize_SPI_Master(void).h> #include <util/delay. Get a scope capture of the output of the DAC. your waveforms from the scope captures and your code for your triangle wave.6V peak-to-peak with a 0. SCK and SS outputs //0xAAA / 0xFFF = 2739 / 4096 = ~ 2. send high byte first while (!(SPSR & (1<<SPIF))). PORTB = 1 << SS. Initialize_SPI_Master(). // end main // make MOSI. } // end while return 0. _delay_us(10). // send low byte next while (!(SPSR & (1<<SPIF))). DDRB = 1<<MOSI | 1<<SCK | 1<<SS.int main(void) { int count = 0. // de-assert slave select } 4 .66 } void Initialize_SPI_Master(void) { SPCR = (0<<SPIE) | (1<<SPE) | (0<<DORD) | (1<<MSTR) | (0<<CPOL) | (1<<CPHA) | (0<<SPR1) | (0<<SPR0) . _delay_us(10). while(1) { Transmit_SPI_Master(0xAAA).// Wait for transmission complete PORTB = 1 << SS.// Wait for transmission complete SPDR = 0xFF & Data.2V //0x333 / 0xFFF = 819 / 4096 = ~ 0. //No interrupts //SPI enabled //shifted out LSB //master //rising leading edge //sample leading edge //clock speed //SPI interrupt flag //Write collision flag //Doubles SPI clock // make sure SS is high } void Transmit_SPI_Master(int Data) { PORTB = 0 << SS. Transmit_SPI_Master(0x333). // Start transmission. // assert the slave select SPDR = (Data >> 8) & 0xF. SPSR = (0<<SPIF) | (0<<WCOL) | (0<<SPI2X) . com/downloads/en/devicedoc/21897b. which comes in a convenient DIP package that is easy for us to use on a breadboard and is only $2.microchip.pdf) To initialize the SPI for communicating with the MCP 4921. The datasheet for this DAC is located at: (http://ww1. SPDR = 0xFF & Data. Also note that from the waveform that the clock edge polarity should be set to leading edge. //Assert slave select SPDR = ((Data >> 8) & 0xF) | 0x70. Another DAC that could be used is the Microchip MCP4921. PORTB = 1 << SS. where the top nibble are some control bits. with the following exceptions: The clock polarity (CPOL) should should be set so that the SCK should idle low and the clock phase (CPHA) should be set so that data is sampled on the rising edge of SCK.Notes The Digilent PMOD DA2 is super expensive (~$30). //Attach configuration Bits onto MSB while (!(SPSR & (1<<SPIF))). void Transmit_SPI_Master(int Data) { PORTB = 0 << SS. Below is a write function to show how a 16b write can be accomplished. while (!(SPSR & (1<<SPIF))). Below is the waveform for writing to the MCP4921. You can see that this 12b DAC requires 16b of data to be written. follow the same initialization code as in the code provided with this lab. } 5 .