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: RTC

Part Number: MSP430F1611
Other Parts Discussed in Thread: MSP430FR4133,

Dear all,

I am trying to interface TelosB with external device called smartmesh mote "www.linear.com/.../4330".

Here, the example they used for interfacing to the mote was MSP430fr4133 launch pad which is quite different from TelosB(msp430f1611).

Referring to the code, LCD functions are not concerned at initialising board can be done seperately with my existing code. 

The part I am stuck in with is this part of code:

void fsm_scheduleEvent(uint16_t delay, fsm_timer_callback cb) {
   
   // remember what function to call
   app_vars.fsmCb       = cb;
   
   // configure/start the RTC
   RTCCTL               =  0;
   RTCMOD               =  delay;                // delay (in 32kHz clock cycles)
   RTCCTL              |=  RTCIE;                // enable interrupts
   RTCCTL              |=  RTCPS_0;              // divider /1
   RTCCTL              |=  RTCSS_2;              // clock source is XT1CLK
   RTCCTL              |=  RTCSR;                // reset the RTC
}

Please correct me if I am wrong, but as far as I know for MSP430f1611, there is no RTC library available.

Could anyone direct me how to go about with this?

full code is attached in this post.

Thank you

Kind regards

#include "board.h"
#include <stdint.h>
#include "dn_ipmt.h"

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

// mote state
#define MOTE_STATE_IDLE           0x01
#define MOTE_STATE_SEARCHING      0x02
#define MOTE_STATE_NEGOCIATING    0x03
#define MOTE_STATE_CONNECTED      0x04
#define MOTE_STATE_OPERATIONAL    0x05

// service types
#define SERVICE_TYPE_BW           0x00

// timings
#define SERIAL_RESPONSE_TIMEOUT   16384          // 16384@32kHz = 500ms
#define CMD_PERIOD                32768          // 32768@32kHz = 1s
#define ONE_SEC                   32768          // 32768@32kHz = 1s
#define DATA_PERIOD_S                10          // number of second between data packets

// app
#define NUM_STEPS                 8
#define DIRECTION_UP              1
#define DIRECTION_DOWN            0

// api
#define SRC_PORT                  0xf0b8
#define DST_PORT                  0xf0b8

//=========================== typedef =========================================

typedef void (*fsm_timer_callback)(void);
typedef void (*fsm_reply_callback)(void);

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

typedef struct {
   // fsm
   fsm_timer_callback   fsmCb;
   // reply
   fsm_reply_callback   replyCb;
   // app
   uint8_t              counter;
   uint8_t              secUntilTx;
   uint8_t              direction;
   // api
   uint8_t              socketId;                          // ID of the mote's UDP socket
   uint8_t              replyBuf[MAX_FRAME_LENGTH];        // holds notifications from ipmt
   uint8_t              notifBuf[MAX_FRAME_LENGTH];        // notifications buffer internal to ipmt
} app_vars_t;

app_vars_t app_vars;

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

// fsm
void fsm_scheduleEvent(uint16_t delay, fsm_timer_callback cb);
void fsm_cancelEvent(void);
void fsm_setCallback(fsm_reply_callback cb);
// ipmt
void dn_ipmt_notif_cb(uint8_t cmdId, uint8_t subCmdId);
void dn_ipmt_reply_cb(uint8_t cmdId);
// app
uint16_t nextValue(void);
// api
void api_response_timeout(void);
void api_getMoteStatus(void);
void api_getMoteStatus_reply(void);
void api_openSocket(void);
void api_openSocket_reply(void);
void api_bindSocket(void);
void api_bindSocket_reply(void);
void api_join(void);
void api_join_reply(void);
void api_sendTo(void);
void api_sendTo_reply(void);

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

int main(void) {
   // hold the watchdog timer
   WDTCTL     =  WDTPW + WDTHOLD;
   
   // initialize board
   board_init();
   
   // reset local variables
   memset(&app_vars,0,sizeof(app_vars));
   
   // initialize the ipmt module
   dn_ipmt_init(
      dn_ipmt_notif_cb,                // notifCb
      app_vars.notifBuf,               // notifBuf
      sizeof(app_vars.notifBuf),       // notifBufLen
      dn_ipmt_reply_cb                 // replyCb
   );
   
   // schedule the first event
   fsm_scheduleEvent(CMD_PERIOD, &api_getMoteStatus);
   
   __bis_SR_register(LPM0_bits | GIE);
}

//=========================== private =========================================

//===== fsm

void fsm_scheduleEvent(uint16_t delay, fsm_timer_callback cb) {
   
   // remember what function to call
   app_vars.fsmCb       = cb;
   
   // configure/start the RTC
   RTCCTL               =  0;
   RTCMOD               =  delay;                // delay (in 32kHz clock cycles)
   RTCCTL              |=  RTCIE;                // enable interrupts
   RTCCTL              |=  RTCPS_0;              // divider /1
   RTCCTL              |=  RTCSS_2;              // clock source is XT1CLK
   RTCCTL              |=  RTCSR;                // reset the RTC
}

