Sunday, 24 May 2015

Huduku - RF Object Locator using MSP430 and TI Chronos Watch




Before talking about the hardware and firmware, I will introduce RF communication.

Radio Frequency has traditionally defined frequencies from a few kHz to roughly 1 GHz. If one considers microwave frequencies as RF, this range extends to 300 GHz.

The Radio frequency waves are used for many purposes and have become synonymous with wireless communication. The RF band is used for communication in marine/aircraft navigation, mobile radio, amateur radio, cellphones, WLAN, Personal area networks, satellite communications and many other purposes. The regulatory authority prescribes the usage of RF bands and only a small RF spectrum can be used for scientific research and other activities. For, United States, this band is 902-928MHz and for Europe and India it is 868-870MHz. The basic RF communication flow is given in figure 1.





So, As a DIYer, we can use the allocated frequency spectrum for wireless communications. Texas Instruments has developed a low power RF communication protocol called SimpliciTI

SimpliciTI is a simple low-power RF network protocol aimed at small RF networks. Such networks typically contain battery operated devices which require long battery life, low data rate and low duty cycle and have a limited number of nodes talking directly to each other or through an access point or range extenders. Access point and range extenders are not required but provide extra functionality such as store and forward messages. With SimpliciTI the MCU resource requirements are minimal which results in the low system cost.

SimpliciTI was designed for easy implementation and deployment out-of-the-box on several TI RF platforms such as the MSP430 family of low-power MCUs and the CC1XXX/CC25XX/CC430 transceivers and SoCs. The sample applications run out-of-the-box on several hardware platforms:
·         SmartRF04 + CC2430EM Development Board
·         SmartRF05 + MSP430F2618 + CC2520EM Development Board
·         MSP430FG4618/F2013 Experimenter Board with CC1100EM, CC1101EM or CC2500EM
·         eZ430-RF2500 Development Tool
·         CC430 Wireless Development Tool
·         CC1110-CC1111DK and CC2510-CC2511DK
For more information, you can check TI's website: Texas Instruments.


For my project, I used Texas Instruments Chronos watch(with an on-chip CC1101 Radio core) to communicate wirelessly with CC110L chip integrated with MSP430. Broadly speaking, the CC1101 and CC110L are almost the with a very few differences. The following features are removed from the Value Line chips versus CC1101:
•  Forward error correction (FEC) and interleaving
•  Wake-on-Radio (WOR) and RCOSC (no RX timeout possible)
•  Data Whitening
•  Preamble quality threshold (PQT) indication (used to gate sync word detection)
•  Link quality (LQI) indication (received signal strength (RSSI) is supported in Value Line parts)
•  Temp sensor
•  PA ramping and shaping
•  MSK and ASK modulation (OOK modulation is supported in Value Line parts)
•  No pin control for strobe commands (SPI strobe commands need to be used)
•  ATEST removed.

eZ430 Chronos:
The eZ430-Chronos is a highly integrated, wireless development system that provides a complete reference design for developers creating wireless smart watch applications. Chronos is a reference platform for many applications, such as wireless watch systems, personal displays for personal area networks, wireless sensor nodes for remote data collection, & other applications.
TI Chronos watch, USB emulator and RF Access point

Based on the CC430F6137 <1 GHz RF SoC, the eZ430-Chronos is a complete CC430-based development system, featuring a 96 segment LCD display and provides an integrated pressure sensor and 3-axis accelerometer for motion sensitive control.
The integrated wireless feature allows the Chronos to act as a central hub for nearby wireless sensors such as pedometers and heartrate monitors. The eZ430-Chronos offers temperature and battery voltage measurement and is complete with a USB-based CC1111(kits with black PCBs) or CC1101(kits with white PCBs) wireless interface to a PC. 
The eZ430-Chronos watch may be disassembled to be reprogrammed with a custom application and includes an eZ430 USB programming interface.

For more info on TI Chronos, go to Chronos wiki.

MSP430 Launchpad
MSP430G2553 Launchpad
MSP430 LaunchPads is a microcontroller development kit from Texas Instruments based on Low power MSP430 series of Microcontrollers. They are easy to use and can be programmed via USB. 









Programming MSP430 and Chronos
MSP430 Launchpad can be programmed using Code Composer Studio ( TI | CCS) or Energia (Energia). Energia is similar to Arduino IDE, is easy to use and has library for most of the peripherals. Code Composer Studio uses Embedded C for programming, a bit difficult for beginners but, it has hardware debug support.

For my project, I have used Energia for MSP430 Launchpad and CCS for Chronos Watch.
The RF Communication Link
In RF Communication, the RF transciever has following components,
  • MCU
  • Local Oscillator (LO)
  • Power Amplifier
  • Low Noise Amplifier(LNA)
  • Balun
  • Antenna
The MCU configures the RF core to operate at
  • Particular Frequency
  • Channel Spacing
  • Data Rate
  • Channel Number
  • Data format including sync word, preamble bits, data whitening etc.
  • Frequency Calibration
  • Packet Automation Control
CC1101/CC110L Radio Core
The CC1101/CC110L Radio core has various registers that can be used to configured to make it operate at a particular settings. The various registers with their functions are as follows:

Block Diagram of CC1101 Based Radio Core

  1. Configuration Registers:
    • IOCFG2:           GDO2 output configuration
    • IOCFG1:           GDO1 output configuration
    • IOCFG0:           GDO0 output configuration
    • FIFOTHR:         RX and TX FIFO Configuration
    • SYNC1:             Sync Word, High Byte, Default D3
    • SYNC0:             Sync Word, Low Byte, Default 91
    • PKTLEN:           Packet Length
    • PKTCTRL1:       Packet Automation Control 1
    • PKTCTRL0:       Packet Automation Control 0
    • ADDR:              Device Address
    • CHNNR:           Channel Number
    • FSCTRL1:         Frequency Synthesizer Control
    • FSCTRL0:         Frequency Synthesizer Control
    • FREQ2:            Frequency Control Word, High Byte
    • FREQ1:            Frequency Control Word, Middle Byte
    • FREQ2:            Frequency Control Word, Low Byte
    • MDMCFG4:     Modem Configuration
    • MDMCFG3:     Modem Configuration
    • MDMCFG2:     Modem Configuration
    • MDMCFG1:     Modem Configuration
    • MDMCFG0:     Modem Configuration
    • DEVIATN:         Modem deviation setting
    • MCSM2:          Main radio control state machine configuration
    • MCSM1:          Main radio control state machine configuration
    • MCSM0:          Main radio control state machine configuration
    • FOCCFG:          Frequency offset compensation configuration
    • BSCFG:             Bit synchronization configuration
    • AGCCTRL2:      AGC Control
    • AGCCTRL1:      AGC Control
    • AGCCTRL0:      AGC Control
    • WOREVT1:      High byte Event 0 timeout
    • WOREVT0:      Low byte Event 0 timeout
    • WORCTRL:      Wake-on-radio control
    • FREND1:          Front-end RX configuration
    • FREND0:          Front-end TX configuration
    • FSCAL3:           Frequency synthesizer calibration
    • FSCAL3:           Frequency synthesizer calibration
    • FSCAL1:           Frequency synthesizer calibration
    • FSCAL0:           Frequency synthesizer calibration
    • FSTEST:            Frequency synthesizer calibration control
    • PTEST:             Production test
    • AGCTEST:        AGC test
    • TEST2:             Various test settings
    • TEST1:             Various test settings
    • TEST0:             Various test settings
