nrf24l01.c

Go to the documentation of this file.
00001 /*
00002  * File:        nrf24l01.c
00003  * Purpose:     nRF24L01 handler functions
00004  * Author:      Peter Ivanov, Olimex Ltd.
00005  * Modified by:
00006  * Created:     2007-10-14 11:29:32
00007  * Last modify: 2007-10-21 11:50:08 ivanovp {Time-stamp}
00008  * Copyright:   (C) Peter Ivanov, 2007
00009  * Licence:     GPL
00010  */
00011 /**
00012  * \file nrf24l01.c
00013  * \brief nRF24L01 handler functions. This is for MOD-NRF24Lx (MOD-NRF24LR or MOD-NRF24LS) extension board. 
00014  * You should connect P3.0 to CSN, P3.1 to MOSI, P3.2 to MISO, P3.3 to CLK and P1.6 to CE using the EXT connector 
00015  * of MSP430-449STK2.
00016  * \author Peter Ivanov, Olimex Ltd.
00017  */
00018 
00019 #include <msp430x44x.h>
00020 #include "nrf24l01.h"
00021 #include "lcd.h"
00022 
00023 #define CSN_TIME      2
00024 #define CE_HIGH_TIME  10000
00025 
00026 /// Receive the packets with following address
00027 unsigned char RX_ADDRESS_P0[5]  = {5,6,7,8,9};
00028 /// Receive the packets with following address
00029 unsigned char RX_ADDRESS_P1[5]  = {0,1,2,3,4};
00030 /// Transmit packets with following address
00031 unsigned char TX_ADDRESS[5]     = {5,6,7,8,9};
00032 unsigned char ADDRESS[5];
00033 
00034 unsigned char status;
00035 
00036 /**
00037  * Software delay.
00038  *
00039  * @param a Number of loop.
00040  */
00041 void Delay (unsigned long a)
00042 { 
00043     while (--a != 0); 
00044 }
00045 
00046 /**
00047  * Internally used function to switch /CS line to high.
00048  */
00049 inline void CSN_HIGH (void)
00050 {
00051     P3OUT |= BIT0; // P3.0 HIGH
00052 }
00053 
00054 /**
00055  * Internally used function to switch /CS line to low.
00056  */
00057 void CSN_LOW (void)
00058 { 
00059     Delay (CSN_TIME);
00060     P3OUT &= ~BIT0; // P3.0 LOW
00061 }
00062 
00063 /**
00064  * Internal function to enable chip nRF24L01 (switch chip enable line to high).
00065  */
00066 void CE_HIGH(void)
00067 { 
00068     P1OUT |= BIT6; // P1.6 HIGH
00069     Delay (CE_HIGH_TIME); 
00070 }
00071 
00072 /**
00073  * Internally used function to disable chip nRF24L01 (switch chip enable line to low).
00074  */
00075 inline void CE_LOW(void)
00076 {
00077     P1OUT &= ~BIT6; // P1.6 LOW
00078 }
00079 
00080 /**
00081  * Internally used function to transmit and receive a byte via SPI channel.
00082  *
00083  * @param data One byte to send.
00084  * @return Received byte.
00085  */
00086 unsigned char SPI_SendByte(unsigned char data)
00087 {
00088     while ((IFG1 & UTXIFG0) == 0);    // wait while not ready / for RX
00089     U0TXBUF = data;                   // write
00090     while ((IFG1 & URXIFG0) == 0);    // wait for RX buffer (full)
00091     return (U0RXBUF);
00092 }
00093 
00094 /**
00095  * Internally used function to send command to the chip NRF24L01 via SPI.
00096  *
00097  * @param cmd Command to send. Example: R_REGISTER
00098  * @param addr Address to send. Example: RX_ADDR_P0
00099  * @param data_byte Data byte to send. This data byte will not be sent in some cases! Check source code!
00100  * @return Status.
00101  */
00102 unsigned char SPI_Send_command_with_ADDR (unsigned char cmd, unsigned char addr, unsigned char data_byte)
00103 {
00104     unsigned char temp,command = 0;
00105     int j, k;
00106     command = (cmd << 5) | addr;
00107     CSN_LOW();
00108     if (cmd == R_REGISTER)
00109     {
00110         if (addr == RX_ADDR_P0 || addr == RX_ADDR_P1 || addr == TX_ADDR)
00111         {
00112 
00113             status = SPI_SendByte(command);
00114             for (k = 0; k < 5; k++)
00115             {
00116                 ADDRESS[k] = SPI_SendByte(NRF_NOP);
00117             }
00118             CSN_HIGH();
00119             return status;
00120         }
00121         else
00122         {
00123             status = SPI_SendByte(command);
00124             temp = SPI_SendByte(NRF_NOP);
00125             CSN_HIGH();
00126             return temp;
00127         }
00128     }
00129     if (cmd == W_REGISTER)
00130     {
00131         if (addr == RX_ADDR_P0)
00132         {
00133             status = SPI_SendByte(command);
00134             for (j = 0; j < 5; j++)
00135             {
00136                 temp = RX_ADDRESS_P0[j];
00137                 SPI_SendByte(temp);
00138             }
00139             CSN_HIGH();
00140             return status;
00141         }
00142 
00143         if (addr == RX_ADDR_P1)
00144         {
00145             status = SPI_SendByte(command);
00146             for (j = 0; j < 5;j++)
00147             {
00148                 temp = RX_ADDRESS_P1[j];
00149                 SPI_SendByte(temp);
00150             }
00151             CSN_HIGH();
00152             return status;
00153         }
00154 
00155         if (addr == TX_ADDR)
00156         {
00157             status = SPI_SendByte(command);
00158             for (j = 0; j < 5;j++)
00159             {
00160                 temp = TX_ADDRESS[j];
00161                 SPI_SendByte(temp);
00162             }
00163             CSN_HIGH();
00164             return status;
00165         }
00166         else
00167         {
00168             temp = SPI_SendByte(command);
00169             SPI_SendByte(data_byte);
00170             CSN_HIGH();
00171             return temp;
00172         }
00173     }
00174 
00175     return 1;
00176 }
00177 
00178 /**
00179  * Internally used function to send command to the chip NRF24L01 via SPI.
00180  *
00181  * @param cmd Command to send. Example: R_REGISTER
00182  * @param data_byte Data byte to send. This data byte will not be sent in some cases! Check source code!
00183  * @return Status.
00184  */
00185 unsigned char SPI_Send_command_without_ADDR (unsigned char cmd, unsigned char data_byte)
00186 {
00187     unsigned char temp = 0;
00188     CSN_LOW();
00189     if (cmd == R_RX_PAYLOAD)
00190     {
00191         status = SPI_SendByte(cmd);
00192         temp = SPI_SendByte(NRF_NOP);
00193         CSN_HIGH();
00194         return temp;
00195     }
00196     if (cmd == W_TX_PAYLOAD)
00197     {
00198         status = SPI_SendByte(cmd);
00199         SPI_SendByte(data_byte);
00200         CSN_HIGH();
00201         return status;
00202     }
00203     status = SPI_SendByte(cmd);
00204     CSN_HIGH();
00205     return status;
00206 
00207 }
00208 
00209 /**
00210  * Initialize SPI interface and chip nRF24L01.
00211  */
00212 void NRF_init (void)
00213 {
00214     ////////////////////////////
00215     // Initialize SPI interface
00216     ////////////////////////////
00217     ME1 |= USPIE0;                          // Enable USART0 SPI mode
00218     UCTL0 |= CHAR + SYNC + MM;              // 8-bit SPI Master **SWRST**
00219     UTCTL0 |= CKPH + SSEL1 + SSEL0 + STC;   // SMCLK, 3-pin mode
00220     UBR00 = 0x02;                           // UCLK/2
00221     UBR10 = 0x00;                           // 0
00222     UMCTL0 = 0x00;                          // no modulation
00223     UCTL0 &= ~SWRST;                        // Initalize USART state machine
00224 
00225     P3SEL |= BIT1 | BIT2 | BIT3;            // P3.1-3 SPI option select
00226     P3DIR |= BIT0 | BIT1 | BIT3;            // P3.0 (#CS), P3.1 (MOSI) and P7.3 (CLK) are outputs
00227     P3DIR &= ~BIT2;                         // P3.2 (MISO) is input
00228     P1DIR |= BIT6;                          // P1.6 (CE) is output
00229     P1DIR &= ~BIT7;                         // P1.7 (IRQ) is input
00230 
00231     // Disable CS
00232     CSN_HIGH();
00233 
00234     ///////////////////////////
00235     // Configure chip nRF24L01
00236     ///////////////////////////
00237 
00238     // Discard transmission
00239     CE_LOW();
00240 
00241     //Write CONFIG register (addres - 0x00)
00242     //00001010 - CRC enable, power-up, RX
00243     status = SPI_Send_command_with_ADDR(W_REGISTER, CONFIG_REG_ADDR, 0x0B);
00244     //Write RX_ADDR_P0 register -> Set receive address data Pipe0 -> address in RX_ADDRESS_P0 array
00245     status = SPI_Send_command_with_ADDR(W_REGISTER, RX_ADDR_P0, NRF_NOP);
00246     //Write RX_ADDR_P1 register -> Set receive address data Pipe1 -> address in RX_ADDRESS_P1 array
00247     status = SPI_Send_command_with_ADDR(W_REGISTER, RX_ADDR_P1, NRF_NOP);
00248     //Write TX_ADDR register -> Transmit address. Used for a PTX device only. Address in TX_ADDRESS array
00249     status = SPI_Send_command_with_ADDR(W_REGISTER, TX_ADDR, NRF_NOP);
00250     //Write RX_PW_P0 register -> Set number of bytes in RX payload in data pipe0 -> 1 byte
00251     status = SPI_Send_command_with_ADDR(W_REGISTER, RX_PW_P0, 1);
00252     //Write RX_PW_P1 register -> Set number of bytes in RX payload in data pipe1 -> 1 byte
00253     status = SPI_Send_command_with_ADDR(W_REGISTER, RX_PW_P1, 1);
00254     NRF_prepareForReceive ();
00255 }
00256 
00257 /**
00258  * Send one byte to the air via chip nRF24L01.
00259  * Addresses are hardcoded:
00260  * @see RX_ADDRESS_P0 RX_ADDRESS_P1 TX_ADDRESS
00261  *
00262  * @param byte The data byte to send.
00263  */
00264 void NRF_send (uint8_t byte)
00265 {
00266     uint8_t status_temp;
00267 
00268     // Chip enable low
00269     CE_LOW();
00270 
00271     // Setting for TX device
00272     // Write CONFIG register -> 00001010 - CRC enable, power-up, TX
00273     status = SPI_Send_command_with_ADDR (W_REGISTER,CONFIG_REG_ADDR, 0x0A);
00274 
00275     // Send payload - send any data
00276     status = SPI_Send_command_without_ADDR (W_TX_PAYLOAD, byte);
00277 
00278     // Pulse for CE -> starts the transmission.
00279     CE_HIGH();
00280     CE_LOW();
00281 
00282     // Read STATUS register
00283     status = SPI_Send_command_without_ADDR(NRF_NOP, NRF_NOP);
00284 
00285     // if exceed number of transmision packets
00286     if ((status & MAX_RT) != 0) 
00287     {
00288 
00289         // Clear MAX_RT bit in status register
00290         status_temp = SPI_Send_command_with_ADDR(W_REGISTER, STATUS_ADDR, (status|MAX_RT));
00291 
00292         // No communication event here
00293         LCD_printf ("MAX RT ");
00294         delayX (500);
00295 
00296         // Flush TX FIFO (in TX mode)
00297         status_temp = SPI_Send_command_without_ADDR(FLUSH_TX, NRF_NOP); // XXX test code
00298     }
00299 
00300     // If packet sent on TX
00301     if ((status & TX_DS) != 0) 
00302     {
00303         // Clear TX_DS bit in status register
00304         status_temp = SPI_Send_command_with_ADDR(W_REGISTER, STATUS_ADDR, (status|TX_DS));
00305 
00306         // Your code here
00307     }
00308 
00309     // If TX full
00310     if ((status & TX_FULL) != 0)
00311     {
00312         // Flush TX FIFO (in TX mode)
00313         status_temp = SPI_Send_command_without_ADDR(FLUSH_TX, NRF_NOP);
00314 
00315         // Your code here
00316         LCD_printf ("TX FULL");
00317         delayX (500);
00318     }
00319 }
00320 
00321 /**
00322  * After sending a byte you may set the device to RX mode.
00323  */
00324 void NRF_prepareForReceive ()
00325 {
00326     // Setting for RX device
00327     //Write CONFIG register -> 00001010 - CRC enable, power-up, RX
00328     status = SPI_Send_command_with_ADDR(W_REGISTER,CONFIG_REG_ADDR, 0x0B);
00329 }
00330 
00331 /**
00332  * Receive one byte from the air via chip nRF24L01. 
00333  * Addresses are hardcoded:
00334  * @see RX_ADDRESS_P0 RX_ADDRESS_P1 TX_ADDRESS
00335  *
00336  * @param byte The data byte to receive.
00337  * @return TRUE: if byte succesfully received.
00338  *         FALSE: if no input data.
00339  */
00340 bool_t NRF_receive (uint8_t *const byte)
00341 {
00342     uint8_t payload;
00343     uint8_t status_temp;
00344 
00345     CE_HIGH ();
00346     if (IRQ ())
00347     {
00348         //Read STATUS status register
00349         status = SPI_Send_command_without_ADDR(NRF_NOP, NRF_NOP);
00350 
00351         // Set high when new data arrives RX FIFO
00352         if ((status & RX_DR) != 0)
00353         {
00354             // Chip enable low
00355             CE_LOW();
00356 
00357             //Read payload data
00358             payload = SPI_Send_command_without_ADDR(R_RX_PAYLOAD, NRF_NOP);
00359 
00360             // Clear RX_DR bit in status register
00361             status_temp = SPI_Send_command_with_ADDR(W_REGISTER, STATUS_ADDR, (status|RX_DR));
00362 
00363             *byte = payload;
00364         
00365             // Flush RX FIFO
00366             status_temp = SPI_Send_command_without_ADDR(FLUSH_RX, NRF_NOP); // XXX test code
00367             return TRUE;
00368         }
00369     }
00370     return FALSE;
00371 }

Generated on Thu Dec 27 14:21:51 2007 for Sample MSP430-449STK2 project by  doxygen 1.5.1