Xmega Application Note


spi_driver.c File Reference

XMEGA SPI driver source file. More...

#include "spi_driver.h"

Include dependency graph for spi_driver.c:

Go to the source code of this file.

Functions

void SPI_MasterCreateDataPacket (SPI_DataPacket_t *dataPacket, const uint8_t *transmitData, uint8_t *receiveData, uint8_t bytesToTransceive, PORT_t *ssPort, uint8_t ssPinMask)
 Create data packet.
void SPI_MasterInit (SPI_Master_t *spi, SPI_t *module, PORT_t *port, bool lsbFirst, SPI_MODE_t mode, SPI_INTLVL_t intLevel, bool clk2x, SPI_PRESCALER_t clockDivision)
 Initialize SPI module as master.
void SPI_MasterInterruptHandler (SPI_Master_t *spi)
 Common SPI master interrupt service routine.
uint8_t SPI_MasterInterruptTransceivePacket (SPI_Master_t *spi, SPI_DataPacket_t *dataPacket)
 Start transmission.
uint8_t SPI_MasterTransceiveByte (SPI_Master_t *spi, uint8_t TXdata)
 SPI mastertransceive byte.
bool SPI_MasterTransceivePacket (SPI_Master_t *spi, SPI_DataPacket_t *dataPacket)
 SPI transceive data packet.
void SPI_SlaveInit (SPI_Slave_t *spi, SPI_t *module, PORT_t *port, bool lsbFirst, SPI_MODE_t mode, SPI_INTLVL_t intLevel)
 Initialize SPI module as slave.


Detailed Description

XMEGA SPI driver source file.

This file contains the function implementations the XMEGA SPI driver.

The driver is not intended for size and/or speed critical code, since most functions are just a few lines of code, and the function call overhead would decrease code performance. The driver is intended for rapid prototyping and documentation purposes for getting started with the XMEGA SPI module.

For size and/or speed critical code, it is recommended to copy the function contents directly into your application instead of making a function call.

Several functions use the following construct: "some_register = ... | (some_parameter ? SOME_BIT_bm : 0) | ..." Although the use of the ternary operator ( if ? then : else ) is discouraged, in some occasions the operator makes it possible to write pretty clean and neat code. In this driver, the construct is used to set or not set a configuration bit based on a boolean input parameter, such as the "some_parameter" in the example above.

Application note:
AVR1309: Using the XMEGA SPI
Documentation
For comprehensive code documentation, supported compilers, compiler settings and supported devices see readme.html
Author:
Atmel Corporation: http://www.atmel.com
Support email: avr@atmel.com
Revision
764
Date
2007-11-06 14:52:26 +0100 (ti, 06 nov 2007)

Copyright (c) 2008, Atmel Corporation All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

3. The name of ATMEL may not be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Definition in file spi_driver.c.


Function Documentation

void SPI_MasterCreateDataPacket ( SPI_DataPacket_t dataPacket,
const uint8_t *  transmitData,
uint8_t *  receiveData,
uint8_t  bytesToTransceive,
PORT_t *  ssPort,
uint8_t  ssPinMask 
)

Create data packet.

This function prepares a data packet for transmission. Note that memory for dataPacket, transmitData and receiveData must be allocated outside this function.

Note:
The size of the receiveData and transmitData must be equal and bytesToTransceive should be set accordingly.
Parameters:
dataPacket Pointer to data packet used for this transmission.
transmitData Pointer to data to transmit.
receiveData Pointer to receive buffer.
bytesToTransceive The number of bytes to transmit/receive.
ssPort Pointer to I/O port where the SS pin used for this transmission is located.
ssPinMask Pin mask selecting the SS pin in ssPort.

Definition at line 173 of file spi_driver.c.

References SPI_DataPacket::bytesToTransceive, SPI_DataPacket::bytesTransceived, SPI_DataPacket::complete, SPI_DataPacket::receiveData, SPI_DataPacket::ssPinMask, SPI_DataPacket::ssPort, and SPI_DataPacket::transmitData.

Referenced by main().

00179 {
00180         dataPacket->ssPort            = ssPort;
00181         dataPacket->ssPinMask         = ssPinMask;
00182         dataPacket->transmitData      = transmitData;
00183         dataPacket->receiveData       = receiveData;
00184         dataPacket->bytesToTransceive  = bytesToTransceive;
00185         dataPacket->bytesTransceived   = 0;
00186         dataPacket->complete          = false;
00187 }