2.                         Status Registers:
o    PARTNUM:      Part Number
o    Version:             Current version number
o    FREQEST:         Frequency offset estimate
o    LQI:                    Demodulator estimate for link quality
o    RSSI:                  Received signal strength indication
o    MARCSTATE:   Control state machine state
o    WORTIME1:      High byte of WOR timer
o    WORTIME0:      Low byte of WOR timer
o    PKTSTATUS:    Current GDOx status and packet status
o    VCO_VC_DAC: Current setting from PLL calibration module
o    TXBYTES:          Underflow and number of bytes in the TX FIFO
o    RXBYTES:          Overflow and number of bytes in the RX FIFO
3.     
                RF1A Registers:
o    RF1AIFCTL0:    Radio interface control register 0
o    RF1AIFCTL1:    Radio interface control register 1
o    RF1AIFIFG:       Radio interface interrupt flag register
o    RF1AIFIE:          Radio interface interrupt enable register
o    RF1AIFERR:      Radio interface error flag register
o    RF1AIFERRV:   Radio interface error vector word register
o    RF1AIFIV:          Radio interface interrupt vector word register
o    RF1AINSTRW:  Radio instruction word register
o    RF1ADINB:        Radio byte data in register
o    RF1AINSTRB:    Radio instruction byte register
o    RF1AINSTR1W:Radio instruction word register with 1-byte auto-read
o    RF1AINSTR1B:  Radio instruction byte register with 1-byte auto-read
o    RF1AINSTR2W: Radio instruction word register with 2-byte auto-read
o    RF1AINSTR2B:  Radio instruction byte register with 2-byte auto-read
o    RF1ADINW:       Radio word data in register
o    RF1ASTATW:    Radio status word register without auto-read
o    RF1ADOUTB:    Radio byte data out register without auto-read
o    RF1ASTATB:     Radio status byte register without auto-read
o    RF1ASTAT1W:  Radio status word register with 1-byte auto-read
o    RF1ADOUT1B:  Radio byte data out register with 1-byte auto-read
o    RF1ASTAT1B:   Radio status byte register with 1-byte auto-read
o    RF1ASTAT2W:  Radio status word register with 2-byte auto-read
o    RF1ADOUT2B:  Radio byte data out register with 2-byte auto-read
o    RF1ASTAT2B:   Radio status byte register with 2-byte auto-read
o    RF1ADOUTW:   Radio core word data out register without auto-read
o    RF1ADOUT1W: Radio core word data out register with 1-byte auto-read
o    RF1ADOUT2W: Radio core word data out register with 2-byte auto-read
o    RF1AIN:              Radio core signal input register



For my project, I used the following Radio Configuration:
Fcarrier = 868MHz
Modulation = GFSK
Data Rate = 38KBaud
Data Whitening = Enabled
Sync Bits = 30/32 Bits
Address Check = Enabled
Channel Spacing =
Channel Number = 5
Packet Mode = Normal Mode, Uses Tx and Rx FIFO
CRC = Enabled
Preamble Bits = Bytes
Variable Packet Length Configured

For this configuration, following register values were used:

1.  Chronos Watch (Crystal Frequency = 26MHz)
0x08,               // FSCTRL1   Frequency synthesizer control.
0x00,               // FSCTRL0   Frequency synthesizer control.
0x21,               // FREQ2     Frequency control word, high byte.
0x62,               // FREQ1     Frequency control word, middle byte.
0x76,               // FREQ0     Frequency control word, low byte.
0xCA,             // MDMCFG4   Modem configuration.
0x7F,              // MDMCFG3   Modem configuration.
0x13,              // MDMCFG2   Modem configuration.
0x21,              // MDMCFG1   Modem configuration.
0x06,              // MDMCFG0   Modem configuration.
0x05,              // CHANNR    Channel number.
0x34,              // DEVIATN   Modem deviation setting (when FSK modulation is enabled).
0x57,              // FREND1    Front end RX configuration.
0x10,              // FREND0    Front end TX configuration.
0x18,              // MCSM0     Main Radio Control State Machine configuration.
0x16,               // FOCCFG    Frequency Offset Compensation Configuration.
0x6C,              // BSCFG     Bit synchronization Configuration.
0x43,               // AGCCTRL2  AGC control.
0x40,               // AGCCTRL1  AGC control.
0x91,               // AGCCTRL0  AGC control.
0xE9,              // FSCAL3    Frequency synthesizer calibration.
0x2A,             // FSCAL2    Frequency synthesizer calibration.
0x00,              // FSCAL1    Frequency synthesizer calibration.
0x1F,              // FSCAL0    Frequency synthesizer calibration.
0x59,              // FSTEST    Frequency synthesizer calibration.
0x81,              // TEST2     Various test settings.
0x35,              // TEST1     Various test settings.
0x09,              // TEST0     Various test settings.
0x07,              // FIFOTHR   RXFIFO and TXFIFO thresholds.
0x29,              // IOCFG2    GDO2 output pin configuration.
0x06,              // IOCFG0    GDO0 output pin configuration. Refer to SmartRF® Studio User       Manual for detailed pseudo register explanation.
0x07,              // PKTCTRL1  Packet automation control. 
0x45,              // PKTCTRL0  Packet automation control. 
0x00,              // ADDR      Device address.
0x78               // PKTLEN    Packet length.

2. MSP430 with CC1101 (Crystal Frequency = 27MHz)

0x2E                      // GDO2 output pin configuration
0x2E                      // GDO1 output pin configuration
0x06                      // GDO0 output pin configuration
0x07                      // RXFIFO and TXFIFO thresholds
0xD3                     // Sync word, high byte
0x91                      // Sync word, low byte
0x78                      // Packet length
0x04                      // Packet automation control
0x45                      // Packet automation control
0x00                      // Device address
0x00                      // Channel number
0x06                      // Frequency synthesizer control
0x00                      // Frequency synthesizer control
0x20,                     // Frequency control word, high byte
0x25,                     // Frequency control word, middle byte
0xED,                    // Frequency control word, low byte
0xEA,                    // Modem configuration
0x71,                     // Modem configuration
0x13                      // Modem configuration
0x20,                     // Modem configuration
0xF8,                     // Modem configuration
0x33,                     // Modem deviation setting (when FSK modulation is enabled)
0x07                      // Main Radio Control State Machine configuration
0x30                      // Main Radio Control State Machine configuration
0x18                       // Main Radio Control State Machine configuration
0x16,                     // Frequency Offset Compensation Configuration
0x6C,                     // Bit synchronization Configuration
0x43,                     // AGC control
0x40                      // AGC control
0x91,                     // AGC control
0x00,                     // Not supported (worevt1)
0x00,                     // Not supported (worevt0)
0xF8,                     // Not supported (worctrl1)
0x56,                     // Front end RX configuration
0x10,                     // Front end RX configuration
0xE9                     // Frequency synthesizer calibration
0x2A,                    // Frequency synthesizer calibration
0x00,                     // Frequency synthesizer calibration
0x1F,                     // Frequency synthesizer calibration
0x00,                     // Not supported (rcctrl1)
0x00,                     // Not supported (rcctrl0)
0x59,                     // Not supported (fstest)
0x7F,                     // Not supported (ptest)
0x3F,                     // Not supporter (agctest)
0x81,                     // Various test settings
0x35,                     // Various test settings
0x09                      // Various test settings

