Wixel SDK
src/spi_master/core/spi_master.c
Go to the documentation of this file.
00001 
00006 #include <cc2511_map.h>
00007 #include <cc2511_types.h>
00008 
00009 #if defined(__CDT_PARSER__)
00010 #define SPI0
00011 #endif
00012 
00013 #if defined(SPI0)
00014 #include <spi0_master.h>
00015 #define INTERRUPT_PRIORITY_GROUP    2
00016 #define ISR_URX()                   ISR(URX0, 0)
00017 #define URXNIF                      URX0IF
00018 #define URXNIE                      URX0IE
00019 #define UNGCR                       U0GCR
00020 #define UNBAUD                      U0BAUD
00021 #define UNDBUF                      U0DBUF
00022 #define spiNMasterInit              spi0MasterInit
00023 #define spiNMasterSetFrequency      spi0MasterSetFrequency
00024 #define spiNMasterSetClockPolarity  spi0MasterSetClockPolarity
00025 #define spiNMasterSetClockPhase     spi0MasterSetClockPhase
00026 #define spiNMasterSetBitOrder       spi0MasterSetBitOrder
00027 #define spiNMasterBusy              spi0MasterBusy
00028 #define spiNMasterBytesLeft         spi0MasterBytesLeft
00029 #define spiNMasterTransfer          spi0MasterTransfer
00030 #define spiNMasterSendByte          spi0MasterSendByte
00031 #define spiNMasterReceiveByte       spi0MasterReceiveByte
00032 
00033 #elif defined(SPI1)
00034 #include <spi1_master.h>
00035 #define INTERRUPT_PRIORITY_GROUP    3
00036 #define ISR_URX()                   ISR(URX1, 0)
00037 #define URXNIF                      URX1IF
00038 #define URXNIE                      URX1IE
00039 #define UNGCR                       U1GCR
00040 #define UNBAUD                      U1BAUD
00041 #define UNDBUF                      U1DBUF
00042 #define spiNMasterInit              spi1MasterInit
00043 #define spiNMasterSetFrequency      spi1MasterSetFrequency
00044 #define spiNMasterSetClockPolarity  spi1MasterSetClockPolarity
00045 #define spiNMasterSetClockPhase     spi1MasterSetClockPhase
00046 #define spiNMasterSetBitOrder       spi1MasterSetBitOrder
00047 #define spiNMasterBusy              spi1MasterBusy
00048 #define spiNMasterBytesLeft         spi1MasterBytesLeft
00049 #define spiNMasterTransfer          spi1MasterTransfer
00050 #define spiNMasterSendByte          spi1MasterSendByte
00051 #define spiNMasterReceiveByte       spi1MasterReceiveByte
00052 #endif
00053 
00054 // txPointer points to the last byte that was written to SPI.
00055 static volatile const uint8 XDATA * DATA txPointer = 0;
00056 
00057 // rxPointer points to the location to store the next byte received from SPI.
00058 static volatile uint8 XDATA * DATA rxPointer = 0;
00059 
00060 // bytesLeft is the number of bytes we still need to send to/receive from SPI.
00061 static volatile uint16 DATA bytesLeft = 0;
00062 
00063 void spiNMasterInit(void)
00064 {
00065     /* From datasheet Table 50 */
00066 
00067     /* USART0 SPI Alt. 1:
00068      *                     SCK  = P0_5
00069      *                     MOSI = P0_3
00070      *                     MISO = P0_2
00071      */
00072 
00073     /* USART1 SPI Alt. 2:
00074      *                    SCK  = P1_5
00075      *                   MOSI  = P1_6
00076      *                   MISO  = P1_7
00077      */
00078 
00079     /* 12.14.2.1: In SPI master mode, only the MOSI, MISO, and SCK should be
00080      * configured as peripherals (see Section 12.4.6.1 and Section 12.4.6.2). If
00081      * the external slave requires a slave select signal (SSN) this can be
00082      * implemented by using a general-purpose I/O pin and control from SW.
00083      */
00084 
00085     // Note: We do NOT set the mode of the RX pin to "peripheral function"
00086     // because that seems to have no benefits, and is actually bad because
00087     // it disables the internal pull-up resistor.
00088 
00089 #ifdef SPI0
00090     P2DIR &= ~0xC0;  // P2DIR.PRIP0 (7:6) = 00 : USART0 takes priority over USART1.
00091     PERCFG &= ~0x01; // PERCFG.U0CFG (0) = 0 (Alt. 1) : USART0 uses alt. location 1.
00092 #else
00093     P2SEL |= 0x40;   // USART1 takes priority over USART0 on Port 1.
00094     PERCFG |= 0x02;  // PERCFG.U1CFG (1) = 1 (Alt. 2) : USART1 uses alt. location 2.
00095 #endif
00096 
00097     // Assumption: The MODE and SLAVE bits in U0CSR/U1CSR are 0 (the default) so
00098     // the USART is already in SPI Master mode.
00099 
00100     // Set the mode of the SCK and MOSI pins to "peripheral function".
00101 #ifdef SPI0
00102     P0SEL |= ((1<<5) | (1<<3)); // P0SEL.SELP0_5 = 1, P0SEL.SELP0_3 = 1
00103 #else
00104     P1SEL |= ((1<<5) | (1<<6)); // P1SEL.SELP1_5 = 1, P1SEL.SELP1_6 = 1
00105 #endif
00106 
00107     // Below, we set the priority of the RX and TX interrupts to be 1 (second lowest priority).
00108     // They need to be higher than the RF interrupt because that one could take a long time.
00109     // The SPI0 interrupts are grouped with the T2 interrupt, so its priority also gets set.
00110     // The SPI1 interrupts are grouped with the T3 interrupts, so its priority also gets set.
00111     IP0 |= (1<<INTERRUPT_PRIORITY_GROUP);
00112     IP1 &= ~(1<<INTERRUPT_PRIORITY_GROUP);
00113 
00114     URXNIF = 0; // Clear RX flag.
00115     EA = 1;     // Enable interrupts in general.
00116 }
00117 
00118 void spiNMasterSetFrequency(uint32 freq)
00119 {
00120     uint32 baudMPlus256;
00121     uint8 baudE = 0;
00122 
00123     // max baud rate is 3000000 (F/8); min is 23 (baudM = 1)
00124     if (freq < 23 || freq > 3000000)
00125         return;
00126 
00127     // 495782 is the largest value that will not overflow the following calculation
00128     while (freq > 495782)
00129     {
00130         baudE++;
00131         freq /= 2;
00132     }
00133 
00134     // calculate baud rate - see datasheet 12.14.3
00135     // this is derived from (baudM + 256) = baud * 2^28 / 24000000
00136     baudMPlus256 = (freq * 11) + (freq * 8663 / 46875);
00137 
00138     // get baudMPlus256 into the range 256-511 (so BAUD_M is in the range 0-255)
00139     while (baudMPlus256 > 0x1ff)
00140     {
00141         baudE++;
00142         baudMPlus256 /= 2;
00143     }
00144     UNGCR &= 0xE0; // preserve CPOL, CPHA, ORDER (7:5)
00145     UNGCR |= baudE; // UNGCR.BAUD_E (4:0)
00146     UNBAUD = baudMPlus256; // UNBAUD.BAUD_M (7:0) - only the lowest 8 bits of baudMPlus256 are used, so this is effectively baudMPlus256 - 256
00147 }
00148 
00149 void spiNMasterSetClockPolarity(BIT polarity)
00150 {
00151     if (polarity == SPI_POLARITY_IDLE_LOW)
00152     {
00153         UNGCR &= ~(1<<7);   // SCK idle low (negative polarity)
00154     }
00155     else
00156     {
00157         UNGCR |= (1<<7);    // SCK idle high (positive polarity)
00158     }
00159 }
00160 
00161 void spiNMasterSetClockPhase(BIT phase)
00162 {
00163     if (phase == SPI_PHASE_EDGE_LEADING)
00164     {
00165         UNGCR &= ~(1<<6);   // data centered on leading (first) edge - rising for idle low, falling for idle high
00166     }
00167     else
00168     {
00169         UNGCR |= (1<<6);    // data centered on trailing (second) edge - falling for idle low, rising for idle high
00170     }
00171 }
00172 
00173 void spiNMasterSetBitOrder(BIT bitOrder)
00174 {
00175     if (bitOrder == SPI_BIT_ORDER_LSB_FIRST)
00176     {
00177         UNGCR &= ~(1<<5);   // LSB first
00178     }
00179     else
00180     {
00181         UNGCR |= (1<<5);    // MSB first
00182     }
00183 }
00184 
00185 BIT spiNMasterBusy(void)
00186 {
00187     return URXNIE;
00188 }
00189 
00190 uint16 spiNMasterBytesLeft(void)
00191 {
00192     uint16 bytes;
00193 
00194     // bytesLeft is 16 bits, so it takes more than one instruction to read. Disable interrupts so it's not updated while we do this
00195     URXNIE = 0;
00196     bytes = bytesLeft;
00197     if (bytes) URXNIE = 1;
00198 
00199     return bytes;
00200 }
00201 
00202 void spiNMasterTransfer(const uint8 XDATA * txBuffer, uint8 XDATA * rxBuffer, uint16 size)
00203 {
00204     if (size)
00205     {
00206         txPointer = txBuffer;
00207         rxPointer = rxBuffer;
00208         bytesLeft = size;
00209 
00210         UNDBUF = *txBuffer; // transmit first byte
00211         URXNIE = 1;         // Enable RX interrupt.
00212     }
00213 }
00214 
00215 uint8 spiNMasterSendByte(uint8 XDATA byte)
00216 {
00217     uint8 XDATA rxByte;
00218 
00219     rxPointer = &rxByte;
00220     bytesLeft = 1;
00221 
00222     UNDBUF = byte;
00223     URXNIE = 1; // Enable RX interrupt.
00224 
00225     while (bytesLeft);
00226     return rxByte;
00227 }
00228 
00229 uint8 spiNMasterReceiveByte(void)
00230 {
00231     return spiNMasterSendByte(0xFF);
00232 }
00233 
00234 ISR_URX()
00235 {
00236     URXNIF = 0;
00237 
00238     *rxPointer = UNDBUF;
00239     rxPointer++;
00240     bytesLeft--;
00241 
00242     if (bytesLeft)
00243     {
00244         txPointer++;
00245         UNDBUF = *txPointer;
00246     }
00247     else
00248     {
00249         URXNIE = 0;
00250     }
00251 }
 All Data Structures Files Functions Variables Typedefs Enumerations Defines