2 * Copyright Droids Corporation (2008)
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * Author : Julien LE GUEN - jlg@jleguen.info
25 #include <aversive/parts.h>
26 #include <aversive/error.h>
32 #include <spi_config.h>
34 /* internal structure to store SS pins */
35 typedef struct _ss_pin {
36 volatile uint8_t *port;
42 static volatile ss_pin_t g_ss_lines[SPI_MAX_SLAVES+1];
43 static volatile uint8_t g_ss_number;
44 static volatile spi_mode_t g_spi_mode;
45 static volatile uint8_t g_slave_selected;
51 * Register a pin as SS line
52 * Returns a unique identifier, or -1 on error
53 * There is always the physical SS line registered as 0
55 int8_t spi_register_ss_line(volatile uint8_t *port, uint8_t bitnum)
57 DEBUG(E_SPI, "Trying to register new SS line: port 0x%x, bitnum %d", port, bitnum);
58 /* too much SS lines (try to change SPI_MAX_SLAVES) */
59 if (g_ss_number >= SPI_MAX_SLAVES+1)
62 g_ss_lines[g_ss_number].port = port;
63 g_ss_lines[g_ss_number].bitnum = bitnum;
64 *(port-1) |= _BV(bitnum); // was DDR(port) |= _BV(bitnum);
65 /* Unselected at first */
66 *port |= (_BV(bitnum));
68 NOTICE(E_SPI, "New Slave Line registered: %d", g_ss_number);
75 * Set data order (default: MSB first)
77 inline void spi_set_data_order(uint8_t order)
79 if (order == SPI_LSB_FIRST)
88 inline uint8_t spi_get_data_order(void)
99 void spi_init(spi_mode_t mode, spi_format_t format, spi_clk_rate_t clk_rate)
101 NOTICE(E_SPI, "Init SPI: mode %d, format %d, clk_rate %d",
102 mode, format, clk_rate);
104 /* Configure SPI pins */
105 DDR(SCK_PORT) |= _BV(SCK_BIT);
106 DDR(MOSI_PORT) |= _BV(MOSI_BIT);
107 DDR(MISO_PORT) &= ~(_BV(MISO_BIT));
108 /* SS pin is not driven by SPI hardware
109 * This is taken care of by spi_register_ss_line()
110 * EVEN for the "default" SS line */
112 g_slave_selected = FALSE;
116 PRR0 &= ~(_BV(PRSPI)); /* Clear power reduction bit */
121 SPCR |= _BV(MSTR); /* XXX Master only for now ! */
122 SPCR |= (uint8_t)format; /* Clock polarity and phase */
124 /* clockrate: SPR0, SPR1, SPI2X */
126 SPR0_REG |= _BV(SPR0);
128 SPR0_REG &= ~(_BV(SPR0));
130 SPR1_REG |= _BV(SPR1);
132 SPR1_REG &= ~(_BV(SPR1));
134 SPI2X_REG |= _BV(SPI2X);
136 SPI2X_REG &= ~(_BV(SPI2X));
138 SPCR |= _BV(SPE); /* Enable SPI */
140 g_spi_mode = SPI_MODE_MASTER;
141 NOTICE(E_SPI, "Init done");
145 * Returns the state of SPI
147 inline spi_mode_t spi_get_mode(void)
153 * Send a byte (and receive one)
154 * Returns the received byte
156 uint8_t spi_send_and_receive_byte(uint8_t byte)
158 //DEBUG(E_SPI, "Sending 0x%x", byte);
159 /* Start transmission */
162 /* Wait for transmission complete
163 * Timings are VERY important, do not bypass this ! */
164 while(!(SPSR & (1<<SPIF)))
166 /* Return received byte */
171 * Send a byte, discard the result
173 inline void spi_send_byte(uint8_t byte)
175 spi_send_and_receive_byte(byte);
179 * Receives a byte (sends a NULL)
181 uint8_t spi_receive_byte(void)
183 return spi_send_and_receive_byte(0x00);
187 * Activates the selected SS line
189 uint8_t spi_slave_select(uint8_t slave)
191 if (g_slave_selected) {
192 ERROR(E_SPI, "A slave is already selected !");
196 *(g_ss_lines[slave].port) &= ~(_BV(g_ss_lines[slave].bitnum));
197 g_slave_selected = TRUE;
202 * Desactivates the selected SS line
204 void spi_slave_deselect(uint8_t slave)
206 *(g_ss_lines[slave].port) |= (_BV(g_ss_lines[slave].bitnum));
207 g_slave_selected = FALSE;
213 void spi_display_ss_lines(void)
216 for (i = 0; i < g_ss_number; i++) {
217 DEBUG(E_SPI, "SS%d: adr 0x%x bitnum %d value 0x%x",
220 g_ss_lines[i].bitnum,
221 *(g_ss_lines[i].port));