Setting the Configuration using Registers:


1. Data Rate

The data rate used when transmitting, or the data rate expected in receive, is programmed by the
MDMCFG3.DRATE_M and the MDMCFG4.DRATE_E configuration registers.



If DRATE_M is rounded to the nearest integer and becomes 256, increment DRATE_E and use
DRATE_M = 0.
The data rate can be set from 0.8 kBaud to 500 kBaud.

2. Receiver Channel Filter Bandwidth
To meet different channel width requirements, the receiver channel filter is programmable. The
MDMCFG4.CHANBW_E and MDMCFG4.CHANBW_M configuration registers control the receiver channel filter bandwidth, which scales with the crystal oscillator frequency.

3. Packet Handling Hardware Support /Packet format
The radio has built-in hardware support for packet oriented radio protocols.
In transmit mode, the packet handler can be configured to add the following elements to the packet stored
in the TX FIFO:
• A programmable number of preamble bytes
• A 2-byte synchronization (sync) word. Can be duplicated to give a 4-byte sync word (recommended). It
is not possible to insert only preamble or insert only a sync word.
• A CRC checksum computed over the data field.
The recommended setting is 4-byte preamble and 4-byte sync word, except for 500-kBaud data rate,
when the recommended preamble length is 8 bytes. In addition, whitening of the data with a PN9
sequence can be implemented on the data field and the optional 2-byte CRC checksum.
In receive mode, the packet handling support deconstructs the data packet by implementing the following
(if enabled):
• Preamble detection
• Sync word detection
• CRC computation and CRC check
• One byte address check
• Packet length check (length byte checked against a programmable maximum length)
• Dewhitening
Optionally, two status bytes (see Table 25-11 and Table 25-12) with RSSI value, Link Quality Indication,
and CRC status can be appended in the RX FIFO.


4. Modulation Formats
The radio supports amplitude, frequency, and phase shift modulation formats. The desired modulation
format is set in the MDMCFG2.MOD_FORMAT register.
Optionally, the data stream can be Manchester coded by the modulator and decoded by the demodulator.
This option is enabled by setting MDMCFG2.MANCHESTER_EN = 1.

4(a) Frequency Shift Keying
The radio has the possibility to use Gaussian shaped 2-FSK (2-GFSK). The 2-FSK signal is then shaped by a Gaussian filter with BT = 0.5, producing a 2-GFSK modulated signal. When 2-FSK or 2-GFSK modulation is used, the DEVIATN register specifies the expected frequency
deviation of incoming signals in RX and should be the same as the TX deviation for demodulation to be performed reliably and robustly.
The frequency deviation is programmed with the DEVIATION_M and DEVIATION_E values in the
DEVIATN register.


5. Sync Word Qualifier
If sync word detection in RX is enabled in register MDMCFG2, the radio does not start filling the RX FIFO and performing the packet filtering before a valid sync word has been detected. The sync word qualifier mode is set by MDMCFG2.SYNC_MODE.


6. Frequency Programming
The frequency programming is designed to minimize the programming needed in a channel-oriented
system. To set up a system with channel numbers, the desired channel spacing is programmed with the MDMCFG0.CHANSPC_M and MDMCFG1.CHANSPC_E registers. The channel spacing registers are mantissa and exponent respectively.
The base or start frequency is set by the 24-bit frequency word located in the FREQ2, FREQ1, and
FREQ0 registers. This word is typically set to the center of the lowest channel frequency that is to be
used. The desired channel number is programmed with the 8-bit channel number register, CHANNR.CHAN, which is multiplied by the channel offset. The resultant carrier frequency is given by:


For more information on Register setting, you can check CC430 family user guide.

Programming MSP430 with RF booster pack

There will be many MSP430 Nodes, with each object. Each will have an address. If the chronos sends an address corresponding to a Node, The Node switches ON the LED and a Speaker. If the user finds the object, the user presses the switch on chronos again, the chronos sends a signal again to switch OFF LED and Speaker. The Flow is:

Object Lost --> Press corresponding key on Chronos --> Chronos sends a particular address to all Nodes --> Address matches at a particular Node --> MSP430 Switches ON LED and Speaker --> User can now find the object --> Object found, Press the switch on chronos again --> Chronos sends the signal back to Node(MSP430) to switch off LED and speaker.

You will need Energia, to program MSP430
//CODE



// The AIR430BoostETSI library uses the SPI library internally. Energia does not
// copy the library to the output folder unless it is referenced here.
// The order of includes is also important due to this fact.
#include <SPI.h>
#include <AIR430BoostETSI.h>

// -----------------------------------------------------------------------------
/**
 *  Defines, enumerations, and structure definitions
 */

boolean cmd1=0;

/**
 *  sControl - control packet.
 */
struct sControl
{
  unsigned char cmd;
};

// -----------------------------------------------------------------------------
/**
 *  Global data
 */

struct sControl rxControl;      // RX control packet

// -----------------------------------------------------------------------------
// Debug print functions

void printRxData()
{
  // Print the last received command to the serial port.
  Serial.print("RX Command: ");
  Serial.println(rxControl.cmd);
}


// Main function

void setup()
{
  // The radio library uses the SPI library internally, this call initializes
  // SPI/CSn and GDO0 lines. Also setup initial address, channel, and TX power.
  Serial.begin(9600);
  Radio.begin(0x00, CHANNEL_1, POWER_MAX);
  Serial.println("Radio Initialized");
  // Setup serial for debug printing.

  
  /*
   *  Setup LED and Speaker.
   *
   *  Note: Set radio first to ensure that GDO2 line isn't being driven by the 
   *  MCU as it is an output from the radio.
   */
  pinMode(RED_LED, OUTPUT);
  digitalWrite(RED_LED, LOW);
}

void loop()
{
  if (Radio.receiverOn((unsigned char*)&rxControl, sizeof(rxControl), 1000) > 0)
  {
      Serial.println("Data Receiving...");
    if (rxControl.cmd == 0xFF)        //Change this to particular address, so we can have a total of 256 Nodes
    { 
      cmd1=!cmd1;                         //Change the address of LED and Speaker
      Serial.print("RED_LED..");
      Serial.println(cmd1);
      digitalWrite(RED_LED, cmd1);
    }   
    printRxData();                         // RX debug information
  }

  delay(200);
}

Programming TI Chronos

TI chronos has CC430F6137 (CC430F6137 Datasheet) microcontroller. To program chronos, you will need USB debugger(provided with Chronos) and Code Composer Studio. 

The Code includes following files:

RF_LED.c
RF_LED.h
RF1A.h
RF1A.c
hal_pmm.h
hal_pmm.h
RfRegSettings.c

1. RF_LED.h

#include "cc430x613x.h"
#include "RF1A.h"
#include "hal_pmm.h"

/*******************
 * Function Definition
 */
void Transmit(unsigned char *buffer, unsigned char length);
void ReceiveOn(void);
void ReceiveOff(void);

void InitButtonLeds(void);
void InitRadio(void);

void init_lcd(void);
void blank_lcd(void);
void print_lcd(void);
void print_obj1(void);
void print_obj2(void);
void print_obj3(void);

2. RF_LED.c

#include "RF_LED.h"

void init_lcd(void);
void blank_lcd(void);
void print_lcd(void);
void print_obj1(void);
void print_obj2(void);
void print_obj3(void);

