This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP430F1611: Clock Drift Compensation.

Part Number: MSP430F1611
Other Parts Discussed in Thread: CC2420

Dear all,

I am using TelosB which is mounted with CC2420 for radio communication.

Here I am trying to achieve clock synchronisation between the TelosB, and to the clock of the network.

So far, I have managed to retrieve the clock of the network.

The system works as follows:

  1. The tag starts its own counter which increments 7.25ms
  2. (The value of counter * 7.25)/(10^-6) to convert the value is microseconds.
  3. The tag only receives if the data packet is the right type.
  4. Value of clock from the network is also multiplied by 7.25ms to compare with the counter of the tag.
  5. These will be compared, and if the difference between two values are bigger than 15us then it will have to sync. However, still some with error grows over the time (clock drift of the TelosB).
  6. To correct this error, need to keeping track of past network's clock and the internal counter value when they were received and calculating the ratio between the elapsed time relative to TelosB and to the network. This number is the drift coefficient and is used to correct delta.
  1.  app_vars.compensatedtime = ((app_vars.current_time - app_vars.capture_previous_time)/app_vars.alpha)+app_vars.capture_time; whre alpha is
  2. app_vars.localdelta = app_vars.current_time - app_vars.previous_time;
  3. app_vars.networkdelta = app_vars.capture_time - app_vars.capture_previous_time;
  4. app_vars.alpha = app_vars.localdelta/app_vars.networkdelta;


By doing this, I should be able to get a relative error less than 15us, which I do not. I believe that there might be a mistake I have made in my code.

The code is attached in this file, any help will be greatly appreciated.

Thank you

#include "sctimer.h"
#include "stdint.h" 
#include "string.h"
#include "stdlib.h"
#include "board.h"
#include "radio.h"
#include "leds.h"
#include "uart.h"

//=========================== defines =========================================

#define LENGTH_PACKET        125+LENGTH_CRC ///< maximum length is 127 bytes
#define CHANNEL              20             
#define LENGTH_SERIAL_FRAME  8              ///< length of the serial frame
#define LENGTH               8              ///< length of the serial frame

//=========================== variables =======================================

typedef struct {
   //radio
   uint8_t    num_startFrame;
   uint8_t    num_endFrame;

   //ultrasound
   uint8_t    num_startUSFrame;
   uint8_t    num_endUSFrame;

} app_dbg_t;

app_dbg_t app_dbg;

typedef struct {
   // rx packet
   volatile   uint8_t    rxpk_done;
              uint8_t    rxpk_buf[LENGTH_PACKET];
              uint8_t    rxpk_len;
   // uart
              uint8_t    uart_txFrame[LENGTH_SERIAL_FRAME];
              uint8_t    uart_counterFrame[LENGTH];
              uint8_t    uart_counterByte;
              uint8_t    uart_lastTxByte;
   volatile   uint8_t    uart_done;
   volatile   uint8_t    uart_counterdone;

   //ASN

   volatile   uint64_t   ASN;
   volatile   uint64_t   num_asn;
   volatile   uint64_t   alpha;
   volatile   float   localdelta;
   volatile   float   networkdelta;
   volatile   float   previous_time;
   volatile   float   current_time;
   volatile   float   capture_previous_time;
   volatile   float   capture_time;
   volatile   float   compensatedtime;

} app_vars_t;

app_vars_t app_vars;


//=========================== prototypes ======================================

// radio
void cb_startFrame(PORT_TIMER_WIDTH timestamp);
void cb_endFrame(PORT_TIMER_WIDTH timestamp);

// uart
void cb_uartTxDone(void);

//ASN counter
void cb_asncounter(void);


//=========================== main ============================================

