Creating the AIR-ZNP Port for the MSP-EXP430F5438A Experimenters Board

=Introduction=

This page will describe how the AIR-ZNP port for the MSP-EXP430F5438A Experimenters board was created. If you would simply like to use the port, consult the AIR-ZNP_Port_for_the_MSP-EXP430F5438A_Experimenters_Board page.

=Steps that were used to create the MSP-EXP430F5438A Experimenters board port of AIR-ZNP software=

The following information is provided for reference only. You can download all these changes by following the instructions in Section 2. This just outlines what changes were made to create the downloads now available in Section 2.

Download the background materials
The following documents provide much of the detailed background required for understanding the MSP430F5438A microcontroller, AIR Module, and experimenters board operation.


 * Download the MSP-EXP430F5438A Experimenters Board Users' Guide from http://www.ti.com/tool/msp-exp430f5438
 * Download the MSP430F5438A Datasheet from http://www.ti.com/product/msp430f5438A
 * Download the MSP430x5xx and MSP430x6xx Family User's Guide from http://www.ti.com/product/msp430f5438A
 * Download the MSP430F543xA, MSP430F541xA Code Examples from the Software section of http://www.ti.com/product/msp430f5438A.
 * Download the A2530R24x Users Guide from http://www.anaren.com/air/products/air-for-zigbee-standard-apps
 * Download the A2530E24A-EMZ Product Brief from https://dl.dropboxusercontent.com/u/19834976/130408a%20-%20A2530E24A-EMZ%20Product%20Brief.pdf

