Updated with latest changes
[hackover2013-badge-firmware.git] / core / ssp / ssp.c
1 /**************************************************************************/
2 /*!
3 @file ssp.c
4 @author K. Townsend (microBuilder.eu)
5 @date 22 March 2010
6 @version 0.10
7
8 @section DESCRIPTION
9
10 Generic code for SSP/SPI communications. By default, the SSP block
11 is initialised in SPI master mode.
12
13 @section Example
14
15 @code
16 #include "core/cpu/cpu.h"
17 #include "core/ssp/ssp.h"
18 ...
19 cpuInit();
20 sspInit(0, sspClockPolarity_High, sspClockPhase_RisingEdge);
21 ...
22 uint8_t request[SSP_FIFOSIZE];
23 uint8_t response[SSP_FIFOSIZE];
24
25 // Send 0x9C to the slave device and wait for a response
26 request[0] = 0x80 | 0x1C;
27 // Toggle the select pin
28 ssp0Select();
29 // Send 1 byte from the request buffer
30 sspSend(0, (uint8_t *)&request, 1);
31 // Receive 1 byte into the response buffer
32 sspReceive(0, (uint8_t *)&response, 1);
33 // Reset the select pin
34 ssp0Deselect();
35 // Print the results
36 debug_printf("Ox%x ", response[0]);
37 @endcode
38
39 @section LICENSE
40
41 Software License Agreement (BSD License)
42
43 Copyright (c) 2010, microBuilder SARL
44 All rights reserved.
45
46 Redistribution and use in source and binary forms, with or without
47 modification, are permitted provided that the following conditions are met:
48 1. Redistributions of source code must retain the above copyright
49 notice, this list of conditions and the following disclaimer.
50 2. Redistributions in binary form must reproduce the above copyright
51 notice, this list of conditions and the following disclaimer in the
52 documentation and/or other materials provided with the distribution.
53 3. Neither the name of the copyright holders nor the
54 names of its contributors may be used to endorse or promote products
55 derived from this software without specific prior written permission.
56
57 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
58 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
59 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
60 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
61 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
62 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
63 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
64 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
65 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
66 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
67 */
68 /**************************************************************************/
69 #include "ssp.h"
70 #include "core/gpio/gpio.h"
71
72 /* Statistics for all interrupts */
73 volatile uint32_t interruptRxStat = 0;
74 volatile uint32_t interruptOverRunStat = 0;
75 volatile uint32_t interruptRxTimeoutStat = 0;
76
77 /**************************************************************************/
78 /*!
79 @brief SSP0 interrupt handler for SPI communication
80
81 The algorithm is, if RXFIFO is at least half full,
82 start receive until it's empty; if TXFIFO is at least
83 half empty, start transmit until it's full.
84 This will maximize the use of both FIFOs and performance.
85 */
86 /**************************************************************************/
87 void SSP_IRQHandler (void)
88 {
89 uint32_t regValue;
90
91 regValue = SSP_SSP0MIS;
92
93 /* Check for overrun interrupt */
94 if ( regValue & SSP_SSP0MIS_RORMIS_FRMRCVD )
95 {
96 interruptOverRunStat++;
97 SSP_SSP0ICR = SSP_SSP0ICR_RORIC_CLEAR; // Clear interrupt
98 }
99
100 /* Check for timeout interrupt */
101 if ( regValue & SSP_SSP0MIS_RTMIS_NOTEMPTY )
102 {
103 interruptRxTimeoutStat++;
104 SSP_SSP0ICR = SSP_SSP0ICR_RTIC_CLEAR; // Clear interrupt
105 }
106
107 /* Check if Rx buffer is at least half-full */
108 if ( regValue & SSP_SSP0MIS_RXMIS_HALFFULL )
109 {
110 // ToDo: Receive until it's empty
111 interruptRxStat++;
112 }
113 return;
114 }
115
116 /**************************************************************************/
117 /*!
118 @brief Initialises the SSP0 port
119
120 By default, SSP0 is set to SPI frame-format with 8-bit data. Pin 2.11
121 is routed to serve as serial clock (SCK), and SSEL (0.2) is set to
122 GPIO to allow manual control of when the SPI port is enabled or
123 disabled. Overrun and timeout interrupts are both enabled.
124
125 @param[in] portNum
126 The SPI port to use (0..1)
127 @param[in] polarity
128 Indicates whether the clock should be held high
129 (sspClockPolarity_High) or low (sspClockPolarity_Low)
130 when inactive.
131 @param[in] phase
132 Indicates whether new bits start on the leading
133 (sspClockPhase_RisingEdge) or falling
134 (sspClockPhase_FallingEdge) edge of clock transitions.
135
136 @note sspSelect() and sspDeselect() macros have been defined in
137 ssp.h to control the SSEL line without having to know the
138 specific pin being used.
139 */
140 /**************************************************************************/
141 void sspInit (uint8_t portNum, sspClockPolarity_t polarity, sspClockPhase_t phase)
142 {
143 gpioInit();
144
145 if (portNum == 0)
146 {
147 /* Reset SSP */
148 SCB_PRESETCTRL &= ~SCB_PRESETCTRL_SSP0_MASK;
149 SCB_PRESETCTRL |= SCB_PRESETCTRL_SSP0_RESETDISABLED;
150
151 /* Enable AHB clock to the SSP domain. */
152 SCB_SYSAHBCLKCTRL |= (SCB_SYSAHBCLKCTRL_SSP0);
153
154 /* Divide by 1 (SSPCLKDIV also enables to SSP CLK) */
155 SCB_SSP0CLKDIV = SCB_SSP0CLKDIV_DIV1;
156
157 /* Set P0.8 to SSP MISO */
158 IOCON_PIO0_8 &= ~IOCON_PIO0_8_FUNC_MASK;
159 IOCON_PIO0_8 |= IOCON_PIO0_8_FUNC_MISO0;
160
161 /* Set P0.9 to SSP MOSI */
162 IOCON_PIO0_9 &= ~IOCON_PIO0_9_FUNC_MASK;
163 IOCON_PIO0_9 |= IOCON_PIO0_9_FUNC_MOSI0;
164
165 /* Set 2.11 to SSP SCK (0.6 and 0.10 can also be used) */
166 #ifdef CFG_SSP0_SCKPIN_2_11
167 IOCON_SCKLOC = IOCON_SCKLOC_SCKPIN_PIO2_11;
168 IOCON_PIO2_11 = IOCON_PIO2_11_FUNC_SCK0;
169 #endif
170
171 /* Set 0.6 to SSP SCK (2.11 and 0.10 can also be used) */
172 #ifdef CFG_SSP0_SCKPIN_0_6
173 IOCON_SCKLOC = IOCON_SCKLOC_SCKPIN_PIO0_6;
174 IOCON_PIO0_6 = IOCON_PIO0_6_FUNC_SCK;
175 #endif
176
177 /* Set P0.2/SSEL to GPIO output and high */
178 IOCON_PIO0_2 &= ~IOCON_PIO0_2_FUNC_MASK;
179 IOCON_PIO0_2 |= IOCON_PIO0_2_FUNC_GPIO;
180 gpioSetDir(SSP0_CSPORT, SSP0_CSPIN, 1);
181 gpioSetValue(SSP0_CSPORT, SSP0_CSPIN, 1);
182 gpioSetPullup(&IOCON_PIO0_2, gpioPullupMode_Inactive); // Board has external pull-up
183
184 /* If SSP0CLKDIV = DIV1 -- (PCLK / (CPSDVSR × [SCR+1])) = (72,000,000 / (2 x [8 + 1])) = 4.0 MHz */
185 uint32_t configReg = ( SSP_SSP0CR0_DSS_8BIT // Data size = 8-bit
186 | SSP_SSP0CR0_FRF_SPI // Frame format = SPI
187 | SSP_SSP0CR0_SCR_8); // Serial clock rate = 8
188
189 // Set clock polarity
190 if (polarity == sspClockPolarity_High)
191 configReg |= SSP_SSP0CR0_CPOL_HIGH; // Clock polarity = High between frames
192 else
193 configReg &= ~SSP_SSP0CR0_CPOL_MASK; // Clock polarity = Low between frames
194
195 // Set edge transition
196 if (phase == sspClockPhase_FallingEdge)
197 configReg |= SSP_SSP0CR0_CPHA_SECOND; // Clock out phase = Trailing edge clock transition
198 else
199 configReg &= ~SSP_SSP0CR0_CPHA_MASK; // Clock out phase = Leading edge clock transition
200
201 // Assign config values to SSP0CR0
202 SSP_SSP0CR0 = configReg;
203
204 /* Clock prescale register must be even and at least 2 in master mode */
205 SSP_SSP0CPSR = SSP_SSP0CPSR_CPSDVSR_DIV2;
206
207 /* Clear the Rx FIFO */
208 uint8_t i, Dummy=Dummy;
209 for ( i = 0; i < SSP_FIFOSIZE; i++ )
210 {
211 Dummy = SSP_SSP0DR;
212 }
213
214 /* Enable the SSP Interrupt */
215 NVIC_EnableIRQ(SSP_IRQn);
216
217 /* Set SSPINMS registers to enable interrupts
218 * enable all error related interrupts */
219 SSP_SSP0IMSC = ( SSP_SSP0IMSC_RORIM_ENBL // Enable overrun interrupt
220 | SSP_SSP0IMSC_RTIM_ENBL); // Enable timeout interrupt
221
222 /* Enable device and set it to master mode, no loopback */
223 SSP_SSP0CR1 = SSP_SSP0CR1_SSE_ENABLED | SSP_SSP0CR1_MS_MASTER | SSP_SSP0CR1_LBM_NORMAL;
224 }
225
226 return;
227 }
228
229 /**************************************************************************/
230 /*!
231 @brief Sends a block of data to the SSP0 port
232
233 @param[in] portNum
234 The SPI port to use (0..1)
235 @param[in] buf
236 Pointer to the data buffer
237 @param[in] length
238 Block length of the data buffer
239 */
240 /**************************************************************************/
241 void sspSend (uint8_t portNum, uint8_t *buf, uint32_t length)
242 {
243 uint32_t i;
244 uint8_t Dummy = Dummy;
245
246 if (portNum == 0)
247 {
248 for (i = 0; i < length; i++)
249 {
250 /* Move on only if NOT busy and TX FIFO not full. */
251 while ((SSP_SSP0SR & (SSP_SSP0SR_TNF_NOTFULL | SSP_SSP0SR_BSY_BUSY)) != SSP_SSP0SR_TNF_NOTFULL);
252 SSP_SSP0DR = *buf;
253 buf++;
254
255 while ( (SSP_SSP0SR & (SSP_SSP0SR_BSY_BUSY|SSP_SSP0SR_RNE_NOTEMPTY)) != SSP_SSP0SR_RNE_NOTEMPTY );
256 /* Whenever a byte is written, MISO FIFO counter increments, Clear FIFO
257 on MISO. Otherwise, when SSP0Receive() is called, previous data byte
258 is left in the FIFO. */
259 Dummy = SSP_SSP0DR;
260 }
261 }
262
263 return;
264 }
265
266 /**************************************************************************/
267 /*!
268 @brief Receives a block of data from the SSP0 port
269
270 @param[in] portNum
271 The SPI port to use (0..1)
272 @param[in] buf
273 Pointer to the data buffer
274 @param[in] length
275 Block length of the data buffer
276 */
277 /**************************************************************************/
278 void sspReceive(uint8_t portNum, uint8_t *buf, uint32_t length)
279 {
280 uint32_t i;
281
282 if (portNum == 0)
283 {
284 for ( i = 0; i < length; i++ )
285 {
286 /* As long as the receive FIFO is not empty, data can be received. */
287 SSP_SSP0DR = 0xFF;
288
289 /* Wait until the Busy bit is cleared */
290 while ( (SSP_SSP0SR & (SSP_SSP0SR_BSY_BUSY|SSP_SSP0SR_RNE_NOTEMPTY)) != SSP_SSP0SR_RNE_NOTEMPTY );
291
292 *buf = SSP_SSP0DR;
293 buf++;
294 }
295 }
296
297 return;
298 }
299
This page took 0.052617 seconds and 5 git commands to generate.