int mote_main(void) {
   
   // clear local variables
   memset(&app_vars,0,sizeof(app_vars_t));
   
   // initialize board
   board_init();


   // set asn counter
   sctimer_setasnreadCb(cb_asncounter);
   
   // add callback functions radio
   sctimer_setStartFrameCb(cb_startFrame);
   sctimer_setEndFrameCb(cb_endFrame);
   
   // setup UART
   uart_setCallbacks(cb_uartTxDone);
   
   // prepare radio
   radio_rfOn();
   radio_setFrequency(CHANNEL);
   
   // switch in RX
   radio_rxEnable();
   radio_rxNow();
   
   while (1) {
      
      // sleep while waiting for at least one of the rxpk_done to be set
      app_vars.rxpk_done = 0;
      while (app_vars.rxpk_done  == 0) {
         board_sleep();
      
      }
      
      // if I get here, I just received a packet
      
      //===== send notification over serial port
      
      // format frame to send over serial port, displays the value of ASN retrieved from the manager
      if (app_vars.rxpk_buf[0] == 0x08){

      app_vars.uart_txFrame[0] = app_vars.rxpk_buf[17];  // ASN #1
      app_vars.uart_txFrame[1] = app_vars.rxpk_buf[18];  // ASN #2
      app_vars.uart_txFrame[2] = app_vars.rxpk_buf[19];  // ASN #3
      app_vars.uart_txFrame[3] = app_vars.rxpk_buf[20];  // ASN #4
      app_vars.uart_txFrame[4] = app_vars.rxpk_buf[21];  // ASN #5
      app_vars.uart_txFrame[5] = 0xff;                   // closing flag
      app_vars.uart_txFrame[6] = 0xff;                   // closing flag
      app_vars.uart_txFrame[7] = 0xff;                   // closing flag

      //app_vars.uart_done          = 0;
      //app_vars.uart_lastTxByte    = 0;

      app_vars.ASN = (uint64_t)app_vars.uart_txFrame[0] + ((uint64_t)app_vars.uart_txFrame[1]<<8) + ((uint64_t)app_vars.uart_txFrame[2]<<16)+((uint64_t)app_vars.uart_txFrame[3]<<24)+((uint64_t)app_vars.uart_txFrame[4]<<32);
      app_vars.capture_time = (app_vars.ASN * 7.25)/100000;  //in us, value from the manager
      app_vars.current_time =(app_vars.num_asn*7.25)/100000; //in us, counter within TelosB

         if(app_vars.current_time - app_vars.capture_time > 15 || app_vars.capture_time - app_vars.current_time > 15){
             app_vars.current_time = app_vars.capture_time;
             leds_all_off();
      
             app_vars.compensatedtime = ((app_vars.current_time - app_vars.capture_previous_time)/app_vars.alpha)+app_vars.capture_time;
             app_vars.localdelta = app_vars.current_time - app_vars.previous_time;
             app_vars.networkdelta = app_vars.capture_time - app_vars.capture_previous_time;  
             app_vars.alpha = app_vars.localdelta/app_vars.networkdelta;
             app_vars.previous_time = app_vars.compensatedtime;             //stored compensated current-time to use it as a referece for alpha
             app_vars.capture_previous_time = app_vars.capture_time;        //stored capture_time value of ASN      
             app_vars.num_asn = (app_vars.compensatedtime*1000000)/7.25;

            /* app_vars.uart_counterFrame[0] = app_vars.compensatedtime; 
             app_vars.uart_counterFrame[1] = app_vars.compensatedtime>>8;
             app_vars.uart_counterFrame[2] = app_vars.compensatedtime>>16;
             app_vars.uart_counterFrame[3] = app_vars.compensatedtime>>24;
             app_vars.uart_counterFrame[4] = app_vars.compensatedtime>>32;
             app_vars.uart_counterFrame[5] = app_vars.compensatedtime>>40;
             app_vars.uart_counterFrame[6] = app_vars.compensatedtime>>48;
             app_vars.uart_counterFrame[7] = app_vars.compensatedtime>>56;

             app_vars.uart_done           = 0;
             app_vars.uart_lastTxByte     = 0;
             app_vars.uart_counterByte    = 0;

             // send app_vars.uart_txFrame over UART
             uart_clearTxInterrupts();
             uart_enableInterrupts();
             //uart_writeByte(app_vars.uart_txFrame[app_vars.uart_lastTxByte]);
             uart_writeByte(app_vars.uart_counterFrame[app_vars.uart_counterByte]);
             while (app_vars.uart_done==0); // busy wait to finish
             uart_disableInterrupts();*/
          }

         else {

             leds_all_on();
/*
             app_vars.uart_counterFrame[0] = app_vars.compensatedtime; 
             app_vars.uart_counterFrame[1] = app_vars.compensatedtime>>8;
             app_vars.uart_counterFrame[2] = app_vars.compensatedtime>>16;
             app_vars.uart_counterFrame[3] = app_vars.compensatedtime>>24;
             app_vars.uart_counterFrame[4] = app_vars.compensatedtime>>32;
             app_vars.uart_counterFrame[5] = app_vars.compensatedtime>>40;
             app_vars.uart_counterFrame[6] = app_vars.compensatedtime>>48;
             app_vars.uart_counterFrame[7] = app_vars.compensatedtime>>56;

             app_vars.uart_done           = 0;
             app_vars.uart_lastTxByte     = 0;
             app_vars.uart_counterByte    = 0;

             // send app_vars.uart_txFrame over UART
             uart_clearTxInterrupts();
             uart_enableInterrupts();
             //uart_writeByte(app_vars.uart_txFrame[app_vars.uart_lastTxByte]);
             uart_writeByte(app_vars.uart_counterFrame[app_vars.uart_counterByte]);
             while (app_vars.uart_done==0); // busy wait to finish
             uart_disableInterrupts();*/
            }
         } 

      else {
          app_vars.uart_done=1;
      }
   }
}