void SPI_MasterInit ( SPI_Master_t spi,
SPI_t *  module,
PORT_t *  port,
bool  lsbFirst,
SPI_MODE_t  mode,
SPI_INTLVL_t  intLevel,
bool  clk2x,
SPI_PRESCALER_t  clockDivision 
)

Initialize SPI module as master.

This function initializes a SPI module as master. The CTRL and INTCTRL registers for the SPI module is set according to the inputs to the function. In addition, data direction for the MOSI and SCK pins is set to output.

Parameters:
spi The SPI_Master_t struct instance.
module The SPI module.
port The I/O port where the SPI module is connected.
lsbFirst Data order will be LSB first if this is set to a non-zero value.
mode SPI mode (Clock polarity and phase).
intLevel SPI interrupt level.
clk2x SPI double speed mode
clockDivision SPI clock prescaler divison factor.

Definition at line 87 of file spi_driver.c.

References SPI_Master::dataPacket, SPI_Master::interrupted, SPI_Master::module, SPI_Master::port, SPI_MOSI_bm, and SPI_SCK_bm.

Referenced by main().

00095 {
00096         spi->module         = module;
00097         spi->port           = port;
00098         spi->interrupted    = false;
00099 
00100         spi->module->CTRL   = clockDivision |                  /* SPI prescaler. */
00101                               (clk2x ? SPI_CLK2X_bm : 0) |     /* SPI Clock double. */
00102                               SPI_ENABLE_bm |                  /* Enable SPI module. */
00103                               (lsbFirst ? SPI_DORD_bm  : 0) |  /* Data order. */
00104                               SPI_MASTER_bm |                  /* SPI master. */
00105                               mode;                            /* SPI mode. */
00106 
00107         /* Interrupt level. */
00108         spi->module->INTCTRL = intLevel;
00109 
00110         /* No assigned data packet. */
00111         spi->dataPacket = NULL;
00112 
00113         /* MOSI and SCK as output. */
00114         spi->port->DIRSET  = SPI_MOSI_bm | SPI_SCK_bm;
00115 }

void SPI_MasterInterruptHandler ( SPI_Master_t spi  ) 

Common SPI master interrupt service routine.

This function is called by the SPI interrupt service handlers. For each SPI module that uses this driver, the ISR should call this function with a pointer to the related SPI_Master_t struct as argument.

Parameters:
spi Pointer to the modules own SPI_Master_t struct.

Definition at line 199 of file spi_driver.c.

References SPI_DataPacket::bytesToTransceive, SPI_DataPacket::bytesTransceived, SPI_DataPacket::complete, dataPacket, SPI_Master::dataPacket, SPI_Master::interrupted, SPI_Master::module, SPI_DataPacket::receiveData, SPI_MasterSSHigh, SPI_DataPacket::ssPinMask, SPI_DataPacket::ssPort, and SPI_DataPacket::transmitData.

Referenced by ISR().

00200 {
00201         uint8_t data;
00202         uint8_t bytesTransceived = spi->dataPacket->bytesTransceived;
00203 
00204         /* If SS pin interrupt (SS used and pulled low).
00205         *  No data received at this point. */
00206         if ( !(spi->module->CTRL & SPI_MASTER_bm) ) {
00207                 spi->interrupted = true;
00208         }
00209 
00210         else {  /* Data interrupt. */
00211 
00212                 /* Store received data. */
00213                 data = spi->module->DATA;
00214                 spi->dataPacket->receiveData[bytesTransceived] = data;
00215 
00216                 /* Next byte. */
00217                 bytesTransceived++;
00218 
00219                 /* If more data. */
00220                 if (bytesTransceived < spi->dataPacket->bytesToTransceive) {
00221                         /* Put data byte in transmit data register. */
00222                         data = spi->dataPacket->transmitData[bytesTransceived];
00223                         spi->module->DATA = data;
00224                 }
00225 
00226                 /* Transmission complete. */
00227                 else {
00228 
00229                         /* Release SS to slave(s). */
00230                         uint8_t ssPinMask = spi->dataPacket->ssPinMask;
00231                         SPI_MasterSSHigh(spi->dataPacket->ssPort, ssPinMask);
00232 
00233                         spi->dataPacket->complete = true;
00234                 }
00235         }
00236         /* Write back bytesTransceived to data packet. */
00237         spi->dataPacket->bytesTransceived = bytesTransceived;
00238 }

