]> begriffs open source - cmsis-freertos/blob - Demo/CORTEX_LM3S811_IAR/LuminaryCode/ssi.c
This is a FreeRTOS header, not RTX.
[cmsis-freertos] / Demo / CORTEX_LM3S811_IAR / LuminaryCode / ssi.c
1 //*****************************************************************************
2 //
3 // ssi.c - Driver for Synchronous Serial Interface.
4 //
5 // Copyright (c) 2005,2006 Luminary Micro, Inc.  All rights reserved.
6 //
7 // Software License Agreement
8 //
9 // Luminary Micro, Inc. (LMI) is supplying this software for use solely and
10 // exclusively on LMI's Stellaris Family of microcontroller products.
11 //
12 // The software is owned by LMI and/or its suppliers, and is protected under
13 // applicable copyright laws.  All rights are reserved.  Any use in violation
14 // of the foregoing restrictions may subject the user to criminal sanctions
15 // under applicable laws, as well as to civil liability for the breach of the
16 // terms and conditions of this license.
17 //
18 // THIS SOFTWARE IS PROVIDED "AS IS".  NO WARRANTIES, WHETHER EXPRESS, IMPLIED
19 // OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
20 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
21 // LMI SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
22 // CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
23 //
24 // This is part of revision 991 of the Stellaris Driver Library.
25 //
26 //*****************************************************************************
27
28 //*****************************************************************************
29 //
30 //! \addtogroup ssi_api
31 //! @{
32 //
33 //*****************************************************************************
34
35 #include "../hw_ints.h"
36 #include "../hw_memmap.h"
37 #include "../hw_ssi.h"
38 #include "../hw_types.h"
39 #include "debug.h"
40 #include "interrupt.h"
41 #include "ssi.h"
42 #include "sysctl.h"
43
44 //*****************************************************************************
45 //
46 //! Configures the synchronous serial interface.
47 //!
48 //! \param ulBase specifies the SSI module base address.
49 //! \param ulProtocol specifies the data transfer protocol.
50 //! \param ulMode specifies the mode of operation.
51 //! \param ulBitRate specifies the clock rate.
52 //! \param ulDataWidth specifies number of bits transfered per frame.
53 //!
54 //! This function configures the synchronous serial interface. It sets
55 //! the SSI protocol, mode of operation, bit rate, and data width.
56 //!
57 //! The parameter \e ulProtocol defines the data frame format. The parameter
58 //! \e ulProtocol can be one of the following values: SSI_FRF_MOTO_MODE_0,
59 //! SSI_FRF_MOTO_MODE_1, SSI_FRF_MOTO_MODE_2, SSI_FRF_MOTO_MODE_3,
60 //! SSI_FRF_TI, or SSI_FRF_NMW. The Motorola frame formats imply the
61 //! following polarity and phase configurations:
62 //! <pre>
63 //! Polarity Phase       Mode
64 //!   0       0   SSI_FRF_MOTO_MODE_0
65 //!   0       1   SSI_FRF_MOTO_MODE_1
66 //!   1       0   SSI_FRF_MOTO_MODE_2
67 //!   1       1   SSI_FRF_MOTO_MODE_3
68 //! </pre>
69 //!
70 //! The parameter \e ulMode defines the operating mode of the SSI module. The
71 //! SSI module can operate as a master or slave; if a slave, the SSI can be
72 //! configured to disable output on its serial output line. The parameter
73 //! \e ulMode can be one of the following values: SSI_MODE_MASTER,
74 //! SSI_MODE_SLAVE, or SSI_MODE_SLAVE_OD.
75 //!
76 //! The parameter \e ulBitRate defines the bit rate for the SSI. This bit rate
77 //! must satisfy the following clock ratio criteria:
78 //! - FSSI >= 2 * bit rate (master mode)
79 //! - FSSI >= 12 * bit rate (slave modes)
80 //!
81 //! where FSSI is the frequency of the clock supplied to the SSI module.
82 //!
83 //! The parameter \e ulDataWidth defines the width of the data transfers.
84 //! The parameter \e ulDataWidth can be a value between 4 and 16, inclusive.
85 //!
86 //! The SSI clocking is dependent upon the system clock rate returned by
87 //! SysCtlClockGet(); if it does not return the correct system clock rate then
88 //! the SSI clock rate will be incorrect.
89 //!
90 //! \return None.
91 //
92 //*****************************************************************************
93 #if defined(GROUP_config) || defined(BUILD_ALL) || defined(DOXYGEN)
94 void
95 SSIConfig(unsigned long ulBase, unsigned long ulProtocol, unsigned long ulMode,
96           unsigned long ulBitRate, unsigned long ulDataWidth)
97 {
98     unsigned long ulMaxBitRate;
99     unsigned long ulRegVal;
100     unsigned long ulPreDiv;
101     unsigned long ulSCR;
102     unsigned long ulSPH_SPO;
103     unsigned long ulClock;
104
105     //
106     // Check the arguments.
107     //
108     ASSERT(ulBase == SSI_BASE);
109     ASSERT((ulProtocol == SSI_FRF_MOTO_MODE_0) ||
110            (ulProtocol == SSI_FRF_MOTO_MODE_1) ||
111            (ulProtocol == SSI_FRF_MOTO_MODE_2) ||
112            (ulProtocol == SSI_FRF_MOTO_MODE_3) ||
113            (ulProtocol == SSI_FRF_TI) ||
114            (ulProtocol == SSI_FRF_NMW));
115     ASSERT((ulMode == SSI_MODE_MASTER) ||
116            (ulMode == SSI_MODE_SLAVE) ||
117            (ulMode == SSI_MODE_SLAVE_OD));
118     ASSERT((ulDataWidth >= 4) && (ulDataWidth <= 16));
119
120     //
121     // Get the processor clock rate.
122     //
123     ulClock = SysCtlClockGet();
124
125     //
126     // Validate the clock speed.
127     //
128     ASSERT(((ulMode == SSI_MODE_MASTER) && (ulBitRate <= (ulClock / 2))) ||
129            ((ulMode != SSI_MODE_MASTER) && (ulBitRate <= (ulClock / 12))));
130     ASSERT((ulClock / ulBitRate) <= (254 * 256));
131
132     //
133     // Set the mode.
134     //
135     ulRegVal = (ulMode == SSI_MODE_SLAVE_OD) ? SSI_CR1_SOD : 0;
136     ulRegVal |= (ulMode == SSI_MODE_MASTER) ? 0 : SSI_CR1_MS;
137     HWREG(ulBase + SSI_O_CR1) = ulRegVal;
138
139     //
140     // Set the clock predivider.
141     //
142     ulMaxBitRate = ulClock / ulBitRate;
143     ulPreDiv = 0;
144     do
145     {
146         ulPreDiv += 2;
147         ulSCR = (ulMaxBitRate / ulPreDiv) - 1;
148     }
149     while(ulSCR > 255);
150     HWREG(ulBase + SSI_O_CPSR) = ulPreDiv;
151
152     //
153     // Set protocol and clock rate.
154     //
155     ulSPH_SPO = ulProtocol << 6;
156     ulProtocol &= SSI_CR0_FRF_MASK;
157     ulRegVal = (ulSCR << 8) | ulSPH_SPO | ulProtocol | (ulDataWidth - 1);
158     HWREG(ulBase + SSI_O_CR0) = ulRegVal;
159 }
160 #endif
161
162 //*****************************************************************************
163 //
164 //! Enables the synchronous serial interface.
165 //!
166 //! \param ulBase specifies the SSI module base address.
167 //!
168 //! This will enable operation of the synchronous serial interface. It must be
169 //! configured before it is enabled.
170 //!
171 //! \return None.
172 //
173 //*****************************************************************************
174 #if defined(GROUP_enable) || defined(BUILD_ALL) || defined(DOXYGEN)
175 void
176 SSIEnable(unsigned long ulBase)
177 {
178     //
179     // Check the arguments.
180     //
181     ASSERT(ulBase == SSI_BASE);
182
183     //
184     // Read-modify-write the enable bit.
185     //
186     HWREG(ulBase + SSI_O_CR1) |= SSI_CR1_SSE;
187 }
188 #endif
189
190 //*****************************************************************************
191 //
192 //! Disables the synchronous serial interface.
193 //!
194 //! \param ulBase specifies the SSI module base address.
195 //!
196 //! This will disable operation of the synchronous serial interface.
197 //!
198 //! \return None.
199 //
200 //*****************************************************************************
201 #if defined(GROUP_disable) || defined(BUILD_ALL) || defined(DOXYGEN)
202 void
203 SSIDisable(unsigned long ulBase)
204 {
205     //
206     // Check the arguments.
207     //
208     ASSERT(ulBase == SSI_BASE);
209
210     //
211     // Read-modify-write the enable bit.
212     //
213     HWREG(ulBase + SSI_O_CR1) &= ~(SSI_CR1_SSE);
214 }
215 #endif
216
217 //*****************************************************************************
218 //
219 //! Registers an interrupt handler for the synchronous serial interface.
220 //!
221 //! \param ulBase specifies the SSI module base address.
222 //! \param pfnHandler is a pointer to the function to be called when the
223 //! synchronous serial interface interrupt occurs.
224 //!
225 //! This sets the handler to be called when an SSI interrupt
226 //! occurs.  This will enable the global interrupt in the interrupt controller;
227 //! specific SSI interrupts must be enabled via SSIIntEnable().  If necessary,
228 //! it is the interrupt handler's responsibility to clear the interrupt source
229 //! via SSIIntClear().
230 //!
231 //! \sa IntRegister() for important information about registering interrupt
232 //! handlers.
233 //!
234 //! \return None.
235 //
236 //*****************************************************************************
237 #if defined(GROUP_intregister) || defined(BUILD_ALL) || defined(DOXYGEN)
238 void
239 SSIIntRegister(unsigned long ulBase, void (*pfnHandler)(void))
240 {
241     //
242     // Check the arguments.
243     //
244     ASSERT(ulBase == SSI_BASE);
245
246     //
247     // Register the interrupt handler, returning an error if an error occurs.
248     //
249     IntRegister(INT_SSI, pfnHandler);
250
251     //
252     // Enable the synchronous serial interface interrupt.
253     //
254     IntEnable(INT_SSI);
255 }
256 #endif
257
258 //*****************************************************************************
259 //
260 //! Unregisters an interrupt handler for the synchronous serial interface.
261 //!
262 //! \param ulBase specifies the SSI module base address.
263 //!
264 //! This function will clear the handler to be called when a SSI
265 //! interrupt occurs.  This will also mask off the interrupt in the interrupt
266 //! controller so that the interrupt handler no longer is called.
267 //!
268 //! \sa IntRegister() for important information about registering interrupt
269 //! handlers.
270 //!
271 //! \return None.
272 //
273 //*****************************************************************************
274 #if defined(GROUP_intunregister) || defined(BUILD_ALL) || defined(DOXYGEN)
275 void
276 SSIIntUnregister(unsigned long ulBase)
277 {
278     //
279     // Check the arguments.
280     //
281     ASSERT(ulBase == SSI_BASE);
282
283     //
284     // Disable the interrupt.
285     //
286     IntDisable(INT_SSI);
287
288     //
289     // Unregister the interrupt handler.
290     //
291     IntUnregister(INT_SSI);
292 }
293 #endif
294
295 //*****************************************************************************
296 //
297 //! Enables individual SSI interrupt sources.
298 //!
299 //! \param ulBase specifies the SSI module base address.
300 //! \param ulIntFlags is a bit mask of the interrupt sources to be enabled.
301 //!
302 //! Enables the indicated SSI interrupt sources.  Only the sources that are
303 //! enabled can be reflected to the processor interrupt; disabled sources
304 //! have no effect on the processor.  The parameter \e ulIntFlags Can be
305 //! any of the SSI_TXFF, SSI_RXFF, SSI_RXTO, or SSI_RXOR values.
306 //!
307 //! \return None.
308 //
309 //*****************************************************************************
310 #if defined(GROUP_intenable) || defined(BUILD_ALL) || defined(DOXYGEN)
311 void
312 SSIIntEnable(unsigned long ulBase, unsigned long ulIntFlags)
313 {
314     //
315     // Check the arguments.
316     //
317     ASSERT(ulBase == SSI_BASE);
318
319     //
320     // Enable the specified interrupts.
321     //
322     HWREG(ulBase + SSI_O_IM) |= ulIntFlags;
323 }
324 #endif
325
326 //*****************************************************************************
327 //
328 //! Disables individual SSI interrupt sources.
329 //!
330 //! \param ulBase specifies the SSI module base address.
331 //! \param ulIntFlags is a bit mask of the interrupt sources to be disabled.
332 //!
333 //! Disables the indicated SSI interrupt sources. The parameter
334 //! \e ulIntFlags Can be any of the SSI_TXFF, SSI_RXFF, SSI_RXTO,
335 //! or SSI_RXOR values.
336 //!
337 //! \return None.
338 //
339 //*****************************************************************************
340 #if defined(GROUP_intdisable) || defined(BUILD_ALL) || defined(DOXYGEN)
341 void
342 SSIIntDisable(unsigned long ulBase, unsigned long ulIntFlags)
343 {
344     //
345     // Check the arguments.
346     //
347     ASSERT(ulBase == SSI_BASE);
348
349     //
350     // Disable the specified interrupts.
351     //
352     HWREG(ulBase + SSI_O_IM) &= ~(ulIntFlags);
353 }
354 #endif
355
356 //*****************************************************************************
357 //
358 //! Gets the current interrupt status.
359 //!
360 //! \param ulBase specifies the SSI module base address.
361 //! \param bMasked is false if the raw interrupt status is required and
362 //! true if the masked interrupt status is required.
363 //!
364 //! This returns the interrupt status for the SSI module.
365 //! Either the raw interrupt status or the status of interrupts that are
366 //! allowed to reflect to the processor can be returned.
367 //!
368 //! \return The current interrupt status, enumerated as a bit field of
369 //! SSI_TXFF, SSI_RXFF, SSI_RXTO, and SSI_RXOR.
370 //
371 //*****************************************************************************
372 #if defined(GROUP_intstatus) || defined(BUILD_ALL) || defined(DOXYGEN)
373 unsigned long
374 SSIIntStatus(unsigned long ulBase, tBoolean bMasked)
375 {
376     //
377     // Check the arguments.
378     //
379     ASSERT(ulBase == SSI_BASE);
380
381     //
382     // Return either the interrupt status or the raw interrupt status as
383     // requested.
384     //
385     if(bMasked)
386     {
387         return(HWREG(ulBase + SSI_O_MIS));
388     }
389     else
390     {
391         return(HWREG(ulBase + SSI_O_RIS));
392     }
393 }
394 #endif
395
396 //*****************************************************************************
397 //
398 //! Clears SSI interrupt sources.
399 //!
400 //! \param ulBase specifies the SSI module base address.
401 //! \param ulIntFlags is a bit mask of the interrupt sources to be cleared.
402 //!
403 //! The specified SSI interrupt sources are cleared, so that
404 //! they no longer assert.  This must be done in the interrupt handler to
405 //! keep it from being called again immediately upon exit.
406 //! The parameter \e ulIntFlags can consist of either or both the SSI_RXTO
407 //! and SSI_RXOR values.
408 //!
409 //! \return None.
410 //
411 //*****************************************************************************
412 #if defined(GROUP_intclear) || defined(BUILD_ALL) || defined(DOXYGEN)
413 void
414 SSIIntClear(unsigned long ulBase, unsigned long ulIntFlags)
415 {
416     //
417     // Check the arguments.
418     //
419     ASSERT(ulBase == SSI_BASE);
420
421     //
422     // Clear the requested interrupt sources.
423     //
424     HWREG(ulBase + SSI_O_ICR) = ulIntFlags;
425 }
426 #endif
427
428 //*****************************************************************************
429 //
430 //! Puts a data element into the SSI transmit FIFO.
431 //!
432 //! \param ulBase specifies the SSI module base address.
433 //! \param ulData data to be transmitted over the SSI interface.
434 //!
435 //! This function will place the supplied data into the transmit FIFO of
436 //! the specified SSI module.
437 //!
438 //! \note The upper 32 - N bits of the \e ulData will be discarded by the
439 //! hardware, where N is the data width as configured by SSIConfig().  For
440 //! example, if the interface is configured for 8 bit data width, the upper 24
441 //! bits of \e ulData will be discarded.
442 //!
443 //! \return None.
444 //
445 //*****************************************************************************
446 #if defined(GROUP_dataput) || defined(BUILD_ALL) || defined(DOXYGEN)
447 void
448 SSIDataPut(unsigned long ulBase, unsigned long ulData)
449 {
450     //
451     // Check the arguments.
452     //
453     ASSERT(ulBase == SSI_BASE);
454     ASSERT((ulData & (0xfffffffe << (HWREG(ulBase + SSI_O_CR0) &
455                                      SSI_CR0_DSS))) == 0);
456
457     //
458     // Wait until there is space.
459     //
460     while(!(HWREG(ulBase + SSI_O_SR) & SSI_SR_TNF))
461     {
462     }
463
464     //
465     // Write the data to the SSI.
466     //
467     HWREG(ulBase + SSI_O_DR) = ulData;
468 }
469 #endif
470
471 //*****************************************************************************
472 //
473 //! Puts a data element into the SSI transmit FIFO.
474 //!
475 //! \param ulBase specifies the SSI module base address.
476 //! \param ulData data to be transmitted over the SSI interface.
477 //!
478 //! This function will place the supplied data into the transmit FIFO of
479 //! the specified SSI module. If there is no space in the FIFO, then this
480 //! function will return a zero.
481 //!
482 //! \note The upper 32 - N bits of the \e ulData will be discarded by the
483 //! hardware, where N is the data width as configured by SSIConfig().  For
484 //! example, if the interface is configured for 8 bit data width, the upper 24
485 //! bits of \e ulData will be discarded.
486 //!
487 //! \return Returns the number of elements written to the SSI transmit FIFO.
488 //
489 //*****************************************************************************
490 #if defined(GROUP_datanonblockingput) || defined(BUILD_ALL) || defined(DOXYGEN)
491 long
492 SSIDataNonBlockingPut(unsigned long ulBase, unsigned long ulData)
493 {
494     //
495     // Check the arguments.
496     //
497     ASSERT(ulBase == SSI_BASE);
498     ASSERT((ulData & (0xfffffffe << (HWREG(ulBase + SSI_O_CR0) &
499                                      SSI_CR0_DSS))) == 0);
500
501     //
502     // Check for space to write.
503     //
504     if(HWREG(ulBase + SSI_O_SR) & SSI_SR_TNF)
505     {
506         HWREG(ulBase + SSI_O_DR) = ulData;
507         return(1);
508     }
509     else
510     {
511         return(0);
512     }
513 }
514 #endif
515
516 //*****************************************************************************
517 //
518 //! Gets a data element from the SSI receive FIFO.
519 //!
520 //! \param ulBase specifies the SSI module base address.
521 //! \param pulData pointer to a storage location for data that was received
522 //! over the SSI interface.
523 //!
524 //! This function will get received data from the receive FIFO of the specified
525 //! SSI module, and place that data into the location specified by the
526 //! \e pulData parameter.
527 //!
528 //! \note Only the lower N bits of the value written to \e pulData will contain
529 //! valid data, where N is the data width as configured by SSIConfig().  For
530 //! example, if the interface is configured for 8 bit data width, only the
531 //! lower 8 bits of the value written to \e pulData will contain valid data.
532 //!
533 //! \return None.
534 //
535 //*****************************************************************************
536 #if defined(GROUP_dataget) || defined(BUILD_ALL) || defined(DOXYGEN)
537 void
538 SSIDataGet(unsigned long ulBase, unsigned long *pulData)
539 {
540     //
541     // Check the arguments.
542     //
543     ASSERT(ulBase == SSI_BASE);
544
545     //
546     // Wait until there is data to be read.
547     //
548     while(!(HWREG(ulBase + SSI_O_SR) & SSI_SR_RNE))
549     {
550     }
551
552     //
553     // Read data from SSI.
554     //
555     *pulData = HWREG(ulBase + SSI_O_DR);
556 }
557 #endif
558
559 //*****************************************************************************
560 //
561 //! Gets a data element from the SSI receive FIFO.
562 //!
563 //! \param ulBase specifies the SSI module base address.
564 //! \param pulData pointer to a storage location for data that was received
565 //! over the SSI interface.
566 //!
567 //! This function will get received data from the receive FIFO of
568 //! the specified SSI module, and place that data into the location specified
569 //! by the \e ulData parameter. If there is no data in the FIFO, then this
570 //! function will return a zero.
571 //!
572 //! \note Only the lower N bits of the value written to \e pulData will contain
573 //! valid data, where N is the data width as configured by SSIConfig().  For
574 //! example, if the interface is configured for 8 bit data width, only the
575 //! lower 8 bits of the value written to \e pulData will contain valid data.
576 //!
577 //! \return Returns the number of elements read from the SSI receive FIFO.
578 //
579 //*****************************************************************************
580 #if defined(GROUP_datanonblockingget) || defined(BUILD_ALL) || defined(DOXYGEN)
581 long
582 SSIDataNonBlockingGet(unsigned long ulBase, unsigned long *pulData)
583
584    //
585     // Check the arguments.
586     //
587     ASSERT(ulBase == SSI_BASE);
588
589     //
590     // Check for data to read.
591     //
592     if(HWREG(ulBase + SSI_O_SR) & SSI_SR_RNE)
593     {
594         *pulData = HWREG(ulBase + SSI_O_DR);
595         return(1);
596     }
597     else
598     {
599         return(0);
600     }
601 }
602 #endif
603
604 //*****************************************************************************
605 //
606 // Close the Doxygen group.
607 //! @}
608 //
609 //*****************************************************************************