cc2430_rf.c

Go to the documentation of this file.
00001 /**
00002  * \file
00003  *         CC2430 RF driver
00004  * \author
00005  *         Zach Shelby <zach@sensinode.com>
00006  *
00007  *  bankable code for cc2430 rf driver.  this code can be placed in any bank.
00008  *
00009  */
00010 
00011 #include <stdio.h>
00012 
00013 #include "contiki.h"
00014 #include "dev/radio.h"
00015 #include "dev/cc2430_rf.h"
00016 #include "cc2430_sfr.h"
00017 #include "sys/clock.h"
00018 
00019 #include "net/packetbuf.h"
00020 #include "net/rime/rimestats.h"
00021 
00022 extern void (* receiver_callback)(const struct radio_driver *);
00023 #ifndef RF_DEFAULT_POWER
00024 #define RF_DEFAULT_POWER 100
00025 #endif
00026 
00027 #ifndef RF_DEFAULT_CHANNEL
00028 #define RF_DEFAULT_CHANNEL 18
00029 #endif
00030 
00031 #ifndef CC2430_CONF_CHECKSUM
00032 #define CC2430_CONF_CHECKSUM 0
00033 #endif /* CC2420_CONF_CHECKSUM */
00034 
00035 #if CC2430_CONF_CHECKSUM
00036 #include "lib/crc16.h"
00037 #define CHECKSUM_LEN 2
00038 #else
00039 #define CHECKSUM_LEN 2
00040 #endif /* CC2430_CONF_CHECKSUM */
00041 #if DEBUG_LEDS
00042 /* moved leds code to BANK1 to make space for cc2430_rf_process in HOME */
00043 /* can't call code in BANK1 from alternate banks unless it is marked with __banked */
00044 #include "dev/leds.h"
00045 #define RF_RX_LED_ON()          leds_on(LEDS_RED);
00046 #define RF_RX_LED_OFF()         leds_off(LEDS_RED);
00047 #define RF_TX_LED_ON()          leds_on(LEDS_GREEN);
00048 #define RF_TX_LED_OFF()         leds_off(LEDS_GREEN);
00049 #else
00050 #define RF_RX_LED_ON()          
00051 #define RF_RX_LED_OFF()         
00052 #define RF_TX_LED_ON()          
00053 #define RF_TX_LED_OFF()         
00054 #endif
00055 #define DEBUG 0
00056 #if DEBUG
00057 #define PRINTF(...) printf(__VA_ARGS__)
00058 #else
00059 #define PRINTF(...) do {} while (0)
00060 #endif
00061 
00062 #define RX_ACTIVE 0x80
00063 #define TX_ACK 0x40
00064 #define TX_ON_AIR 0x20
00065 #define RX_NO_DMA
00066 
00067 #ifdef HAVE_RF_ERROR
00068 uint8_t rf_error = 0;
00069 #endif
00070 
00071 uint8_t rf_initialized = 0;
00072 uint8_t rf_tx_power;
00073 uint8_t rf_flags;
00074 uint8_t rf_channel = 0;
00075 rf_address_mode_t rf_addr_mode;
00076 uint16_t rf_manfid;
00077 uint8_t rf_softack;
00078 uint16_t rf_panid;
00079 
00080 /*---------------------------------------------------------------------------*/
00081 PROCESS_NAME(cc2430_rf_process);
00082 /*---------------------------------------------------------------------------*/
00083 
00084 const struct radio_driver cc2430_rf_driver =
00085   {
00086     cc2430_rf_send,
00087     cc2430_rf_read,
00088     cc2430_rf_set_receiver,
00089     cc2430_rf_on,
00090     cc2430_rf_off,
00091   };
00092 
00093 /*---------------------------------------------------------------------------*/
00094 void
00095 cc2430_rf_init(void) __banked
00096 {
00097   if(rf_initialized) {
00098     return;
00099   }
00100 
00101   PRINTF("cc2430_rf_init called\n");
00102 
00103   RFPWR &= ~RREG_RADIO_PD;      /*make sure it's powered*/
00104   while((RFPWR & ADI_RADIO_PD) == 1);
00105   while((RFIF & IRQ_RREG_ON) == 0);     /*wait for power up*/
00106   SLEEP &= ~OSC_PD; /*Osc on*/
00107   while((SLEEP & XOSC_STB) == 0);       /*wait for power up*/
00108 
00109   rf_flags = 0;
00110   rf_softack = 0;
00111 
00112   FSMTC1 = 1;   /*don't abort reception, if enable called, accept ack, auto rx after tx*/
00113 
00114   MDMCTRL0H = 0x02;      /* Generic client, standard hysteresis, decoder on 0x0a */
00115   MDMCTRL0L = 0xE2;      /* automatic ACK and CRC, standard CCA and preamble 0xf2 */
00116 
00117   MDMCTRL1H = 0x30;                     /* Defaults */
00118   MDMCTRL1L = 0x0;
00119 
00120   RXCTRL0H = 0x32;                      /* RX tuning optimized */
00121   RXCTRL0L = 0xf5;
00122 
00123   /* get ID for MAC */
00124   rf_manfid = CHVER;
00125   rf_manfid <<= 8;
00126   rf_manfid += CHIPID;
00127   cc2430_rf_channel_set(RF_DEFAULT_CHANNEL);
00128   cc2430_rf_command(ISFLUSHTX);
00129   cc2430_rf_command(ISFLUSHRX);
00130 
00131   cc2430_rf_set_addr(0xffff, 0x0000, NULL);
00132   cc2430_rf_address_decoder_mode(RF_DECODER_NONE);
00133 
00134   RFIM = IRQ_FIFOP;
00135   RFIF &= ~(IRQ_FIFOP);
00136 
00137   S1CON &= ~(RFIF_0 | RFIF_1);
00138   IEN2 |= RFIE;
00139 
00140   RF_TX_LED_OFF();
00141   RF_RX_LED_OFF();
00142   rf_initialized = 1;
00143   process_start(&cc2430_rf_process, NULL);
00144 }
00145 /*---------------------------------------------------------------------------*/
00146 int
00147 cc2430_rf_send_b(void *payload, unsigned short payload_len) __banked
00148 {
00149   uint8_t i, counter;
00150   
00151   if(rf_flags & TX_ACK) {
00152     return -1;
00153   }
00154   if((rf_flags & RX_ACTIVE) == 0) {
00155     cc2430_rf_rx_enable();
00156   }
00157   /* Check packet attributes */
00158   /*printf("packetbuf_attr: txpower = %d\n", packetbuf_attr(PACKETBUF_ATTR_RADIO_TXPOWER));*/
00159   /* Should set TX power according to this if > 0 */
00160 
00161   PRINTF("cc2430_rf: sending %ud byte payload\n", payload_len);
00162 
00163   RIMESTATS_ADD(lltx);
00164 
00165   cc2430_rf_command(ISFLUSHTX);
00166   PRINTF("cc2430_rf: sent = ");
00167   /* Send the phy length byte first */
00168   RFD = payload_len+CHECKSUM_LEN;       /* Payload plus FCS */
00169   PRINTF("(%d)", payload_len+CHECKSUM_LEN);
00170   for(i = 0 ; i < payload_len; i++) {
00171     RFD = ((unsigned char*)(payload))[i];
00172     PRINTF("%02X", ((unsigned char*)(payload))[i]);
00173   }
00174   PRINTF("\n");
00175 
00176   /* Leave space for the FCS */
00177   RFD = 0;
00178   RFD = 0;
00179 
00180   if(cc2430_rf_cca_check(0,0) == -1) {
00181     return -1;
00182   }
00183 
00184   /* Start the transmission */
00185 
00186   RFIF &= ~IRQ_TXDONE;
00187   cc2430_rf_command(ISTXON);
00188   counter = 0;
00189   while(!(RFSTATUS & TX_ACTIVE) && (counter++ < 3)) {
00190     clock_delay(10);
00191   }
00192 
00193   if(!(RFSTATUS & TX_ACTIVE)) {
00194     PRINTF("cc2430_rf: TX never active.\n");
00195     cc2430_rf_command(ISFLUSHTX);
00196     return -1;
00197   } else {
00198     RF_RX_LED_OFF();
00199     RF_TX_LED_ON();
00200     // rf_flags |= TX_ON_AIR;
00201   }
00202   return 1;
00203 }
00204 /*---------------------------------------------------------------------------*/
00205 int
00206 cc2430_rf_read_banked(void *buf, unsigned short bufsize) __banked
00207 {
00208   uint8_t i, len;
00209 #if CC2420_CONF_CHECKSUM
00210   uint16_t checksum;
00211 #endif /* CC2420_CONF_CHECKSUM */
00212 
00213   /* RX interrupt polled the cc2430_rf_process, now read the RX FIFO */
00214 
00215   /* Check the length */
00216   len = RFD;
00217 
00218   /* Check for validity */
00219   if(len > CC2430_MAX_PACKET_LEN) {
00220     /* Oops, we must be out of sync. */
00221         PRINTF("error: bad sync\n");
00222     cc2430_rf_command(ISFLUSHRX);
00223     RIMESTATS_ADD(badsynch);
00224     return 0;
00225   }
00226 
00227   if(len <= CC2430_MIN_PACKET_LEN) {
00228         PRINTF("error: too short\n");
00229     cc2430_rf_command(ISFLUSHRX);
00230     RIMESTATS_ADD(tooshort);
00231     return 0;
00232   }
00233 
00234   if(len - CHECKSUM_LEN > bufsize) {
00235         PRINTF("error: too long\n");
00236     cc2430_rf_command(ISFLUSHRX);
00237     RIMESTATS_ADD(toolong);
00238     return 0;
00239   }
00240 
00241   /* Read the buffer */
00242   PRINTF("cc2430_rf: read = ");
00243   PRINTF("(%d)", len);
00244   for(i = 0; i < (len - CHECKSUM_LEN); i++) {
00245       ((unsigned char*)(buf))[i] = RFD;
00246       PRINTF("%02X", ((unsigned char*)(buf))[i]);
00247   }
00248   PRINTF("\n");
00249 
00250 #if CC2430_CONF_CHECKSUM
00251     /* Deal with the checksum */
00252     checksum = RFD * 256;
00253     checksum += RFD;
00254 #endif /* CC2430_CONF_CHECKSUM */
00255   packetbuf_set_attr(PACKETBUF_ATTR_RSSI, ((int8_t) RFD) - 45);
00256   packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, RFD);
00257 
00258   RFIF &= ~IRQ_FIFOP;
00259   RFSTATUS &= ~FIFO;
00260   cc2430_rf_command(ISFLUSHRX);
00261   cc2430_rf_command(ISFLUSHRX);
00262   RF_RX_LED_OFF();
00263 
00264   RIMESTATS_ADD(llrx);
00265 
00266   return (len - CHECKSUM_LEN);
00267 }
00268 /**
00269  * Execute a single CSP command.
00270  *
00271  * \param command command to execute
00272  *
00273  */
00274 void cc2430_rf_command(uint8_t command) __banked
00275 {
00276   if(command >= 0xE0) { /*immediate strobe*/
00277     uint8_t fifo_count;
00278     switch(command) {   /*hardware bug workaround*/
00279     case ISRFOFF:
00280     case ISRXON:
00281     case ISTXON:
00282       fifo_count = RXFIFOCNT;
00283       RFST = command;
00284       clock_delay(2);
00285       if(fifo_count != RXFIFOCNT) {
00286         RFST = ISFLUSHRX;
00287         RFST = ISFLUSHRX;
00288       }
00289       break;
00290 
00291     default:
00292       RFST = command;
00293     }
00294   } else if(command == SSTART) {
00295     RFIF &= ~IRQ_CSP_STOP;      /*clear IRQ flag*/
00296     RFST = SSTOP;       /*make sure there is a stop in the end*/
00297     RFST = ISSTART;     /*start execution*/
00298     while((RFIF & IRQ_CSP_STOP) == 0);
00299   } else {
00300     RFST = command;     /*write command*/
00301   }
00302 }
00303 /*---------------------------------------------------------------------------*/
00304 /*---------------------------------------------------------------------------*/
00305 
00306 /**
00307  * Select RF channel.
00308  *
00309  * \param channel channel number to select
00310  *
00311  * \return channel value or negative (invalid channel number)
00312  */
00313 
00314  /* channel freqdiv = (2048 + FSCTRL(9:0)) / 4
00315             freq = (2048 + FSCTRL(9:0)) MHz */
00316 
00317 int8_t
00318 cc2430_rf_channel_set(uint8_t channel)
00319 {
00320   uint16_t freq;
00321 
00322   if((channel < 11) || (channel > 26)) {
00323     return -1;
00324   }
00325 
00326   cc2430_rf_command(ISSTOP);    /*make sure CSP is not running*/
00327   cc2430_rf_command(ISRFOFF);
00328   /* Channel values: 11-26 */
00329   freq = (uint16_t) channel - 11;
00330   freq *= 5;    /*channel spacing*/
00331   freq += 357; /*correct channel range*/
00332   freq |= 0x4000; /*LOCK_THR = 1*/
00333   FSCTRLH = (freq >> 8);
00334   FSCTRLL = (uint8_t)freq;
00335 
00336   cc2430_rf_command(ISRXON);
00337 
00338   rf_channel = channel;
00339 
00340   return (int8_t) channel;
00341 }
00342 /*---------------------------------------------------------------------------*/
00343 /*PA_LEVEL TXCTRL register Output Power [dBm] Current Consumption [mA]
00344         31 0xA0FF 0 17.4
00345         27 0xA0FB -1 16.5
00346         23 0xA0F7 -3 15.2
00347         19 0xA0F3 -5 13.9
00348         15 0xA0EF -7 12.5
00349         11 0xA0EB -10 11.2
00350          7 0xA0E7 -15 9.9
00351          3 0xA0E3 -25 8.5*/
00352 
00353 /**
00354  * Select RF transmit power.
00355  *
00356  * \param new_power new power level (in per cent)
00357  *
00358  * \return new level or negative (value out of range)
00359  */
00360 
00361 int8_t
00362 cc2430_rf_power_set(uint8_t new_power)
00363 {
00364   uint16_t power;
00365 
00366   if(new_power > 100) {
00367     return -1;
00368   }
00369 
00370   power = 31 * new_power;
00371   power /= 100;
00372   power += 0xA160;
00373 
00374   /* Set transmitter power */
00375   TXCTRLH = (power >> 8);
00376   TXCTRLL = (uint8_t)power;
00377 
00378   rf_tx_power = (int8_t) new_power;
00379   return rf_tx_power;
00380 }
00381 /*---------------------------------------------------------------------------*/
00382 /**
00383  * Enable RF receiver.
00384  *
00385  *
00386  * \return pdTRUE
00387  * \return pdFALSE      bus not free
00388  */
00389 int8_t
00390 cc2430_rf_rx_enable(void) __banked
00391 {
00392   PRINTF("cc2430_rf_rx_enable called\n");
00393   if(!(rf_flags & RX_ACTIVE)) {
00394     IOCFG0 = 0x7f;   // Set the FIFOP threshold 127
00395     RSSIH = 0xd2; /* -84dbm = 0xd2 default, 0xe0 -70 dbm */
00396     rf_flags |= RX_ACTIVE;
00397 
00398     RFPWR &= ~RREG_RADIO_PD;    /*make sure it's powered*/
00399     while((RFIF & IRQ_RREG_ON) == 0);   /*wait for power up*/
00400     SLEEP &= ~OSC_PD; /*Osc on*/
00401     while((SLEEP & XOSC_STB) == 0);     /*wait for power up*/
00402 
00403     cc2430_rf_command(ISRXON);
00404     cc2430_rf_command(ISFLUSHRX);
00405   }
00406   PRINTF("cc2430_rf_rx_enable done\n");
00407   return 1;
00408 }
00409 /*---------------------------------------------------------------------------*/
00410 /**
00411  * Disable RF receiver.
00412  *
00413  *
00414  * \return pdTRUE
00415  * \return pdFALSE      bus not free
00416  */
00417 int8_t cc2430_rf_rx_disable(void) __banked
00418 {
00419   cc2430_rf_command(ISSTOP);    /*make sure CSP is not running*/
00420   cc2430_rf_command(ISRFOFF);
00421 
00422   RFPWR |= RREG_RADIO_PD;               /*RF powerdown*/
00423 
00424   rf_flags = 0;
00425   return 1;
00426 }
00427 /*---------------------------------------------------------------------------*/
00428 /**
00429  * Enable RF transmitter.
00430  *
00431  *
00432  * \return pdTRUE
00433  * \return pdFALSE      bus not free
00434  */
00435 int8_t
00436 cc2430_rf_tx_enable(void)
00437 {
00438   DMAARM = 0x80 + (1 << 0);     /*ABORT + channel bit*/
00439 
00440   return 1;
00441 }
00442 
00443 /**
00444         * Set MAC addresses
00445         *
00446         *       \param pan The PAN address to set
00447         *       \param adde The short address to set
00448         *       \param ieee_addr The 64-bit IEEE address to set
00449         */
00450 void
00451 cc2430_rf_set_addr(unsigned pan, unsigned addr, const uint8_t *ieee_addr)
00452 {
00453         uint8_t f;
00454         __xdata unsigned char *ptr;
00455 
00456         rf_panid = pan;
00457         PANIDH = pan >> 8;
00458         PANIDL = pan & 0xff;
00459 
00460         SHORTADDRH = addr >> 8;
00461         SHORTADDRL = addr & 0xff;
00462 
00463         if(ieee_addr != NULL) {
00464                 ptr = &IEEE_ADDR0;
00465             /* LSB first, MSB last for 802.15.4 addresses in CC2420 */
00466                 for (f = 0; f < 8; f++) {
00467                         *ptr++ = ieee_addr[f];
00468                 }
00469         }
00470 }
00471 
00472 /*---------------------------------------------------------------------------*/
00473 /**
00474  * Set address decoder on/off.
00475  *
00476  * \param param 1=on 0=off.
00477  * \return pdTRUE operation successful
00478  */
00479 int8_t
00480 cc2430_rf_address_decoder_mode(rf_address_mode_t mode)
00481 {
00482   int8_t retval = -1;
00483 
00484   rf_softack = 0;
00485   /* set oscillator on*/
00486   switch(mode) {
00487   case RF_SOFTACK_MONITOR:
00488     rf_softack = 1;
00489   case RF_MONITOR:
00490     MDMCTRL0H |= 0x10;   /*Address-decode off , coordinator*/
00491     MDMCTRL0L &= ~0x10;  /*no automatic ACK */
00492     break;
00493 
00494   case RF_DECODER_COORDINATOR:
00495     MDMCTRL0H |= 0x18;   /*Address-decode on , coordinator*/
00496     MDMCTRL0L |= 0x10;   /*automatic ACK */
00497     break;
00498 
00499   case RF_DECODER_ON:
00500     MDMCTRL0H |= 0x08;   /*Address-decode on */
00501     MDMCTRL0L &= ~0x10;  /* no automatic ACK */
00502     break;
00503 
00504   default:
00505     MDMCTRL0H &= ~0x18;  /* Generic client */
00506     MDMCTRL0L &= ~0x10;  /* no automatic ACK */
00507     break;
00508   }
00509   rf_addr_mode = mode;
00510 
00511   retval = 1;
00512   return retval;
00513 }
00514 /*---------------------------------------------------------------------------*/
00515 /**
00516  * Channel energy detect.
00517  *
00518  * Coordinator use this function detect best channel for PAN-network.
00519  * \return RSSI-energy level dBm.
00520  * \return 0    operation failed.
00521  */
00522 
00523 int8_t
00524 cc2430_rf_analyze_rssi(void)
00525 {
00526   int8_t retval = -128;
00527   /*pause_us(128);*/
00528 
00529   retval = (int8_t)RSSIL;
00530   retval -= 45;
00531   return retval;
00532 }
00533 /*---------------------------------------------------------------------------*/
00534 /**
00535  * Clear channel assesment check.
00536  *
00537  * \return pdTRUE       CCA clear
00538  * \return pdFALSE      CCA reserved
00539  */
00540 int8_t
00541 cc2430_rf_cca_check(uint8_t backoff_count, uint8_t slotted)
00542 {
00543   uint8_t counter, cca = 1;
00544   int8_t retval = 1;
00545   backoff_count;
00546   cc2430_rf_command(ISRXON);
00547 
00548   clock_delay(64);
00549   switch(slotted) {
00550   case 1:
00551 
00552     if(RFSTATUS & CCA) {
00553       counter = 0;
00554       cca = 1;
00555       while(cca != 0) {
00556         if(counter > 1) {
00557           cca = 0;
00558         }
00559         clock_delay(256);
00560         if(!(RFSTATUS & CCA)) {
00561           cca = 0;
00562           retval = -1;
00563         }
00564         counter++;
00565       }
00566     } else {
00567       retval = -1;
00568     }
00569     break;
00570 
00571   case 0:
00572     if(!(RFSTATUS & CCA)) {
00573       retval = -1;
00574     } else {
00575 
00576     }
00577     break;
00578   }
00579   return retval;
00580 }
00581 /*---------------------------------------------------------------------------*/
00582 /**
00583  * Send ACK.
00584  *
00585  *\param pending set up pending flag if pending > 0.
00586  */
00587 void
00588 cc2430_rf_send_ack(uint8_t pending) __banked
00589 {
00590   if(pending) {
00591     cc2430_rf_command(ISACKPEND);
00592   } else {
00593     cc2430_rf_command(ISACK);
00594   }
00595 }
00596 /*---------------------------------------------------------------------------*/

Generated on Mon Apr 11 14:23:38 2011 for Contiki 2.5 by  doxygen 1.6.1