uint8_t SPI_MasterInterruptTransceivePacket ( SPI_Master_t spi,
SPI_DataPacket_t dataPacket 
)

Start transmission.

This function starts a SPI transmission. A data packet must be prepared for transmission first.

Parameters:
spi The SPI_Master_t struct instance.
dataPacket The SPI_dataPacket_t struct instance.
Returns:
Status code
Return values:
SPI_OK The transmission was completed successfully.
SPI_BUSY The SPI module is busy.
SPI_INTERRUPTED The transmission was interrupted by another master.

Definition at line 255 of file spi_driver.c.

References SPI_DataPacket::bytesTransceived, SPI_DataPacket::complete, SPI_Master::dataPacket, SPI_Master::interrupted, SPI_Master::module, SPI_Master::port, SPI_BUSY, SPI_INTERRUPTED, SPI_MasterSSLow, SPI_OK, SPI_SS_bm, SPI_DataPacket::ssPinMask, SPI_DataPacket::ssPort, and SPI_DataPacket::transmitData.

Referenced by main().

00257 {
00258         uint8_t data;
00259         bool interrupted = spi->interrupted;
00260 
00261         /* If no packets sent so far. */
00262         if (spi->dataPacket == NULL) {
00263                 spi->dataPacket = dataPacket;
00264         }
00265 
00266         /* If ongoing transmission. */
00267         else if (spi->dataPacket->complete == false) {
00268                 return (SPI_BUSY);
00269         }
00270 
00271         /* If interrupted by other master. */
00272         else if (interrupted) {
00273                 /* If SS released. */
00274                 if (spi->port->OUT & SPI_SS_bm) {
00275                         /* No longer interrupted. */
00276                         interrupted = false;
00277                 }
00278                 else {
00279                         return (SPI_INTERRUPTED);
00280                 }
00281         }
00282 
00283         /* NOT interrupted by other master.
00284         * Start transmission. */
00285         spi->dataPacket = dataPacket;
00286         spi->dataPacket->complete = false;
00287         spi->interrupted = false;
00288 
00289         /* SS to slave(s) low.*/
00290         uint8_t ssPinMask = spi->dataPacket->ssPinMask;
00291         SPI_MasterSSLow(spi->dataPacket->ssPort, ssPinMask);
00292 
00293         spi->dataPacket->bytesTransceived = 0;
00294 
00295         /* Start sending data. */
00296         data = spi->dataPacket->transmitData[0];
00297         spi->module->DATA = data;
00298 
00299         /* Successs */
00300         return (SPI_OK);
00301 }

uint8_t SPI_MasterTransceiveByte ( SPI_Master_t spi,
uint8_t  TXdata 
)

SPI mastertransceive byte.

This function clocks data in the DATA register to the slave, while data from the slave is clocked into the DATA register. The function does not check for ongoing access from other masters before initiating a transfer. For multimaster systems, checkers should be added to avoid bus contention.

SS line(s) must be pulled low before calling this function and released when finished.

Note:
This function is blocking and will not finish unless a successful transfer has been completed. It is recommended to use the interrupt-driven driver for applications where blocking functionality is not wanted.
Parameters:
spi The SPI_Master_t struct instance.
TXdata Data to transmit to slave.
Returns:
Data received from slave.

Definition at line 324 of file spi_driver.c.

References SPI_Master::module.

Referenced by main().

00325 {
00326         /* Send pattern. */
00327         spi->module->DATA = TXdata;
00328 
00329         /* Wait for transmission complete. */
00330         while(!(spi->module->STATUS & SPI_IF_bm)) {
00331 
00332         }
00333         /* Read received data. */
00334         uint8_t result = spi->module->DATA;
00335 
00336         return(result);
00337 }

bool SPI_MasterTransceivePacket ( SPI_Master_t spi,
SPI_DataPacket_t dataPacket 
)

SPI transceive data packet.