Determine which ports, connections, peripherals will be used
Review MSP-EXP430F5438A board schematics (see Experimenters Board Users Guide at http://www.ti.com/tool/msp-exp430f5438) to determine which ports / peripherals / connections will be used with the A2530R24A-EMZ board. It is important to compile a cross-reference of the connections between MSP430F5438A ports, the Experimenters board's RF1 and RF2 connectors, and the A2530R24A module by comparing the Experimenters board schematics and the A2530R24A-EMZ connector pinout (contained in the product brief).



The following MSP430F5438A ports are used / connected. There are 11 connections to the A2530 module that are required. One of them is via a pull-down resistor located on the A2530-EMZ board. The other 10 are connected through the RF connectors on the Experimenter board from the MSP430F5438A.

There are two LED's on the Experimenters board that are used by the AIR-ZNP examples.

There are two switches on the Experimenters board that are used by the AIR-ZNP examples.

There is a USB Virtual COM port on the Experimenters board that is used by the AIR-ZNP examples. These ports are connected to the USB Mini-B connector on the Experimenters board. Once configured, a Hyperterminal-style terminal emulator can be used to view debug information (set up as 115200, 8N1).

And for debugging purposes only, the three MSP-430 Clocks (ACLK-32KHz, SMCLK-4MHz and MCLK-8MHz) are available on MSP430F5438A pins.

Plus, TimerA1 is used by the AIR-ZNP examples internally

Create a new AIR-ZNP hal_MSP-EXP430F5438A.c file for the Experimenters board
Start by copying the hal_launchpad.c and .h files into new hal_MSP-EXP430F5438A.c and .h files. Then essentially going routine by routine, we will modify to accommodate the differences between the LaunchPad/MSP430G2553 board and the new Experimenters board.

Port Pin Setup
Modify the portInit function to properly set up the LEDs, Switches, SPI, and other ports used in the AIR-ZNP software:


 * For P1, set LED1/P1.0, LED2/P1.1, MRST/P1.2, MRDY/P1.6 as output. And set MRST=1 to let the module out of reset state.
 * For P2, setup and enable high-to-low edge interrupts for SW1/P2.6 and SW2/P2.7.
 * For P3, set MODULE_SS/P3.0 as an output, and MOSI/P3.1, MISO/P3.2, SCLK/P3.3 to their SPI functions.
 * For P5, set USB_TXD/P5.6 and USB_RXD/P5.7 to their UART functions.
 * For P8, set CFG1/P8.2 as an output and to 1.
 * For P11, set ACLK/P11.0, MCLK/P11.1 and SMCLK/P11.2 to their clock output functions.

void portInit {   //    //    Initialize Ports //   /*PORT 1: 1.0    LED (Red on MSP-EXP430F5438A) 1.1    LED (Yellow on MSP-EXP430F5438A) 1.2    MRST (module reset) 1.4    SRDY (Slave Ready) 1.5    GPIO3 1.6    MRDY (Master Ready) */   P1DIR = BIT0 + BIT1 + BIT2 + BIT6;        // Enable as outputs P1OUT = BIT2;                            // Deassert MRST /*PORT 2: 2.6    S1    2.7     S2    */ P2IE |= BIT6 + BIT7;                     // S1, S2 interrupt enabled P2IES |= BIT6 + BIT7;                    // S1, S2 Hi/Lo edge P2IFG &= ~(BIT6+BIT7);                   // S1, S2 IFG cleared /*PORT 3: 3.0    MODULE_SS 3.1    MOSI 3.2    MISO 3.3    SCLK */   P3DIR |= BIT0; P3SEL |= BIT1 + BIT2 + BIT3;             // MOSI, MISO, SCLK functions /*PORT 5: 5.6    USB_TXD / UCA1TXD 5.7    USB_RXD / UCA1RXD */   P5SEL = (BIT6+BIT7);                      // USCI_A1 TXD / RXD /*PORT 8: 8.2    CFG1                              // CFG1=1 => use SPI interface between MSP and A2530 module // CFG0=0 => no 32KHz crystal on A2530 (pulled down on A2530-EMZ board) */   P8DIR = BIT2; P8OUT = BIT2;                            // CFG1 => USE SPI /*PORT 11: 11.0    ACLK 11.1    MCLK 11.2    SMCLK */   P11DIR |= BIT0+BIT1+BIT2;                 // ACLK, MCLK, SMCLK set out to pins P11SEL |= BIT0+BIT1+BIT2;                // P11.0,1,2 for debugging purposes. }

Clock Setup - 8 MHz
From the Code Examples, use msp430x54xA_UCS_2.c as an example to set up the 8 MHz DCO-based clock in the oscInit function.

void oscInit { WDTCTL = WDTPW + WDTHOLD; // Stop WDT UCSCTL3 |= SELREF_2;                     // Set DCO FLL reference = REFO UCSCTL4 |= SELA_2;                       // Set ACLK = REFO

__bis_SR_register(SCG0);                 // Disable the FLL control loop UCSCTL0 = 0x0000;                        // Set lowest possible DCOx, MODx UCSCTL1 = DCORSEL_5;                     // Select DCO range 16MHz operation UCSCTL2 = FLLD_1 + 249;                  // Set DCO Multiplier for 8MHz // (N + 1) * FLLRef = Fdco // (249 + 1) * 32768 = 8MHz // Set FLL Div = fDCOCLK/2 __bic_SR_register(SCG0);                 // Enable the FLL control loop

// Worst-case settling time for the DCO when the DCO range bits have been // changed is n x 32 x 32 x f_MCLK / f_FLL_reference. See UCS chapter in 5xx // UG for optimization. // 32 x 32 x 8 MHz / 32,768 Hz = 250000 = MCLK cycles for DCO to settle __delay_cycles(250000);

// Loop until XT1,XT2 & DCO fault flag is cleared do { UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + XT1HFOFFG + DCOFFG); // Clear XT2,XT1,DCO fault flags SFRIFG1 &= ~OFIFG;                     // Clear fault flags }while (SFRIFG1&OFIFG);                  // Test oscillator fault flag }

UART Setup - 115200 baud
Once the UART setup is complete, the Hello World example should be able to run. It will print out Hello World once per second. So this will test both the UART, and the clock (since the once per second is based on the 8 MHz clock setting).

From the Code Examples, use msp430x54xA_uscia0_uart_01.c as an example of how to set up the 115200 baud, 8N1 USB UART. Note that the example needs to be slightly modified because it assumes a 1 MHz clock, and we are using an 8 MHz clock. In the MSP430F5438A Family Users Guide, table 34-4 contains the settings needed.

Note that for an 8,000,000 Hz clock, the three settings for 115200 baud are UCBRx=69, UCBRSx=4, UCBRFx=0.

void halUartInit { UCA1CTL1 |= UCSWRST;                      // **Put state machine in reset** UCA1CTL1 |= UCSSEL_2;                    // SMCLK UCA1BR0 = 69;                            // 8MHz 115200 (see User's Guide) UCA1BR1 = 0;                             // 8MHz 115200 UCA1MCTL |= UCBRS_4 + UCBRF_0;           // Modulation UCBRSx=4, UCBRFx=0 UCA1CTL1 &= ~UCSWRST;                    // **Initialize USCI state machine** UCA1IE |= UCRXIE;                        // Enable USCI_A1 RX interrupt }

Plus, the UCA1 interrupt service routine needs to be added. Again, the example above serves as a great starting point. The only change is to call debugConsoleIsr when a receive interrupt is activated.

__interrupt void USCI_A1_ISR(void) { switch(__even_in_range(UCA1IV,4)) { case 0:break;                             // Vector 0 - no interrupt case 2:                                  // Vector 2 - RXIFG debugConsoleIsr(UCA1RXBUF);        //reading this register clears the interrupt flag break; case 4:break;                            // Vector 4 - TXIFG default: break; } }
 * 1) pragma vector=USCI_A1_VECTOR

Again, the putChar function must be slightly modified to accommodate the UCA1 port, and the MSP430F5xxx interrupt structure.

int putchar(int c) { while (!(UCA1IFG&UCTXIFG));             // Wait for ready UCA1TXBUF = (uint8_t) (c & 0xFF); return c; }

LED Setup
The LED functions must be modified to use P1.0 and P1.1 as LED (0) and LED (1).

int16_t setLed(uint8_t led) {   switch (led) {   case 0: P1OUT |= BIT0;      // Red return 0; case 1: P1OUT |= BIT1;     // Yellow return 0; default: return -1; } }

int16_t clearLed(uint8_t led) {   switch (led) {   case 0: P1OUT &= ~BIT0;     // Red return 0; case 1: P1OUT &= ~BIT1;     // Yellow return 0; default: return -1; } }

void clearLeds {    P1OUT &= ~(BIT0+BIT1); }

int16_t toggleLed(uint8_t led) {   switch (led) {   case 0: P1OUT ^= BIT0;      // Red return 0; case 1: P1OUT ^= BIT1;     // Yellow return 0; default: return -1; } }

Button Setup
The function is modified to handle the two switches on P2.6 and P2.7. Plus, the ISR is modified to increase / decrease the LCD contrast if it is in use. The code example msp430x54xA_P1_02.c is a good starting point.

uint8_t buttonIsPressed(uint8_t button) {   if (button == ANY_BUTTON) return (~P2IN & (BIT6|BIT7)); else if (button == BUTTON_0) return (~P2IN & BIT6); else if (button == BUTTON_1) return (~P2IN & BIT7); return 0; }

__interrupt void Port_2(void) {   if (P2IFG & BIT6)                   //Modify this based on which pin is connected to Button {       buttonIsr(BUTTON_0);            // Button 0 was pressed contrastVal -= 4; halLcdSetContrast(contrastVal); // Lower the LCD contrast if (wakeupFlags & WAKEUP_AFTER_BUTTON) HAL_WAKEUP; }   if (P2IFG & BIT7)                   //Modify this based on which pin is connected to Button {       buttonIsr(BUTTON_1);            // Button 1 was pressed contrastVal += 4; halLcdSetContrast(contrastVal); // Raise the LCD contrast if (wakeupFlags & WAKEUP_AFTER_BUTTON) HAL_WAKEUP; }   P2IFG = 0;                          // clear the interrupt }
 * 1) pragma vector=PORT2_VECTOR
 * 1) ifdef USE_LCD
 * 1) endif
 * 1) ifdef USE_LCD
 * 1) endif

VCC sensor setup
The getVcc3 function has been modified to work with the MSP430F5438A. The code example msp430x54xA_adc12_10.c is a good starting point.

uint16_t getVcc3 { uint16_t temp;

/* Initialize the shared reference module */ REFCTL0 = REFMSTR + REFVSEL_2 + REFON;   // Enable internal 2.5V reference /* Initialize ADC12_A */ ADC12CTL0 = ADC12SHT0_8 + ADC12ON;       // Set sample time ADC12CTL1 = ADC12SHP;                    // Enable sample timer ADC12MCTL0 = ADC12SREF_1 + ADC12INCH_11; // ADC input ch A11 => Vcc/2 sense __delay_cycles(75);                      // delay to allow Ref to settle // based on default DCO frequency. // See Datasheet for typical settle // time. ADC12CTL0 |= ADC12ENC; ADC12CTL0 |= ADC12SC;                    // Sampling and conversion start

while (ADC12CTL1 & ADC12BUSY) ;          // Wait for conversion to complete temp = ADC12MEM0;                        // Put reading in temp ADC12CTL0 = 0;                           // Turn off ADC REFCTL0 = 0;                             // Turn off REF

return (temp * 5) / 4;                   // Convert ADC reading to mVDC }

Temp Sensor setup
A function has been added that reads the internal MSP-430 temperature sensor, and returns its value. The code example msp430x54xA_adc12_10.c is a good starting point.

uint16_t mspGetTemperature {                                                     //See device datasheet for TLV table memory mapping
 * 1) define CALADC12_15V_30C *((unsigned int *)0x1A1A)   // Temperature Sensor Calibration-30 C
 * 1) define CALADC12_15V_85C *((unsigned int *)0x1A1C)   // Temperature Sensor Calibration-85 C

unsigned int temp; volatile float temperatureDegC; volatile float temperatureDegF;

/* Initialize the shared reference module */ REFCTL0 = REFMSTR + REFVSEL_0 + REFON;   // Enable internal 1.5V reference /* Initialize ADC12_A */ ADC12CTL0 = ADC12SHT0_8 + ADC12ON;       // Set sample time ADC12CTL1 = ADC12SHP;                    // Enable sample timer ADC12MCTL0 = ADC12SREF_1 + ADC12INCH_10; // ADC input ch A10 => temp sense __delay_cycles(75);                      // delay to allow Ref to settle // based on default DCO frequency. // See Datasheet for typical settle // time. ADC12CTL0 |= ADC12ENC; ADC12CTL0 |= ADC12SC;                    // Sampling and conversion start

while (ADC12CTL1 & ADC12BUSY) ;          // Wait for conversion to complete temp = ADC12MEM0;                        // Put reading in temp ADC12CTL0 = 0;                           // Turn off ADC REFCTL0 = 0;                             // Turn off REF

// Temperature in Celsius. See the Device Descriptor Table section in the // System Resets, Interrupts, and Operating Modes, System Control Module // chapter in the device user's guide for background information on the // used formula. temperatureDegC = (float)(((long)temp - CALADC12_15V_30C) * (85 - 30)) / (CALADC12_15V_85C - CALADC12_15V_30C) + 30.0f;

// Temperature in Fahrenheit Tf = (9/5)*Tc + 32 temperatureDegF = temperatureDegC * 9.0f / 5.0f + 32.0f; return (int16_t) (100.0f * temperatureDegC); }

SPI Setup
From the Code Examples, use the msp430x54xA_uscia0_spi_09.c to help set up the halSpiInitModule routine. There are a couple of differences.


 * the example uses UCA0, and we need to use UCB0.
 * We use low clock polarity (so UCCKPH instead of UCCKPL).
 * The interrupts are not used in our examples.

void halSpiInitModule {   UCB0CTL1 |= UCSWRST;                            //hold SPI interface in reset UCB0CTL0 = UCCKPH | UCMSB | UCMST | UCSYNC;    //clock polarity = inactive is LOW (CPOL=0); Clock Phase = 0; MSB first; Master Mode; Synchronous Mode UCB0CTL1 |= UCSSEL_2;                          //serial clock source = SMCLK UCB0BR0 = 2; UCB0BR1 = 0;                      //SPI running at 2MHz (SMCLK / 2) UCB0CTL1 &= ~UCSWRST;                          //start USCI_B1 state machine }

The spiWrite function must be slightly modified for the newer MSP430F5xxx interrupt structure.

void spiWrite(uint8_t *bytes, uint8_t numBytes) {   while (numBytes--) {         UCB0TXBUF = *bytes; while (!(UCB0IFG&UCRXIFG)) ;     //WAIT for a character to be received, if any *bytes++ = UCB0RXBUF;            //read bytes } }

The SRDY interrupt vector accommodates the new P1.4 port.

__interrupt void Port_1(void) {   if (P1IFG & BIT4)                   //Modify this based on which pin is connected to SRDY {       srdyIsr; if (wakeupFlags & WAKEUP_AFTER_SRDY) HAL_WAKEUP; }   P1IFG = 0;                          // clear the interrupt }
 * 1) pragma vector=PORT1_VECTOR

Timer Setup
Since on the MSP-EXP430F5438A Experimenters board, the ACLK is a 32KHz clock driven by a crystal, the calibrateVlo function simply needs to set the frequency to 32768.

int16_t calibrateVlo { vloFrequency = 32768; return vloFrequency; }

The initTimer function differs from the LaunchPad/MSP430G2553 version in a few ways. First, the TimerA1 is used. Second, the code has been modified so that the TimerA1 ISR will be called once per second. The code in msp430x54xA_ta3_02.c is a good starting point. The main difference being that we are using ACLK (so TASSEL_1), not SMCLK to drive the timer.

This requires two new global variables at the top of the hal_MSP-EXP430F5438A.c file (that weren't present for the LaunchPad / MSP430G2553 version:

uint8_t wakeupSeconds = 0; // Number of seconds between wakeups uint8_t currentSeconds = 0; // Number of seconds since last wakeup

The initTimer routine then sets up the TimerA1 to interrupt once per second.

int16_t initTimer(uint8_t seconds) {     if ((seconds > TIMER_MAX_SECONDS) || (seconds == 0)) return -1; if (vloFrequency == 0) return -2; wakeupSeconds = seconds; wakeupFlags |= WAKEUP_AFTER_TIMER; TA1CCTL0 = CCIE;                         // CCR0 interrupt enabled TA1CCR0 = vloFrequency;                  // Interrupt every second TA1CTL = TASSEL_1 + MC_1 + TACLR;        // ACLK, UpMode, Clear return 0; }

The code in the ISR determines if the necessary number of seconds has passed, and if it is time to "wakeup" the processor.

__interrupt void TIMER1_A0_ISR(void) {   if (++currentSeconds >= wakeupSeconds) {       currentSeconds = 0; timerIsr; if (wakeupFlags & WAKEUP_AFTER_TIMER) {           HAL_WAKEUP; }   } }
 * 1) pragma vector=TIMER1_A0_VECTOR

The stopTimer routine simply turns off the timer.

void stopTimer {   TA1CTL = MC_0; }

LCD Setup
The halInit function is modified to add the initialization of the LCD screen on the Experimenters board. Use of the LCD is controlled by a pre-defined variable USE_LCD that can be added in the Project Options.

Note that some code has been added to take a first guess at the contrast value to use for the LCD. The S1 and S2 switches can be used to decrease / increase the contrast. This requires one new global variable at the top of the hal_MSP-EXP430F5438A.c file to hold the contrast value.

/** Contrast value for the LCD uint8_t contrastVal = 90;
 * 1) ifdef USE_LCD
 * 1) endif

void halInit {   oscInit;                      // Initialize oscillators portInit;                    // Configure GPIO ports halUartInit;                 // Initialize UART halLcdInit;                  // Initialize LCD contrastVal = INITIAL_CONTRAST + (NOMINAL_VCC - ((getVcc3+50)/100)) * DECREMENT_PER_TENTH; halLcdSetContrast(contrastVal); // Set the contrast halLcdClearScreen;           // Clear the screen SPI_SS_CLEAR;                // Deselect Module stopTimer;                   //  Stop Timer A:    //Point the function pointers to doNothing so that they don't trigger a restart debugConsoleIsr = &doNothing; buttonIsr = &doNothing;
 * 1) ifdef USE_LCD
 * 2) define INITIAL_CONTRAST 90        // Guess at 90 for a contrast val at nominal voltage.
 * 3) define NOMINAL_VCC 34             // Nominal voltage in tenths -- i.e. 3.4V
 * 4) define DECREMENT_PER_TENTH 4      // As voltage goes up by a tenth, contrast goes down by 4.
 * 1) endif

halSpiInitModule; clearLeds; displayVersion; }
 * 1) ifdef TESTING_SPI_UART_VERSION
 * 1) endif

A function that outputs important values to the LCD screen has been added. Calls to the lcdPrintStatus function can be added to the example programs in opportune places.

char * encodeHexByte (uint8_t zm, char *temptr) {   uint8_t x;    x = zm / 16; *temptr++ = x + '0' + (x>9 ? 7 : 0); x = zm % 16; *temptr++ = x + '0' + (x>9 ? 7 : 0); return temptr; } char * encodeDecByte (uint8_t zm, char *temptr) {   uint8_t x;    x = zm / 100; if (x>0) *temptr++ = x + '0'; x = (zm % 100) / 10; if (x>0) *temptr++ = x + '0'; x = zm % 10; *temptr++ = x + '0'; return temptr; }
 * 1) ifdef USE_LCD

void myStrCopy (char *source, char *dest, uint8_t MAX_LEN) { uint8_t i = 0; uint8_t done = 0; while (done == 0) {   if (i >= MAX_LEN)      // if it overflows, set last to zero. {     done = 1; dest[MAX_LEN-1] = 0; }   else {     dest[i] = source[i]; if (source[i] == 0) done = 1; i++; } } }

void lcdPrintStatus {   uint8_t line = 0; char *temptr; char outputString[MAX_LEN]; halLcdClearScreen;                   // Clear the screen myStrCopy ("Anaren AIR-ZNP\0", outputString, MAX_LEN); halLcdPrintLine(outputString, line++, OVERWRITE_TEXT);   // Write something.
 * 1) define MAX_LEN 18                        // number of chars on an lcd line

myStrCopy ("MSP FW rev xxxx\0", outputString, MAX_LEN); char moduleVer[12] = MODULE_INTERFACE_STRING; for (uint8_t i=0; i<4; i++) outputString[11+i] = moduleVer[6+i]; halLcdPrintLine(outputString, line++, OVERWRITE_TEXT); myStrCopy ("A2530 vx-xx-x.x.x\0", outputString, MAX_LEN); sysVersion; temptr = encodeDecByte (zmBuf[SYS_VERSION_RESULT_START_FIELD+0], &outputString[7]); temptr = encodeHexByte (zmBuf[SYS_VERSION_RESULT_START_FIELD+1], &outputString[9]); temptr = encodeDecByte (zmBuf[SYS_VERSION_RESULT_START_FIELD+2], &outputString[12]); temptr = encodeDecByte (zmBuf[SYS_VERSION_RESULT_START_FIELD+3], &outputString[14]); temptr = encodeDecByte (zmBuf[SYS_VERSION_RESULT_START_FIELD+4], &outputString[16]); *temptr = 0; halLcdPrintLine(outputString, line++, OVERWRITE_TEXT);

zbGetDeviceInfo(DIP_STATE); myStrCopy (getDeviceStateName(zmBuf[SRSP_DIP_VALUE_FIELD]), outputString, MAX_LEN); for (uint8_t i=0; i=SRSP_DIP_VALUE_FIELD; i--) {     temptr = encodeHexByte (zmBuf[i], temptr); }   *temptr = 0; halLcdPrintLine(outputString, line++, OVERWRITE_TEXT);

myStrCopy ("ShortAddr 0xxxxx\0", outputString, MAX_LEN); zbGetDeviceInfo(DIP_SHORT_ADDRESS); temptr = &outputString[12]; for (uint8_t i = SRSP_DIP_VALUE_FIELD+1; i>=SRSP_DIP_VALUE_FIELD; i--) {     temptr = encodeHexByte (zmBuf[i], temptr); }   *temptr = 0; halLcdPrintLine(outputString, line++, OVERWRITE_TEXT);

myStrCopy ("ParentAddr 0xxxxx\0", outputString, MAX_LEN); zbGetDeviceInfo(DIP_PARENT_SHORT_ADDRESS); temptr = &outputString[13]; for (uint8_t i = SRSP_DIP_VALUE_FIELD+1; i>=SRSP_DIP_VALUE_FIELD; i--) {     temptr = encodeHexByte (zmBuf[i], temptr); }   *temptr = 0; halLcdPrintLine(outputString, line++, OVERWRITE_TEXT);

myStrCopy ("Chan xx Pan xxxx\0", outputString, MAX_LEN); zbGetDeviceInfo(DIP_CHANNEL); temptr = &outputString[5]; for (uint8_t i = SRSP_DIP_VALUE_FIELD; i>=SRSP_DIP_VALUE_FIELD; i--) {     temptr = encodeDecByte (zmBuf[i], temptr); }   temptr = &outputString[12]; zbGetDeviceInfo(DIP_PANID); for (uint8_t i = SRSP_DIP_VALUE_FIELD+1; i>=SRSP_DIP_VALUE_FIELD; i--) {     temptr = encodeHexByte (zmBuf[i], temptr); }   *temptr = 0; halLcdPrintLine(outputString, line++, OVERWRITE_TEXT); myStrCopy ("x.xV xx.x^C\0", outputString, MAX_LEN); uint16_t vcc = getVcc3; vcc += 50;                             // round to tenths outputString[0] = vcc/1000 + '0'; vcc = vcc % 1000; outputString[2] = vcc/100 + '0'; uint16_t tempC = mspGetTemperature; tempC += 5;                                        // round to tenths of degrees. outputString[5] = tempC / 1000 + '0'; tempC %= 1000; outputString[6] = tempC / 100 + '0'; tempC %= 100; outputString[8] = tempC / 10 + '0'; halLcdPrintLine(outputString, line++, OVERWRITE_TEXT); }
 * 1) endif

Stub out the unused functions
Since there is no RGB LED on the Experimenters board, the three routines are simply stubbed out.

void halRgbLedPwmInit { }

void halRgbSetLeds(uint8_t red, uint8_t blue, uint8_t green) { }

void halRgbLedTest { }

Add the new functions to the list of global functions
The three new functions (getVcc3, mspGetTemperature, and lcdPrintStatus) need to be added to the list of global functions at the top of the .h file.

uint16_t mspGetTemperature; uint16_t getVcc3; void lcdPrintStatus;

Change the LED definitions
There are only two LEDs. So there is some function overlap.


 * 1) define ON_NETWORK_LED         1
 * 2) define NETWORK_FAILURE_LED    1
 * 3) define SEND_MESSAGE_LED       0

Modify the SPI function definitions
Some of the control bits have moved to different ports. As such, these macros need to change:

The SRDY Interrupt is on P1.4.


 * 1) define ENABLE_SRDY_INTERRUPT    (P1IE |= BIT4)
 * 2) define DISABLE_SRDY_INTERRUPT   (P1IE &= ~BIT4)
 * 3) define SRDY_IS_HIGH             (P1IN & BIT4)
 * 4) define SRDY_IS_LOW              ((~P1IN) & BIT4)

The MRST line is on P1.2.


 * 1) define RADIO_ON                 (P1OUT |= BIT2)  //ZM Reset Line
 * 2) define RADIO_OFF                (P1OUT &= ~BIT2)

Since MRDY is not connected via hardware to MODULE_SS, both must be changed when activating / deactivating the SPI slave select.


 * 1) define SPI_SS_SET               (P3OUT &= ~BIT0); (P1OUT &= ~BIT6)  //active low, control SS and MRDY
 * 2) define SPI_SS_CLEAR             (P3OUT |= BIT0); (P1OUT |= BIT6)

Complete adding the new HAL files to the projects
The procedure in AIR-ZNP_Port_for_the_MSP-EXP430F5438A_Experimenters_Board can now be executed to complete creating new configurations, adding the new HAL files to the projects, and defining the appropriate pre-defined symbols. Once done, the projects should build without error.