#define  PACKET_LEN         (0x02)     // PACKET_LEN <= 61
#define  RSSI_IDX           (PACKET_LEN+1)  // Index of appended RSSI 
#define  CRC_LQI_IDX        (PACKET_LEN+2)  // Index of appended LQI, checksum
#define  CRC_OK             (BIT7)          // CRC_OK bit 
#define  PATABLE_VAL        (0x51)          // 0 dBm output 

extern RF_SETTINGS rfSettings;

unsigned char * lcdmem;

unsigned char packetReceived;
unsigned char packetTransmit; 

unsigned char RxBuffer[64];
unsigned char RxBufferLength = 0;
const unsigned char TxBuffer1[3]= {PACKET_LEN, 0xFF, 0x00};
const unsigned char TxBuffer2[3]= {PACKET_LEN, 0xFF, 0xFF};
const unsigned char TxBuffer3[3]= {PACKET_LEN, 0xFF, 0xAA};
unsigned char buttonPressed = 0;
unsigned int i=0;

unsigned char transmitting = 0; 
unsigned char receiving = 0;
unsigned int l=0;

void main( void )
{  
  // Stop watchdog timer to prevent time out reset 
  WDTCTL = WDTPW + WDTHOLD; 

  // Increase PMMCOREV level to 2 for proper radio operation
  SetVCore(2);                            
  
  ResetRadioCore();     
  InitRadio();
  InitButtonLeds();
  init_lcd();

  ReceiveOn(); 
  receiving = 1; 
    
  while (1)
  { 
    
    if ((P2IN & 0x10))                     // Process a button press->transmit
    {   
      ReceiveOff();
      receiving = 0; 
      Transmit( (unsigned char*)TxBuffer1, sizeof TxBuffer1);
      transmitting = 1;

      print_obj1();
      for(l=0;l<25000;l++);
      blank_lcd();
      for(l=0;l<25000;l++);

    }

    if ((P2IN & 0x01))                     // Process a button press->transmit
    {
      ReceiveOff();
      receiving = 0;
      Transmit( (unsigned char*)TxBuffer2, sizeof TxBuffer2);
      transmitting = 1;

      print_obj2();
      for(l=0;l<25000;l++);
      blank_lcd();
      for(l=0;l<25000;l++);
    }

    if ((P2IN & 0x02))                     // Process a button press->transmit
        {
          ReceiveOff();
          receiving = 0;
          Transmit( (unsigned char*)TxBuffer3, sizeof TxBuffer3);
          transmitting = 1;

          print_obj3();
          for(l=0;l<25000;l++);
          blank_lcd();
          for(l=0;l<25000;l++);
      }



    else if(!transmitting)
    {
      ReceiveOn();      
      receiving = 1; 
    }
  }
}

void InitButtonLeds(void)
{
  // Set up the buttons 
  P2DIR = 0xEC; //1110 1100
  P2REN = 0xFF;
  P2OUT = 0x00;
}


void InitRadio(void)
{
  // Set the High-Power Mode Request Enable bit so LPM3 can be entered
  // with active radio enabled 
  PMMCTL0_H = 0xA5;
  PMMCTL0_L |= PMMHPMRE_L; 
  PMMCTL0_H = 0x00; 
  
  WriteRfSettings(&rfSettings);
  
  WriteSinglePATable(PATABLE_VAL);
}

void Transmit(unsigned char *buffer, unsigned char length)
{
  RF1AIES |= BIT9;                          
  RF1AIFG &= ~BIT9;                         // Clear pending interrupts
  RF1AIE |= BIT9;                           // Enable TX end-of-packet interrupt
  
  WriteBurstReg(RF_TXFIFOWR, buffer, length);     
  
  Strobe( RF_STX );                         // Strobe STX   
}

void ReceiveOn(void)
{  
  RF1AIES |= BIT9;                          // Falling edge of RFIFG9
  RF1AIFG &= ~BIT9;                         // Clear a pending interrupt
  RF1AIE  |= BIT9;                          // Enable the interrupt 
  
  // Radio is in IDLE following a TX, so strobe SRX to enter Receive Mode
  Strobe( RF_SRX );                      
}

void ReceiveOff(void)
{
  RF1AIE &= ~BIT9;                          // Disable RX interrupts
  RF1AIFG &= ~BIT9;                         // Clear pending IFG

  // It is possible that ReceiveOff is called while radio is receiving a packet.
  // Therefore, it is necessary to flush the RX FIFO after issuing IDLE strobe 
  // such that the RXFIFO is empty prior to receiving a packet.
  Strobe( RF_SIDLE );
  Strobe( RF_SFRX  );                       
}

#pragma vector=CC1101_VECTOR
__interrupt void CC1101_ISR(void)
{
  switch(__even_in_range(RF1AIV,32))        // Prioritizing Radio Core Interrupt 
  {
    case  0: break;                         // No RF core interrupt pending                                            
    case  2: break;                         // RFIFG0 
    case  4: break;                         // RFIFG1
    case  6: break;                         // RFIFG2
    case  8: break;                         // RFIFG3
    case 10: break;                         // RFIFG4
    case 12: break;                         // RFIFG5
    case 14: break;                         // RFIFG6          
    case 16: break;                         // RFIFG7
    case 18: break;                         // RFIFG8
    case 20:                                // RFIFG9
      if(receiving)     // RX end of packet
      {
        // Read the length byte from the FIFO       
        RxBufferLength = ReadSingleReg( RXBYTES );               
        ReadBurstReg(RF_RXFIFORD, RxBuffer, RxBufferLength); 
        
        // Stop here to see contents of RxBuffer
        __no_operation();     
        
        // Check the CRC results
        if(RxBuffer[CRC_LQI_IDX] & CRC_OK)  
          P1OUT ^= BIT0;                    // Toggle LED1      
      }
      else if(transmitting)     // TX end of packet
      {
        RF1AIE &= ~BIT9;                    // Disable TX end-of-packet interrupt
        P3OUT &= ~BIT6;                     // Turn off LED after Transmit               
        transmitting = 0; 
      }
      else while(1);      // trap 
      break;
    case 22: break;                         // RFIFG10
    case 24: break;                         // RFIFG11
    case 26: break;                         // RFIFG12
    case 28: break;                         // RFIFG13
    case 30: break;                         // RFIFG14
    case 32: break;                         // RFIFG15
  }  
  __bic_SR_register_on_exit(LPM3_bits);     
}


void init_lcd(void)
{
// Clear entire display memory
LCDBMEMCTL |= LCDCLRBM + LCDCLRM;

// LCD_FREQ = ACLK/16/8 = 256Hz
// Frame frequency = 256Hz/4 = 64Hz, LCD mux 4, LCD on
LCDBCTL0 = (LCDDIV0 + LCDDIV1 + LCDDIV2 + LCDDIV3) | (LCDPRE0 + LCDPRE1) | LCD4MUX | LCDON;

// LCB_BLK_FREQ = ACLK/8/4096 = 1Hz
LCDBBLKCTL = LCDBLKPRE0 | LCDBLKPRE1 | LCDBLKDIV0 | LCDBLKDIV1 | LCDBLKDIV2 | LCDBLKMOD0;

// I/O to COM outputs
P5SEL |= (BIT5 | BIT6 | BIT7);
P5DIR |= (BIT5 | BIT6 | BIT7);

// Activate LCD output
LCDBPCTL0 = 0xFFFF;  // Select LCD segments S0-S15
LCDBPCTL1 = 0x00FF;  // Select LCD segments S16-S22
}

void blank_lcd(void)
{
// Clear entire display memory
LCDBMEMCTL |= LCDCLRBM + LCDCLRM;

}

void print_lcd(void)
{
// LCD_B Base Address is 0A00H page 30 y in SALS554 document
// show 'h'
lcdmem  = (unsigned char *)0x0A21;
*lcdmem = (unsigned char)(*lcdmem | (BIT2+BIT1+BIT6+BIT0));
// show 'i'
lcdmem  = (unsigned char *)0x0A22;
*lcdmem = (unsigned char)(*lcdmem | (BIT2));
}

void print_obj1(void)
{
//show 'O'
lcdmem  = (unsigned char *)0x0A2B;
*lcdmem = (unsigned char)(*lcdmem | (BIT2+BIT1+BIT6+BIT0+BIT3+BIT4));
// show 'b'
lcdmem  = (unsigned char *)0x0A2A;
*lcdmem = (unsigned char)(*lcdmem | (BIT2+BIT3+BIT4+BIT5+BIT6));
// show 'J'
lcdmem  = (unsigned char *)0x0A29;
*lcdmem = (unsigned char)(*lcdmem | (BIT2+BIT3+BIT1+BIT6));
// show '1'
lcdmem  = (unsigned char *)0x0A28;
*lcdmem = (unsigned char)(*lcdmem | (BIT2+BIT1));
// show Alarm
lcdmem  = (unsigned char *)0x0A23;
*lcdmem = (unsigned char)(*lcdmem | (BIT3));
// show 'Wireless'
lcdmem  = (unsigned char *)0x0A24;
*lcdmem = (unsigned char)(*lcdmem | (BIT3));
lcdmem  = (unsigned char *)0x0A25;
*lcdmem = (unsigned char)(*lcdmem | (BIT3));
lcdmem  = (unsigned char *)0x0A26;
*lcdmem = (unsigned char)(*lcdmem | (BIT3));

}

void print_obj2(void)
{
//show 'O'
lcdmem  = (unsigned char *)0x0A2B;
*lcdmem = (unsigned char)(*lcdmem | (BIT2+BIT1+BIT6+BIT0+BIT3+BIT4));
// show 'b'
lcdmem  = (unsigned char *)0x0A2A;
*lcdmem = (unsigned char)(*lcdmem | (BIT2+BIT3+BIT4+BIT5+BIT6));
// show 'J'
lcdmem  = (unsigned char *)0x0A29;
*lcdmem = (unsigned char)(*lcdmem | (BIT2+BIT3+BIT1+BIT6));
// show '2'
lcdmem  = (unsigned char *)0x0A28;
*lcdmem = (unsigned char)(*lcdmem | (BIT0+BIT1+BIT5+BIT6+BIT3));
// show Alarm
lcdmem  = (unsigned char *)0x0A23;
*lcdmem = (unsigned char)(*lcdmem | (BIT3));
// show 'Wireless'
lcdmem  = (unsigned char *)0x0A24;
*lcdmem = (unsigned char)(*lcdmem | (BIT3));
lcdmem  = (unsigned char *)0x0A25;
*lcdmem = (unsigned char)(*lcdmem | (BIT3));
lcdmem  = (unsigned char *)0x0A26;
*lcdmem = (unsigned char)(*lcdmem | (BIT3));

}

void print_obj3(void)
{
//show 'O'
lcdmem  = (unsigned char *)0x0A2B;
*lcdmem = (unsigned char)(*lcdmem | (BIT2+BIT1+BIT6+BIT0+BIT3+BIT4));
// show 'b'
lcdmem  = (unsigned char *)0x0A2A;
*lcdmem = (unsigned char)(*lcdmem | (BIT2+BIT3+BIT4+BIT5+BIT6));
// show 'J'
lcdmem  = (unsigned char *)0x0A29;
*lcdmem = (unsigned char)(*lcdmem | (BIT2+BIT3+BIT1+BIT6));
// show '3'
lcdmem  = (unsigned char *)0x0A28;
*lcdmem = (unsigned char)(*lcdmem | (BIT0+BIT1+BIT2+BIT3+BIT5));
// show Alarm
lcdmem  = (unsigned char *)0x0A23;
*lcdmem = (unsigned char)(*lcdmem | (BIT3));
// show 'Wireless'
lcdmem  = (unsigned char *)0x0A24;
*lcdmem = (unsigned char)(*lcdmem | (BIT3));
lcdmem  = (unsigned char *)0x0A25;
*lcdmem = (unsigned char)(*lcdmem | (BIT3));
lcdmem  = (unsigned char *)0x0A26;
*lcdmem = (unsigned char)(*lcdmem | (BIT3));

}

3. RF1A.c

#include "RF1A.h"
#include "cc430x613x.h"

// *****************************************************************************
// @fn          Strobe
// @brief       Send a command strobe to the radio. Includes workaround for RF1A7
// @param       unsigned char strobe        The strobe command to be sent
// @return      unsigned char statusByte    The status byte that follows the strobe
// *****************************************************************************
unsigned char Strobe(unsigned char strobe)
{
  unsigned char statusByte = 0;
  unsigned int  gdo_state;
  
  // Check for valid strobe command 
  if((strobe == 0xBD) || ((strobe >= RF_SRES) && (strobe <= RF_SNOP)))
  {
    // Clear the Status read flag 
    RF1AIFCTL1 &= ~(RFSTATIFG);    
    
    // Wait for radio to be ready for next instruction
    while( !(RF1AIFCTL1 & RFINSTRIFG));
    
    // Write the strobe instruction
    if ((strobe > RF_SRES) && (strobe < RF_SNOP))
    {
      gdo_state = ReadSingleReg(IOCFG2);    // buffer IOCFG2 state
      WriteSingleReg(IOCFG2, 0x29);         // chip-ready to GDO2
      
      RF1AINSTRB = strobe; 
      if ( (RF1AIN&0x04)== 0x04 )           // chip at sleep mode
      {
        if ( (strobe == RF_SXOFF) || (strobe == RF_SPWD) || (strobe == RF_SWOR) ) { }
        else  
        {
          while ((RF1AIN&0x04)== 0x04);     // chip-ready ?
          // Delay for ~810usec at 1.05MHz CPU clock, see erratum RF1A7
          __delay_cycles(850);             
        }
      }
      WriteSingleReg(IOCFG2, gdo_state);    // restore IOCFG2 setting
    
      while( !(RF1AIFCTL1 & RFSTATIFG) );
    }
    else                     // chip active mode (SRES)
    {
      RF1AINSTRB = strobe;     
    }
    statusByte = RF1ASTATB;
  }
  return statusByte;
}

// *****************************************************************************
// @fn          ReadSingleReg
// @brief       Read a single byte from the radio register
// @param       unsigned char addr      Target radio register address
// @return      unsigned char data_out  Value of byte that was read
// *****************************************************************************
unsigned char ReadSingleReg(unsigned char addr)
{
  unsigned char data_out;
  
  // Check for valid configuration register address, 0x3E refers to PATABLE 
  if ((addr <= 0x2E) || (addr == 0x3E))
    // Send address + Instruction + 1 dummy byte (auto-read)
    RF1AINSTR1B = (addr | RF_SNGLREGRD);    
  else
    // Send address + Instruction + 1 dummy byte (auto-read)
    RF1AINSTR1B = (addr | RF_STATREGRD);    
  
  while (!(RF1AIFCTL1 & RFDOUTIFG) );
  data_out = RF1ADOUTB;                    // Read data and clears the RFDOUTIFG

  return data_out;
}