void fsm_cancelEvent(void) {
   // stop the RTC
   RTCCTL               =  0;
   
   // clear function to call
   app_vars.fsmCb       = NULL;
}

void fsm_setCallback(fsm_reply_callback cb) {
   app_vars.replyCb     = cb;
}

//===== ipmt

void dn_ipmt_notif_cb(uint8_t cmdId, uint8_t subCmdId) {
   dn_ipmt_events_nt* dn_ipmt_events_notif;
   
   switch (cmdId) {
      case CMDID_EVENTS:
         
         // parse notification
         dn_ipmt_events_notif = (dn_ipmt_events_nt*)app_vars.notifBuf;
         
         switch (dn_ipmt_events_notif->state) {
            case MOTE_STATE_IDLE:
               fsm_scheduleEvent(CMD_PERIOD,api_getMoteStatus);
               break;
            case MOTE_STATE_OPERATIONAL:
               fsm_scheduleEvent(CMD_PERIOD,api_sendTo);
               break;
            default:
               // nothing to do
               break;
         }
         break;
      default:
         // nothing to do
         break;
   }
}

void dn_ipmt_reply_cb(uint8_t cmdId) {
   app_vars.replyCb();
}

//===== app

uint16_t nextValue(void) {
   uint16_t newValue;
   
   // decide whether to go up or down
   if (app_vars.counter==0) {
      app_vars.direction = DIRECTION_UP;
   }
   if (app_vars.counter==NUM_STEPS-1) {
      app_vars.direction = DIRECTION_DOWN;
   }
   
   // calculate new value
   if (app_vars.direction==DIRECTION_UP) {
      app_vars.counter++;
   } else {
      app_vars.counter--;
   }
   
   newValue  = 0x10000/NUM_STEPS;
   newValue *= app_vars.counter;
   
   return newValue;
}

//===== api

void api_response_timeout(void) {
  // issue cancel command
   dn_ipmt_cancelTx();
   
   // schedule first event
   fsm_scheduleEvent(CMD_PERIOD, &api_getMoteStatus);
}

//=== getMoteStatus

void api_getMoteStatus(void) {
   
  
   // arm callback
   fsm_setCallback(api_getMoteStatus_reply);
   
   // issue function
   dn_ipmt_getParameter_moteStatus(
      (dn_ipmt_getParameter_moteStatus_rpt*)(app_vars.replyBuf)
   );
   
   // schedule timeout event
   fsm_scheduleEvent(SERIAL_RESPONSE_TIMEOUT, api_response_timeout);
}

void api_getMoteStatus_reply(void) {
   dn_ipmt_getParameter_moteStatus_rpt* reply;
   
   // cancel timeout
   fsm_cancelEvent();
   
   // parse reply
   reply = (dn_ipmt_getParameter_moteStatus_rpt*)app_vars.replyBuf;
   
   // choose next step
   switch (reply->state) {
      case MOTE_STATE_IDLE:
         fsm_scheduleEvent(CMD_PERIOD, &api_openSocket);
         break;
      case MOTE_STATE_OPERATIONAL:
         fsm_scheduleEvent(CMD_PERIOD,api_sendTo);
         break;
      default:
         fsm_scheduleEvent(CMD_PERIOD, api_getMoteStatus);
         break;
   }
}

//=== openSocket

void api_openSocket(void) {
  
   // arm callback
   fsm_setCallback(api_openSocket_reply);
   
   // issue function
   dn_ipmt_openSocket(
      0,                                              // protocol
      (dn_ipmt_openSocket_rpt*)(app_vars.replyBuf)    // reply
   );
   
   // schedule timeout event
   fsm_scheduleEvent(SERIAL_RESPONSE_TIMEOUT, api_response_timeout);
}

void api_openSocket_reply(void) {
   dn_ipmt_openSocket_rpt* reply;
   
   // cancel timeout
   fsm_cancelEvent();
   
   // parse reply
   reply = (dn_ipmt_openSocket_rpt*)app_vars.replyBuf;
   
   // store the socketID
   app_vars.socketId = reply->socketId;
   
   // choose next step
   fsm_scheduleEvent(CMD_PERIOD, api_bindSocket);
}

//===== bindSocket

void api_bindSocket(void) {
   
   
   // arm callback
   fsm_setCallback(api_bindSocket_reply);
   
   // issue function
   dn_ipmt_bindSocket(
      app_vars.socketId,                              // socketId
      SRC_PORT,                                       // port
      (dn_ipmt_bindSocket_rpt*)(app_vars.replyBuf)    // reply
   );
   
   // schedule timeout event
   fsm_scheduleEvent(SERIAL_RESPONSE_TIMEOUT, api_response_timeout);
}

void api_bindSocket_reply(void) {
   // cancel timeout
   fsm_cancelEvent();
   
   // choose next step
   fsm_scheduleEvent(CMD_PERIOD, api_join);
}

//===== join

void api_join(void) {
   
   
   // arm callback
   fsm_setCallback(api_join_reply);
   
   // issue function
   dn_ipmt_join(
      (dn_ipmt_join_rpt*)(app_vars.replyBuf)     // reply
   );
   
   // schedule timeout event
   fsm_scheduleEvent(SERIAL_RESPONSE_TIMEOUT, api_response_timeout);
}

