Contiki 2.5
radio.c
Go to the documentation of this file.
1 /* Copyright (c) 2008, Swedish Institute of Computer Science
2  * All rights reserved.
3  *
4  * Additional fixes for AVR contributed by:
5  * Colin O'Flynn coflynn@newae.com
6  * Eric Gnoske egnoske@gmail.com
7  * Blake Leverett bleverett@gmail.com
8  * Mike Vidales mavida404@gmail.com
9  * Kevin Brown kbrown3@uccs.edu
10  * Nate Bohlmann nate@elfwerks.com
11  *
12  * All rights reserved.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions are met:
16  *
17  * * Redistributions of source code must retain the above copyright
18  * notice, this list of conditions and the following disclaimer.
19  * * Redistributions in binary form must reproduce the above copyright
20  * notice, this list of conditions and the following disclaimer in
21  * the documentation and/or other materials provided with the
22  * distribution.
23  * * Neither the name of the copyright holders nor the names of
24  * contributors may be used to endorse or promote products derived
25  * from this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  *
39  * $Id: radio.c,v 1.5 2010/02/12 18:00:30 dak664 Exp $
40 */
41 
42 /**
43  * \brief This module contains the radio driver code for the Atmel
44  * AT86RF230, '231, and '212 chips.
45  *
46  * \author Blake Leverett <bleverett@gmail.com>
47  * Mike Vidales <mavida404@gmail.com>
48  * Eric Gnoske <egnoske@gmail.com>
49  *
50 */
51 
52 /** \addtogroup wireless
53  * @{
54  */
55 
56 /**
57  * \defgroup radiorf230 RF230 interface
58  * @{
59  */
60 /**
61  * \file
62  * This file contains radio driver code.
63  *
64  */
65 
66 
67 
68 /*============================ INCLUDE =======================================*/
69 #include <stdlib.h>
70 #include <util/delay.h>
71 #include "radio.h"
72 #include "hal.h"
73 #include "process.h"
74 #include "sicslowmac.h"
75 #include "frame.h"
76 
77 /*============================ MACROS ========================================*/
78 #define RADIO_CCA_DONE_MASK (1 << 7) /**< Mask used to check the CCA_DONE bit. */
79 #define RADIO_CCA_IDLE_MASK (1 << 6) /**< Mask used to check the CCA_STATUS bit. */
80 
81 #define RADIO_START_CCA (1) /**< Value in the CCA_REQUEST subregister that initiate a cca. */
82 
83 #define RADIO_TRANSMISSION_SUCCESS (0)
84 #define RADIO_BUSY_CHANNEL (3)
85 #define RADIO_MIN_IEEE_FRAME_LENGTH (5)
86 /*============================ TYPEDEFS ======================================*/
87 
88 /** \brief This enumeration defines the necessary timing information for the
89  * AT86RF230 radio transceiver. All times are in microseconds.
90  *
91  * These constants are extracted from the datasheet.
92  */
93 typedef enum{
94  TIME_TO_ENTER_P_ON = 510, /**< Transition time from VCC is applied to P_ON. */
95  TIME_P_ON_TO_TRX_OFF = 510, /**< Transition time from P_ON to TRX_OFF. */
96  TIME_SLEEP_TO_TRX_OFF = 880, /**< Transition time from SLEEP to TRX_OFF. */
97  TIME_RESET = 6, /**< Time to hold the RST pin low during reset */
98  TIME_ED_MEASUREMENT = 140, /**< Time it takes to do a ED measurement. */
99  TIME_CCA = 140, /**< Time it takes to do a CCA. */
100  TIME_PLL_LOCK = 150, /**< Maximum time it should take for the PLL to lock. */
101  TIME_FTN_TUNING = 25, /**< Maximum time it should take to do the filter tuning. */
102  TIME_NOCLK_TO_WAKE = 6, /**< Transition time from *_NOCLK to being awake. */
103  TIME_CMD_FORCE_TRX_OFF = 1, /**< Time it takes to execute the FORCE_TRX_OFF command. */
104  TIME_TRX_OFF_TO_PLL_ACTIVE = 180, /**< Transition time from TRX_OFF to: RX_ON, PLL_ON, TX_ARET_ON and RX_AACK_ON. */
105  TIME_STATE_TRANSITION_PLL_ACTIVE = 1, /**< Transition time from PLL active state to another. */
107 
108 /*============================ VARIABLES =====================================*/
109 static hal_rx_start_isr_event_handler_t user_rx_event;
110 static hal_trx_end_isr_event_handler_t user_trx_end_event;
111 static radio_rx_callback rx_frame_callback;
112 static uint8_t rssi_val;
113 static uint8_t rx_mode;
114 uint8_t rxMode = RX_AACK_ON;
115 
116 /* See clock.c and httpd-cgi.c for RADIOSTATS code */
117 #define RADIOSTATS 0
118 #if RADIOSTATS
119 uint8_t RF230_radio_on, RF230_rsigsi;
120 uint16_t RF230_sendpackets,RF230_receivepackets,RF230_sendfail,RF230_receivefail;
121 #endif
122 
123 static hal_rx_frame_t rx_frame;
124 static parsed_frame_t parsed_frame;
125 
126 /*============================ PROTOTYPES ====================================*/
127 bool radio_is_sleeping(void);
128 static void radio_rx_start_event(uint32_t const isr_timestamp, uint8_t const frame_length);
129 static void radio_trx_end_event(uint32_t const isr_timestamp);
130 
131 /** \brief Initialize the Transceiver Access Toolbox and lower layers.
132  *
133  * If the initialization is successful the radio transceiver will be in
134  * TRX_OFF state.
135  *
136  * \note This function must be called prior to any of the other functions in
137  * this file! Can be called from any transceiver state.
138  *
139  * \param cal_rc_osc If true, the radio's accurate clock is used to calibrate the
140  * CPU's internal RC oscillator.
141  *
142  * \param rx_event Optional pointer to a user-defined function to be called on an
143  * RX_START interrupt. Use NULL for no handler.
144  *
145  * \param trx_end_event Optional pointer to a user-defined function to be called on an
146  * TRX_END interrupt. Use NULL for no handler.
147  *
148  * \param rx_callback Optional pointer to a user-defined function that receives
149  * a frame from the radio one byte at a time. If the index parameter to
150  * this callback is 0xff, then the function should reset its state and prepare
151  * for a frame from the radio, with one call per byte.
152  *
153  * \retval RADIO_SUCCESS The radio transceiver was successfully initialized
154  * and put into the TRX_OFF state.
155  * \retval RADIO_UNSUPPORTED_DEVICE The connected device is not an Atmel
156  * AT86RF230 radio transceiver.
157  * \retval RADIO_TIMED_OUT The radio transceiver was not able to initialize and
158  * enter TRX_OFF state within the specified time.
159  */
161 radio_init(bool cal_rc_osc,
163  hal_trx_end_isr_event_handler_t trx_end_event,
164  radio_rx_callback rx_callback)
165 {
166  radio_status_t init_status = RADIO_SUCCESS;
167 
168  delay_us(TIME_TO_ENTER_P_ON);
169 
170  /* calibrate oscillator */
171  if (cal_rc_osc){
173  }
174 
175  /* Initialize Hardware Abstraction Layer. */
176  hal_init();
177 
178  radio_reset_trx(); /* Do HW reset of radio transeiver. */
179 
180  /* Force transition to TRX_OFF. */
182  delay_us(TIME_P_ON_TO_TRX_OFF); /* Wait for the transition to be complete. */
183 
184  if (radio_get_trx_state() != TRX_OFF){
185  init_status = RADIO_TIMED_OUT;
186  } else {
187  /* Read Version Number */
188  uint8_t version_number = hal_register_read(RG_VERSION_NUM);
189 
190  if ((version_number != RF230_REVA) && (version_number != RF230_REVB))
191  init_status = RADIO_UNSUPPORTED_DEVICE;
192  else {
193  if (hal_register_read(RG_MAN_ID_0) != SUPPORTED_MANUFACTURER_ID)
194  init_status = RADIO_UNSUPPORTED_DEVICE;
195  else
196  hal_register_write(RG_IRQ_MASK, RF230_SUPPORTED_INTERRUPT_MASK);
197  }
198 #if RADIOSTATS
199  RF230_radio_on = 1;
200 #endif
201  }
202 
203  /* set callbacks for events. Save user's rx_event, which we will */
204  /* call from radio_rx_start_event(). Same with trx_end */
205  user_rx_event = rx_event;
206  user_trx_end_event = trx_end_event;
207  hal_set_rx_start_event_handler(radio_rx_start_event);
208  hal_set_trx_end_event_handler(radio_trx_end_event);
209 
210  rx_frame_callback = rx_callback;
211 
212  return init_status;
213 }
214 
215 /*---------------------------------------------------------------------------*/
216 uint8_t *
217 radio_frame_data(void)
218 {
219  return rx_frame.data;
220 }
221 
222 uint8_t
223 radio_frame_length(void)
224 {
225  return rx_frame.length;
226 }
227 
228 /*---------------------------------------------------------------------------*/
229 static void
230 radio_rx_start_event(uint32_t const isr_timestamp, uint8_t const frame_length)
231 {
232  /* save away RSSI */
233  rssi_val = hal_subregister_read( SR_RSSI );
234 
235  /* call user's rx_start event handler */
236  if (user_rx_event)
237  user_rx_event(isr_timestamp, frame_length);
238 }
239 
240 /*---------------------------------------------------------------------------*/
241 uint8_t
242 radio_get_saved_rssi_value(void)
243 {
244  return rssi_val;
245 }
246 
247 /*---------------------------------------------------------------------------*/
248 static void
249 radio_trx_end_event(uint32_t const isr_timestamp)
250 {
251  volatile uint8_t status;
252 
253  /* call user's trx_end event handler */
254  if (user_trx_end_event){
255  user_trx_end_event(isr_timestamp);
256  return;
257  }
258  if (rx_mode){
259  /* radio has received frame, store it away */
260 #if RADIOSTATS
261  RF230_rsigsi=rssi_val;
262  RF230_receivepackets++;
263 #endif
264  parsed_frame.time = isr_timestamp;
265  parsed_frame.rssi = rssi_val;
266 
267  hal_frame_read(&rx_frame, NULL);
268  rx_frame_parse(&rx_frame, &parsed_frame);
269  }
270 
271  if (!rx_mode){
272  /* Put radio back into receive mode. */
274  radio_set_trx_state(rxMode);
275 
276  /* transmit mode, put end-of-transmit event in queue */
277  event_object_t event;
278  event.event = 0;
279  event.data = 0;
281  switch(status){
282  case TRAC_SUCCESS:
283  case TRAC_SUCCESS_DATA_PENDING:
284  event.event = MAC_EVENT_ACK;
285  break;
286  case TRAC_NO_ACK:
287  case TRAC_CHANNEL_ACCESS_FAILURE:
288  event.event = MAC_EVENT_NACK;
289 #if RADIOSTATS
290  RF230_sendfail++;
291 #endif
292  break;
293  case TRAC_SUCCESS_WAIT_FOR_ACK:
294  /* should only happen in RX mode */
295  case TRAC_INVALID:
296  /* should never happen here */
297  default:
298 #if RADIOSTATS
299  RF230_sendfail++;
300 #endif
301  break;
302  }
303  if (event.event)
304  mac_put_event(&event);
305  process_post(&mac_process, event.event, event.data);
306  }
307 }
308 /*----------------------------------------------------------------------------*/
309 /** \brief This function will return the channel used by the radio transceiver.
310  *
311  * \return Current channel, 11 to 26.
312  */
313 uint8_t
315 {
317 }
318 /*----------------------------------------------------------------------------*/
319 /** \brief This function will change the operating channel.
320  *
321  * \param channel New channel to operate on. Must be between 11 and 26.
322  *
323  * \retval RADIO_SUCCESS New channel set.
324  * \retval RADIO_WRONG_STATE Transceiver is in a state where the channel cannot
325  * be changed (SLEEP).
326  * \retval RADIO_INVALID_ARGUMENT Channel argument is out of bounds.
327  * \retval RADIO_TIMED_OUT The PLL did not lock within the specified time.
328  */
331 {
332  /*Do function parameter and state check.*/
333  if ((channel < RF230_MIN_CHANNEL) ||
334  (channel > RF230_MAX_CHANNEL)){
335  return RADIO_INVALID_ARGUMENT;
336  }
337 
338  if (radio_is_sleeping() == true){
339  return RADIO_WRONG_STATE;
340  }
341 
342  if (radio_get_operating_channel() == channel){
343  return RADIO_SUCCESS;
344  }
345 
346  /*Set new operating channel.*/
348 
349  /* Read current state and wait for the PLL_LOCK interrupt if the */
350  /* radio transceiver is in either RX_ON or PLL_ON. */
351  uint8_t trx_state = radio_get_trx_state();
352 
353  if ((trx_state == RX_ON) ||
354  (trx_state == PLL_ON)){
355  delay_us(TIME_PLL_LOCK);
356  }
357 
358  radio_status_t channel_set_status = RADIO_TIMED_OUT;
359 
360  /* Check that the channel was set properly. */
361  if (radio_get_operating_channel() == channel){
362  channel_set_status = RADIO_SUCCESS;
363  }
364 
365  return channel_set_status;
366 }
367 
368 /*----------------------------------------------------------------------------*/
369 /** \brief This function will read and return the output power level.
370  *
371  * \returns 0 to 15 Current output power in "TX power settings" as defined in
372  * the radio transceiver's datasheet
373  */
374 uint8_t
376 {
378 }
379 
380 /*----------------------------------------------------------------------------*/
381 /** \brief This function will change the output power level.
382  *
383  * \param power_level New output power level in the "TX power settings"
384  * as defined in the radio transceiver's datasheet.
385  *
386  * \retval RADIO_SUCCESS New output power set successfully.
387  * \retval RADIO_INVALID_ARGUMENT The supplied function argument is out of bounds.
388  * \retval RADIO_WRONG_STATE It is not possible to change the TX power when the
389  * device is sleeping.
390  */
392 radio_set_tx_power_level(uint8_t power_level)
393 {
394 
395  /*Check function parameter and state.*/
396  if (power_level > TX_PWR_17_2DBM){
397  return RADIO_INVALID_ARGUMENT;
398  }
399 
400  if (radio_is_sleeping() == true){
401  return RADIO_WRONG_STATE;
402  }
403 
404  /*Set new power level*/
405  hal_subregister_write(SR_TX_PWR, power_level);
406 
407  return RADIO_SUCCESS;
408 }
409 
410 /*----------------------------------------------------------------------------*/
411 /** \brief This function returns the current CCA mode used.
412  *
413  * \return CCA mode currently used, 0 to 3.
414  */
415 uint8_t
417 {
419 }
420 
421 /*----------------------------------------------------------------------------*/
422 /** \brief This function returns the current ED threshold used by the CCA algorithm.
423  *
424  * \return Current ED threshold, 0 to 15.
425  */
426 uint8_t
428 {
430 }
431 
432 /*----------------------------------------------------------------------------*/
433 /** \brief This function will configure the Clear Channel Assessment algorithm.
434  *
435  * \param mode Three modes are available: Energy above threshold, carrier
436  * sense only and carrier sense with energy above threshold.
437  * \param ed_threshold Above this energy threshold the channel is assumed to be
438  * busy. The threshold is given in positive dBm values.
439  * Ex. -91 dBm gives a csThreshold of 91. Value range for
440  * the variable is [61 to 91]. Only valid for the CCA_ED
441  * and CCA_CARRIER_SENSE_ED modes.
442  *
443  * \retval RADIO_SUCCESS Mode and its parameters successfully changed.
444  * \retval RADIO_WRONG_STATE This function cannot be called in the SLEEP state.
445  * \retval RADIO_INVALID_ARGUMENT If one of the three function arguments are out
446  * of bounds.
447  */
449 radio_set_cca_mode(uint8_t mode, uint8_t ed_threshold)
450 {
451  /*Check function parameters and state.*/
452  if ((mode != CCA_ED) &&
453  (mode != CCA_CARRIER_SENSE) &&
454  (mode != CCA_CARRIER_SENSE_WITH_ED)){
455  return RADIO_INVALID_ARGUMENT;
456  }
457 
458  /* Ensure that the ED threshold is within bounds. */
459  if (ed_threshold > RF230_MAX_ED_THRESHOLD){
460  return RADIO_INVALID_ARGUMENT;
461  }
462 
463  /* Ensure that the radio transceiver is not sleeping. */
464  if (radio_is_sleeping() == true){
465  return RADIO_WRONG_STATE;
466  }
467 
468  /*Change cca mode and ed threshold.*/
470  hal_subregister_write(SR_CCA_ED_THRES, ed_threshold);
471 
472  return RADIO_SUCCESS;
473 }
474 
475 /*----------------------------------------------------------------------------*/
476 /** \brief This function returns the Received Signal Strength Indication.
477  *
478  * \note This function should only be called from the: RX_ON and BUSY_RX. This
479  * can be ensured by reading the current state of the radio transceiver
480  * before executing this function!
481  * \param rssi Pointer to memory location where RSSI value should be written.
482  * \retval RADIO_SUCCESS The RSSI measurement was successful.
483  * \retval RADIO_WRONG_STATE The radio transceiver is not in RX_ON or BUSY_RX.
484  */
486 radio_get_rssi_value(uint8_t *rssi)
487 {
488 
489  uint8_t current_state = radio_get_trx_state();
491 
492  /*The RSSI measurement should only be done in RX_ON or BUSY_RX.*/
493  if ((current_state == RX_ON) ||
494  (current_state == BUSY_RX)){
495  *rssi = hal_subregister_read(SR_RSSI);
496  retval = RADIO_SUCCESS;
497  }
498 
499  return retval;
500 }
501 
502 /*----------------------------------------------------------------------------*/
503 /** \brief This function returns the current threshold volatge used by the
504  * battery monitor (BATMON_VTH).
505  *
506  * \note This function can not be called from P_ON or SLEEP. This is ensured
507  * by reading the device state before calling this function.
508  *
509  * \return Current threshold voltage, 0 to 15.
510  */
511 uint8_t
513 {
515 }
516 
517 /*----------------------------------------------------------------------------*/
518 /** \brief This function returns if high or low voltage range is used.
519  *
520  * \note This function can not be called from P_ON or SLEEP. This is ensured
521  * by reading the device state before calling this function.
522  *
523  * \retval 0 Low voltage range selected.
524  * \retval 1 High voltage range selected.
525  */
526 uint8_t
528 {
530 }
531 
532 /*----------------------------------------------------------------------------*/
533 /** \brief This function is used to configure the battery monitor module
534  *
535  * \param range True means high voltage range and false low voltage range.
536  * \param voltage_threshold The datasheet defines 16 voltage levels for both
537  * low and high range.
538  * \retval RADIO_SUCCESS Battery monitor configured
539  * \retval RADIO_WRONG_STATE The device is sleeping.
540  * \retval RADIO_INVALID_ARGUMENT The voltage_threshold parameter is out of
541  * bounds (Not within [0 - 15]).
542  */
544 radio_batmon_configure(bool range, uint8_t voltage_threshold)
545 {
546 
547  /*Check function parameters and state.*/
548  if (voltage_threshold > BATTERY_MONITOR_HIGHEST_VOLTAGE){
549  return RADIO_INVALID_ARGUMENT;
550  }
551 
552  if (radio_is_sleeping() == true){
553  return RADIO_WRONG_STATE;
554  }
555 
556  /*Write new voltage range and voltage level.*/
557  if (range == true){
558  hal_subregister_write(SR_BATMON_HR, BATTERY_MONITOR_HIGH_VOLTAGE);
559  } else {
560  hal_subregister_write(SR_BATMON_HR, BATTERY_MONITOR_LOW_VOLTAGE);
561  }
562 
563  hal_subregister_write(SR_BATMON_VTH, voltage_threshold);
564 
565  return RADIO_SUCCESS;
566 }
567 
568 /*----------------------------------------------------------------------------*/
569 /** \brief This function returns the status of the Battery Monitor module.
570  *
571  * \note This function can not be called from P_ON or SLEEP. This is ensured
572  * by reading the device state before calling this function.
573  *
574  * \retval RADIO_BAT_LOW Battery voltage is below the programmed threshold.
575  * \retval RADIO_BAT_OK Battery voltage is above the programmed threshold.
576  */
579 {
580 
581  radio_status_t batmon_status = RADIO_BAT_LOW;
582 
584  BATTERY_MONITOR_VOLTAGE_UNDER_THRESHOLD){
585  batmon_status = RADIO_BAT_OK;
586  }
587 
588  return batmon_status;
589 }
590 
591 /*----------------------------------------------------------------------------*/
592 /** \brief This function returns the current clock setting for the CLKM pin.
593  *
594  * \retval CLKM_DISABLED CLKM pin is disabled.
595  * \retval CLKM_1MHZ CLKM pin is prescaled to 1 MHz.
596  * \retval CLKM_2MHZ CLKM pin is prescaled to 2 MHz.
597  * \retval CLKM_4MHZ CLKM pin is prescaled to 4 MHz.
598  * \retval CLKM_8MHZ CLKM pin is prescaled to 8 MHz.
599  * \retval CLKM_16MHZ CLKM pin is not prescaled. Output is 16 MHz.
600  */
601 uint8_t
603 {
605 }
606 
607 /*----------------------------------------------------------------------------*/
608 /** \brief This function changes the prescaler on the CLKM pin.
609  *
610  * \param direct This boolean variable is used to determine if the frequency
611  * of the CLKM pin shall be changed directly or not. If direct
612  * equals true, the frequency will be changed directly. This is
613  * fine if the CLKM signal is used to drive a timer etc. on the
614  * connected microcontroller. However, the CLKM signal can also
615  * be used to clock the microcontroller itself. In this situation
616  * it is possible to change the CLKM frequency indirectly
617  * (direct == false). When the direct argument equlas false, the
618  * CLKM frequency will be changed first after the radio transceiver
619  * has been taken to SLEEP and awaken again.
620  * \param clock_speed This parameter can be one of the following constants:
621  * CLKM_DISABLED, CLKM_1MHZ, CLKM_2MHZ, CLKM_4MHZ, CLKM_8MHZ
622  * or CLKM_16MHZ.
623  *
624  * \retval RADIO_SUCCESS Clock speed updated. New state is TRX_OFF.
625  * \retval RADIO_INVALID_ARGUMENT Requested clock speed is out of bounds.
626  */
628 radio_set_clock_speed(bool direct, uint8_t clock_speed)
629 {
630  /*Check function parameter and current clock speed.*/
631  if (clock_speed > CLKM_16MHZ){
632  return RADIO_INVALID_ARGUMENT;
633  }
634 
635  if (radio_get_clock_speed() == clock_speed){
636  return RADIO_SUCCESS;
637  }
638 
639  /*Select to change the CLKM frequency directly or after returning from SLEEP.*/
640  if (direct == false){
642  } else {
644  }
645 
646  hal_subregister_write(SR_CLKM_CTRL, clock_speed);
647 
648  return RADIO_SUCCESS;
649 }
650 
651 /*----------------------------------------------------------------------------*/
652 /** \brief This function calibrates the Single Side Band Filter.
653  *
654  * \retval RADIO_SUCCESS Filter is calibrated.
655  * \retval RADIO_TIMED_OUT The calibration could not be completed within time.
656  * \retval RADIO_WRONG_STATE This function can only be called from TRX_OFF or
657  * PLL_ON.
658  */
661 {
662  /*Check current state. Only possible to do filter calibration from TRX_OFF or PLL_ON.*/
663  uint8_t trx_state = radio_get_trx_state();
664 
665  if ((trx_state != TRX_OFF) &&
666  (trx_state != PLL_ON)){
667  return RADIO_WRONG_STATE;
668  }
669 
670  /* Start the tuning algorithm by writing one to the FTN_START subregister. */
672  delay_us(TIME_FTN_TUNING); /* Wait for the calibration to finish. */
673 
674  radio_status_t filter_calibration_status = RADIO_TIMED_OUT;
675 
676  /* Verify the calibration result. */
677  if (hal_subregister_read(SR_FTN_START) == FTN_CALIBRATION_DONE){
678  filter_calibration_status = RADIO_SUCCESS;
679  }
680 
681  return filter_calibration_status;
682 }
683 
684 /*----------------------------------------------------------------------------*/
685 /** \brief This function calibrates the PLL.
686  *
687  * \retval RADIO_SUCCESS PLL Center Frequency and Delay Cell is calibrated.
688  * \retval RADIO_TIMED_OUT The calibration could not be completed within time.
689  * \retval RADIO_WRONG_STATE This function can only be called from PLL_ON.
690  */
693 {
694 
695  /*Check current state. Only possible to calibrate PLL from PLL_ON state*/
696  if (radio_get_trx_state() != PLL_ON){
697  return RADIO_WRONG_STATE;
698  }
699 
700  /* Initiate the DCU and CF calibration loops. */
703 
704  /* Wait maximum 150 us for the PLL to lock. */
706  delay_us(TIME_PLL_LOCK);
707 
708  radio_status_t pll_calibration_status = RADIO_TIMED_OUT;
709 
710  if (hal_get_pll_lock_flag() > 0){
711  if (hal_subregister_read(SR_PLL_DCU_START) == PLL_DCU_CALIBRATION_DONE){
712  if (hal_subregister_read(SR_PLL_CF_START) == PLL_CF_CALIBRATION_DONE){
713  pll_calibration_status = RADIO_SUCCESS;
714  }
715  }
716  }
717 
718  return pll_calibration_status;
719 }
720 
721 /*----------------------------------------------------------------------------*/
722 /** \brief This function return the Radio Transceivers current state.
723  *
724  * \retval P_ON When the external supply voltage (VDD) is
725  * first supplied to the transceiver IC, the
726  * system is in the P_ON (Poweron) mode.
727  * \retval BUSY_RX The radio transceiver is busy receiving a
728  * frame.
729  * \retval BUSY_TX The radio transceiver is busy transmitting a
730  * frame.
731  * \retval RX_ON The RX_ON mode enables the analog and digital
732  * receiver blocks and the PLL frequency
733  * synthesizer.
734  * \retval TRX_OFF In this mode, the SPI module and crystal
735  * oscillator are active.
736  * \retval PLL_ON Entering the PLL_ON mode from TRX_OFF will
737  * first enable the analog voltage regulator. The
738  * transceiver is ready to transmit a frame.
739  * \retval BUSY_RX_AACK The radio was in RX_AACK_ON mode and received
740  * the Start of Frame Delimiter (SFD). State
741  * transition to BUSY_RX_AACK is done if the SFD
742  * is valid.
743  * \retval BUSY_TX_ARET The radio transceiver is busy handling the
744  * auto retry mechanism.
745  * \retval RX_AACK_ON The auto acknowledge mode of the radio is
746  * enabled and it is waiting for an incomming
747  * frame.
748  * \retval TX_ARET_ON The auto retry mechanism is enabled and the
749  * radio transceiver is waiting for the user to
750  * send the TX_START command.
751  * \retval RX_ON_NOCLK The radio transceiver is listening for
752  * incomming frames, but the CLKM is disabled so
753  * that the controller could be sleeping.
754  * However, this is only true if the controller
755  * is run from the clock output of the radio.
756  * \retval RX_AACK_ON_NOCLK Same as the RX_ON_NOCLK state, but with the
757  * auto acknowledge module turned on.
758  * \retval BUSY_RX_AACK_NOCLK Same as BUSY_RX_AACK, but the controller
759  * could be sleeping since the CLKM pin is
760  * disabled.
761  * \retval STATE_TRANSITION The radio transceiver's state machine is in
762  * transition between two states.
763  */
764 uint8_t
766 {
768 }
769 
770 /*----------------------------------------------------------------------------*/
771 /** \brief This function checks if the radio transceiver is sleeping.
772  *
773  * \retval true The radio transceiver is in SLEEP or one of the *_NOCLK
774  * states.
775  * \retval false The radio transceiver is not sleeping.
776  */
778 {
779  bool sleeping = false;
780 
781  /* The radio transceiver will be at SLEEP or one of the *_NOCLK states only if */
782  /* the SLP_TR pin is high. */
783  if (hal_get_slptr() != 0){
784  sleeping = true;
785  }
786 
787  return sleeping;
788 }
789 
790 /*----------------------------------------------------------------------------*/
791 /** \brief This function will change the current state of the radio
792  * transceiver's internal state machine.
793  *
794  * \param new_state Here is a list of possible states:
795  * - RX_ON Requested transition to RX_ON state.
796  * - TRX_OFF Requested transition to TRX_OFF state.
797  * - PLL_ON Requested transition to PLL_ON state.
798  * - RX_AACK_ON Requested transition to RX_AACK_ON state.
799  * - TX_ARET_ON Requested transition to TX_ARET_ON state.
800  *
801  * \retval RADIO_SUCCESS Requested state transition completed
802  * successfully.
803  * \retval RADIO_INVALID_ARGUMENT Supplied function parameter out of bounds.
804  * \retval RADIO_WRONG_STATE Illegal state to do transition from.
805  * \retval RADIO_BUSY_STATE The radio transceiver is busy.
806  * \retval RADIO_TIMED_OUT The state transition could not be completed
807  * within resonable time.
808  */
810 radio_set_trx_state(uint8_t new_state)
811 {
812  uint8_t original_state;
813 
814  /*Check function paramter and current state of the radio transceiver.*/
815  if (!((new_state == TRX_OFF) ||
816  (new_state == RX_ON) ||
817  (new_state == PLL_ON) ||
818  (new_state == RX_AACK_ON) ||
819  (new_state == TX_ARET_ON))){
820  return RADIO_INVALID_ARGUMENT;
821  }
822 
823  if (radio_is_sleeping() == true){
824  return RADIO_WRONG_STATE;
825  }
826 
827  // Wait for radio to finish previous operation
828  for(;;)
829  {
830  original_state = radio_get_trx_state();
831  if (original_state != BUSY_TX_ARET &&
832  original_state != BUSY_RX_AACK &&
833  original_state != BUSY_RX &&
834  original_state != BUSY_TX)
835  break;
836  }
837 
838  if (new_state == original_state){
839  return RADIO_SUCCESS;
840  }
841 
842 
843  /* At this point it is clear that the requested new_state is: */
844  /* TRX_OFF, RX_ON, PLL_ON, RX_AACK_ON or TX_ARET_ON. */
845 
846  /* The radio transceiver can be in one of the following states: */
847  /* TRX_OFF, RX_ON, PLL_ON, RX_AACK_ON, TX_ARET_ON. */
848  if(new_state == TRX_OFF){
849  radio_reset_state_machine(); /* Go to TRX_OFF from any state. */
850  } else {
851  /* It is not allowed to go from RX_AACK_ON or TX_AACK_ON and directly to */
852  /* TX_AACK_ON or RX_AACK_ON respectively. Need to go via RX_ON or PLL_ON. */
853  if ((new_state == TX_ARET_ON) &&
854  (original_state == RX_AACK_ON)){
855  /* First do intermediate state transition to PLL_ON, then to TX_ARET_ON. */
856  /* The final state transition to TX_ARET_ON is handled after the if-else if. */
859  } else if ((new_state == RX_AACK_ON) &&
860  (original_state == TX_ARET_ON)){
861  /* First do intermediate state transition to RX_ON, then to RX_AACK_ON. */
862  /* The final state transition to RX_AACK_ON is handled after the if-else if. */
865  }
866 
867  /* Any other state transition can be done directly. */
868  hal_subregister_write(SR_TRX_CMD, new_state);
869 
870  /* When the PLL is active most states can be reached in 1us. However, from */
871  /* TRX_OFF the PLL needs time to activate. */
872  if (original_state == TRX_OFF){
873  delay_us(TIME_TRX_OFF_TO_PLL_ACTIVE);
874  } else {
876  }
877  } /* end: if(new_state == TRX_OFF) ... */
878 
879  /*Verify state transition.*/
880  radio_status_t set_state_status = RADIO_TIMED_OUT;
881 
882  if (radio_get_trx_state() == new_state){
883  set_state_status = RADIO_SUCCESS;
884  /* set rx_mode flag based on mode we're changing to */
885  if (new_state == RX_ON ||
886  new_state == RX_AACK_ON){
887  rx_mode = true;
888  } else {
889  rx_mode = false;
890  }
891  }
892 
893  return set_state_status;
894 }
895 
896 /*----------------------------------------------------------------------------*/
897 /** \brief This function will put the radio transceiver to sleep.
898  *
899  * \retval RADIO_SUCCESS Sleep mode entered successfully.
900  * \retval RADIO_TIMED_OUT The transition to TRX_OFF took too long.
901  */
904 {
905  if (radio_is_sleeping() == true){
906  return RADIO_SUCCESS;
907  }
908 
909  radio_reset_state_machine(); /* Force the device into TRX_OFF. */
910 
911  radio_status_t enter_sleep_status = RADIO_TIMED_OUT;
912 
913  if (radio_get_trx_state() == TRX_OFF){
914  /* Enter Sleep. */
916  enter_sleep_status = RADIO_SUCCESS;
917 #if RADIOSTATS
918  RF230_radio_on = 0;
919 #endif
920  }
921 
922  return enter_sleep_status;
923 }
924 
925 /*----------------------------------------------------------------------------*/
926 /** \brief This function will take the radio transceiver from sleep mode and
927  * put it into the TRX_OFF state.
928  *
929  * \retval RADIO_SUCCESS Left sleep mode and entered TRX_OFF state.
930  * \retval RADIO_TIMED_OUT Transition to TRX_OFF state timed out.
931  */
934 {
935  /* Check if the radio transceiver is actually sleeping. */
936  if (radio_is_sleeping() == false){
937  return RADIO_SUCCESS;
938  }
939 
941  delay_us(TIME_SLEEP_TO_TRX_OFF);
942 
943  radio_status_t leave_sleep_status = RADIO_TIMED_OUT;
944 
945  /* Ensure that the radio transceiver is in the TRX_OFF state. */
946  if (radio_get_trx_state() == TRX_OFF){
947  leave_sleep_status = RADIO_SUCCESS;
948 #if RADIOSTATS
949  RF230_radio_on = 1;
950 #endif
951  }
952 
953  return leave_sleep_status;
954 }
955 
956 /*----------------------------------------------------------------------------*/
957 /** \brief This function will reset the state machine (to TRX_OFF) from any of
958  * its states, except for the SLEEP state.
959  */
960 void
962 {
964  delay_us(TIME_NOCLK_TO_WAKE);
966  delay_us(TIME_CMD_FORCE_TRX_OFF);
967 }
968 
969 /*----------------------------------------------------------------------------*/
970 /** \brief This function will reset all the registers and the state machine of
971  * the radio transceiver.
972  */
973 void
975 {
976  hal_set_rst_low();
978  delay_us(TIME_RESET);
980 }
981 
982 /*----------------------------------------------------------------------------*/
983 /** \brief This function will enable or disable automatic CRC during frame
984  * transmission.
985  *
986  * \param auto_crc_on If this parameter equals true auto CRC will be used for
987  * all frames to be transmitted. The framelength must be
988  * increased by two bytes (16 bit CRC). If the parameter equals
989  * false, the automatic CRC will be disabled.
990  */
991 void
992 radio_use_auto_tx_crc(bool auto_crc_on)
993 {
994  if (auto_crc_on == true){
996  } else {
998  }
999 }
1000 
1001 /*----------------------------------------------------------------------------*/
1002 /** \brief This function will download a frame to the radio transceiver's
1003  * transmit buffer and send it.
1004  *
1005  * \param data_length Length of the frame to be transmitted. 1 to 128 bytes are the valid lengths.
1006  * \param *data Pointer to the data to transmit
1007  *
1008  * \retval RADIO_SUCCESS Frame downloaded and sent successfully.
1009  * \retval RADIO_INVALID_ARGUMENT If the dataLength is 0 byte or more than 127
1010  * bytes the frame will not be sent.
1011  * \retval RADIO_WRONG_STATE It is only possible to use this function in the
1012  * PLL_ON and TX_ARET_ON state. If any other state is
1013  * detected this error message will be returned.
1014  */
1016 radio_send_data(uint8_t data_length, uint8_t *data)
1017 {
1018  /*Check function parameters and current state.*/
1019  if (data_length > RF230_MAX_TX_FRAME_LENGTH){
1020 #if RADIOSTATS
1021  RF230_sendfail++;
1022 #endif
1023  return RADIO_INVALID_ARGUMENT;
1024  }
1025 
1026  /* If we are busy, return */
1028  {
1029 #if RADIOSTATS
1030  RF230_sendfail++;
1031 #endif
1032  return RADIO_WRONG_STATE;
1033  }
1034 
1037 
1038  /*Do frame transmission.*/
1039  /* Toggle the SLP_TR pin to initiate the frame transmission. */
1042 
1043  hal_frame_write(data, data_length); /* Then write data to the frame buffer. */
1044 #if RADIOSTATS
1045  RF230_sendpackets++;
1046 #endif
1047  return RADIO_SUCCESS;
1048 }
1049 
1050 /*----------------------------------------------------------------------------*/
1051 /** \brief This function will read the I_AM_COORD sub register.
1052  *
1053  * \retval 0 Not coordinator.
1054  * \retval 1 Coordinator role enabled.
1055  */
1056 uint8_t
1058 {
1060 }
1061 
1062 /*----------------------------------------------------------------------------*/
1063 /** \brief This function will set the I_AM_COORD sub register.
1064  *
1065  * \param[in] i_am_coordinator If this parameter is true, the associated
1066  * coordinator role will be enabled in the radio
1067  * transceiver's address filter.
1068  * False disables the same feature.
1069  */
1070 void
1071 radio_set_device_role(bool i_am_coordinator)
1072 {
1073  hal_subregister_write(SR_I_AM_COORD, i_am_coordinator);
1074 }
1075 
1076 /*----------------------------------------------------------------------------*/
1077 /** \brief This function will return the PANID used by the address filter.
1078  *
1079  * \retval Any value from 0 to 0xFFFF.
1080  */
1081 uint16_t
1083 {
1084 
1085  uint8_t pan_id_15_8 = hal_register_read(RG_PAN_ID_1); /* Read pan_id_15_8. */
1086  uint8_t pan_id_7_0 = hal_register_read(RG_PAN_ID_0); /* Read pan_id_7_0. */
1087 
1088  uint16_t pan_id = ((uint16_t)(pan_id_15_8 << 8)) | pan_id_7_0;
1089 
1090  return pan_id;
1091 }
1092 
1093 /*----------------------------------------------------------------------------*/
1094 /** \brief This function will set the PANID used by the address filter.
1095  *
1096  * \param new_pan_id Desired PANID. Can be any value from 0x0000 to 0xFFFF
1097  */
1098 void
1099 radio_set_pan_id(uint16_t new_pan_id)
1100 {
1101 
1102  uint8_t pan_byte = new_pan_id & 0xFF; /* Extract new_pan_id_7_0. */
1103  hal_register_write(RG_PAN_ID_0, pan_byte);
1104 
1105  pan_byte = (new_pan_id >> 8*1) & 0xFF; /* Extract new_pan_id_15_8. */
1106  hal_register_write(RG_PAN_ID_1, pan_byte);
1107 }
1108 
1109 /*----------------------------------------------------------------------------*/
1110 /** \brief This function will return the current short address used by the
1111  * address filter.
1112  *
1113  * \retval Any value from 0x0000 to 0xFFFF
1114  */
1115 uint16_t
1117 {
1118 
1119  uint8_t short_address_15_8 = hal_register_read(RG_SHORT_ADDR_1); /* Read short_address_15_8. */
1120  uint8_t short_address_7_0 = hal_register_read(RG_SHORT_ADDR_1); /* Read short_address_7_0. */
1121 
1122  uint16_t short_address = ((uint16_t)(short_address_15_8 << 8)) | short_address_7_0;
1123 
1124  return short_address;
1125 }
1126 
1127 /*----------------------------------------------------------------------------*/
1128 /** \brief This function will set the short address used by the address filter.
1129  *
1130  * \param new_short_address Short address to be used by the address filter.
1131  */
1132 void
1133 radio_set_short_address(uint16_t new_short_address)
1134 {
1135 
1136  uint8_t short_address_byte = new_short_address & 0xFF; /* Extract short_address_7_0. */
1137  hal_register_write(RG_SHORT_ADDR_0, short_address_byte);
1138 
1139  short_address_byte = (new_short_address >> 8*1) & 0xFF; /* Extract short_address_15_8. */
1140  hal_register_write(RG_SHORT_ADDR_1, short_address_byte);
1141 }
1142 
1143 /*----------------------------------------------------------------------------*/
1144 /** \brief This function will read the extended address used by the address
1145  * filter.
1146  *
1147  * \note In this function a pointer is used to convey the 64-bit result, since
1148  * it is very inefficient to use the stack for this.
1149  *
1150  * \return Extended Address, any 64-bit value.
1151  */
1152 void
1153 radio_get_extended_address(uint8_t *extended_address)
1154 {
1155  *extended_address++ = hal_register_read(RG_IEEE_ADDR_0);
1156  *extended_address++ = hal_register_read(RG_IEEE_ADDR_1);
1157  *extended_address++ = hal_register_read(RG_IEEE_ADDR_2);
1158  *extended_address++ = hal_register_read(RG_IEEE_ADDR_3);
1159  *extended_address++ = hal_register_read(RG_IEEE_ADDR_4);
1160  *extended_address++ = hal_register_read(RG_IEEE_ADDR_5);
1161  *extended_address++ = hal_register_read(RG_IEEE_ADDR_6);
1162  *extended_address = hal_register_read(RG_IEEE_ADDR_7);
1163 }
1164 
1165 /*----------------------------------------------------------------------------*/
1166 /** \brief This function will set a new extended address to be used by the
1167  * address filter.
1168  *
1169  * \param extended_address Extended address to be used by the address filter.
1170  */
1171 void
1172 radio_set_extended_address(uint8_t *extended_address)
1173 {
1174  hal_register_write(RG_IEEE_ADDR_0, *extended_address++);
1175  hal_register_write(RG_IEEE_ADDR_1, *extended_address++);
1176  hal_register_write(RG_IEEE_ADDR_2, *extended_address++);
1177  hal_register_write(RG_IEEE_ADDR_3, *extended_address++);
1178  hal_register_write(RG_IEEE_ADDR_4, *extended_address++);
1179  hal_register_write(RG_IEEE_ADDR_5, *extended_address++);
1180  hal_register_write(RG_IEEE_ADDR_6, *extended_address++);
1181  hal_register_write(RG_IEEE_ADDR_7, *extended_address++);
1182 }
1183 
1184 /*----------------------------------------------------------------------------*/
1185 /** \brief This function will configure the CSMA algorithm used by the radio
1186  * transceiver when transmitting data from TX_ARET_ON state.
1187  *
1188  * \param seed0 Lower 8 bits of the seed used for the random number generator
1189  * in the CSMA algorithm. Value range: 0 to 255.
1190  * \param be_csma_seed1 Is a combined argument of the MIN_BE, MAX_CSMA_RETRIES
1191  * and SEED1 variables:
1192  * -# MIN_BE: Bit[7:6] Minimum back-off exponent in the
1193  * CSMA/CA algorithm.
1194  * -# MAX_CSMA_RETRIES: Bit[5:3] Number of retries in
1195  * TX_ARET_ON mode to repeat the CSMA/CA procedures
1196  * before the ARET procedure gives up.
1197  * -# SEED1: Bits[2:0] Higher 3 bits of CSMA_SEED, bits[10:8]
1198  * Seed for the random number generator in the
1199  * CSMA/CA algorithm.
1200  * \retval RADIO_SUCCESS The CSMA algorithm was configured successfully.
1201  * \retval RADIO_WRONG_STATE This function should not be called in the
1202  * SLEEP state.
1203  */
1205 radio_configure_csma(uint8_t seed0, uint8_t be_csma_seed1)
1206 {
1207 
1208  /*Check state.*/
1209  if (radio_is_sleeping() == true){
1210  return RADIO_WRONG_STATE;
1211  }
1212 
1213  /*Extract parameters, and configure the CSMA-CA algorithm.*/
1214  uint8_t back_off_exponent = (be_csma_seed1 & 0xC0) >> 6;
1215  uint8_t csma_retries = (be_csma_seed1 & 0x38) >> 3;
1216  uint8_t seed1 = (be_csma_seed1 & 0x07);
1217 
1218  hal_subregister_write(SR_MAX_FRAME_RETRIES, 0); /* AT86RF230 rev A errata. */
1220  hal_subregister_write(SR_MIN_BE, back_off_exponent);
1223 
1224  return RADIO_SUCCESS;
1225 }
1226 
1227 /*----------------------------------------------------------------------------*/
1228 /**
1229  \brief Calibrate the internal RC oscillator
1230 
1231  This function calibrates the internal RC oscillator, based
1232  on the 1 MHz clock supplied by the AT86RF2xx. In order to
1233  verify the calibration result you can program the CKOUT fuse
1234  and monitor the CPU clock on an I/O pin.
1235 
1236  \return TRUE if calibrate passed; FALSE if calibrate failed.
1237 */
1238 bool
1240 {
1241  bool success = false;
1242 
1243  /* Use the 1 MHz CLK_M from the AT86RF230. */
1244  uint16_t temp, counter;
1245  uint8_t osccal_saved;
1246  uint8_t tccr2b, tccr1b, tccr1a;
1247 
1248  /* in the following line, 1000000ULL represents the 1MHz input signal */
1249  /* from the radio. 265 is the number of counts to overflow 8-bit */
1250  /* timer 2. 32 is the divide by 32 prescaler for timer 1. F_CPU is */
1251  /* the main clock frequency. */
1252 #define TARGETVAL ((1000000ULL * 256 * 32) / F_CPU)
1253 
1254 
1255  osccal_saved = OSCCAL;
1256  cli();
1257 
1259 
1260  /* Save current values of timer status. */
1261  tccr2b = TCCR2B;
1262  tccr1b = TCCR1B;
1263  tccr1a = TCCR1A;
1264 
1265  /* Stop timers 1 and 2. */
1266  /* Set timer 1 to normal mode (no CTC, no PWM, just count). */
1267  TCCR2B = 0;
1268  TCCR1B = 0;
1269  TCCR1A = 0;
1270 
1271  for (counter = 0; counter < 1000; counter++){
1272  /* Delete pending timer 1 and 2 interrupts, and clear the */
1273  /* counters. */
1274  TIFR1 = 0xFF;
1275  TIFR2 = 0xFF;
1276  TCNT2 = 0;
1277  TCNT1 = 0;
1278  /* Timer 2 driven from clock divided by 32 */
1279  TCCR2B = (1 << CS21) | (1 << CS20);
1280  /* Timer 1 driven with external clock */
1281  TCCR1B = (1 << CS12) | (1 << CS11);
1282 
1283  /* Wait for timer 2 to overflow. */
1284  while (!(TIFR2 & (1 << TOV2))){
1285  ;
1286  }
1287 
1288  /* Stop timer 1. Now, TCNT1 contains the number of CPU cycles */
1289  /* counted while timer 2 was counting */
1290  TCCR1B = 0;
1291  TCCR2B = 0;
1292 
1293  temp = TCNT1;
1294 
1295  if (temp < (uint16_t)(0.995 * TARGETVAL)){
1296  /* Too fast, slow down */
1297  OSCCAL--;
1298  } else if (temp > (uint16_t)(1.005 * TARGETVAL)){
1299  /* Too slow, speed up */
1300  OSCCAL++;
1301  } else {
1302  /* We are within +/- 0.5 % of our target frequency, so we're */
1303  /* done. */
1304  success = true;
1305  break;
1306  }
1307  }
1308 
1309  radio_set_clock_speed(true, CLKM_DISABLED);
1310 
1311  /* restore timer status regs */
1312  TCCR2B = tccr2b;
1313  TCCR1B = tccr1b;
1314  TCCR1A = tccr1a;
1315  if (!success){
1316  /* We failed, therefore restore previous OSCCAL value. */
1317  OSCCAL = osccal_saved;
1318  }
1319 
1320  return success;
1321 }
1322 
1323 /*----------------------------------------------------------------------------*/
1324 /**
1325  \brief Calibrate the internal RC oscillator
1326 
1327  This function calibrates the internal RC oscillator, based
1328  on an external 32KHz crystal connected to TIMER2. In order to
1329  verify the calibration result you can program the CKOUT fuse
1330  and monitor the CPU clock on an I/O pin.
1331 */
1332 void
1334 {
1335  /* Calibrate RC Oscillator: The calibration routine is done by clocking TIMER2
1336  * from the external 32kHz crystal while running an internal timer simultaneously.
1337  * The internal timer will be clocked at the same speed as the internal RC
1338  * oscillator, while TIMER2 is running at 32768 Hz. This way it is not necessary
1339  * to use a timed loop, and keep track cycles in timed loop vs. optimization
1340  * and compiler.
1341  */
1342  uint8_t osccal_original = OSCCAL;
1343  volatile uint16_t temp;
1344 
1345  /* This is bad practice, but seems to work. */
1346  OSCCAL = 0x80;
1347 
1348 
1349  // PRR0 &= ~((1 << PRTIM2)|(1 << PRTIM1)); /* Enable Timer 1 and 2 */
1350 
1351  TIMSK2 = 0x00; /* Disable Timer/Counter 2 interrupts. */
1352  TIMSK1 = 0x00; /* Disable Timer/Counter 1 interrupts. */
1353 
1354  /* Enable TIMER/COUNTER 2 to be clocked from the external 32kHz clock crystal.
1355  * Then wait for the timer to become stable before doing any calibration.
1356  */
1357  ASSR |= (1 << AS2);
1358  while (ASSR & ((1 << TCN2UB)|(1 << OCR2AUB)|(1 << TCR2AUB)|(1 << TCR2BUB))) { ; }
1359  TCCR2B = 1 << CS20; /* run timer 2 at divide by 1 (32KHz) */
1360 
1362 
1363  uint8_t counter = 128;
1364  bool cal_ok = false;
1365  do{
1366  /* wait for timer to be ready for updated config */
1367  TCCR1B = 1 << CS10;
1368 
1369  while (ASSR & ((1 << TCN2UB)|(1 << OCR2AUB)|(1 << TCR2AUB)|(1 << TCR2BUB))) { ; }
1370 
1371  TCNT2 = 0x80;
1372  TCNT1 = 0;
1373 
1374  TIFR2 = 0xFF;
1375 
1376  /* Wait for TIMER/COUNTER 2 to overflow. Stop TIMER/COUNTER 1 and 2, and
1377  * read the counter value of TIMER/COUNTER 1. It will now contain the
1378  * number of cpu cycles elapsed within the period.
1379  */
1380  while (!(TIFR2 & (1 << TOV2))){
1381  ;
1382  }
1383  temp = TCNT1;
1384 
1385  TCCR1B = 0;
1386 
1387 #define cal_upper (31250*1.05) // 32812 = 0x802c
1388 #define cal_lower (31250*0.95) // 29687 = 0x73f7
1389  /* Iteratively reduce the error to be within limits */
1390  if (temp < cal_lower) {
1391  /* Too slow. Put the hammer down. */
1392  OSCCAL++;
1393  } else if (temp > cal_upper) {
1394  /* Too fast, retard. */
1395  OSCCAL--;
1396  } else {
1397  /* The CPU clock frequency is now within +/- 0.5% of the target value. */
1398  cal_ok = true;
1399  }
1400 
1401  counter--;
1402  } while ((counter != 0) && (false == cal_ok));
1403 
1404  if (true != cal_ok) {
1405  /* We failed, therefore restore previous OSCCAL value. */
1406  OSCCAL = osccal_original;
1407  }
1408 
1409  TCCR2B = 0;
1410 
1411  ASSR &= ~(1 << AS2);
1412 
1413  /* Disable both timers again to save power. */
1414  // PRR0 |= (1 << PRTIM2);/* |(1 << PRTIM1); */
1415 
1417 }
1418 
1419 /** @} */
1420 /** @} */
1421 /*EOF*/