Contiki 2.5
cc2430_rf.c
Go to the documentation of this file.
1 /**
2  * \file
3  * CC2430 RF driver
4  * \author
5  * Zach Shelby <zach@sensinode.com>
6  *
7  * bankable code for cc2430 rf driver. this code can be placed in any bank.
8  *
9  */
10 
11 #include <stdio.h>
12 
13 #include "contiki.h"
14 #include "dev/radio.h"
15 #include "dev/cc2430_rf.h"
16 #include "cc2430_sfr.h"
17 #include "sys/clock.h"
18 
19 #include "net/packetbuf.h"
20 #include "net/rime/rimestats.h"
21 
22 extern void (* receiver_callback)(const struct radio_driver *);
23 #ifndef RF_DEFAULT_POWER
24 #define RF_DEFAULT_POWER 100
25 #endif
26 
27 #ifndef RF_DEFAULT_CHANNEL
28 #define RF_DEFAULT_CHANNEL 18
29 #endif
30 
31 #ifndef CC2430_CONF_CHECKSUM
32 #define CC2430_CONF_CHECKSUM 0
33 #endif /* CC2420_CONF_CHECKSUM */
34 
35 #if CC2430_CONF_CHECKSUM
36 #include "lib/crc16.h"
37 #define CHECKSUM_LEN 2
38 #else
39 #define CHECKSUM_LEN 2
40 #endif /* CC2430_CONF_CHECKSUM */
41 #if DEBUG_LEDS
42 /* moved leds code to BANK1 to make space for cc2430_rf_process in HOME */
43 /* can't call code in BANK1 from alternate banks unless it is marked with __banked */
44 #include "dev/leds.h"
45 #define RF_RX_LED_ON() leds_on(LEDS_RED);
46 #define RF_RX_LED_OFF() leds_off(LEDS_RED);
47 #define RF_TX_LED_ON() leds_on(LEDS_GREEN);
48 #define RF_TX_LED_OFF() leds_off(LEDS_GREEN);
49 #else
50 #define RF_RX_LED_ON()
51 #define RF_RX_LED_OFF()
52 #define RF_TX_LED_ON()
53 #define RF_TX_LED_OFF()
54 #endif
55 #define DEBUG 0
56 #if DEBUG
57 #define PRINTF(...) printf(__VA_ARGS__)
58 #else
59 #define PRINTF(...) do {} while (0)
60 #endif
61 
62 #define RX_ACTIVE 0x80
63 #define TX_ACK 0x40
64 #define TX_ON_AIR 0x20
65 #define RX_NO_DMA
66 
67 #ifdef HAVE_RF_ERROR
68 uint8_t rf_error = 0;
69 #endif
70 
71 uint8_t rf_initialized = 0;
72 uint8_t rf_tx_power;
73 uint8_t rf_flags;
74 uint8_t rf_channel = 0;
75 rf_address_mode_t rf_addr_mode;
76 uint16_t rf_manfid;
77 uint8_t rf_softack;
78 uint16_t rf_panid;
79 
80 /*---------------------------------------------------------------------------*/
81 PROCESS_NAME(cc2430_rf_process);
82 /*---------------------------------------------------------------------------*/
83 
84 const struct radio_driver cc2430_rf_driver =
85  {
86  cc2430_rf_send,
87  cc2430_rf_read,
88  cc2430_rf_set_receiver,
89  cc2430_rf_on,
90  cc2430_rf_off,
91  };
92 
93 /*---------------------------------------------------------------------------*/
94 void
95 cc2430_rf_init(void) __banked
96 {
97  if(rf_initialized) {
98  return;
99  }
100 
101  PRINTF("cc2430_rf_init called\n");
102 
103  RFPWR &= ~RREG_RADIO_PD; /*make sure it's powered*/
104  while((RFPWR & ADI_RADIO_PD) == 1);
105  while((RFIF & IRQ_RREG_ON) == 0); /*wait for power up*/
106  SLEEP &= ~OSC_PD; /*Osc on*/
107  while((SLEEP & XOSC_STB) == 0); /*wait for power up*/
108 
109  rf_flags = 0;
110  rf_softack = 0;
111 
112  FSMTC1 = 1; /*don't abort reception, if enable called, accept ack, auto rx after tx*/
113 
114  MDMCTRL0H = 0x02; /* Generic client, standard hysteresis, decoder on 0x0a */
115  MDMCTRL0L = 0xE2; /* automatic ACK and CRC, standard CCA and preamble 0xf2 */
116 
117  MDMCTRL1H = 0x30; /* Defaults */
118  MDMCTRL1L = 0x0;
119 
120  RXCTRL0H = 0x32; /* RX tuning optimized */
121  RXCTRL0L = 0xf5;
122 
123  /* get ID for MAC */
124  rf_manfid = CHVER;
125  rf_manfid <<= 8;
126  rf_manfid += CHIPID;
127  cc2430_rf_channel_set(RF_DEFAULT_CHANNEL);
128  cc2430_rf_command(ISFLUSHTX);
129  cc2430_rf_command(ISFLUSHRX);
130 
131  cc2430_rf_set_addr(0xffff, 0x0000, NULL);
132  cc2430_rf_address_decoder_mode(RF_DECODER_NONE);
133 
134  RFIM = IRQ_FIFOP;
135  RFIF &= ~(IRQ_FIFOP);
136 
137  S1CON &= ~(RFIF_0 | RFIF_1);
138  IEN2 |= RFIE;
139 
140  RF_TX_LED_OFF();
141  RF_RX_LED_OFF();
142  rf_initialized = 1;
143  process_start(&cc2430_rf_process, NULL);
144 }
145 /*---------------------------------------------------------------------------*/
146 int
147 cc2430_rf_send_b(void *payload, unsigned short payload_len) __banked
148 {
149  uint8_t i, counter;
150 
151  if(rf_flags & TX_ACK) {
152  return -1;
153  }
154  if((rf_flags & RX_ACTIVE) == 0) {
156  }
157  /* Check packet attributes */
158  /*printf("packetbuf_attr: txpower = %d\n", packetbuf_attr(PACKETBUF_ATTR_RADIO_TXPOWER));*/
159  /* Should set TX power according to this if > 0 */
160 
161  PRINTF("cc2430_rf: sending %ud byte payload\n", payload_len);
162 
163  RIMESTATS_ADD(lltx);
164 
165  cc2430_rf_command(ISFLUSHTX);
166  PRINTF("cc2430_rf: sent = ");
167  /* Send the phy length byte first */
168  RFD = payload_len+CHECKSUM_LEN; /* Payload plus FCS */
169  PRINTF("(%d)", payload_len+CHECKSUM_LEN);
170  for(i = 0 ; i < payload_len; i++) {
171  RFD = ((unsigned char*)(payload))[i];
172  PRINTF("%02X", ((unsigned char*)(payload))[i]);
173  }
174  PRINTF("\n");
175 
176  /* Leave space for the FCS */
177  RFD = 0;
178  RFD = 0;
179 
180  if(cc2430_rf_cca_check(0,0) == -1) {
181  return -1;
182  }
183 
184  /* Start the transmission */
185 
186  RFIF &= ~IRQ_TXDONE;
187  cc2430_rf_command(ISTXON);
188  counter = 0;
189  while(!(RFSTATUS & TX_ACTIVE) && (counter++ < 3)) {
190  clock_delay(10);
191  }
192 
193  if(!(RFSTATUS & TX_ACTIVE)) {
194  PRINTF("cc2430_rf: TX never active.\n");
195  cc2430_rf_command(ISFLUSHTX);
196  return -1;
197  } else {
198  RF_RX_LED_OFF();
199  RF_TX_LED_ON();
200  // rf_flags |= TX_ON_AIR;
201  }
202  return 1;
203 }
204 /*---------------------------------------------------------------------------*/
205 int
206 cc2430_rf_read_banked(void *buf, unsigned short bufsize) __banked
207 {
208  uint8_t i, len;
209 #if CC2420_CONF_CHECKSUM
210  uint16_t checksum;
211 #endif /* CC2420_CONF_CHECKSUM */
212 
213  /* RX interrupt polled the cc2430_rf_process, now read the RX FIFO */
214 
215  /* Check the length */
216  len = RFD;
217 
218  /* Check for validity */
219  if(len > CC2430_MAX_PACKET_LEN) {
220  /* Oops, we must be out of sync. */
221  PRINTF("error: bad sync\n");
222  cc2430_rf_command(ISFLUSHRX);
223  RIMESTATS_ADD(badsynch);
224  return 0;
225  }
226 
227  if(len <= CC2430_MIN_PACKET_LEN) {
228  PRINTF("error: too short\n");
229  cc2430_rf_command(ISFLUSHRX);
230  RIMESTATS_ADD(tooshort);
231  return 0;
232  }
233 
234  if(len - CHECKSUM_LEN > bufsize) {
235  PRINTF("error: too long\n");
236  cc2430_rf_command(ISFLUSHRX);
237  RIMESTATS_ADD(toolong);
238  return 0;
239  }
240 
241  /* Read the buffer */
242  PRINTF("cc2430_rf: read = ");
243  PRINTF("(%d)", len);
244  for(i = 0; i < (len - CHECKSUM_LEN); i++) {
245  ((unsigned char*)(buf))[i] = RFD;
246  PRINTF("%02X", ((unsigned char*)(buf))[i]);
247  }
248  PRINTF("\n");
249 
250 #if CC2430_CONF_CHECKSUM
251  /* Deal with the checksum */
252  checksum = RFD * 256;
253  checksum += RFD;
254 #endif /* CC2430_CONF_CHECKSUM */
255  packetbuf_set_attr(PACKETBUF_ATTR_RSSI, ((int8_t) RFD) - 45);
256  packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, RFD);
257 
258  RFIF &= ~IRQ_FIFOP;
259  RFSTATUS &= ~FIFO;
260  cc2430_rf_command(ISFLUSHRX);
261  cc2430_rf_command(ISFLUSHRX);
262  RF_RX_LED_OFF();
263 
264  RIMESTATS_ADD(llrx);
265 
266  return (len - CHECKSUM_LEN);
267 }
268 /**
269  * Execute a single CSP command.
270  *
271  * \param command command to execute
272  *
273  */
274 void cc2430_rf_command(uint8_t command) __banked
275 {
276  if(command >= 0xE0) { /*immediate strobe*/
277  uint8_t fifo_count;
278  switch(command) { /*hardware bug workaround*/
279  case ISRFOFF:
280  case ISRXON:
281  case ISTXON:
282  fifo_count = RXFIFOCNT;
283  RFST = command;
284  clock_delay(2);
285  if(fifo_count != RXFIFOCNT) {
286  RFST = ISFLUSHRX;
287  RFST = ISFLUSHRX;
288  }
289  break;
290 
291  default:
292  RFST = command;
293  }
294  } else if(command == SSTART) {
295  RFIF &= ~IRQ_CSP_STOP; /*clear IRQ flag*/
296  RFST = SSTOP; /*make sure there is a stop in the end*/
297  RFST = ISSTART; /*start execution*/
298  while((RFIF & IRQ_CSP_STOP) == 0);
299  } else {
300  RFST = command; /*write command*/
301  }
302 }
303 /*---------------------------------------------------------------------------*/
304 /*---------------------------------------------------------------------------*/
305 
306 /**
307  * Select RF channel.
308  *
309  * \param channel channel number to select
310  *
311  * \return channel value or negative (invalid channel number)
312  */
313 
314  /* channel freqdiv = (2048 + FSCTRL(9:0)) / 4
315  freq = (2048 + FSCTRL(9:0)) MHz */
316 
317 int8_t
318 cc2430_rf_channel_set(uint8_t channel)
319 {
320  uint16_t freq;
321 
322  if((channel < 11) || (channel > 26)) {
323  return -1;
324  }
325 
326  cc2430_rf_command(ISSTOP); /*make sure CSP is not running*/
327  cc2430_rf_command(ISRFOFF);
328  /* Channel values: 11-26 */
329  freq = (uint16_t) channel - 11;
330  freq *= 5; /*channel spacing*/
331  freq += 357; /*correct channel range*/
332  freq |= 0x4000; /*LOCK_THR = 1*/
333  FSCTRLH = (freq >> 8);
334  FSCTRLL = (uint8_t)freq;
335 
336  cc2430_rf_command(ISRXON);
337 
338  rf_channel = channel;
339 
340  return (int8_t) channel;
341 }
342 /*---------------------------------------------------------------------------*/
343 /*PA_LEVEL TXCTRL register Output Power [dBm] Current Consumption [mA]
344  31 0xA0FF 0 17.4
345  27 0xA0FB -1 16.5
346  23 0xA0F7 -3 15.2
347  19 0xA0F3 -5 13.9
348  15 0xA0EF -7 12.5
349  11 0xA0EB -10 11.2
350  7 0xA0E7 -15 9.9
351  3 0xA0E3 -25 8.5*/
352 
353 /**
354  * Select RF transmit power.
355  *
356  * \param new_power new power level (in per cent)
357  *
358  * \return new level or negative (value out of range)
359  */
360 
361 int8_t
362 cc2430_rf_power_set(uint8_t new_power)
363 {
364  uint16_t power;
365 
366  if(new_power > 100) {
367  return -1;
368  }
369 
370  power = 31 * new_power;
371  power /= 100;
372  power += 0xA160;
373 
374  /* Set transmitter power */
375  TXCTRLH = (power >> 8);
376  TXCTRLL = (uint8_t)power;
377 
378  rf_tx_power = (int8_t) new_power;
379  return rf_tx_power;
380 }
381 /*---------------------------------------------------------------------------*/
382 /**
383  * Enable RF receiver.
384  *
385  *
386  * \return pdTRUE
387  * \return pdFALSE bus not free
388  */
389 int8_t
390 cc2430_rf_rx_enable(void) __banked
391 {
392  PRINTF("cc2430_rf_rx_enable called\n");
393  if(!(rf_flags & RX_ACTIVE)) {
394  IOCFG0 = 0x7f; // Set the FIFOP threshold 127
395  RSSIH = 0xd2; /* -84dbm = 0xd2 default, 0xe0 -70 dbm */
396  rf_flags |= RX_ACTIVE;
397 
398  RFPWR &= ~RREG_RADIO_PD; /*make sure it's powered*/
399  while((RFIF & IRQ_RREG_ON) == 0); /*wait for power up*/
400  SLEEP &= ~OSC_PD; /*Osc on*/
401  while((SLEEP & XOSC_STB) == 0); /*wait for power up*/
402 
403  cc2430_rf_command(ISRXON);
404  cc2430_rf_command(ISFLUSHRX);
405  }
406  PRINTF("cc2430_rf_rx_enable done\n");
407  return 1;
408 }
409 /*---------------------------------------------------------------------------*/
410 /**
411  * Disable RF receiver.
412  *
413  *
414  * \return pdTRUE
415  * \return pdFALSE bus not free
416  */
417 int8_t cc2430_rf_rx_disable(void) __banked
418 {
419  cc2430_rf_command(ISSTOP); /*make sure CSP is not running*/
420  cc2430_rf_command(ISRFOFF);
421 
422  RFPWR |= RREG_RADIO_PD; /*RF powerdown*/
423 
424  rf_flags = 0;
425  return 1;
426 }
427 /*---------------------------------------------------------------------------*/
428 /**
429  * Enable RF transmitter.
430  *
431  *
432  * \return pdTRUE
433  * \return pdFALSE bus not free
434  */
435 int8_t
437 {
438  DMAARM = 0x80 + (1 << 0); /*ABORT + channel bit*/
439 
440  return 1;
441 }
442 
443 /**
444  * Set MAC addresses
445  *
446  * \param pan The PAN address to set
447  * \param adde The short address to set
448  * \param ieee_addr The 64-bit IEEE address to set
449  */
450 void
451 cc2430_rf_set_addr(unsigned pan, unsigned addr, const uint8_t *ieee_addr)
452 {
453  uint8_t f;
454  __xdata unsigned char *ptr;
455 
456  rf_panid = pan;
457  PANIDH = pan >> 8;
458  PANIDL = pan & 0xff;
459 
460  SHORTADDRH = addr >> 8;
461  SHORTADDRL = addr & 0xff;
462 
463  if(ieee_addr != NULL) {
464  ptr = &IEEE_ADDR0;
465  /* LSB first, MSB last for 802.15.4 addresses in CC2420 */
466  for (f = 0; f < 8; f++) {
467  *ptr++ = ieee_addr[f];
468  }
469  }
470 }
471 
472 /*---------------------------------------------------------------------------*/
473 /**
474  * Set address decoder on/off.
475  *
476  * \param param 1=on 0=off.
477  * \return pdTRUE operation successful
478  */
479 int8_t
480 cc2430_rf_address_decoder_mode(rf_address_mode_t mode)
481 {
482  int8_t retval = -1;
483 
484  rf_softack = 0;
485  /* set oscillator on*/
486  switch(mode) {
487  case RF_SOFTACK_MONITOR:
488  rf_softack = 1;
489  case RF_MONITOR:
490  MDMCTRL0H |= 0x10; /*Address-decode off , coordinator*/
491  MDMCTRL0L &= ~0x10; /*no automatic ACK */
492  break;
493 
494  case RF_DECODER_COORDINATOR:
495  MDMCTRL0H |= 0x18; /*Address-decode on , coordinator*/
496  MDMCTRL0L |= 0x10; /*automatic ACK */
497  break;
498 
499  case RF_DECODER_ON:
500  MDMCTRL0H |= 0x08; /*Address-decode on */
501  MDMCTRL0L &= ~0x10; /* no automatic ACK */
502  break;
503 
504  default:
505  MDMCTRL0H &= ~0x18; /* Generic client */
506  MDMCTRL0L &= ~0x10; /* no automatic ACK */
507  break;
508  }
509  rf_addr_mode = mode;
510 
511  retval = 1;
512  return retval;
513 }
514 /*---------------------------------------------------------------------------*/
515 /**
516  * Channel energy detect.
517  *
518  * Coordinator use this function detect best channel for PAN-network.
519  * \return RSSI-energy level dBm.
520  * \return 0 operation failed.
521  */
522 
523 int8_t
525 {
526  int8_t retval = -128;
527  /*pause_us(128);*/
528 
529  retval = (int8_t)RSSIL;
530  retval -= 45;
531  return retval;
532 }
533 /*---------------------------------------------------------------------------*/
534 /**
535  * Clear channel assesment check.
536  *
537  * \return pdTRUE CCA clear
538  * \return pdFALSE CCA reserved
539  */
540 int8_t
541 cc2430_rf_cca_check(uint8_t backoff_count, uint8_t slotted)
542 {
543  uint8_t counter, cca = 1;
544  int8_t retval = 1;
545  backoff_count;
546  cc2430_rf_command(ISRXON);
547 
548  clock_delay(64);
549  switch(slotted) {
550  case 1:
551 
552  if(RFSTATUS & CCA) {
553  counter = 0;
554  cca = 1;
555  while(cca != 0) {
556  if(counter > 1) {
557  cca = 0;
558  }
559  clock_delay(256);
560  if(!(RFSTATUS & CCA)) {
561  cca = 0;
562  retval = -1;
563  }
564  counter++;
565  }
566  } else {
567  retval = -1;
568  }
569  break;
570 
571  case 0:
572  if(!(RFSTATUS & CCA)) {
573  retval = -1;
574  } else {
575 
576  }
577  break;
578  }
579  return retval;
580 }
581 /*---------------------------------------------------------------------------*/
582 /**
583  * Send ACK.
584  *
585  *\param pending set up pending flag if pending > 0.
586  */
587 void
588 cc2430_rf_send_ack(uint8_t pending) __banked
589 {
590  if(pending) {
591  cc2430_rf_command(ISACKPEND);
592  } else {
593  cc2430_rf_command(ISACK);
594  }
595 }
596 /*---------------------------------------------------------------------------*/