AVRly - AVR Development Resources
atmega_spi.c
Go to the documentation of this file.
1/******************************************************************************
2 @copyright Copyright © 2022 by Jason Duffy.
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 SOFTWARE.
21******************************************************************************/
22
23/**
24 * @file atmega_spi.c
25 * @ingroup mcp48x2
26 * @author Jason Duffy
27 * @date 9th April 2022
28 * @brief Driver for SPI communication between the ATmega328P and other SPI
29 * compatible devices.
30 * @bug No known bugs.
31 * @details This file provides the basic SPI comms setup and initialisation
32 * instructions. The following ports/pins must be defined in pin_defines.h:
33 * SPI_DDR, SPI_PORT, SPI_MOSI SPI_MISO, SPI_SCK, SPI_SS.
34 */
35
36#include <avr/io.h>
37#include <avr/interrupt.h>
38
39#include "atmega_spi.h"
40#include "pin_defines.h"
41
42/*
43 * Initialisation routine to set up SPI comms. Must be called before any other
44 * functions in this file can be used.
45 * @param transfer_mode lsb_first or msb_first.
46 * @param control_mode controller or peripheral.
47 * @param polarity_mode rising_edge or falling_edge.
48 * @param phase_mode lead_sample_rising_edge or lead_setup_rising_edge.
49 * @param clk_rate Sets the speed of the SPI clock - divided down from F_CPU
50 * speed.
51 * @param dbl_clock single_speed or double_speed.
52 */
53void init_spi(spi_transfer_mode_t transfer_mode,
54 spi_control_mode_t control_mode,
55 spi_polarity_mode_t polarity_mode,
56 spi_phase_mode_t phase_mode,
57 spi_clk_rate_t clk_rate,
58 spi_dbl_clk_mode_t dbl_clock)
59{
60 SPI_DDR |= (1 << SPI_MOSI); // Set MOSI as output.
61 SPI_DDR |= (1 << SPI_SCK); // Set SCK as output.
62 SPI_DDR &= ~(1 << SPI_MISO); // Set MISO as input.
63 SPI_DDR &= ~(1 << SPI_SS); // Set SS as input.
64 SPI_PORT |= (1 << SPI_MISO); // Set pullup on MISO.
65 SPI_PORT |= (1 << SPI_SS); // Set pullup on SS.
66
67 cli(); // Clear interrupt enable flag.
68 SPCR |= (transfer_mode << DORD); // Set data order.
69 SPCR |= (control_mode << MSTR); // Controller/peripheral mode select.
70 SPCR |= (polarity_mode << CPOL); // Set polarity of SPI data.
71 SPCR |= (phase_mode << CPHA); // Set phase of SPI data.
72 SPCR |= (clk_rate); // Set speed
73
74 SPSR |= (dbl_clock << SPI2X); // Set double speed bit.
75
76 SPCR |= (1 << SPE); // Enable SPI.
77
78 sei(); // Set interrupt enable flag.
79}
80
81
82/*
83 * Sends out a byte of data over SPI and returns the byte it receives.
84 */
85uint8_t spi_trade_byte(uint8_t data)
86{
87 SPDR = data; // Send out byte of data.
88 loop_until_bit_is_set(SPSR, SPIF); // Wait for flag to be set.
89 data = SPDR; // Store the data received.
90 return data;
91}
92
93
94/*
95 * Sends out a 16bit word of data over spi (in two bytes) and returns the byte
96 * it receives.
97 */
98uint16_t spi_trade_word(uint16_t data)
99{
100 uint8_t msb = 0;
101 uint8_t lsb = 0;
102
103 // Split word to send into 2 bytes and send the first one out.
104 msb |= (data >> 8U);
105 lsb |= (data);
106 SPDR = msb;
107 loop_until_bit_is_set(SPSR, SPIF);
108 msb = SPDR; // Store the byte received.
109
110 // Send the second byte out.
111 SPDR = lsb;
112 loop_until_bit_is_set(SPSR, SPIF);
113 lsb = SPDR; // Store the second byte received.
114
115 // Combine the bytes received into 1 word.
116 uint16_t received_data = 0;
117 received_data = (msb << 8U);
118 received_data |= (lsb);
119
120 return received_data;
121}
void init_spi(spi_transfer_mode_t transfer_mode, spi_control_mode_t control_mode, spi_polarity_mode_t polarity_mode, spi_phase_mode_t phase_mode, spi_clk_rate_t clk_rate, spi_dbl_clk_mode_t dbl_clock)
Initialisation routine to set up SPI comms.
Definition: atmega_spi.c:53
uint8_t spi_trade_byte(uint8_t data)
Sends out a byte of data over SPI and returns the byte it receives.
Definition: atmega_spi.c:85
uint16_t spi_trade_word(uint16_t data)
Sends out a 16bit word of data over spi (in two bytes) and returns the byte it receives.
Definition: atmega_spi.c:98
spi_dbl_clk_mode_t
Enumerated constants for selecting whether the SPI clock speed is doubled.
Definition: atmega_spi.h:97
spi_transfer_mode_t
Enumerated constants for selecting the transfer mode, most significant bit first of least significant...
Definition: atmega_spi.h:46
spi_phase_mode_t
Enumerated constants for selecting the SPI phase mode, on leading clock edge.
Definition: atmega_spi.h:76
spi_polarity_mode_t
Enumerated constants for selecting the SPI polarity mode, rising or falling on leading clock edge.
Definition: atmega_spi.h:66
spi_clk_rate_t
Enumerated constants for selecting the SPI clock rate.
Definition: atmega_spi.h:86
spi_control_mode_t
Enumerated constants for selecting whether the host MCU is the controller or peripheral (formerly kno...
Definition: atmega_spi.h:56
Driver for SPI communication between the ATmega328P and other SPI compatible devices.
Definitions for pin mapping (for CCS81 gas sensor)