⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cc1000controlp.nc

📁 tinyos-2.x.rar
💻 NC
字号:
/* $Id: CC1000ControlP.nc,v 1.5 2008/06/26 04:39:06 regehr Exp $
 * "Copyright (c) 2000-2005 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 * Copyright (c) 2002-2005 Intel Corporation
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE     
 * file. If you do not find these files, copies can be found by writing to
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
 * 94704.  Attention:  Intel License Inquiry.
 */
#include "CC1000Const.h"
#include "Timer.h"

/**
 * This module provides the CONTROL functionality for the Chipcon1000
 * series radio.  It exports a custom interface to control CC1000
 * operation.
 *
 * @author Philip Buonadonna
 * @author Jaein Jeong
 * @author David Gay
 */
module CC1000ControlP @safe() {
  provides {
    interface CC1000Control;
  }
  uses {
    interface HplCC1000 as CC;
    interface BusyWait<TMicro, uint16_t>;
  }
}
implementation
{
  uint8_t txCurrent, rxCurrent, power;

  enum {
    IF = 150000,
    FREQ_MIN = 4194304,
    FREQ_MAX = 16751615
  };

  const_uint32_t fRefTbl[9] = {2457600,
			       2106514,
			       1843200,
			       1638400,
			       1474560,
			       1340509,
			       1228800,
			       1134277,
			       1053257};
  
  const_uint16_t corTbl[9] = {1213,
			      1416,
			      1618,
			      1820,
			      2022,
			      2224,
			      2427,
			      2629,
			      2831};
  
  const_uint16_t fSepTbl[9] = {0x1AA,
			       0x1F1,
			       0x238,
			       0x280,
			       0x2C7,
			       0x30E,
			       0x355,
			       0x39C,
			       0x3E3};
  
  void calibrateNow() {
    // start cal
    call CC.write(CC1K_CAL,
		  1 << CC1K_CAL_START |
		  1 << CC1K_CAL_WAIT |
		  6 << CC1K_CAL_ITERATE);
    while ((call CC.read(CC1K_CAL) & 1 << CC1K_CAL_COMPLETE) == 0)
      ;

    //exit cal mode
    call CC.write(CC1K_CAL, 1 << CC1K_CAL_WAIT | 6 << CC1K_CAL_ITERATE);
  }

  void calibrate() {
    call CC.write(CC1K_PA_POW, 0x00);  // turn off rf amp
    call CC.write(CC1K_TEST4, 0x3f);   // chip rate >= 38.4kb

    // RX - configure main freq A
    call CC.write(CC1K_MAIN, 1 << CC1K_TX_PD | 1 << CC1K_RESET_N);

    calibrateNow();

    // TX - configure main freq B
    call CC.write(CC1K_MAIN,
		  1 << CC1K_RXTX |
		  1 << CC1K_F_REG |
		  1 << CC1K_RX_PD | 
		  1 << CC1K_RESET_N);
    // Set TX current
    call CC.write(CC1K_CURRENT, txCurrent);
    call CC.write(CC1K_PA_POW, 0);

    calibrateNow();
    
    call CC1000Control.rxMode();
  }

  /*
   * cc1000ComputeFreq(uint32_t desiredFreq);
   *
   * Compute an achievable frequency and the necessary CC1K parameters from
   * a given desired frequency (Hz). The function returns the actual achieved
   * channel frequency in Hz.
   *
   * This routine assumes the following:
   *  - Crystal Freq: 14.7456 MHz
   *  - LO Injection: High
   *  - Separation: 64 KHz
   *  - IF: 150 KHz
   * 
   * Approximate costs for this function:
   *  - ~870 bytes FLASH
   *  - ~32 bytes RAM
   *  - 9400 cycles
   */
  uint32_t cc1000SetFrequency(uint32_t desiredFreq) {
    uint32_t ActualChannel = 0;
    uint32_t RXFreq = 0, TXFreq = 0;
    int32_t Offset = 0x7fffffff;
    uint16_t FSep = 0;
    uint8_t RefDiv = 0;
    uint8_t i, match, frontend;

    for (i = 0; i < 9; i++)
      {
	uint32_t NRef = desiredFreq + IF;
	uint32_t FRef = read_uint32_t(&fRefTbl[i]);
	uint32_t Channel = 0;
	uint32_t RXCalc = 0, TXCalc = 0;
	int32_t  diff;

	NRef = ((desiredFreq + IF)  <<  2) / FRef;
	if (NRef & 0x1)
	  NRef++;

	if (NRef & 0x2)
	  {
	    RXCalc = 16384 >> 1;
	    Channel = FRef >> 1;
	  }

	NRef >>= 2;

	RXCalc += (NRef * 16384) - 8192;
	if ((RXCalc < FREQ_MIN) || (RXCalc > FREQ_MAX)) 
	  continue;
    
	TXCalc = RXCalc - read_uint16_t(&corTbl[i]);
	if (TXCalc < FREQ_MIN || TXCalc > FREQ_MAX)
	  continue;

	Channel += NRef * FRef;
	Channel -= IF;

	diff = Channel - desiredFreq;
	if (diff < 0)
	  diff = -diff;

	if (diff < Offset)
	  {
	    RXFreq = RXCalc;
	    TXFreq = TXCalc;
	    ActualChannel = Channel;
	    FSep = read_uint16_t(&fSepTbl[i]);
	    RefDiv = i + 6;
	    Offset = diff;
	  }
      }

    if (RefDiv != 0)
      {
	call CC.write(CC1K_FREQ_0A, RXFreq);
	call CC.write(CC1K_FREQ_1A, RXFreq >> 8);
	call CC.write(CC1K_FREQ_2A, RXFreq >> 16);

	call CC.write(CC1K_FREQ_0B, TXFreq);
	call CC.write(CC1K_FREQ_1B, TXFreq >> 8);
	call CC.write(CC1K_FREQ_2B, TXFreq >> 16);

	call CC.write(CC1K_FSEP0, FSep);
	call CC.write(CC1K_FSEP1, FSep >> 8);

	if (ActualChannel < 500000000)
	  {
	    if (ActualChannel < 400000000)
	      {
		rxCurrent = 8 << CC1K_VCO_CURRENT | 1 << CC1K_LO_DRIVE;
		txCurrent = 9 << CC1K_VCO_CURRENT | 1 << CC1K_PA_DRIVE;
	      }
	    else
	      {
		rxCurrent = 4 << CC1K_VCO_CURRENT | 1 << CC1K_LO_DRIVE;
		txCurrent = 8 << CC1K_VCO_CURRENT | 1 << CC1K_PA_DRIVE;
	      }
	    frontend = 1 << CC1K_IF_RSSI;
	    match = 7 << CC1K_RX_MATCH;
	  }
	else
	  {
	    rxCurrent = 8 << CC1K_VCO_CURRENT | 3 << CC1K_LO_DRIVE;
	    txCurrent = 15 << CC1K_VCO_CURRENT | 3 << CC1K_PA_DRIVE;

	    frontend =
	      1 << CC1K_BUF_CURRENT | 2 << CC1K_LNA_CURRENT | 
	      1 << CC1K_IF_RSSI;
	    match = 2 << CC1K_RX_MATCH; // datasheet says to use 1...
	  }
	call CC.write(CC1K_CURRENT, rxCurrent);
	call CC.write(CC1K_MATCH, match);
	call CC.write(CC1K_FRONT_END, frontend);
	call CC.write(CC1K_PLL, RefDiv << CC1K_REFDIV);
      }

    return ActualChannel;
  }

  command void CC1000Control.init() {
    call CC.init();

    // wake up xtal and reset unit
    call CC.write(CC1K_MAIN,
		  1 << CC1K_RX_PD | 1 << CC1K_TX_PD | 
		  1 << CC1K_FS_PD | 1 << CC1K_BIAS_PD); 
    // clear reset.
    call CC1000Control.coreOn();
    call BusyWait.wait(2000);

    // Set default parameter values
    // POWER: 0dbm (~900MHz), 6dbm (~430MHz)
    power = 8 << CC1K_PA_HIGHPOWER | 0 << CC1K_PA_LOWPOWER;
    call CC.write(CC1K_PA_POW, power);

    // select Manchester Violation for CHP_OUT
    call CC.write(CC1K_LOCK_SELECT, 9 << CC1K_LOCK_SELECT);

    // Default modem values = 19.2 Kbps (38.4 kBaud), Manchester encoded
    call CC.write(CC1K_MODEM2, 0);
    call CC.write(CC1K_MODEM1, 
		  3 << CC1K_MLIMIT |
		  1 << CC1K_LOCK_AVG_MODE | 
		  3 << CC1K_SETTLING |
		  1 << CC1K_MODEM_RESET_N);
    call CC.write(CC1K_MODEM0, 
		  5 << CC1K_BAUDRATE |
		  1 << CC1K_DATA_FORMAT | 
		  1 << CC1K_XOSC_FREQ);

    call CC.write(CC1K_FSCTRL, 1 << CC1K_FS_RESET_N);

#ifdef CC1K_DEF_FREQ
    call CC1000Control.tuneManual(CC1K_DEF_FREQ);
#else
    call CC1000Control.tunePreset(CC1K_DEF_PRESET);
#endif
    call CC1000Control.off();
  }

  command void CC1000Control.tunePreset(uint8_t freq) {
    int i;

    // FREQA, FREQB, FSEP, CURRENT(RX), FRONT_END, POWER, PLL
    for (i = CC1K_FREQ_2A; i <= CC1K_PLL; i++)
      call CC.write(i, read_uint8_t(&CC1K_Params[freq][i]));
    call CC.write(CC1K_MATCH, read_uint8_t(&CC1K_Params[freq][CC1K_MATCH]));
    rxCurrent = read_uint8_t(&CC1K_Params[freq][CC1K_CURRENT]);
    txCurrent = read_uint8_t(&CC1K_Params[freq][CC1K_MATCH + 1]);
    power = read_uint8_t(&CC1K_Params[freq][CC1K_PA_POW]);

    calibrate();
  }

  command uint32_t CC1000Control.tuneManual(uint32_t DesiredFreq) {
    uint32_t actualFreq;

    actualFreq = cc1000SetFrequency(DesiredFreq);

    calibrate();

    return actualFreq;
  }

  async command void CC1000Control.txMode() {
    // MAIN register to TX mode
    call CC.write(CC1K_MAIN,
		  1 << CC1K_RXTX |
		  1 << CC1K_F_REG |
		  1 << CC1K_RX_PD | 
		  1 << CC1K_RESET_N);
    // Set the TX mode VCO Current
    call CC.write(CC1K_CURRENT, txCurrent);
    call BusyWait.wait(250);
    call CC.write(CC1K_PA_POW, power);
    call BusyWait.wait(20);
  }

  async command void CC1000Control.rxMode() {
    // MAIN register to RX mode
    // Powerup Freqency Synthesizer and Receiver
    call CC.write(CC1K_CURRENT, rxCurrent);
    call CC.write(CC1K_PA_POW, 0); // turn off power amp
    call CC.write(CC1K_MAIN, 1 << CC1K_TX_PD | 1 << CC1K_RESET_N);
    call BusyWait.wait(125);
  }

  async command void CC1000Control.coreOn() {
    // MAIN register to SLEEP mode
    call CC.write(CC1K_MAIN,
		  1 << CC1K_RX_PD |
		  1 << CC1K_TX_PD | 
		  1 << CC1K_FS_PD |
		  1 << CC1K_BIAS_PD |
		  1 << CC1K_RESET_N);
  }

  async command void CC1000Control.biasOn() {
    call CC.write(CC1K_MAIN,
		  1 << CC1K_RX_PD |
		  1 << CC1K_TX_PD | 
		  1 << CC1K_FS_PD | 
		  1 << CC1K_RESET_N);
  }


  async command void CC1000Control.off() {
    // MAIN register to power down mode. Shut everything off
    call CC.write(CC1K_MAIN,
		  1 << CC1K_RX_PD |
		  1 << CC1K_TX_PD | 
		  1 << CC1K_FS_PD |
		  1 << CC1K_CORE_PD |
		  1 << CC1K_BIAS_PD |
		  1 << CC1K_RESET_N);
    call CC.write(CC1K_PA_POW, 0);  // turn off rf amp
  }

  command void CC1000Control.setRFPower(uint8_t newPower) {
    power = newPower;
  }

  command uint8_t CC1000Control.getRFPower() {
    return power;
  }

  command void CC1000Control.selectLock(uint8_t fn) {
    // Select function of CHP_OUT pin (readable via getLock)
    call CC.write(CC1K_LOCK, fn << CC1K_LOCK_SELECT);
  }

  command uint8_t CC1000Control.getLock() {
    return call CC.getLOCK(); 
  }

  command bool CC1000Control.getLOStatus() {
    // We use a high-side LO (local oscillator) frequency -> data will be
    // inverted. See cc1000ComputeFreq and CC1000 datasheet p.23.
    return TRUE;
  }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -