| Xmega Application Note | |||||
XMEGA SPI driver source file. More...
#include "spi_driver.h"
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. | |
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.
Copyright (c) 2009 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.
4. This software may only be redistributed and used in connection with an Atmel AVR product.
THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 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.
| 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.
| 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 176 of file spi_driver.c.
References SPI_DataPacket::ssPort, SPI_DataPacket::ssPinMask, SPI_DataPacket::transmitData, SPI_DataPacket::receiveData, SPI_DataPacket::bytesToTransceive, SPI_DataPacket::bytesTransceived, and SPI_DataPacket::complete.
Referenced by main().
{
dataPacket->ssPort = ssPort;
dataPacket->ssPinMask = ssPinMask;
dataPacket->transmitData = transmitData;
dataPacket->receiveData = receiveData;
dataPacket->bytesToTransceive = bytesToTransceive;
dataPacket->bytesTransceived = 0;
dataPacket->complete = false;
}
| 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.
| 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 90 of file spi_driver.c.
References SPI_Master::module, SPI_Master::port, SPI_Master::interrupted, SPI_Master::dataPacket, SPI_MOSI_bm, and SPI_SCK_bm.
Referenced by main().
{
spi->module = module;
spi->port = port;
spi->interrupted = false;
spi->module->CTRL = clockDivision | /* SPI prescaler. */
(clk2x ? SPI_CLK2X_bm : 0) | /* SPI Clock double. */
SPI_ENABLE_bm | /* Enable SPI module. */
(lsbFirst ? SPI_DORD_bm : 0) | /* Data order. */
SPI_MASTER_bm | /* SPI master. */
mode; /* SPI mode. */
/* Interrupt level. */
spi->module->INTCTRL = intLevel;
/* No assigned data packet. */
spi->dataPacket = NULL;
/* MOSI and SCK as output. */
spi->port->DIRSET = SPI_MOSI_bm | SPI_SCK_bm;
}
| 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.
| spi | Pointer to the modules own SPI_Master_t struct. |
Definition at line 202 of file spi_driver.c.
References SPI_Master::dataPacket, SPI_DataPacket::bytesTransceived, SPI_Master::module, SPI_Master::interrupted, SPI_DataPacket::receiveData, dataPacket, SPI_DataPacket::bytesToTransceive, SPI_DataPacket::transmitData, SPI_DataPacket::ssPinMask, SPI_MasterSSHigh, SPI_DataPacket::ssPort, and SPI_DataPacket::complete.
Referenced by ISR().
{
uint8_t data;
uint8_t bytesTransceived = spi->dataPacket->bytesTransceived;
/* If SS pin interrupt (SS used and pulled low).
* No data received at this point. */
if ( !(spi->module->CTRL & SPI_MASTER_bm) ) {
spi->interrupted = true;
}
else { /* Data interrupt. */
/* Store received data. */
data = spi->module->DATA;
spi->dataPacket->receiveData[bytesTransceived] = data;
/* Next byte. */
bytesTransceived++;
/* If more data. */
if (bytesTransceived < spi->dataPacket->bytesToTransceive) {
/* Put data byte in transmit data register. */
data = spi->dataPacket->transmitData[bytesTransceived];
spi->module->DATA = data;
}
/* Transmission complete. */
else {
/* Release SS to slave(s). */
uint8_t ssPinMask = spi->dataPacket->ssPinMask;
SPI_MasterSSHigh(spi->dataPacket->ssPort, ssPinMask);
spi->dataPacket->complete = true;
}
}
/* Write back bytesTransceived to data packet. */
spi->dataPacket->bytesTransceived = bytesTransceived;
}
| 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.
| spi | The SPI_Master_t struct instance. |
| dataPacket | The SPI_dataPacket_t struct instance. |
| 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 258 of file spi_driver.c.
References SPI_Master::interrupted, SPI_Master::dataPacket, dataPacket, SPI_DataPacket::complete, SPI_BUSY, SPI_Master::port, SPI_SS_bm, SPI_INTERRUPTED, SPI_DataPacket::ssPinMask, SPI_MasterSSLow, SPI_DataPacket::ssPort, SPI_DataPacket::bytesTransceived, SPI_DataPacket::transmitData, SPI_Master::module, and SPI_OK.
Referenced by main().
{
uint8_t data;
bool interrupted = spi->interrupted;
/* If no packets sent so far. */
if (spi->dataPacket == NULL) {
spi->dataPacket = dataPacket;
}
/* If ongoing transmission. */
else if (spi->dataPacket->complete == false) {
return (SPI_BUSY);
}
/* If interrupted by other master. */
else if (interrupted) {
/* If SS released. */
if (spi->port->OUT & SPI_SS_bm) {
/* No longer interrupted. */
interrupted = false;
}
else {
return (SPI_INTERRUPTED);
}
}
/* NOT interrupted by other master.
* Start transmission. */
spi->dataPacket = dataPacket;
spi->dataPacket->complete = false;
spi->interrupted = false;
/* SS to slave(s) low.*/
uint8_t ssPinMask = spi->dataPacket->ssPinMask;
SPI_MasterSSLow(spi->dataPacket->ssPort, ssPinMask);
spi->dataPacket->bytesTransceived = 0;
/* Start sending data. */
data = spi->dataPacket->transmitData[0];
spi->module->DATA = data;
/* Successs */
return (SPI_OK);
}
| 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.
| spi | The SPI_Master_t struct instance. |
| TXdata | Data to transmit to slave. |
Definition at line 327 of file spi_driver.c.
References SPI_Master::module.
Referenced by main().
| 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.
| spi | The SPI_Master_t struct instance. |
| dataPacket | The SPI_dataPacket_t struct instance. |
| true | Success |
| false | Failure |
Definition at line 357 of file spi_driver.c.
References SPI_Master::dataPacket, dataPacket, SPI_DataPacket::ssPinMask, SPI_DataPacket::ssPort, SPI_MasterSSLow, SPI_DataPacket::bytesToTransceive, SPI_DataPacket::transmitData, SPI_Master::module, SPI_DataPacket::receiveData, SPI_MasterSSHigh, SPI_DataPacket::bytesTransceived, and SPI_DataPacket::complete.
Referenced by main().
{
/* Check if data packet has been created. */
if(dataPacket == NULL) {
return false;
}
/* Assign datapacket to SPI module. */
spi->dataPacket = dataPacket;
uint8_t ssPinMask = spi->dataPacket->ssPinMask;
/* If SS signal to slave(s). */
if (spi->dataPacket->ssPort != NULL) {
/* SS to slave(s) low. */
SPI_MasterSSLow(spi->dataPacket->ssPort, ssPinMask);
}
/* Transceive bytes. */
uint8_t bytesTransceived = 0;
uint8_t bytesToTransceive = dataPacket->bytesToTransceive;
while (bytesTransceived < bytesToTransceive) {
/* Send pattern. */
uint8_t data = spi->dataPacket->transmitData[bytesTransceived];
spi->module->DATA = data;
/* Wait for transmission complete. */
while(!(spi->module->STATUS & SPI_IF_bm)) {
}
/* Read received data. */
data = spi->module->DATA;
spi->dataPacket->receiveData[bytesTransceived] = data;
bytesTransceived++;
}
/* If SS signal to slave(s). */
if (spi->dataPacket->ssPort != NULL) {
/* Release SS to slave(s). */
SPI_MasterSSHigh(spi->dataPacket->ssPort, ssPinMask);
}
/* Set variables to indicate that transmission is complete. */
spi->dataPacket->bytesTransceived = bytesTransceived;
spi->dataPacket->complete = true;
/* Report success. */
return true;
}
| 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.
| 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 135 of file spi_driver.c.
References SPI_Slave::module, SPI_Slave::port, and SPI_MISO_bm.
Referenced by main().
{
/* SPI module. */
spi->module = module;
spi->port = port;
spi->module->CTRL = SPI_ENABLE_bm | /* Enable SPI module. */
(lsbFirst ? SPI_DORD_bm : 0) | /* Data order. */
mode; /* SPI mode. */
/* Interrupt level. */
spi->module->INTCTRL = intLevel;
/* MISO as output. */
spi->port->DIRSET = SPI_MISO_bm;
}