This function transceives a number of bytes contained in a data packet struct. The SS line is kept low until all bytes are transceived. The received bytes are stored in the data packet struct.

Parameters:
spi The SPI_Master_t struct instance.
dataPacket The SPI_dataPacket_t struct instance.
Returns:
Wether the function was successfully completed
Return values:
true Success
false Failure

Definition at line 354 of file spi_driver.c.

References SPI_DataPacket::bytesToTransceive, SPI_DataPacket::bytesTransceived, SPI_DataPacket::complete, SPI_Master::dataPacket, SPI_Master::module, SPI_DataPacket::receiveData, SPI_MasterSSHigh, SPI_MasterSSLow, SPI_DataPacket::ssPinMask, SPI_DataPacket::ssPort, and SPI_DataPacket::transmitData.

Referenced by main().

00356 {
00357         /* Check if data packet has been created. */
00358         if(dataPacket == NULL) {
00359                 return false;
00360         }
00361 
00362         /* Assign datapacket to SPI module. */
00363         spi->dataPacket = dataPacket;
00364 
00365         uint8_t ssPinMask = spi->dataPacket->ssPinMask;
00366 
00367         /* If SS signal to slave(s). */
00368         if (spi->dataPacket->ssPort != NULL) {
00369                 /* SS to slave(s) low. */
00370                 SPI_MasterSSLow(spi->dataPacket->ssPort, ssPinMask);
00371         }
00372 
00373         /* Transceive bytes. */
00374         uint8_t bytesTransceived = 0;
00375         uint8_t bytesToTransceive = dataPacket->bytesToTransceive;
00376         while (bytesTransceived < bytesToTransceive) {
00377 
00378                 /* Send pattern. */
00379                 uint8_t data = spi->dataPacket->transmitData[bytesTransceived];
00380                 spi->module->DATA = data;
00381 
00382                 /* Wait for transmission complete. */
00383                 while(!(spi->module->STATUS & SPI_IF_bm)) {
00384 
00385                 }
00386                 /* Read received data. */
00387                 data = spi->module->DATA;
00388                 spi->dataPacket->receiveData[bytesTransceived] = data;
00389 
00390                 bytesTransceived++;
00391         }
00392 
00393         /* If SS signal to slave(s). */
00394         if (spi->dataPacket->ssPort != NULL) {
00395                 /* Release SS to slave(s). */
00396                 SPI_MasterSSHigh(spi->dataPacket->ssPort, ssPinMask);
00397         }
00398 
00399         /* Set variables to indicate that transmission is complete. */
00400         spi->dataPacket->bytesTransceived = bytesTransceived;
00401         spi->dataPacket->complete = true;
00402 
00403         /* Report success. */
00404         return true;
00405 }

void SPI_SlaveInit ( SPI_Slave_t spi,
SPI_t *  module,
PORT_t *  port,
bool  lsbFirst,
SPI_MODE_t  mode,
SPI_INTLVL_t  intLevel 
)

Initialize SPI module as slave.

This function initializes a SPI module as slave. The CTRL and INTCTRL registers for the SPI module is set according to the inputs to the function. In addition, data direction for the MISO pin is set to output.

Parameters:
spi The SPI_Slave_t instance.
module Pointer to the SPI module.
port The I/O port where the SPI module is connected.
lsbFirst Data order will be LSB first if this is set to true.
mode SPI mode (Clock polarity and phase).
intLevel SPI interrupt level.

Definition at line 132 of file spi_driver.c.

References SPI_Slave::module, SPI_Slave::port, and SPI_MISO_bm.

Referenced by main().

00138 {
00139         /* SPI module. */
00140         spi->module       = module;
00141         spi->port         = port;
00142 
00143         spi->module->CTRL = SPI_ENABLE_bm |                /* Enable SPI module. */
00144                             (lsbFirst ? SPI_DORD_bm : 0) | /* Data order. */
00145                             mode;                          /* SPI mode. */
00146 
00147         /* Interrupt level. */
00148         spi->module->INTCTRL = intLevel;
00149 
00150         /* MISO as output. */
00151         spi->port->DIRSET = SPI_MISO_bm;
00152 }

@DOC_TITLE@
Generated on Mon Nov 2 13:52:26 2009 for AVR1309 Using the XMEGA SPI by doxygen 1.5.9