LT_SPI

Committer:
roger5641
Date:
Sun Nov 12 01:21:36 2017 +0000
Revision:
0:516e11acba42
ver1

Who changed what in which revision?

UserRevisionLine numberNew contents of line
roger5641 0:516e11acba42 1 //! @todo Review this document.
roger5641 0:516e11acba42 2 /*!
roger5641 0:516e11acba42 3 LT_SPI: Routines to communicate with ATmega328P's hardware SPI port.
roger5641 0:516e11acba42 4
roger5641 0:516e11acba42 5 @verbatim
roger5641 0:516e11acba42 6
roger5641 0:516e11acba42 7 LT_SPI implements the low level master SPI bus routines using
roger5641 0:516e11acba42 8 the hardware SPI port.
roger5641 0:516e11acba42 9
roger5641 0:516e11acba42 10 SPI Frequency = (CPU Clock frequency)/(16+2(TWBR)*Prescaler)
roger5641 0:516e11acba42 11 SPCR = SPI Control Register (SPIE SPE DORD MSTR CPOL CPHA SPR1 SPR0)
roger5641 0:516e11acba42 12 SPSR = SPI Status Register (SPIF WCOL - - - - - SPI2X)
roger5641 0:516e11acba42 13
roger5641 0:516e11acba42 14 Data Modes:
roger5641 0:516e11acba42 15 CPOL CPHA Leading Edge Trailing Edge
roger5641 0:516e11acba42 16 0 0 sample rising setup falling
roger5641 0:516e11acba42 17 0 1 setup rising sample falling
roger5641 0:516e11acba42 18 1 0 sample falling setup rising
roger5641 0:516e11acba42 19 1 1 sample rising setup rising
roger5641 0:516e11acba42 20
roger5641 0:516e11acba42 21 CPU Frequency = 16MHz on Arduino Uno
roger5641 0:516e11acba42 22 SCK Frequency
roger5641 0:516e11acba42 23 SPI2X SPR1 SPR0 Frequency Uno_Frequency
roger5641 0:516e11acba42 24 0 0 0 fosc/4 4 MHz
roger5641 0:516e11acba42 25 0 0 1 fosc/16 1 MHz
roger5641 0:516e11acba42 26 0 1 0 fosc/64 250 kHz
roger5641 0:516e11acba42 27 0 1 1 fosc/128 125 kHz
roger5641 0:516e11acba42 28 0 0 0 fosc/2 8 MHz
roger5641 0:516e11acba42 29 0 0 1 fosc/8 2 MHz
roger5641 0:516e11acba42 30 0 1 0 fosc/32 500 kHz
roger5641 0:516e11acba42 31
roger5641 0:516e11acba42 32 @endverbatim
roger5641 0:516e11acba42 33
roger5641 0:516e11acba42 34 REVISION HISTORY
roger5641 0:516e11acba42 35 $Revision: 6237 $
roger5641 0:516e11acba42 36 $Date: 2016-12-20 15:09:16 -0800 (Tue, 20 Dec 2016) $
roger5641 0:516e11acba42 37
roger5641 0:516e11acba42 38 Copyright (c) 2013, Linear Technology Corp.(LTC)
roger5641 0:516e11acba42 39 All rights reserved.
roger5641 0:516e11acba42 40
roger5641 0:516e11acba42 41 Redistribution and use in source and binary forms, with or without
roger5641 0:516e11acba42 42 modification, are permitted provided that the following conditions are met:
roger5641 0:516e11acba42 43
roger5641 0:516e11acba42 44 1. Redistributions of source code must retain the above copyright notice, this
roger5641 0:516e11acba42 45 list of conditions and the following disclaimer.
roger5641 0:516e11acba42 46 2. Redistributions in binary form must reproduce the above copyright notice,
roger5641 0:516e11acba42 47 this list of conditions and the following disclaimer in the documentation
roger5641 0:516e11acba42 48 and/or other materials provided with the distribution.
roger5641 0:516e11acba42 49
roger5641 0:516e11acba42 50 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
roger5641 0:516e11acba42 51 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
roger5641 0:516e11acba42 52 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
roger5641 0:516e11acba42 53 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
roger5641 0:516e11acba42 54 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
roger5641 0:516e11acba42 55 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
roger5641 0:516e11acba42 56 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
roger5641 0:516e11acba42 57 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
roger5641 0:516e11acba42 58 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
roger5641 0:516e11acba42 59 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
roger5641 0:516e11acba42 60
roger5641 0:516e11acba42 61 The views and conclusions contained in the software and documentation are those
roger5641 0:516e11acba42 62 of the authors and should not be interpreted as representing official policies,
roger5641 0:516e11acba42 63 either expressed or implied, of Linear Technology Corp.
roger5641 0:516e11acba42 64
roger5641 0:516e11acba42 65 The Linear Technology Linduino is not affiliated with the official Arduino team.
roger5641 0:516e11acba42 66 However, the Linduino is only possible because of the Arduino team's commitment
roger5641 0:516e11acba42 67 to the open-source community. Please, visit http://www.arduino.cc and
roger5641 0:516e11acba42 68 http://store.arduino.cc , and consider a purchase that will help fund their
roger5641 0:516e11acba42 69 ongoing work.
roger5641 0:516e11acba42 70 */
roger5641 0:516e11acba42 71
roger5641 0:516e11acba42 72 //! @ingroup Linduino
roger5641 0:516e11acba42 73 //! @{
roger5641 0:516e11acba42 74 //! @defgroup LT_SPI LT_SPI: Routines to communicate with ATmega328P's hardware SPI port.
roger5641 0:516e11acba42 75 //! @}
roger5641 0:516e11acba42 76
roger5641 0:516e11acba42 77 /*! @file
roger5641 0:516e11acba42 78 @ingroup LT_SPI
roger5641 0:516e11acba42 79 Library for LT_SPI: Routines to communicate with ATmega328P's hardware SPI port.
roger5641 0:516e11acba42 80 */
roger5641 0:516e11acba42 81 #include <stdint.h>
roger5641 0:516e11acba42 82 #include "LT_SPI.h"
roger5641 0:516e11acba42 83
roger5641 0:516e11acba42 84 //DigitalOut QUIKEVAL_GPIO D9; //!< Linduino QuikEval GPIO pin (QuikEval connector pin 14) connects to Arduino pin 9
roger5641 0:516e11acba42 85 //DigitalOut QUIKEVAL_CS A3; //!< QuikEval CS pin (SPI chip select on QuikEval connector pin 6) connects to Arduino SS pin.
roger5641 0:516e11acba42 86 //DigitalInOut QUIKEVAL_MUX_MODE_PIN(8,output); /*!< QUIKEVAL_MUX_MODE_PIN defines the control pin for the QuikEval MUX.
roger5641 0:516e11acba42 87 //The I2C port's SCL and the SPI port's SCK signals share the same pin on the Linduino's QuikEval connector.
roger5641 0:516e11acba42 88 //Additionally, the I2C port's SDA and the SPI port's MOSI signals share the same pin on the Linduino's QuikEval connector.
roger5641 0:516e11acba42 89 //The pair of pins connected to the QuikEval connector is switched using a MUX on the Linduino board.
roger5641 0:516e11acba42 90 //The control pin to switch the MUX is defined as QUIKEVAL_MUX_MODE_PIN (Arduino pin 8). */
roger5641 0:516e11acba42 91
roger5641 0:516e11acba42 92 void output_low(uint8_t pin)
roger5641 0:516e11acba42 93 {
roger5641 0:516e11acba42 94 pin = 0;
roger5641 0:516e11acba42 95 }
roger5641 0:516e11acba42 96 void output_high(uint8_t pin)
roger5641 0:516e11acba42 97 {
roger5641 0:516e11acba42 98 pin = 1;
roger5641 0:516e11acba42 99 }
roger5641 0:516e11acba42 100
roger5641 0:516e11acba42 101
roger5641 0:516e11acba42 102 // Reads and sends a byte
roger5641 0:516e11acba42 103 // Return 0 if successful, 1 if failed
roger5641 0:516e11acba42 104 void spi_transfer_byte(uint8_t cs_pin, uint8_t tx, uint8_t *rx)
roger5641 0:516e11acba42 105 {
roger5641 0:516e11acba42 106 output_low(cs_pin); //! 1) Pull CS low
roger5641 0:516e11acba42 107
roger5641 0:516e11acba42 108 *rx = spi.write(tx); //! 2) Read byte and send byte
roger5641 0:516e11acba42 109
roger5641 0:516e11acba42 110 output_high(cs_pin); //! 3) Pull CS high
roger5641 0:516e11acba42 111 }
roger5641 0:516e11acba42 112
roger5641 0:516e11acba42 113 // Reads and sends a word
roger5641 0:516e11acba42 114 // Return 0 if successful, 1 if failed
roger5641 0:516e11acba42 115 void spi_transfer_word(uint8_t cs_pin, uint16_t tx, uint16_t *rx)
roger5641 0:516e11acba42 116 {
roger5641 0:516e11acba42 117 union
roger5641 0:516e11acba42 118 {
roger5641 0:516e11acba42 119 uint8_t b[2];
roger5641 0:516e11acba42 120 uint16_t w;
roger5641 0:516e11acba42 121 } data_tx;
roger5641 0:516e11acba42 122
roger5641 0:516e11acba42 123 union
roger5641 0:516e11acba42 124 {
roger5641 0:516e11acba42 125 uint8_t b[2];
roger5641 0:516e11acba42 126 uint16_t w;
roger5641 0:516e11acba42 127 } data_rx;
roger5641 0:516e11acba42 128
roger5641 0:516e11acba42 129 data_tx.w = tx;
roger5641 0:516e11acba42 130
roger5641 0:516e11acba42 131 output_low(cs_pin); //! 1) Pull CS low
roger5641 0:516e11acba42 132
roger5641 0:516e11acba42 133 data_rx.b[1] = spi.write(data_tx.b[1]); //! 2) Read MSB and send MSB
roger5641 0:516e11acba42 134 data_rx.b[0] = spi.write(data_tx.b[0]); //! 3) Read LSB and send LSB
roger5641 0:516e11acba42 135
roger5641 0:516e11acba42 136 *rx = data_rx.w;
roger5641 0:516e11acba42 137
roger5641 0:516e11acba42 138 output_high(cs_pin); //! 4) Pull CS high
roger5641 0:516e11acba42 139 }
roger5641 0:516e11acba42 140
roger5641 0:516e11acba42 141 // Reads and sends a byte array
roger5641 0:516e11acba42 142 void spi_transfer_block(uint8_t cs_pin, uint8_t *tx, uint8_t *rx, uint8_t length)
roger5641 0:516e11acba42 143 {
roger5641 0:516e11acba42 144 int8_t i;
roger5641 0:516e11acba42 145
roger5641 0:516e11acba42 146 output_low(cs_pin); //! 1) Pull CS low
roger5641 0:516e11acba42 147
roger5641 0:516e11acba42 148 for (i=(length-1); i >= 0; i--)
roger5641 0:516e11acba42 149 rx[i] = spi.write(tx[i]); //! 2) Read and send byte array
roger5641 0:516e11acba42 150
roger5641 0:516e11acba42 151 output_high(cs_pin); //! 3) Pull CS high
roger5641 0:516e11acba42 152 }
roger5641 0:516e11acba42 153
roger5641 0:516e11acba42 154 // Connect SPI pins to QuikEval connector through the Linduino MUX. This will disconnect I2C.
roger5641 0:516e11acba42 155 //void quikeval_SPI_connect()
roger5641 0:516e11acba42 156 //{
roger5641 0:516e11acba42 157 // output_high(QUIKEVAL_CS); //! 1) Pull Chip Select High
roger5641 0:516e11acba42 158 //
roger5641 0:516e11acba42 159 // //! 2) Enable Main SPI
roger5641 0:516e11acba42 160 // pinMode(QUIKEVAL_MUX_MODE_PIN, OUTPUT);
roger5641 0:516e11acba42 161 // QUIKEVAL_MUX_MODE_PIN = 0;
roger5641 0:516e11acba42 162 //}
roger5641 0:516e11acba42 163
roger5641 0:516e11acba42 164 // Configure the SPI port for 4MHz SCK.
roger5641 0:516e11acba42 165 // This function or spi_enable() must be called
roger5641 0:516e11acba42 166 // before using the other SPI routines.
roger5641 0:516e11acba42 167 //void quikeval_SPI_init(void) // Initializes SPI
roger5641 0:516e11acba42 168 //{
roger5641 0:516e11acba42 169 // spi_enable(SPI_CLOCK_DIV16); //! 1) Configure the spi port for 4MHz SCK
roger5641 0:516e11acba42 170 //}
roger5641 0:516e11acba42 171
roger5641 0:516e11acba42 172 // Setup the processor for hardware SPI communication.
roger5641 0:516e11acba42 173 // Must be called before using the other SPI routines.
roger5641 0:516e11acba42 174 // Alternatively, call quikeval_SPI_connect(), which automatically
roger5641 0:516e11acba42 175 // calls this function.
roger5641 0:516e11acba42 176 void spi_enable(void) // Configures SCK frequency. Use constant defined in header file.
roger5641 0:516e11acba42 177 {
roger5641 0:516e11acba42 178 //pinMode(SCK, OUTPUT); //! 1) Setup SCK as output
roger5641 0:516e11acba42 179 //pinMode(MOSI, OUTPUT); //! 2) Setup MOSI as output
roger5641 0:516e11acba42 180 //pinMode(QUIKEVAL_CS, OUTPUT); //! 3) Setup CS as output
roger5641 0:516e11acba42 181 spi.format(16,3);
roger5641 0:516e11acba42 182 spi.frequency(1000000);
roger5641 0:516e11acba42 183 }
roger5641 0:516e11acba42 184
roger5641 0:516e11acba42 185 // Disable the SPI hardware port
roger5641 0:516e11acba42 186 //void spi_disable()
roger5641 0:516e11acba42 187 //{
roger5641 0:516e11acba42 188 // spi.end();
roger5641 0:516e11acba42 189 //}
roger5641 0:516e11acba42 190
roger5641 0:516e11acba42 191 // Write a data byte using the SPI hardware
roger5641 0:516e11acba42 192 //void spi_write(int8_t data) // Byte to be written to SPI port
roger5641 0:516e11acba42 193 //{
roger5641 0:516e11acba42 194 // SPDR = data; //! 1) Start the SPI transfer
roger5641 0:516e11acba42 195 // while (!(SPSR & _BV(SPIF))); //! 2) Wait until transfer complete
roger5641 0:516e11acba42 196 //}
roger5641 0:516e11acba42 197
roger5641 0:516e11acba42 198 // Read and write a data byte using the SPI hardware
roger5641 0:516e11acba42 199 // Returns the data byte read
roger5641 0:516e11acba42 200 //int8_t spi_read(int8_t data) //!The data byte to be written
roger5641 0:516e11acba42 201 //{
roger5641 0:516e11acba42 202 // SPDR = data; //! 1) Start the SPI transfer
roger5641 0:516e11acba42 203 // while (!(SPSR & _BV(SPIF))); //! 2) Wait until transfer complete
roger5641 0:516e11acba42 204 // return SPDR; //! 3) Return the data read
roger5641 0:516e11acba42 205 //}
roger5641 0:516e11acba42 206
roger5641 0:516e11acba42 207 // Below are implementations of spi_read, etc. that do not use the
roger5641 0:516e11acba42 208 // Arduino SPI library. To use these functions, uncomment them and comment out
roger5641 0:516e11acba42 209 // the correcsponding function above.
roger5641 0:516e11acba42 210 //
roger5641 0:516e11acba42 211 // // Reads and sends a byte
roger5641 0:516e11acba42 212 // // Return 0 if successful, 1 if failed
roger5641 0:516e11acba42 213 // uint8_t spi_transfer_byte(uint8_t cs_pin, uint8_t tx, uint8_t *rx)
roger5641 0:516e11acba42 214 // {
roger5641 0:516e11acba42 215 // output_low(cs_pin); //! 1) Pull CS low
roger5641 0:516e11acba42 216 //
roger5641 0:516e11acba42 217 // *rx = spi_read(tx); //! 2) Read byte and send byte
roger5641 0:516e11acba42 218 //
roger5641 0:516e11acba42 219 // output_high(cs_pin); //! 3) Pull CS high
roger5641 0:516e11acba42 220 //
roger5641 0:516e11acba42 221 // return(0);
roger5641 0:516e11acba42 222 // }
roger5641 0:516e11acba42 223 //
roger5641 0:516e11acba42 224 // // Reads and sends a word
roger5641 0:516e11acba42 225 // // Return 0 if successful, 1 if failed
roger5641 0:516e11acba42 226 // uint8_t spi_transfer_word(uint8_t cs_pin, uint16_t tx, uint16_t *rx)
roger5641 0:516e11acba42 227 // {
roger5641 0:516e11acba42 228 // union
roger5641 0:516e11acba42 229 // {
roger5641 0:516e11acba42 230 // uint8_t b[2];
roger5641 0:516e11acba42 231 // uint16_t w;
roger5641 0:516e11acba42 232 // } data_tx;
roger5641 0:516e11acba42 233 //
roger5641 0:516e11acba42 234 // union
roger5641 0:516e11acba42 235 // {
roger5641 0:516e11acba42 236 // uint8_t b[2];
roger5641 0:516e11acba42 237 // uint16_t w;
roger5641 0:516e11acba42 238 // } data_rx;
roger5641 0:516e11acba42 239 //
roger5641 0:516e11acba42 240 // data_tx.w = tx;
roger5641 0:516e11acba42 241 //
roger5641 0:516e11acba42 242 // output_low(cs_pin); //! 1) Pull CS low
roger5641 0:516e11acba42 243 //
roger5641 0:516e11acba42 244 // data_rx.b[1] = spi_read(data_tx.b[1]); //! 2) Read MSB and send MSB
roger5641 0:516e11acba42 245 // data_rx.b[0] = spi_read(data_tx.b[0]); //! 3) Read LSB and send LSB
roger5641 0:516e11acba42 246 // *rx = data_rx.w;
roger5641 0:516e11acba42 247 //
roger5641 0:516e11acba42 248 // output_high(cs_pin); //! 4) Pull CS high
roger5641 0:516e11acba42 249 //
roger5641 0:516e11acba42 250 // return(0);
roger5641 0:516e11acba42 251 // }
roger5641 0:516e11acba42 252 //
roger5641 0:516e11acba42 253 // // Reads and sends a byte array
roger5641 0:516e11acba42 254 // // Return 0 if successful, 1 if failed
roger5641 0:516e11acba42 255 // uint8_t spi_transfer_block(uint8_t cs_pin, uint8_t *tx, uint8_t *rx, uint8_t length)
roger5641 0:516e11acba42 256 // {
roger5641 0:516e11acba42 257 // int8_t i;
roger5641 0:516e11acba42 258 //
roger5641 0:516e11acba42 259 // output_low(cs_pin); //! 1) Pull CS low
roger5641 0:516e11acba42 260 //
roger5641 0:516e11acba42 261 // for(i=0; i < length; i++)
roger5641 0:516e11acba42 262 // rx[i] = spi_read(tx[i]); //! 2) Read and send byte array
roger5641 0:516e11acba42 263 //
roger5641 0:516e11acba42 264 // output_high(cs_pin); //! 3) Pull CS high
roger5641 0:516e11acba42 265 //
roger5641 0:516e11acba42 266 // return(0);
roger5641 0:516e11acba42 267 // }
roger5641 0:516e11acba42 268 //
roger5641 0:516e11acba42 269 // // Connect SPI pins to QuikEval connector through the Linduino MUX. This will disconnect I2C.
roger5641 0:516e11acba42 270 // void quikeval_SPI_connect()
roger5641 0:516e11acba42 271 // {
roger5641 0:516e11acba42 272 // output_high(QUIKEVAL_CS); //! 1) Pull Chip Select High
roger5641 0:516e11acba42 273 //
roger5641 0:516e11acba42 274 // //! 2) Enable Main SPI
roger5641 0:516e11acba42 275 // pinMode(QUIKEVAL_MUX_MODE_PIN, OUTPUT);
roger5641 0:516e11acba42 276 // digitalWrite(QUIKEVAL_MUX_MODE_PIN, LOW);
roger5641 0:516e11acba42 277 // }
roger5641 0:516e11acba42 278 //
roger5641 0:516e11acba42 279 // // Configure the SPI port for 4MHz SCK.
roger5641 0:516e11acba42 280 // // This function or spi_enable() must be called
roger5641 0:516e11acba42 281 // // before using the other SPI routines.
roger5641 0:516e11acba42 282 // void quikeval_SPI_init(void) // Initializes SPI
roger5641 0:516e11acba42 283 // {
roger5641 0:516e11acba42 284 // spi_enable(SPI_CLOCK_DIV32); //! 2) Configure the spi port for 4MHz SCK
roger5641 0:516e11acba42 285 // }
roger5641 0:516e11acba42 286 //
roger5641 0:516e11acba42 287 // // Setup the processor for hardware SPI communication.
roger5641 0:516e11acba42 288 // // Must be called before using the other SPI routines.
roger5641 0:516e11acba42 289 // // Alternatively, call quikeval_SPI_connect(), which automatically
roger5641 0:516e11acba42 290 // // calls this function.
roger5641 0:516e11acba42 291 // void spi_enable(uint8_t spi_clock_divider) // Configures SCK frequency. Use constant defined in header file.
roger5641 0:516e11acba42 292 // {
roger5641 0:516e11acba42 293 // pinMode(SCK, OUTPUT); //! 1) Setup SCK as output
roger5641 0:516e11acba42 294 // pinMode(MOSI, OUTPUT); //! 2) Setup MOSI as output
roger5641 0:516e11acba42 295 // pinMode(QUIKEVAL_CS, OUTPUT); //! 3) Setup CS as output
roger5641 0:516e11acba42 296 // output_low(SCK);
roger5641 0:516e11acba42 297 // output_low(MOSI);
roger5641 0:516e11acba42 298 // output_high(QUIKEVAL_CS);
roger5641 0:516e11acba42 299 // SPCR |= _BV(MSTR); //! 4) Set the SPI port to master mode
roger5641 0:516e11acba42 300 // //! 5) Set the SPI hardware rate
roger5641 0:516e11acba42 301 // SPCR = (SPCR & ~SPI_CLOCK_MASK) | (spi_clock_divider & SPI_CLOCK_MASK);
roger5641 0:516e11acba42 302 // SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((spi_clock_divider >> 2) & SPI_2XCLOCK_MASK);
roger5641 0:516e11acba42 303 // SPCR |= _BV(SPE); //! 5) Enable the SPI port
roger5641 0:516e11acba42 304 // }
roger5641 0:516e11acba42 305 //
roger5641 0:516e11acba42 306 // // Disable the SPI hardware port
roger5641 0:516e11acba42 307 // void spi_disable()
roger5641 0:516e11acba42 308 // {
roger5641 0:516e11acba42 309 // SPCR &= ~_BV(SPE);
roger5641 0:516e11acba42 310 // }