void api_join_reply(void) {
   // cancel timeout
   fsm_cancelEvent();
   
   // choose next step
   // no next step at this point. FSM will advance when we received a "joined"
   // notification
}

//===== sendTo

void api_sendTo(void) {
   uint8_t  payload[2];
   uint8_t  dest_addr[16];
   
   // send only every DATA_PERIOD_S seconds
   if (app_vars.secUntilTx>0) {
      // decrement number of second to still wait
      app_vars.secUntilTx--;
      
      // cancel timeout
      fsm_cancelEvent();
      
      // choose next step
      fsm_scheduleEvent(ONE_SEC, api_sendTo);
      
      return;
   } else {
      app_vars.secUntilTx = DATA_PERIOD_S;
   }
   
   // arm callback
   fsm_setCallback(api_sendTo_reply);
   
   // create payload
   dn_write_uint16_t(payload, nextValue());
   memcpy(dest_addr,ipv6Addr_manager,16);
   
   // issue function
   dn_ipmt_sendTo(
      app_vars.socketId,                                   // socketId
      dest_addr,                                           // destIP
      DST_PORT,                                            // destPort
      SERVICE_TYPE_BW,                                     // serviceType
      0,                                                   // priority
      0xffff,                                              // packetId
      payload,                                             // payload
      sizeof(payload),                                     // payloadLen
      (dn_ipmt_sendTo_rpt*)(app_vars.replyBuf)             // reply
   );
   
   // schedule timeout event
   fsm_scheduleEvent(SERIAL_RESPONSE_TIMEOUT, api_response_timeout);
}

void api_sendTo_reply(void) {
   
   // cancel timeout
   fsm_cancelEvent();
   
   // choose next step
   fsm_scheduleEvent(ONE_SEC, api_sendTo);
}

//=========================== interrupts ======================================

#pragma vector = RTC_VECTOR
__interrupt void RTC_ISR(void) {
   volatile uint16_t iv;
   iv = RTCIV;
   
   app_vars.fsmCb();
}

  • The F1611 doesn't have an RTC module per se, but you can provide some RTC-style function using an ordinary timer. If the TelosB has a 32kHz (XT1) crystal, I suggest using ACLK to run the timer.

    This code fragment suggests that the rest of the code doesn't ask much of the RTC, really just a one-shot delay; this isn't difficult with TimerA or TimerB. (You may want to check your current code base, to see if that function already exists.)
  • Thank you for your post.

    This is what I wrote for TelsoB, to carry out the function of RTC.

    void fsm_scheduleEvent(uint16_t delay, fsm_timer_callback cb) {
       
       // remember what function to call
       app_vars.fsmCb       = cb;
       
       // configure/start the RTC
       RTCCTL               =  0;
       RTCMOD               =  delay;                // delay (in 32kHz clock cycles)
       RTCCTL              |=  RTCIE;                // enable interrupts
       RTCCTL              |=  RTCPS_0;              // divider /1
       RTCCTL              |=  RTCSS_2;              // clock source is XT1CLK
       RTCCTL              |=  RTCSR;                // reset the RTC
      
     //configure for TelosB
     TACCTL0 = CCIE; // capture/compare interrupt enable
     TACTL = TASSEL_1 | MC_1; // Select ACLK, 'counts up' mode, input divider (1)
     TACCR0 = 32786; //delay of one second to mimic the delay mode of RTC
     TACCTL0    =  OUTMOD_5; //reset the timer, but not sure whether this is needed because it will reset after it's counted to 32786.
    }
    #pragma vector = RTC_VECTOR
    __interrupt void RTC_ISR(void) {
       volatile uint16_t iv;
       iv = RTCIV;
       
       app_vars.fsmCb();
    }
    
    //brief This function is called when the TimerA interrupt fires for TelosB to replace the RTC_VECTOR
    #pragma vector = TIMERA0_VECTOR
    __interrupt void TIMERA0_ISR (void) {
       volatile uint16_t iv;                  
       iv = TAIV;
    
       app_vars.fsmCb();
    }
    
    if you think I am missing out on something, please let me know
    THank you
  • I think you're on the right track (based on my reading of the intent), but

    1) There's no need to set OUTMOD. (Also, the way you're doing it clears CCIE.)
    2) Set CCR0 to be ="delay", not 32768.

    > TACCTL0 = CCIE; // capture/compare interrupt enable
    > TACCR0 = delay; //delay for this many (32kHz) ticks to mimic the delay mode of RTC
    > TACTL = TASSEL_1 | MC_2|TACLR; // Select ACLK, continuous mode, input divider (1), restart at 0.

    I've also changed one subtle thing: By using continuous mode (MC_2), you can be fairly sure you can stop the timer in time, even for very short delays.

    3) In the ISR, don't read TAIV (it isn't relevant), but do stop the timer with
    > TACTL= 0;
    It seems a bit odd that the RTC code doesn't do that. Maybe they suppose that this function will be called again in less than 1 second?

**Attention** This is a public forum