1 //*****************************************************************************
\r
3 // ssi.c - Driver for Synchronous Serial Interface.
\r
5 // Copyright (c) 2005,2006 Luminary Micro, Inc. All rights reserved.
\r
7 // Software License Agreement
\r
9 // Luminary Micro, Inc. (LMI) is supplying this software for use solely and
\r
10 // exclusively on LMI's Stellaris Family of microcontroller products.
\r
12 // The software is owned by LMI and/or its suppliers, and is protected under
\r
13 // applicable copyright laws. All rights are reserved. Any use in violation
\r
14 // of the foregoing restrictions may subject the user to criminal sanctions
\r
15 // under applicable laws, as well as to civil liability for the breach of the
\r
16 // terms and conditions of this license.
\r
18 // THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
\r
19 // OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
\r
20 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
\r
21 // LMI SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
\r
22 // CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
\r
24 // This is part of revision 991 of the Stellaris Driver Library.
\r
26 //*****************************************************************************
\r
28 //*****************************************************************************
\r
30 //! \addtogroup ssi_api
\r
33 //*****************************************************************************
\r
35 #include "../hw_ints.h"
\r
36 #include "../hw_memmap.h"
\r
37 #include "../hw_ssi.h"
\r
38 #include "../hw_types.h"
\r
40 #include "interrupt.h"
\r
44 //*****************************************************************************
\r
46 //! Configures the synchronous serial interface.
\r
48 //! \param ulBase specifies the SSI module base address.
\r
49 //! \param ulProtocol specifies the data transfer protocol.
\r
50 //! \param ulMode specifies the mode of operation.
\r
51 //! \param ulBitRate specifies the clock rate.
\r
52 //! \param ulDataWidth specifies number of bits transfered per frame.
\r
54 //! This function configures the synchronous serial interface. It sets
\r
55 //! the SSI protocol, mode of operation, bit rate, and data width.
\r
57 //! The parameter \e ulProtocol defines the data frame format. The parameter
\r
58 //! \e ulProtocol can be one of the following values: SSI_FRF_MOTO_MODE_0,
\r
59 //! SSI_FRF_MOTO_MODE_1, SSI_FRF_MOTO_MODE_2, SSI_FRF_MOTO_MODE_3,
\r
60 //! SSI_FRF_TI, or SSI_FRF_NMW. The Motorola frame formats imply the
\r
61 //! following polarity and phase configurations:
\r
63 //! Polarity Phase Mode
\r
64 //! 0 0 SSI_FRF_MOTO_MODE_0
\r
65 //! 0 1 SSI_FRF_MOTO_MODE_1
\r
66 //! 1 0 SSI_FRF_MOTO_MODE_2
\r
67 //! 1 1 SSI_FRF_MOTO_MODE_3
\r
70 //! The parameter \e ulMode defines the operating mode of the SSI module. The
\r
71 //! SSI module can operate as a master or slave; if a slave, the SSI can be
\r
72 //! configured to disable output on its serial output line. The parameter
\r
73 //! \e ulMode can be one of the following values: SSI_MODE_MASTER,
\r
74 //! SSI_MODE_SLAVE, or SSI_MODE_SLAVE_OD.
\r
76 //! The parameter \e ulBitRate defines the bit rate for the SSI. This bit rate
\r
77 //! must satisfy the following clock ratio criteria:
\r
78 //! - FSSI >= 2 * bit rate (master mode)
\r
79 //! - FSSI >= 12 * bit rate (slave modes)
\r
81 //! where FSSI is the frequency of the clock supplied to the SSI module.
\r
83 //! The parameter \e ulDataWidth defines the width of the data transfers.
\r
84 //! The parameter \e ulDataWidth can be a value between 4 and 16, inclusive.
\r
86 //! The SSI clocking is dependent upon the system clock rate returned by
\r
87 //! SysCtlClockGet(); if it does not return the correct system clock rate then
\r
88 //! the SSI clock rate will be incorrect.
\r
92 //*****************************************************************************
\r
93 #if defined(GROUP_config) || defined(BUILD_ALL) || defined(DOXYGEN)
\r
95 SSIConfig(unsigned long ulBase, unsigned long ulProtocol, unsigned long ulMode,
\r
96 unsigned long ulBitRate, unsigned long ulDataWidth)
\r
98 unsigned long ulMaxBitRate;
\r
99 unsigned long ulRegVal;
\r
100 unsigned long ulPreDiv;
\r
101 unsigned long ulSCR;
\r
102 unsigned long ulSPH_SPO;
\r
103 unsigned long ulClock;
\r
106 // Check the arguments.
\r
108 ASSERT(ulBase == SSI_BASE);
\r
109 ASSERT((ulProtocol == SSI_FRF_MOTO_MODE_0) ||
\r
110 (ulProtocol == SSI_FRF_MOTO_MODE_1) ||
\r
111 (ulProtocol == SSI_FRF_MOTO_MODE_2) ||
\r
112 (ulProtocol == SSI_FRF_MOTO_MODE_3) ||
\r
113 (ulProtocol == SSI_FRF_TI) ||
\r
114 (ulProtocol == SSI_FRF_NMW));
\r
115 ASSERT((ulMode == SSI_MODE_MASTER) ||
\r
116 (ulMode == SSI_MODE_SLAVE) ||
\r
117 (ulMode == SSI_MODE_SLAVE_OD));
\r
118 ASSERT((ulDataWidth >= 4) && (ulDataWidth <= 16));
\r
121 // Get the processor clock rate.
\r
123 ulClock = SysCtlClockGet();
\r
126 // Validate the clock speed.
\r
128 ASSERT(((ulMode == SSI_MODE_MASTER) && (ulBitRate <= (ulClock / 2))) ||
\r
129 ((ulMode != SSI_MODE_MASTER) && (ulBitRate <= (ulClock / 12))));
\r
130 ASSERT((ulClock / ulBitRate) <= (254 * 256));
\r
135 ulRegVal = (ulMode == SSI_MODE_SLAVE_OD) ? SSI_CR1_SOD : 0;
\r
136 ulRegVal |= (ulMode == SSI_MODE_MASTER) ? 0 : SSI_CR1_MS;
\r
137 HWREG(ulBase + SSI_O_CR1) = ulRegVal;
\r
140 // Set the clock predivider.
\r
142 ulMaxBitRate = ulClock / ulBitRate;
\r
147 ulSCR = (ulMaxBitRate / ulPreDiv) - 1;
\r
149 while(ulSCR > 255);
\r
150 HWREG(ulBase + SSI_O_CPSR) = ulPreDiv;
\r
153 // Set protocol and clock rate.
\r
155 ulSPH_SPO = ulProtocol << 6;
\r
156 ulProtocol &= SSI_CR0_FRF_MASK;
\r
157 ulRegVal = (ulSCR << 8) | ulSPH_SPO | ulProtocol | (ulDataWidth - 1);
\r
158 HWREG(ulBase + SSI_O_CR0) = ulRegVal;
\r
162 //*****************************************************************************
\r
164 //! Enables the synchronous serial interface.
\r
166 //! \param ulBase specifies the SSI module base address.
\r
168 //! This will enable operation of the synchronous serial interface. It must be
\r
169 //! configured before it is enabled.
\r
173 //*****************************************************************************
\r
174 #if defined(GROUP_enable) || defined(BUILD_ALL) || defined(DOXYGEN)
\r
176 SSIEnable(unsigned long ulBase)
\r
179 // Check the arguments.
\r
181 ASSERT(ulBase == SSI_BASE);
\r
184 // Read-modify-write the enable bit.
\r
186 HWREG(ulBase + SSI_O_CR1) |= SSI_CR1_SSE;
\r
190 //*****************************************************************************
\r
192 //! Disables the synchronous serial interface.
\r
194 //! \param ulBase specifies the SSI module base address.
\r
196 //! This will disable operation of the synchronous serial interface.
\r
200 //*****************************************************************************
\r
201 #if defined(GROUP_disable) || defined(BUILD_ALL) || defined(DOXYGEN)
\r
203 SSIDisable(unsigned long ulBase)
\r
206 // Check the arguments.
\r
208 ASSERT(ulBase == SSI_BASE);
\r
211 // Read-modify-write the enable bit.
\r
213 HWREG(ulBase + SSI_O_CR1) &= ~(SSI_CR1_SSE);
\r
217 //*****************************************************************************
\r
219 //! Registers an interrupt handler for the synchronous serial interface.
\r
221 //! \param ulBase specifies the SSI module base address.
\r
222 //! \param pfnHandler is a pointer to the function to be called when the
\r
223 //! synchronous serial interface interrupt occurs.
\r
225 //! This sets the handler to be called when an SSI interrupt
\r
226 //! occurs. This will enable the global interrupt in the interrupt controller;
\r
227 //! specific SSI interrupts must be enabled via SSIIntEnable(). If necessary,
\r
228 //! it is the interrupt handler's responsibility to clear the interrupt source
\r
229 //! via SSIIntClear().
\r
231 //! \sa IntRegister() for important information about registering interrupt
\r
236 //*****************************************************************************
\r
237 #if defined(GROUP_intregister) || defined(BUILD_ALL) || defined(DOXYGEN)
\r
239 SSIIntRegister(unsigned long ulBase, void (*pfnHandler)(void))
\r
242 // Check the arguments.
\r
244 ASSERT(ulBase == SSI_BASE);
\r
247 // Register the interrupt handler, returning an error if an error occurs.
\r
249 IntRegister(INT_SSI, pfnHandler);
\r
252 // Enable the synchronous serial interface interrupt.
\r
254 IntEnable(INT_SSI);
\r
258 //*****************************************************************************
\r
260 //! Unregisters an interrupt handler for the synchronous serial interface.
\r
262 //! \param ulBase specifies the SSI module base address.
\r
264 //! This function will clear the handler to be called when a SSI
\r
265 //! interrupt occurs. This will also mask off the interrupt in the interrupt
\r
266 //! controller so that the interrupt handler no longer is called.
\r
268 //! \sa IntRegister() for important information about registering interrupt
\r
273 //*****************************************************************************
\r
274 #if defined(GROUP_intunregister) || defined(BUILD_ALL) || defined(DOXYGEN)
\r
276 SSIIntUnregister(unsigned long ulBase)
\r
279 // Check the arguments.
\r
281 ASSERT(ulBase == SSI_BASE);
\r
284 // Disable the interrupt.
\r
286 IntDisable(INT_SSI);
\r
289 // Unregister the interrupt handler.
\r
291 IntUnregister(INT_SSI);
\r
295 //*****************************************************************************
\r
297 //! Enables individual SSI interrupt sources.
\r
299 //! \param ulBase specifies the SSI module base address.
\r
300 //! \param ulIntFlags is a bit mask of the interrupt sources to be enabled.
\r
302 //! Enables the indicated SSI interrupt sources. Only the sources that are
\r
303 //! enabled can be reflected to the processor interrupt; disabled sources
\r
304 //! have no effect on the processor. The parameter \e ulIntFlags Can be
\r
305 //! any of the SSI_TXFF, SSI_RXFF, SSI_RXTO, or SSI_RXOR values.
\r
309 //*****************************************************************************
\r
310 #if defined(GROUP_intenable) || defined(BUILD_ALL) || defined(DOXYGEN)
\r
312 SSIIntEnable(unsigned long ulBase, unsigned long ulIntFlags)
\r
315 // Check the arguments.
\r
317 ASSERT(ulBase == SSI_BASE);
\r
320 // Enable the specified interrupts.
\r
322 HWREG(ulBase + SSI_O_IM) |= ulIntFlags;
\r
326 //*****************************************************************************
\r
328 //! Disables individual SSI interrupt sources.
\r
330 //! \param ulBase specifies the SSI module base address.
\r
331 //! \param ulIntFlags is a bit mask of the interrupt sources to be disabled.
\r
333 //! Disables the indicated SSI interrupt sources. The parameter
\r
334 //! \e ulIntFlags Can be any of the SSI_TXFF, SSI_RXFF, SSI_RXTO,
\r
335 //! or SSI_RXOR values.
\r
339 //*****************************************************************************
\r
340 #if defined(GROUP_intdisable) || defined(BUILD_ALL) || defined(DOXYGEN)
\r
342 SSIIntDisable(unsigned long ulBase, unsigned long ulIntFlags)
\r
345 // Check the arguments.
\r
347 ASSERT(ulBase == SSI_BASE);
\r
350 // Disable the specified interrupts.
\r
352 HWREG(ulBase + SSI_O_IM) &= ~(ulIntFlags);
\r
356 //*****************************************************************************
\r
358 //! Gets the current interrupt status.
\r
360 //! \param ulBase specifies the SSI module base address.
\r
361 //! \param bMasked is false if the raw interrupt status is required and
\r
362 //! true if the masked interrupt status is required.
\r
364 //! This returns the interrupt status for the SSI module.
\r
365 //! Either the raw interrupt status or the status of interrupts that are
\r
366 //! allowed to reflect to the processor can be returned.
\r
368 //! \return The current interrupt status, enumerated as a bit field of
\r
369 //! SSI_TXFF, SSI_RXFF, SSI_RXTO, and SSI_RXOR.
\r
371 //*****************************************************************************
\r
372 #if defined(GROUP_intstatus) || defined(BUILD_ALL) || defined(DOXYGEN)
\r
374 SSIIntStatus(unsigned long ulBase, tBoolean bMasked)
\r
377 // Check the arguments.
\r
379 ASSERT(ulBase == SSI_BASE);
\r
382 // Return either the interrupt status or the raw interrupt status as
\r
387 return(HWREG(ulBase + SSI_O_MIS));
\r
391 return(HWREG(ulBase + SSI_O_RIS));
\r
396 //*****************************************************************************
\r
398 //! Clears SSI interrupt sources.
\r
400 //! \param ulBase specifies the SSI module base address.
\r
401 //! \param ulIntFlags is a bit mask of the interrupt sources to be cleared.
\r
403 //! The specified SSI interrupt sources are cleared, so that
\r
404 //! they no longer assert. This must be done in the interrupt handler to
\r
405 //! keep it from being called again immediately upon exit.
\r
406 //! The parameter \e ulIntFlags can consist of either or both the SSI_RXTO
\r
407 //! and SSI_RXOR values.
\r
411 //*****************************************************************************
\r
412 #if defined(GROUP_intclear) || defined(BUILD_ALL) || defined(DOXYGEN)
\r
414 SSIIntClear(unsigned long ulBase, unsigned long ulIntFlags)
\r
417 // Check the arguments.
\r
419 ASSERT(ulBase == SSI_BASE);
\r
422 // Clear the requested interrupt sources.
\r
424 HWREG(ulBase + SSI_O_ICR) = ulIntFlags;
\r
428 //*****************************************************************************
\r
430 //! Puts a data element into the SSI transmit FIFO.
\r
432 //! \param ulBase specifies the SSI module base address.
\r
433 //! \param ulData data to be transmitted over the SSI interface.
\r
435 //! This function will place the supplied data into the transmit FIFO of
\r
436 //! the specified SSI module.
\r
438 //! \note The upper 32 - N bits of the \e ulData will be discarded by the
\r
439 //! hardware, where N is the data width as configured by SSIConfig(). For
\r
440 //! example, if the interface is configured for 8 bit data width, the upper 24
\r
441 //! bits of \e ulData will be discarded.
\r
445 //*****************************************************************************
\r
446 #if defined(GROUP_dataput) || defined(BUILD_ALL) || defined(DOXYGEN)
\r
448 SSIDataPut(unsigned long ulBase, unsigned long ulData)
\r
451 // Check the arguments.
\r
453 ASSERT(ulBase == SSI_BASE);
\r
454 ASSERT((ulData & (0xfffffffe << (HWREG(ulBase + SSI_O_CR0) &
\r
455 SSI_CR0_DSS))) == 0);
\r
458 // Wait until there is space.
\r
460 while(!(HWREG(ulBase + SSI_O_SR) & SSI_SR_TNF))
\r
465 // Write the data to the SSI.
\r
467 HWREG(ulBase + SSI_O_DR) = ulData;
\r
471 //*****************************************************************************
\r
473 //! Puts a data element into the SSI transmit FIFO.
\r
475 //! \param ulBase specifies the SSI module base address.
\r
476 //! \param ulData data to be transmitted over the SSI interface.
\r
478 //! This function will place the supplied data into the transmit FIFO of
\r
479 //! the specified SSI module. If there is no space in the FIFO, then this
\r
480 //! function will return a zero.
\r
482 //! \note The upper 32 - N bits of the \e ulData will be discarded by the
\r
483 //! hardware, where N is the data width as configured by SSIConfig(). For
\r
484 //! example, if the interface is configured for 8 bit data width, the upper 24
\r
485 //! bits of \e ulData will be discarded.
\r
487 //! \return Returns the number of elements written to the SSI transmit FIFO.
\r
489 //*****************************************************************************
\r
490 #if defined(GROUP_datanonblockingput) || defined(BUILD_ALL) || defined(DOXYGEN)
\r
492 SSIDataNonBlockingPut(unsigned long ulBase, unsigned long ulData)
\r
495 // Check the arguments.
\r
497 ASSERT(ulBase == SSI_BASE);
\r
498 ASSERT((ulData & (0xfffffffe << (HWREG(ulBase + SSI_O_CR0) &
\r
499 SSI_CR0_DSS))) == 0);
\r
502 // Check for space to write.
\r
504 if(HWREG(ulBase + SSI_O_SR) & SSI_SR_TNF)
\r
506 HWREG(ulBase + SSI_O_DR) = ulData;
\r
516 //*****************************************************************************
\r
518 //! Gets a data element from the SSI receive FIFO.
\r
520 //! \param ulBase specifies the SSI module base address.
\r
521 //! \param pulData pointer to a storage location for data that was received
\r
522 //! over the SSI interface.
\r
524 //! This function will get received data from the receive FIFO of the specified
\r
525 //! SSI module, and place that data into the location specified by the
\r
526 //! \e pulData parameter.
\r
528 //! \note Only the lower N bits of the value written to \e pulData will contain
\r
529 //! valid data, where N is the data width as configured by SSIConfig(). For
\r
530 //! example, if the interface is configured for 8 bit data width, only the
\r
531 //! lower 8 bits of the value written to \e pulData will contain valid data.
\r
535 //*****************************************************************************
\r
536 #if defined(GROUP_dataget) || defined(BUILD_ALL) || defined(DOXYGEN)
\r
538 SSIDataGet(unsigned long ulBase, unsigned long *pulData)
\r
541 // Check the arguments.
\r
543 ASSERT(ulBase == SSI_BASE);
\r
546 // Wait until there is data to be read.
\r
548 while(!(HWREG(ulBase + SSI_O_SR) & SSI_SR_RNE))
\r
553 // Read data from SSI.
\r
555 *pulData = HWREG(ulBase + SSI_O_DR);
\r
559 //*****************************************************************************
\r
561 //! Gets a data element from the SSI receive FIFO.
\r
563 //! \param ulBase specifies the SSI module base address.
\r
564 //! \param pulData pointer to a storage location for data that was received
\r
565 //! over the SSI interface.
\r
567 //! This function will get received data from the receive FIFO of
\r
568 //! the specified SSI module, and place that data into the location specified
\r
569 //! by the \e ulData parameter. If there is no data in the FIFO, then this
\r
570 //! function will return a zero.
\r
572 //! \note Only the lower N bits of the value written to \e pulData will contain
\r
573 //! valid data, where N is the data width as configured by SSIConfig(). For
\r
574 //! example, if the interface is configured for 8 bit data width, only the
\r
575 //! lower 8 bits of the value written to \e pulData will contain valid data.
\r
577 //! \return Returns the number of elements read from the SSI receive FIFO.
\r
579 //*****************************************************************************
\r
580 #if defined(GROUP_datanonblockingget) || defined(BUILD_ALL) || defined(DOXYGEN)
\r
582 SSIDataNonBlockingGet(unsigned long ulBase, unsigned long *pulData)
\r
585 // Check the arguments.
\r
587 ASSERT(ulBase == SSI_BASE);
\r
590 // Check for data to read.
\r
592 if(HWREG(ulBase + SSI_O_SR) & SSI_SR_RNE)
\r
594 *pulData = HWREG(ulBase + SSI_O_DR);
\r
604 //*****************************************************************************
\r
606 // Close the Doxygen group.
\r
609 //*****************************************************************************
\r