//=========================== callbacks =======================================

//===== radio

void cb_startFrame(PORT_TIMER_WIDTH timestamp) {
   
   // update debug stats
   app_dbg.num_startFrame++;

}

void cb_endFrame(PORT_TIMER_WIDTH timestamp) {
   
   // update debug stats
    app_dbg.num_endFrame++;
   // indicate I just received a packet
    app_vars.rxpk_done = 1;

   // get packet from radio
    radio_getReceivedFrame(
      app_vars.rxpk_buf,
      &app_vars.rxpk_len,
      sizeof(app_vars.rxpk_buf));
}

//==== ASN counter


void cb_asncounter(void){
   
    app_vars.num_asn++;
}

//===== uart

void cb_uartTxDone(void) {
   
   uart_clearTxInterrupts();
   
   // prepare to send the next byte
   // app_vars.uart_lastTxByte++;
   app_vars.uart_counterByte++;

/*  if (app_vars.uart_lastTxByte<sizeof(app_vars.uart_txFrame)) {
      uart_writeByte(app_vars.uart_txFrame[app_vars.uart_lastTxByte]);
   }else */if(app_vars.uart_counterByte<sizeof(app_vars.uart_counterFrame)){
         uart_writeByte(app_vars.uart_counterFrame[app_vars.uart_counterByte]);
      }
         else {
               app_vars.uart_done=1;
   }
}


  • I'm not sure the units are being used consistently here. As I understand it , 1 timer tick represents 7.25 ms (milliseconds).

    > app_vars.capture_time = (app_vars.ASN * 7.25)/100000; //in us, value from the manager
    > app_vars.current_time =(app_vars.num_asn*7.25)/100000; //in us, counter within TelosB

    After multiplying by 7.25 to get ms, you could (a) divide by 1000 to get (float) seconds, or (b) multiply by 1000 to get (integer) usec (microseconds), but this seems to do neither of those. The subsequent comparison with the value "15" seems to expect (b).

    > if(app_vars.current_time - app_vars.capture_time > 15 || app_vars.capture_time - app_vars.current_time > 15)

    Later,
    > app_vars.num_asn = (app_vars.compensatedtime*1000000)/7.25;

    This seems to expect (float) seconds, but after multiplying by 1 million to get usec, it should divide by (7.25*1000) usec to get timer ticks.
  • Dear Bruce,

    Thank you for your reply.

    You correctly so, I've made a silly mistake in terms of maths.

    here is modified code of it,

    app_vars.ASN = (uint64_t)app_vars.uart_txFrame[0] + ((uint64_t)app_vars.uart_txFrame[1]<<8) + ((uint64_t)app_vars.uart_txFrame[2]<<16)+((uint64_t)app_vars.uart_txFrame[3]<<24)+((uint64_t)app_vars.uart_txFrame[4]<<32);
    app_vars.current_network_time = (app_vars.ASN * 7.25)*1000000;      //  to get values in us
    app_vars.current_local_time = ((app_vars.num_asn * 7.25)*1000000); //  to get values in us


    // ----- before calculating the new alpha and stuff you toggle led if error is too big
    app_vars.compensated_time = (app_vars.current_local_time - app_vars.previous_local_time)*alpha + app_vars.previous_network_time;

    if (abs(app_vars.current_network_time - app_vars.compensatedtime) > 15) {
    leds_all_on();
    } else {
    leds_all_off();
    }

    // ----- calculate the new alpha
    app_vars.local_delta = app_vars.current_local_time - app_vars.previous_local_time;
    app_vars.network_delta = app_vars.current_network_time - app_vars.previous_network_time;

    if (app_vars.previous_local_time == 0) { // you don't want to calculate alpha when previous_local and previous_network are still initialized to 0
    app_vars.alpha = 1 // it should be initialized to 1 and I'm redoing it here just to make sure
    } else {
    app_vars.alpha = app_vars.local_delta / app_vars.network_delta; 
    }

    app_vars.previous_local_time = app_vars.current_local_time;
    app_vars.previous_network_time = app_vars.current_network_time;

    app_vars.num_asn = (app_vars.compensated_time/(1000000*7.25);  //to convert us to get timer ticks

     


    This seems okay for me, however I am not too sure if my code is written correctly with what I am trying to implement

  • f this code does what you want, that's good, but it (still) doesn't match your description.

    If ASN is in units of 7.25 milliseconds, then current_network_time is in units of nanoseconds. The later arithmetic with compensated_time inverts this correctly, but the comparison with "15" is in nanoseconds, not microseconds.

**Attention** This is a public forum