1 /**************************************************************************/
4 @author K. Townsend (microBuilder.eu)
10 Generic code for SSP/SPI communications. By default, the SSP block
11 is initialised in SPI master mode.
16 #include "core/cpu/cpu.h"
17 #include "core/ssp/ssp.h"
20 sspInit(0, sspClockPolarity_High, sspClockPhase_RisingEdge);
22 uint8_t request[SSP_FIFOSIZE];
23 uint8_t response[SSP_FIFOSIZE];
25 // Send 0x9C to the slave device and wait for a response
26 request[0] = 0x80 | 0x1C;
27 // Toggle the select pin
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
36 debug_printf("Ox%x ", response[0]);
41 Software License Agreement (BSD License)
43 Copyright (c) 2010, microBuilder SARL
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.
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.
68 /**************************************************************************/
70 #include "core/gpio/gpio.h"
72 /* Statistics for all interrupts */
73 volatile uint32_t interruptRxStat
= 0;
74 volatile uint32_t interruptOverRunStat
= 0;
75 volatile uint32_t interruptRxTimeoutStat
= 0;
77 /**************************************************************************/
79 @brief SSP0 interrupt handler for SPI communication
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.
86 /**************************************************************************/
87 void SSP_IRQHandler (void)
91 regValue
= SSP_SSP0MIS
;
93 /* Check for overrun interrupt */
94 if ( regValue
& SSP_SSP0MIS_RORMIS_FRMRCVD
)
96 interruptOverRunStat
++;
97 SSP_SSP0ICR
= SSP_SSP0ICR_RORIC_CLEAR
; // Clear interrupt
100 /* Check for timeout interrupt */
101 if ( regValue
& SSP_SSP0MIS_RTMIS_NOTEMPTY
)
103 interruptRxTimeoutStat
++;
104 SSP_SSP0ICR
= SSP_SSP0ICR_RTIC_CLEAR
; // Clear interrupt
107 /* Check if Rx buffer is at least half-full */
108 if ( regValue
& SSP_SSP0MIS_RXMIS_HALFFULL
)
110 // ToDo: Receive until it's empty
116 /**************************************************************************/
118 @brief Initialises the SSP0 port
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.
126 The SPI port to use (0..1)
128 Indicates whether the clock should be held high
129 (sspClockPolarity_High) or low (sspClockPolarity_Low)
132 Indicates whether new bits start on the leading
133 (sspClockPhase_RisingEdge) or falling
134 (sspClockPhase_FallingEdge) edge of clock transitions.
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.
140 /**************************************************************************/
141 void sspInit (uint8_t portNum
, sspClockPolarity_t polarity
, sspClockPhase_t phase
)
148 SCB_PRESETCTRL
&= ~SCB_PRESETCTRL_SSP0_MASK
;
149 SCB_PRESETCTRL
|= SCB_PRESETCTRL_SSP0_RESETDISABLED
;
151 /* Enable AHB clock to the SSP domain. */
152 SCB_SYSAHBCLKCTRL
|= (SCB_SYSAHBCLKCTRL_SSP0
);
154 /* Divide by 1 (SSPCLKDIV also enables to SSP CLK) */
155 SCB_SSP0CLKDIV
= SCB_SSP0CLKDIV_DIV1
;
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
;
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
;
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
;
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
;
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
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
189 // Set clock polarity
190 if (polarity
== sspClockPolarity_High
)
191 configReg
|= SSP_SSP0CR0_CPOL_HIGH
; // Clock polarity = High between frames
193 configReg
&= ~SSP_SSP0CR0_CPOL_MASK
; // Clock polarity = Low between frames
195 // Set edge transition
196 if (phase
== sspClockPhase_FallingEdge
)
197 configReg
|= SSP_SSP0CR0_CPHA_SECOND
; // Clock out phase = Trailing edge clock transition
199 configReg
&= ~SSP_SSP0CR0_CPHA_MASK
; // Clock out phase = Leading edge clock transition
201 // Assign config values to SSP0CR0
202 SSP_SSP0CR0
= configReg
;
204 /* Clock prescale register must be even and at least 2 in master mode */
205 SSP_SSP0CPSR
= SSP_SSP0CPSR_CPSDVSR_DIV2
;
207 /* Clear the Rx FIFO */
208 uint8_t i
, Dummy
=Dummy
;
209 for ( i
= 0; i
< SSP_FIFOSIZE
; i
++ )
214 /* Enable the SSP Interrupt */
215 NVIC_EnableIRQ(SSP_IRQn
);
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
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
;
229 /**************************************************************************/
231 @brief Sends a block of data to the SSP0 port
234 The SPI port to use (0..1)
236 Pointer to the data buffer
238 Block length of the data buffer
240 /**************************************************************************/
241 void sspSend (uint8_t portNum
, uint8_t *buf
, uint32_t length
)
244 uint8_t Dummy
= Dummy
;
248 for (i
= 0; i
< length
; i
++)
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
);
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. */
266 /**************************************************************************/
268 @brief Receives a block of data from the SSP0 port
271 The SPI port to use (0..1)
273 Pointer to the data buffer
275 Block length of the data buffer
277 /**************************************************************************/
278 void sspReceive(uint8_t portNum
, uint8_t *buf
, uint32_t length
)
284 for ( i
= 0; i
< length
; i
++ )
286 /* As long as the receive FIFO is not empty, data can be received. */
289 /* Wait until the Busy bit is cleared */
290 while ( (SSP_SSP0SR
& (SSP_SSP0SR_BSY_BUSY
|SSP_SSP0SR_RNE_NOTEMPTY
)) != SSP_SSP0SR_RNE_NOTEMPTY
);