-
Notifications
You must be signed in to change notification settings - Fork 1
/
spi.h
156 lines (145 loc) · 5.68 KB
/
spi.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/* Copyright (C) 2014 David Zanetti
*
* This file is part of libkakapo.
*
* libkakapo is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License.
*
* libkakapo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libkapapo.
*
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SPI_H_INCLUDED
#define SPI_H_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif
/** \file
* \brief SPI driver public API
*
* Simple SPI interface. Does not buffer or get driven from
* interrupts, but probably should be.
*
* Usage:
*
* + spi_init(): used to create the SPI instance
*
* + spi_conf(): set the bitrate, polarity
*
* + spi_txrx(): submit a single byte to the SPI interface
*
* Note: all handling of CS lines must be done in your own code,
* this code does not presume any specific CS state.
*
* Note: you MUST set the port's slave-select pin to OUTPUT if you
* intend to use this port in master mode, EVEN IF you don't have
* a CS line attached to it.
*
* To Do:
*
* + Make interrupt driven with buffering
*
* + Support slave mode
*/
/** \brief SPI mode types */
typedef enum {
spi_mode0 = 0, /**< Leading = rising/sample, trailing = falling/setup */
spi_mode1, /**< Leading = rising/setup, trailing = falling/sample */
spi_mode2, /**< Leading = falling/sample, trailing = rising/setup */
spi_mode3, /**< Leading = falling/setup, trailing = rising/sample */
} spi_mode_t;
/** \brief SPI clock division */
typedef enum {
spi_perdiv4 = 0, /**< CLKper/4, CLK2X 0 */
spi_perdiv16, /**< CLKper/16, CLK2X 0 */
spi_perdiv64, /**< CLKper/64, CLK2X 0 */
spi_perdiv128, /**< CLKper/128, CLK2X 0 */
spi_perdiv2, /**< CLKper/2, CLK2X 1 */
spi_perdiv8, /**< CLKper/8, CLK2X 1 */
spi_perdiv32, /**< CLKper/32, CLK2X 1 */
/**< Not defined: CLKper/64, CLK2X 1 */
} spi_clkdiv_t;
/** \brief Define what SPI hardware exists */
/* E5/B1/B3 has 1 SPI, A1/A1U has 4, everyone else has 2 */
#if defined(_xmega_type_E5)|| defined(_xmega_type_B1) || defined (_xmega_type_B3)
#define MAX_SPI_PORTS 1 /**< Maximum number of SPI ports supported */
#define SPI_PORT_INIT {0} /**< Array to init port struct array with */
typedef enum {
spi_c = 0, /**< SPI on PORTC, pins 4,5,6,7 */
} spi_portname_t;
#elif defined (_xmega_type_A1) || defined (_xmega_type_A1U)
#define MAX_SPI_PORTS 4 /**< Maximum number of SPI ports supported */
#define SPI_PORT_INIT {0,0,0,0} /**< Array to init port struct array with */
typedef enum {
spi_c = 0, /**< SPI on PORTC, pins 4,5,6,7 */
spi_d, /**< SPI on PORTD, pins 4,5,6,7 */
spi_e, /**< SPI on PORTE, pins 4,5,6,7 */
spi_f, /**< SPI on PORTF, pins 4,5,6,7 */
} spi_portname_t;
#else
#define MAX_SPI_PORTS 2 /**< Maximum number of SPI ports supported */
#define SPI_PORT_INIT {0,0} /**< Array to init port struct array with */
typedef enum {
spi_c = 0, /**< SPI on PORTC, pins 4,5,6,7 */
spi_d, /**< SPI on PORTD, pins 4,5,6,7 */
} spi_portname_t;
#endif
/** \brief Initalise an SPI port
* \param port Name of the port
* \param timeout_us Timeout in us for operations
* \return 0 for sucess, errors.h otherwise
*/
int spi_init(spi_portname_t port, uint16_t timeout_us);
/** \brief Configure and SPI port
*
* SPI is clocked from a division of the 1x perpherial clock. Note that
* the maximum clock is F_CPU/2. SPI modes affect whether SCK is high
* or low at the start of a burst, and when MOSI/MISO are sampled.
*
* \param port Name of the port
* \param clock Clock division from system clock
* \param mode SPI mode to use
* \param txdummy What to TX when generating clocks (see spi_txrx()).
* \return 0 for success, errors.h otherwise
*/
int spi_conf(spi_portname_t port, spi_clkdiv_t clock, spi_mode_t mode, uint8_t txdummy);
/** \brief Transmit/Receive SPI data
*
* In SPI, receive and transmit are done at the same time on different lines.
* The master set MOSI to the next bit to be sent to the slave, clocks SCK, and
* the slave sets MISO to the next bit to be sent to the master before SCK
* cycle completes, followed by the master reading MISO for the read bit.
*
* This means a "read" from a slave device is for the master to clock SCK
* and read MISO. Conversely, a "write" to a slave device is for the master
* to clock SCK with bits already set on MOSI. The other line is effectively
* discarded.
*
* This function provides two buffer pointers: one for TX bytes from the master,
* and one for RX bytes from the slave to be stored in. They MUST NOT be the same
* bufffer, as this seems to cause corruption. If a buffer is NULL the it is
* either generated (for TX) or discarded (for RX). The data generated is based
* on the txdummy param from spi_conf(). This is required as the SPI master must
* generate clocks, which it only does when it has data to transmit.
*
* \param port Name of the port
* \param tx_buf A buffer containing len bytes to transmit. May be NULL, this
* forces SPI port to transmit zeros (useful for reads).
* \param rx_buf A buffer containing len bytes to be written to from receive.
* May be NULL, this discards any read data (useful for writes).
* \param len Length of each buffer (for both)
* \return data received or errors.h
*/
int spi_txrx(spi_portname_t port, void *tx_buf, void *rx_buf, uint16_t len);
#ifdef __cplusplus
}
#endif
#endif // SPI_H_INCLUDED