2 * Copyright © 2010 Keith Packard <keithp@keithp.com>
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; version 2 of the License.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
20 /* Default pin usage for existing Altus Metrum devices */
21 #if !HAS_SPI_0 && !HAS_SPI_1
27 #define SPI_CONST 0xff
31 * USART0 SPI config alt 1
38 * USART0 SPI config alt 2
45 * USART1 SPI config alt 1
52 * USART1 SPI config alt 2
60 * Chip select is the responsibility of the caller in master mode
65 #define SPI_BUF U0DBUFXADDR
66 #define SPI_BAUD U0BAUD
68 #define SPI_CFG_MASK PERCFG_U0CFG_ALT_MASK
69 #define SPI_DMA_TX DMA_CFG0_TRIGGER_UTX0
70 #define SPI_DMA_RX DMA_CFG0_TRIGGER_URX0
73 #define SPI_CFG PERCFG_U0CFG_ALT_1
75 #define SPI_BITS (1 << 3) | (1 << 2) | (1 << 5)
76 #define SPI_CSS_BIT (1 << 4)
80 #define SPI_CFG PERCFG_U0CFG_ALT_2
82 #define SPI_PRI P2SEL_PRI3P1_USART0
83 #define SPI_BITS (1 << 5) | (1 << 4) | (1 << 3)
84 #define SPI_CSS_BIT (1 << 2)
91 #define SPI_BUF U1DBUFXADDR
92 #define SPI_BAUD U1BAUD
94 #define SPI_CFG_MASK PERCFG_U1CFG_ALT_MASK
95 #define SPI_DMA_TX DMA_CFG0_TRIGGER_UTX1
96 #define SPI_DMA_RX DMA_CFG0_TRIGGER_URX1
99 #define SPI_CFG PERCFG_U1CFG_ALT_1
100 #define SPI_SEL P0SEL
101 #define SPI_BITS (1 << 4) | (1 << 5) | (1 << 3)
102 #define SPI_CSS_BIT (1 << 2)
106 #define SPI_CFG PERCFG_U1CFG_ALT_2
107 #define SPI_SEL P1SEL
108 #define SPI_PRI P2SEL_PRI3P1_USART1
109 #define SPI_BITS (1 << 6) | (1 << 7) | (1 << 5)
110 #define SPI_CSS_BIT (1 << 4)
116 #define CSS SPI_CSS_BIT
117 #define UxCSR_DIRECTION UxCSR_SLAVE
120 #define UxCSR_DIRECTION UxCSR_MASTER
123 /* Shared mutex to protect SPI bus, must cover the entire
124 * operation, from CS low to CS high. This means that any SPI
125 * user must protect the SPI bus with this mutex
127 __xdata uint8_t ao_spi_mutex;
128 __xdata uint8_t ao_spi_dma_in_done;
129 __xdata uint8_t ao_spi_dma_out_done;
131 uint8_t ao_spi_dma_out_id;
132 uint8_t ao_spi_dma_in_id;
134 static __xdata uint8_t ao_spi_const;
136 /* Send bytes over SPI.
138 * This sets up two DMA engines, one writing the data and another reading
139 * bytes coming back. We use the bytes coming back to tell when the transfer
140 * is complete, as the transmit register is double buffered and hence signals
141 * completion one byte before the transfer is actually complete
144 ao_spi_send_bus(void __xdata *block, uint16_t len) __reentrant
146 ao_dma_set_transfer(ao_spi_dma_in_id,
150 DMA_CFG0_WORDSIZE_8 |
151 DMA_CFG0_TMODE_SINGLE |
155 DMA_CFG1_PRIORITY_NORMAL);
156 ao_dma_set_transfer(ao_spi_dma_out_id,
160 DMA_CFG0_WORDSIZE_8 |
161 DMA_CFG0_TMODE_SINGLE |
165 DMA_CFG1_PRIORITY_NORMAL);
167 ao_dma_start(ao_spi_dma_in_id);
168 ao_dma_start(ao_spi_dma_out_id);
169 ao_dma_trigger(ao_spi_dma_out_id);
171 __critical while (!ao_spi_dma_in_done)
172 ao_sleep(&ao_spi_dma_in_done);
178 ao_spi_send_wait(void)
180 __critical while (!ao_spi_dma_in_done)
181 ao_sleep(&ao_spi_dma_in_done);
185 /* Receive bytes over SPI.
187 * This sets up tow DMA engines, one reading the data and another
188 * writing constant values to the SPI transmitter as that is what
189 * clocks the data coming in.
192 ao_spi_recv_bus(void __xdata *block, uint16_t len) __reentrant
194 ao_dma_set_transfer(ao_spi_dma_in_id,
198 DMA_CFG0_WORDSIZE_8 |
199 DMA_CFG0_TMODE_SINGLE |
203 DMA_CFG1_PRIORITY_NORMAL);
205 ao_spi_const = SPI_CONST;
208 ao_dma_set_transfer(ao_spi_dma_out_id,
212 DMA_CFG0_WORDSIZE_8 |
213 DMA_CFG0_TMODE_SINGLE |
217 DMA_CFG1_PRIORITY_NORMAL);
220 ao_dma_start(ao_spi_dma_in_id);
222 ao_dma_start(ao_spi_dma_out_id);
223 ao_dma_trigger(ao_spi_dma_out_id);
224 __critical while (!ao_spi_dma_in_done)
225 ao_sleep(&ao_spi_dma_in_done);
231 ao_spi_recv_wait(void)
233 __critical while (!ao_spi_dma_in_done)
234 ao_sleep(&ao_spi_dma_in_done);
241 /* Set up the USART pin assignment */
242 PERCFG = (PERCFG & ~SPI_CFG_MASK) | SPI_CFG;
244 /* Ensure that SPI USART takes precidence over the other USART
245 * for pins that they share
248 P2SEL = (P2SEL & ~P2SEL_PRI3P1_MASK) | SPI_PRI;
251 /* Make the SPI pins be controlled by the USART peripheral */
252 SPI_SEL |= SPI_BITS | CSS;
255 ao_spi_dma_out_id = ao_dma_alloc(&ao_spi_dma_out_done);
258 ao_spi_dma_in_id = ao_dma_alloc(&ao_spi_dma_in_done);
262 * SPI master/slave mode
264 SPI_CSR = (UxCSR_MODE_SPI | UxCSR_RE | UxCSR_DIRECTION);
266 /* Set the baud rate and signal parameters
268 * The cc1111 is limited to a 24/8 MHz SPI clock.
269 * Every peripheral I've ever seen goes faster than that,
270 * so set the clock to 3MHz (BAUD_E 17, BAUD_M 0)
273 SPI_GCR = (UxGCR_CPOL_NEGATIVE |
274 UxGCR_CPHA_FIRST_EDGE |
276 (17 << UxGCR_BAUD_E_SHIFT));