// *****************************************************************************
// @fn          WriteSingleReg
// @brief       Write a single byte to a radio register
// @param       unsigned char addr      Target radio register address
// @param       unsigned char value     Value to be written
// @return      none
// *****************************************************************************
void WriteSingleReg(unsigned char addr, unsigned char value)
{   
  while (!(RF1AIFCTL1 & RFINSTRIFG));       // Wait for the Radio to be ready for next instruction
  RF1AINSTRB = (addr | RF_SNGLREGWR);     // Send address + Instruction

  RF1ADINB = value;      // Write data in 

  __no_operation(); 
}
        
// *****************************************************************************
// @fn          ReadBurstReg
// @brief       Read multiple bytes to the radio registers
// @param       unsigned char addr      Beginning address of burst read
// @param       unsigned char *buffer   Pointer to data table
// @param       unsigned char count     Number of bytes to be read
// @return      none
// *****************************************************************************
void ReadBurstReg(unsigned char addr, unsigned char *buffer, unsigned char count)
{
  unsigned int i;
  if(count > 0)
  {
    while (!(RF1AIFCTL1 & RFINSTRIFG));       // Wait for INSTRIFG
    RF1AINSTR1B = (addr | RF_REGRD);          // Send addr of first conf. reg. to be read 
                                              // ... and the burst-register read instruction
    for (i = 0; i < (count-1); i++)
    {
      while (!(RFDOUTIFG&RF1AIFCTL1));        // Wait for the Radio Core to update the RF1ADOUTB reg
      buffer[i] = RF1ADOUT1B;                 // Read DOUT from Radio Core + clears RFDOUTIFG
                                              // Also initiates auo-read for next DOUT byte
    }
    buffer[count-1] = RF1ADOUT0B;             // Store the last DOUT from Radio Core  
  }
}  

// *****************************************************************************
// @fn          WriteBurstReg
// @brief       Write multiple bytes to the radio registers
// @param       unsigned char addr      Beginning address of burst write
// @param       unsigned char *buffer   Pointer to data table
// @param       unsigned char count     Number of bytes to be written
// @return      none
// *****************************************************************************
void WriteBurstReg(unsigned char addr, unsigned char *buffer, unsigned char count)
{  
  unsigned char i;

  if(count > 0)
  {
    while (!(RF1AIFCTL1 & RFINSTRIFG));       // Wait for the Radio to be ready for next instruction
    RF1AINSTRW = ((addr | RF_REGWR)<<8 ) + buffer[0]; // Send address + Instruction
  
    for (i = 1; i < count; i++)
    {
      RF1ADINB = buffer[i];                   // Send data
      while (!(RFDINIFG & RF1AIFCTL1));       // Wait for TX to finish
    } 
    i = RF1ADOUTB;                            // Reset RFDOUTIFG flag which contains status byte  
  }
}

// *****************************************************************************
// @fn          ResetRadioCore
// @brief       Reset the radio core using RF_SRES command
// @param       none
// @return      none
// *****************************************************************************
void ResetRadioCore (void)
{
  Strobe(RF_SRES);                          // Reset the Radio Core
  Strobe(RF_SNOP);                          // Reset Radio Pointer
}

// *****************************************************************************
// @fn          WriteRfSettings
// @brief       Write the minimum set of RF configuration register settings
// @param       RF_SETTINGS *pRfSettings  Pointer to the structure that holds the rf settings
// @return      none
// *****************************************************************************
void WriteRfSettings(RF_SETTINGS *pRfSettings) {
    WriteSingleReg(FSCTRL1,  pRfSettings->fsctrl1);
    WriteSingleReg(FSCTRL0,  pRfSettings->fsctrl0);
    WriteSingleReg(FREQ2,    pRfSettings->freq2);
    WriteSingleReg(FREQ1,    pRfSettings->freq1);
    WriteSingleReg(FREQ0,    pRfSettings->freq0);
    WriteSingleReg(MDMCFG4,  pRfSettings->mdmcfg4);
    WriteSingleReg(MDMCFG3,  pRfSettings->mdmcfg3);
    WriteSingleReg(MDMCFG2,  pRfSettings->mdmcfg2);
    WriteSingleReg(MDMCFG1,  pRfSettings->mdmcfg1);
    WriteSingleReg(MDMCFG0,  pRfSettings->mdmcfg0);
    WriteSingleReg(CHANNR,   pRfSettings->channr);
    WriteSingleReg(DEVIATN,  pRfSettings->deviatn);
    WriteSingleReg(FREND1,   pRfSettings->frend1);
    WriteSingleReg(FREND0,   pRfSettings->frend0);
    WriteSingleReg(MCSM0 ,   pRfSettings->mcsm0);
    WriteSingleReg(FOCCFG,   pRfSettings->foccfg);
    WriteSingleReg(BSCFG,    pRfSettings->bscfg);
    WriteSingleReg(AGCCTRL2, pRfSettings->agcctrl2);
    WriteSingleReg(AGCCTRL1, pRfSettings->agcctrl1);
    WriteSingleReg(AGCCTRL0, pRfSettings->agcctrl0);
    WriteSingleReg(FSCAL3,   pRfSettings->fscal3);
    WriteSingleReg(FSCAL2,   pRfSettings->fscal2);
    WriteSingleReg(FSCAL1,   pRfSettings->fscal1);
    WriteSingleReg(FSCAL0,   pRfSettings->fscal0);
    WriteSingleReg(FSTEST,   pRfSettings->fstest);
    WriteSingleReg(TEST2,    pRfSettings->test2);
    WriteSingleReg(TEST1,    pRfSettings->test1);
    WriteSingleReg(TEST0,    pRfSettings->test0);
    WriteSingleReg(FIFOTHR,  pRfSettings->fifothr);
    WriteSingleReg(IOCFG2,   pRfSettings->iocfg2);
    WriteSingleReg(IOCFG0,   pRfSettings->iocfg0);
    WriteSingleReg(PKTCTRL1, pRfSettings->pktctrl1);
    WriteSingleReg(PKTCTRL0, pRfSettings->pktctrl0);
    WriteSingleReg(ADDR,     pRfSettings->addr);
    WriteSingleReg(PKTLEN,   pRfSettings->pktlen);
}

// *****************************************************************************
// @fn          WritePATable
// @brief       Write data to power table
// @param       unsigned char value Value to write
// @return      none
// *****************************************************************************
void WriteSinglePATable(unsigned char value)
{
  while( !(RF1AIFCTL1 & RFINSTRIFG));
  RF1AINSTRW = 0x3E00 + value;              // PA Table single write
  
  while( !(RF1AIFCTL1 & RFINSTRIFG));
  RF1AINSTRB = RF_SNOP;                     // reset PA_Table pointer
}

