1 /**************************************************************************/
4 @author K. Townsend (microBuilder.eu)
8 Generic code for SSP/SPI communications. By default, the SSP block
9 is initialised in SPI master mode.
14 #include "core/cpu/cpu.h"
15 #include "core/ssp/ssp.h"
18 sspInit(0, sspClockPolarity_High, sspClockPhase_RisingEdge);
20 uint8_t request[SSP_FIFOSIZE];
21 uint8_t response[SSP_FIFOSIZE];
23 // Send 0x9C to the slave device and wait for a response
24 request[0] = 0x80 | 0x1C;
25 // Toggle the select pin
27 // Send 1 byte from the request buffer
28 sspSend(0, (uint8_t *)&request, 1);
29 // Receive 1 byte into the response buffer
30 sspReceive(0, (uint8_t *)&response, 1);
31 // Reset the select pin
34 debug_printf("Ox%x ", response[0]);
39 Software License Agreement (BSD License)
41 Copyright (c) 2012, K. Townsend
44 Redistribution and use in source and binary forms, with or without
45 modification, are permitted provided that the following conditions are met:
46 1. Redistributions of source code must retain the above copyright
47 notice, this list of conditions and the following disclaimer.
48 2. Redistributions in binary form must reproduce the above copyright
49 notice, this list of conditions and the following disclaimer in the
50 documentation and/or other materials provided with the distribution.
51 3. Neither the name of the copyright holders nor the
52 names of its contributors may be used to endorse or promote products
53 derived from this software without specific prior written permission.
55 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
56 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
57 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
58 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
59 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
60 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
61 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
62 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
63 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
64 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
66 /**************************************************************************/
68 #include "core/gpio/gpio.h"
70 /* Statistics for all interrupts */
71 volatile uint32_t interruptRxStat
= 0;
72 volatile uint32_t interruptOverRunStat
= 0;
73 volatile uint32_t interruptRxTimeoutStat
= 0;
75 /**************************************************************************/
77 @brief SSP0 interrupt handler for SPI communication
79 The algorithm is, if RXFIFO is at least half full,
80 start receive until it's empty; if TXFIFO is at least
81 half empty, start transmit until it's full.
82 This will maximize the use of both FIFOs and performance.
84 /**************************************************************************/
85 void SSP_IRQHandler (void)
89 regValue
= SSP_SSP0MIS
;
91 /* Check for overrun interrupt */
92 if ( regValue
& SSP_SSP0MIS_RORMIS_FRMRCVD
)
94 interruptOverRunStat
++;
95 SSP_SSP0ICR
= SSP_SSP0ICR_RORIC_CLEAR
; // Clear interrupt
98 /* Check for timeout interrupt */
99 if ( regValue
& SSP_SSP0MIS_RTMIS_NOTEMPTY
)
101 interruptRxTimeoutStat
++;
102 SSP_SSP0ICR
= SSP_SSP0ICR_RTIC_CLEAR
; // Clear interrupt
105 /* Check if Rx buffer is at least half-full */
106 if ( regValue
& SSP_SSP0MIS_RXMIS_HALFFULL
)
108 // ToDo: Receive until it's empty
114 /**************************************************************************/
116 @brief Initialises the SSP0 port
118 By default, SSP0 is set to SPI frame-format with 8-bit data. Pin 2.11
119 is routed to serve as serial clock (SCK), and SSEL (0.2) is set to
120 GPIO to allow manual control of when the SPI port is enabled or
121 disabled. Overrun and timeout interrupts are both enabled.
124 The SPI port to use (0..1)
126 Indicates whether the clock should be held high
127 (sspClockPolarity_High) or low (sspClockPolarity_Low)
130 Indicates whether new bits start on the leading
131 (sspClockPhase_RisingEdge) or falling
132 (sspClockPhase_FallingEdge) edge of clock transitions.
134 @note sspSelect() and sspDeselect() macros have been defined in
135 ssp.h to control the SSEL line without having to know the
136 specific pin being used.
138 /**************************************************************************/
139 void sspInit (uint8_t portNum
, sspClockPolarity_t polarity
, sspClockPhase_t phase
)
146 SCB_PRESETCTRL
&= ~SCB_PRESETCTRL_SSP0_MASK
;
147 SCB_PRESETCTRL
|= SCB_PRESETCTRL_SSP0_RESETDISABLED
;
149 /* Enable AHB clock to the SSP domain. */
150 SCB_SYSAHBCLKCTRL
|= (SCB_SYSAHBCLKCTRL_SSP0
);
152 /* Divide by 1 (SSPCLKDIV also enables to SSP CLK) */
153 SCB_SSP0CLKDIV
= SCB_SSP0CLKDIV_DIV1
;
155 /* Set P0.8 to SSP MISO */
156 IOCON_PIO0_8
&= ~IOCON_PIO0_8_FUNC_MASK
;
157 IOCON_PIO0_8
|= IOCON_PIO0_8_FUNC_MISO0
;
159 /* Set P0.9 to SSP MOSI */
160 IOCON_PIO0_9
&= ~IOCON_PIO0_9_FUNC_MASK
;
161 IOCON_PIO0_9
|= IOCON_PIO0_9_FUNC_MOSI0
;
163 /* Set 2.11 to SSP SCK (0.6 and 0.10 can also be used) */
164 #ifdef CFG_SSP0_SCKPIN_2_11
165 IOCON_SCKLOC
= IOCON_SCKLOC_SCKPIN_PIO2_11
;
166 IOCON_PIO2_11
= IOCON_PIO2_11_FUNC_SCK0
;
169 /* Set 0.6 to SSP SCK (2.11 and 0.10 can also be used) */
170 #ifdef CFG_SSP0_SCKPIN_0_6
171 IOCON_SCKLOC
= IOCON_SCKLOC_SCKPIN_PIO0_6
;
172 IOCON_PIO0_6
= IOCON_PIO0_6_FUNC_SCK
;
175 /* Set P0.2/SSEL to GPIO output and high */
176 IOCON_PIO0_2
&= ~IOCON_PIO0_2_FUNC_MASK
;
177 IOCON_PIO0_2
|= IOCON_PIO0_2_FUNC_GPIO
;
178 gpioSetDir(SSP0_CSPORT
, SSP0_CSPIN
, 1);
179 gpioSetValue(SSP0_CSPORT
, SSP0_CSPIN
, 1);
180 gpioSetPullup(&IOCON_PIO0_2
, gpioPullupMode_Inactive
); // Board has external pull-up
182 /* If SSP0CLKDIV = DIV1 -- (PCLK / (CPSDVSR * [SCR+1])) = (72,000,000 / (2 x [8 + 1])) = 4.0 MHz */
183 uint32_t configReg
= ( SSP_SSP0CR0_DSS_8BIT
// Data size = 8-bit
184 | SSP_SSP0CR0_FRF_SPI
// Frame format = SPI
185 | SSP_SSP0CR0_SCR_8
); // Serial clock rate = 8
187 // Set clock polarity
188 if (polarity
== sspClockPolarity_High
)
189 configReg
|= SSP_SSP0CR0_CPOL_HIGH
; // Clock polarity = High between frames
191 configReg
&= ~SSP_SSP0CR0_CPOL_MASK
; // Clock polarity = Low between frames
193 // Set edge transition
194 if (phase
== sspClockPhase_FallingEdge
)
195 configReg
|= SSP_SSP0CR0_CPHA_SECOND
; // Clock out phase = Trailing edge clock transition
197 configReg
&= ~SSP_SSP0CR0_CPHA_MASK
; // Clock out phase = Leading edge clock transition
199 // Assign config values to SSP0CR0
200 SSP_SSP0CR0
= configReg
;
202 /* Clock prescale register must be even and at least 2 in master mode */
203 SSP_SSP0CPSR
= SSP_SSP0CPSR_CPSDVSR_DIV2
;
205 /* Clear the Rx FIFO */
206 uint8_t i
, Dummy
=Dummy
;
207 for ( i
= 0; i
< SSP_FIFOSIZE
; i
++ )
212 /* Enable the SSP Interrupt */
213 NVIC_EnableIRQ(SSP_IRQn
);
215 /* Set SSPINMS registers to enable interrupts
216 * enable all error related interrupts */
217 SSP_SSP0IMSC
= ( SSP_SSP0IMSC_RORIM_ENBL
// Enable overrun interrupt
218 | SSP_SSP0IMSC_RTIM_ENBL
); // Enable timeout interrupt
220 /* Enable device and set it to master mode, no loopback */
221 SSP_SSP0CR1
= SSP_SSP0CR1_SSE_ENABLED
| SSP_SSP0CR1_MS_MASTER
| SSP_SSP0CR1_LBM_NORMAL
;
227 /**************************************************************************/
229 @brief Sends a block of data to the SSP0 port
232 The SPI port to use (0..1)
234 Pointer to the data buffer
236 Block length of the data buffer
238 /**************************************************************************/
239 void sspSend (uint8_t portNum
, uint8_t const *buf
, uint32_t length
)
242 uint8_t Dummy
= Dummy
;
246 for (i
= 0; i
< length
; i
++)
248 /* Move on only if NOT busy and TX FIFO not full. */
249 while ((SSP_SSP0SR
& (SSP_SSP0SR_TNF_NOTFULL
| SSP_SSP0SR_BSY_BUSY
)) != SSP_SSP0SR_TNF_NOTFULL
);
253 while ( (SSP_SSP0SR
& (SSP_SSP0SR_BSY_BUSY
|SSP_SSP0SR_RNE_NOTEMPTY
)) != SSP_SSP0SR_RNE_NOTEMPTY
);
254 /* Whenever a byte is written, MISO FIFO counter increments, Clear FIFO
255 on MISO. Otherwise, when SSP0Receive() is called, previous data byte
256 is left in the FIFO. */
264 /**************************************************************************/
266 @brief Receives a block of data from the SSP0 port
269 The SPI port to use (0..1)
271 Pointer to the data buffer
273 Block length of the data buffer
275 /**************************************************************************/
276 void sspReceive(uint8_t portNum
, uint8_t *buf
, uint32_t length
)
282 for ( i
= 0; i
< length
; i
++ )
284 /* As long as the receive FIFO is not empty, data can be received. */
287 /* Wait until the Busy bit is cleared */
288 while ( (SSP_SSP0SR
& (SSP_SSP0SR_BSY_BUSY
|SSP_SSP0SR_RNE_NOTEMPTY
)) != SSP_SSP0SR_RNE_NOTEMPTY
);
298 void sspSendReceive(uint8_t portNum
, uint8_t *buf
, uint32_t length
)
301 uint8_t Dummy
= Dummy
;
305 for (i
= 0; i
< length
; i
++)
307 /* Move on only if NOT busy and TX FIFO not full. */
308 while ((SSP_SSP0SR
& (SSP_SSP0SR_TNF_NOTFULL
| SSP_SSP0SR_BSY_BUSY
)) != SSP_SSP0SR_TNF_NOTFULL
);
311 while ( (SSP_SSP0SR
& (SSP_SSP0SR_BSY_BUSY
|SSP_SSP0SR_RNE_NOTEMPTY
)) != SSP_SSP0SR_RNE_NOTEMPTY
);
312 /* Whenever a byte is written, MISO FIFO counter increments, Clear FIFO
313 on MISO. Otherwise, when SSP0Receive() is called, previous data byte
314 is left in the FIFO. */