Você está na página 1de 4

CPE 329: Serial Peripheral Interface (SPI)

Using the ATmega 328 and the Ardunio Uno

Revisions
Created by John Oliver 10.05.2011 Edited by John Oliver 03.20.2012

Objective
Understand how Serial Peripheral Interface operates Understand how the different configurations of the SPI impact the way data is transmitted or received

Introduction
This document will introduce to you the Serial Peripheral Interface (SPI) protocol and walkthrough the setup and use of the SPI port of the ATmega328. SPI provides for fast data transfers synchronized to a clock signal. This serial protocol is a full-duplex connection that can send and receive one bit per clock. SPI is a master-slave protocol where the master initiates any transfers (reads or writes). Depending on how the SPI is setup, data can be transferred on the rising or the falling edge of the clock. Generally, there are four signal lines: 1. a clock, called SCK 2. a slave-select called SS (Slave Select) or CS (Chip Select) a. think of this as an active-low enable signal 3. a master-out/slave-in called MOSI (Master-Out-Slave-In) 4. a master-in/slave out called MISO(Master-In-Slave-OUT)

Figure 1. Example SPI Master Write

Figure 1 shows an example waveform of a SPI byte transfer. In Figure 1, CS first goes low (active low). Then SCK (CLK) starts. Transferring data bits are then placed on the MOSI line, one per clock. In Figure 1, the SPI is setup so that the clock phase is where the data is valid on the rising edge for a SCK that idles low. Optionally, the clock phase can be set so the data is transferred on the falling edge of the clock, and/or the SS line can be set to idle high. Regardless of setup, for every assertion of the SS, a chunk of data is transmitted. The size of this chunk of data can vary from device to device (chunk = 1 byte as shown in Figure 1). For this tutorial, all we will do is setup the SPI and play with its configuration in order to help us understand what the clock phase and polarity mean for the SPI interface. The SPI peripheral is similar to GPIOs and Timers, there are several control and data registers that must be modified to get the SPI to work. We will observe how the SPI performs on a logic analyzer. For this tutorial, we will use the ATmega as an SPI master (since we are not connecting it to any devices today). The SPI for the ATmega328 is muxed with the pins of PORTB (see the alternate functions sub-section of the I/O ports section of the datasheet, or the Getting Started Guide). As you know the SPI is a 4-wire synchronous communications protocol, but can be reduced to a 3-wire interface if the master only needs to write to an SPI device (no MISO needed). The three signals required are SS, SCK and MOSI, which share the pins PB2, PB5 and PB3, respectively. To initialize the SPI, we need to make sure that the relevant pins are setup as outputs and that we setup the SPI configuration registers. It is also good practice to clear the SPI status register before using the SPI. See the function Initialize_SPI_Master from the code at the end of this tutorial. Now that initialization is done, we need to perform a write (again see the Transmit_SPI_Master function from the code @ the end of the tutorial). To perform the writes, we: first need to put a byte into the SPI's data register SPDR. assert SS (active low). poll the status register to see when this byte has been transmitted - waiting in a busy loop 2

until the byte transfer has been completed. Alternatively, you can setup the SPI to generate an interrupt when the byte has been transferred. deactivate SS. Thats all there is to it! Note, you could always bit-bang with GPIOs to perform the SPI. It is just much simpler to use the SPI hardware built for you.

References:
There are several documents that are handy in learning about the SPI. The first is the datasheet, of course. There also exists a handy appnote by ATMEL called: "AVR151: Setup And Use of The SPI". It has some associated code on the ATMEL website as well.

Assignment:
1.

Use a logic analyzer and capture the SCK, MOSI and S signals from the tutorial code. Create an electronic document using scope waveform captures that that compares these signals for all the possible combinations of CPHA and CPOL (total of 4 sets of waveforms). You can save the images off the scope by inserting a USB memory stick into the scope. Put your names on the document and label all waveforms with the SPHA and CPOL setting. Submit your document to the Polylearn site. Logic analyzer pods can be checked-out from the senior projects room. Also play around with the data byte you are sending out so you can fully understand what is going on here (you dont need to draw diagrams for different data bytes).

2.

//define internal CLK speed #define F_CPU 16000000 #define MOSI 3 #define SCK 5 #define SS 2 // PB pin 3 // PB pin 1 // PB pin 2

#include <avr/io.h> #include <util/delay.h> void Initialize_SPI_Master(void); void Transmit_SPI_Master(char Data);

int main(void) { DDRB = 1<<MOSI | 1<<SCK | 1<<SS; Initialize_SPI_Master(); while(1) { Transmit_SPI_Master(0xF0); _delay_us(100); Transmit_SPI_Master(0x0F); _delay_us(100); } // end while return 0; // end main // make MOSI, SCK and SS outputs

void Initialize_SPI_Master(void) { SPCR = (0<<SPIE) | //No interrupts (1<<SPE) | //SPI enabled (0<<DORD) | //shifted out LSB (1<<MSTR) | //master (0<<CPOL) | //rising leading edge (1<<CPHA) | //sample leading edge (0<<SPR1) | (0<<SPR0) ; //clock speed SPSR = (0<<SPIF) | //SPI interrupt flag (0<<WCOL) | //Write collision flag (0<<SPI2X) ; //Doubles SPI clock PORTB = 1 << SS; // make sure SS is high

} void Transmit_SPI_Master(char Data) { PORTB = 0 << SS; // assert the slave select SPDR = Data; // Start transmission, send high byte first while (!(SPSR & (1<<SPIF)));// Wait (poll) for transmission complete PORTB = 1 << SS; // deassert the slave select }

Você também pode gostar