// *****************************************************************************
// @fn          WritePATable
// @brief       Write to multiple locations in power table 
// @param       unsigned char *buffer Pointer to the table of values to be written 
// @param       unsigned char count Number of values to be written
// @return      none
// *****************************************************************************
void WriteBurstPATable(unsigned char *buffer, unsigned char count)
{
  volatile char i = 0; 
  
  while( !(RF1AIFCTL1 & RFINSTRIFG));
  RF1AINSTRW = 0x7E00 + buffer[i];          // PA Table burst write   

  for (i = 1; i < count; i++)
  {
    RF1ADINB = buffer[i];                   // Send data
    while (!(RFDINIFG & RF1AIFCTL1));       // Wait for TX to finish
  } 
  i = RF1ADOUTB;                            // Reset RFDOUTIFG flag which contains status byte

  while( !(RF1AIFCTL1 & RFINSTRIFG));
  RF1AINSTRB = RF_SNOP;                     // reset PA Table pointer
}

4. RF1A.h



/* ------------------------------------------------------------------------------------------------
 *                                          Defines
 * ------------------------------------------------------------------------------------------------
 */

/********************
 * Variable definition
 */
typedef struct S_RF_SETTINGS {
    unsigned char fsctrl1;   // Frequency synthesizer control.
    unsigned char fsctrl0;   // Frequency synthesizer control.
    unsigned char freq2;     // Frequency control word, high byte.
    unsigned char freq1;     // Frequency control word, middle byte.
    unsigned char freq0;     // Frequency control word, low byte.
    unsigned char mdmcfg4;   // Modem configuration.
    unsigned char mdmcfg3;   // Modem configuration.
    unsigned char mdmcfg2;   // Modem configuration.
    unsigned char mdmcfg1;   // Modem configuration.
    unsigned char mdmcfg0;   // Modem configuration.
    unsigned char channr;    // Channel number.
    unsigned char deviatn;   // Modem deviation setting (when FSK modulation is enabled).
    unsigned char frend1;    // Front end RX configuration.
    unsigned char frend0;    // Front end RX configuration.
    unsigned char mcsm0;     // Main Radio Control State Machine configuration.
    unsigned char foccfg;    // Frequency Offset Compensation Configuration.
    unsigned char bscfg;     // Bit synchronization Configuration.
    unsigned char agcctrl2;  // AGC control.
    unsigned char agcctrl1;  // AGC control.
    unsigned char agcctrl0;  // AGC control.
    unsigned char fscal3;    // Frequency synthesizer calibration.
    unsigned char fscal2;    // Frequency synthesizer calibration.
    unsigned char fscal1;    // Frequency synthesizer calibration.
    unsigned char fscal0;    // Frequency synthesizer calibration.
    unsigned char fstest;    // Frequency synthesizer calibration control
    unsigned char test2;     // Various test settings.
    unsigned char test1;     // Various test settings.
    unsigned char test0;     // Various test settings.
    unsigned char fifothr;   // RXFIFO and TXFIFO thresholds.
    unsigned char iocfg2;    // GDO2 output pin configuration
    unsigned char iocfg0;    // GDO0 output pin configuration
    unsigned char pktctrl1;  // Packet automation control.
    unsigned char pktctrl0;  // Packet automation control.
    unsigned char addr;      // Device address.
    unsigned char pktlen;    // Packet length.
} RF_SETTINGS;

void ResetRadioCore (void);
unsigned char Strobe(unsigned char strobe);

void WriteRfSettings(RF_SETTINGS *pRfSettings);

void WriteSingleReg(unsigned char addr, unsigned char value);
void WriteBurstReg(unsigned char addr, unsigned char *buffer, unsigned char count);
unsigned char ReadSingleReg(unsigned char addr);
void ReadBurstReg(unsigned char addr, unsigned char *buffer, unsigned char count);
void WriteSinglePATable(unsigned char value);
void WriteBurstPATable(unsigned char *buffer, unsigned char count); 

5. hal_pmm.h


#ifndef __PMM
#define __PMM

#define PMM_STATUS_OK     0
#define PMM_STATUS_ERROR  1

//====================================================================
/**
  * Set the VCore to a new level if it is possible and return a
  * error - value.
  *
  * \param      level       PMM level ID
  * \return int     1: error / 0: done
  */
unsigned int SetVCore (unsigned char level);

//====================================================================
/**
  * Set the VCore to a higher level, if it is possible.
  * Return a 1 if voltage at highside (Vcc) is to low
  * for the selected Level (level).
  *
  * \param      level       PMM level ID
  * \return int     1: error / 0: done
  */
unsigned int SetVCoreUp (unsigned char level);

//====================================================================
/**
  * Set the VCore to a lower level.
  * Return a 1 if voltage at highside (Vcc) is still to low
  * for the selected Level (level).
  *
  * \param      level       PMM level ID
  * \return int     1: done with error / 0: done without error
  */
unsigned int SetVCoreDown (unsigned char level);

#endif /* __PMM */

6. hal_pmm.c

#include "cc430f6137.h"
#include "hal_pmm.h"

#define _HAL_PMM_DISABLE_SVML_
#define _HAL_PMM_DISABLE_SVSL_
#define _HAL_PMM_DISABLE_FULL_PERFORMANCE_


//****************************************************************************//
#ifdef _HAL_PMM_DISABLE_SVML_
#define _HAL_PMM_SVMLE SVMLE
#else
#define _HAL_PMM_SVMLE 0
#endif
#ifdef _HAL_PMM_DISABLE_SVSL_
#define _HAL_PMM_SVSLE SVSLE
#else
#define _HAL_PMM_SVSLE 0
#endif
#ifdef _HAL_PMM_DISABLE_FULL_PERFORMANCE_
#define _HAL_PMM_SVSFP SVSLFP
#else
#define _HAL_PMM_SVSFP 0
#endif
//****************************************************************************//
// Set VCore
//****************************************************************************//
unsigned int SetVCore (unsigned char level)
{
  unsigned int actlevel;
  unsigned int status = 0;
  level &= PMMCOREV_3;                       // Set Mask for Max. level
  actlevel = (PMMCTL0 & PMMCOREV_3);         // Get actual VCore

  while (((level != actlevel) && (status == 0)) || (level < actlevel)) // step by step increase or decrease
  {
    if (level > actlevel)
      status = SetVCoreUp(++actlevel);
    else
      status = SetVCoreDown(--actlevel);
  }
  return status;
}

//****************************************************************************//
// Set VCore Up
//****************************************************************************//
unsigned int SetVCoreUp (unsigned char level)
{
  unsigned int PMMRIE_backup,SVSMHCTL_backup;

  // Open PMM registers for write access
  PMMCTL0_H = 0xA5;

  // Disable dedicated Interrupts to prevent that needed flags will be cleared
  PMMRIE_backup = PMMRIE;
  PMMRIE &= ~(SVSMHDLYIE | SVSMLDLYIE | SVMLVLRIE | SVMHVLRIE | SVMHVLRPE);
  // Set SVM highside to new level and check if a VCore increase is possible
  SVSMHCTL_backup = SVSMHCTL;
  PMMIFG &= ~(SVMHIFG | SVSMHDLYIFG);
  SVSMHCTL = SVMHE | SVMHFP | (SVSMHRRL0 * level);
  // Wait until SVM highside is settled
  while ((PMMIFG & SVSMHDLYIFG) == 0);
  // Disable full-performance mode to save energy
  SVSMHCTL &= ~_HAL_PMM_SVSFP ;
  // Check if a VCore increase is possible
  if ((PMMIFG & SVMHIFG) == SVMHIFG){ //-> Vcc is to low for a Vcore increase
   // recover the previous settings
   PMMIFG &= ~SVSMHDLYIFG;
   SVSMHCTL = SVSMHCTL_backup;
   // Wait until SVM highside is settled
   while ((PMMIFG & SVSMHDLYIFG) == 0);
   // Clear all Flags
   PMMIFG &= ~(SVMHVLRIFG | SVMHIFG | SVSMHDLYIFG | SVMLVLRIFG | SVMLIFG | SVSMLDLYIFG);
   // backup PMM-Interrupt-Register
   PMMRIE = PMMRIE_backup;
  
   // Lock PMM registers for write access
   PMMCTL0_H = 0x00;
   return PMM_STATUS_ERROR;                       // return: voltage not set
  }
  // Set also SVS highside to new level //-> Vcc is high enough for a Vcore increase
  SVSMHCTL |= SVSHE | (SVSHRVL0 * level);
  // Set SVM low side to new level
  SVSMLCTL = SVMLE | SVMLFP | (SVSMLRRL0 * level);
  // Wait until SVM low side is settled
  while ((PMMIFG & SVSMLDLYIFG) == 0);
  // Clear already set flags
  PMMIFG &= ~(SVMLVLRIFG | SVMLIFG);
  // Set VCore to new level
  PMMCTL0_L = PMMCOREV0 * level;
  // Wait until new level reached
  if (PMMIFG & SVMLIFG)
  while ((PMMIFG & SVMLVLRIFG) == 0);
  // Set also SVS/SVM low side to new level
  PMMIFG &= ~SVSMLDLYIFG;
  SVSMLCTL |= SVSLE | (SVSLRVL0 * level);
  // wait for lowside delay flags
  while ((PMMIFG & SVSMLDLYIFG) == 0);

// Disable SVS/SVM Low
// Disable full-performance mode to save energy
  SVSMLCTL &= ~(_HAL_PMM_DISABLE_SVSL_+_HAL_PMM_DISABLE_SVML_+_HAL_PMM_SVSFP );

  // Clear all Flags
  PMMIFG &= ~(SVMHVLRIFG | SVMHIFG | SVSMHDLYIFG | SVMLVLRIFG | SVMLIFG | SVSMLDLYIFG);
  // backup PMM-Interrupt-Register
  PMMRIE = PMMRIE_backup;

  // Lock PMM registers for write access
  PMMCTL0_H = 0x00;
  return PMM_STATUS_OK;                               // return: OK
}

//****************************************************************************//
// Set VCore down (Independent from the enabled Interrupts in PMMRIE)
//****************************************************************************//
unsigned int SetVCoreDown (unsigned char level)
{
  unsigned int PMMRIE_backup;

  // Open PMM registers for write access
  PMMCTL0_H = 0xA5;

  // Disable dedicated Interrupts to prevent that needed flags will be cleared
  PMMRIE_backup = PMMRIE;
  PMMRIE &= ~(SVSMHDLYIE | SVSMLDLYIE | SVMLVLRIE | SVMHVLRIE | SVMHVLRPE);

  // Set SVM high side and SVM low side to new level
  PMMIFG &= ~(SVMHIFG | SVSMHDLYIFG | SVMLIFG | SVSMLDLYIFG);
  SVSMHCTL = SVMHE | SVMHFP | (SVSMHRRL0 * level);
  SVSMLCTL = SVMLE | SVMLFP | (SVSMLRRL0 * level);
  // Wait until SVM high side and SVM low side is settled
  while ((PMMIFG & SVSMHDLYIFG) == 0 || (PMMIFG & SVSMLDLYIFG) == 0);

  // Set VCore to new level
  PMMCTL0_L = PMMCOREV0 * level;

  // Set also SVS highside and SVS low side to new level
  PMMIFG &= ~(SVSHIFG | SVSMHDLYIFG | SVSLIFG | SVSMLDLYIFG);
  SVSMHCTL |= SVSHE | SVSHFP | (SVSHRVL0 * level);
  SVSMLCTL |= SVSLE | SVSLFP | (SVSLRVL0 * level);
  // Wait until SVS high side and SVS low side is settled
  while ((PMMIFG & SVSMHDLYIFG) == 0 || (PMMIFG & SVSMLDLYIFG) == 0);
  // Disable full-performance mode to save energy
  SVSMHCTL &= ~_HAL_PMM_SVSFP;
// Disable SVS/SVM Low
// Disable full-performance mode to save energy
  SVSMLCTL &= ~(_HAL_PMM_DISABLE_SVSL_+_HAL_PMM_DISABLE_SVML_+_HAL_PMM_SVSFP );
  // Clear all Flags
  PMMIFG &= ~(SVMHVLRIFG | SVMHIFG | SVSMHDLYIFG | SVMLVLRIFG | SVMLIFG | SVSMLDLYIFG);
  // backup PMM-Interrupt-Register
  PMMRIE = PMMRIE_backup;
  // Lock PMM registers for write access
  PMMCTL0_H = 0x00;

  if ((PMMIFG & SVMHIFG) == SVMHIFG)
    return PMM_STATUS_ERROR;   // Highside is still to low for the adjusted VCore Level
  else return PMM_STATUS_OK; // Return: OK
}

7.  RfRegSettings.c

RF_SETTINGS rfSettings = {
    0x08,   // FSCTRL1   Frequency synthesizer control.
    0x00,   // FSCTRL0   Frequency synthesizer control.
    0x21,   // FREQ2     Frequency control word, high byte.
    0x62,   // FREQ1     Frequency control word, middle byte.
    0x76,   // FREQ0     Frequency control word, low byte.
    0xCA,   // MDMCFG4   Modem configuration.
    0x7F,   // MDMCFG3   Modem configuration. 
    0x13,   // MDMCFG2   Modem configuration. 
    0x21,   // MDMCFG1   Modem configuration. 
    0x06,   // MDMCFG0   Modem configuration. 
    0x05,   // CHANNR    Channel number.  
    0x34,   // DEVIATN   Modem deviation setting (when FSK modulation is enabled).
    0x57,   // FREND1    Front end RX configuration. 
    0x10,   // FREND0    Front end TX configuration.
    0x18,   // MCSM0     Main Radio Control State Machine configuration.
    0x16,   // FOCCFG    Frequency Offset Compensation Configuration.
    0x6C,   // BSCFG     Bit synchronization Configuration.
    0x43,   // AGCCTRL2  AGC control.
    0x40,   // AGCCTRL1  AGC control.
    0x91,   // AGCCTRL0  AGC control.
    0xE9,   // FSCAL3    Frequency synthesizer calibration.
    0x2A,   // FSCAL2    Frequency synthesizer calibration.
    0x00,   // FSCAL1    Frequency synthesizer calibration.
    0x1F,   // FSCAL0    Frequency synthesizer calibration.
    0x59,   // FSTEST    Frequency synthesizer calibration.
    0x81,   // TEST2     Various test settings.
    0x35,   // TEST1     Various test settings.
    0x09,   // TEST0     Various test settings.
    0x07,   // FIFOTHR   RXFIFO and TXFIFO thresholds.
    0x29,   // IOCFG2    GDO2 output pin configuration.
    0x06,   // IOCFG0    GDO0 output pin configuration. Refer to SmartRF® Studio User Manual for detailed pseudo register explanation.
    0x07,   // PKTCTRL1  Packet automation control.  
    0x45,   // PKTCTRL0  Packet automation control.  
    0x00,   // ADDR      Device address.
    0x78    // PKTLEN    Packet length.
};


The Video:


Thank you for reading my post, will be uploading a video soon.



No comments:

Post a Comment