//***************************************************************************************

// Adapter 16 - Both

//   Calibrates DCO synced to 32768 crystal (1MHz)

//   Uses UART (UART uses ACLK from crystal)

 

// MSP430G2553

 

// Jed Margolin  2/27/2016.

//  Built with Code Composer Studio v6

//***************************************************************************************

// main.c

 

#include <msp430.h>

//#include <msp430G2553.h>

 

#define DELTA_1MHZ    244           // 244 x 4096Hz = 999.4Hz

#define DELTA_8MHZ    1953         // 1953 x 4096Hz = 7.99MHz

#define DELTA_12MHZ   2930        // 2930 x 4096Hz = 12.00MHz

#define DELTA_16MHZ   3906       // 3906 x 4096Hz = 15.99MHz

#define TIME 6

#define DCOUNT 8

 

void wait(unsigned int);

void wait2(void);

void uartsetup_4800(void);

void uart_init(void);

void uart_send_byte(unsigned char byte);

void Set_DCO(unsigned int Delta);

 

static volatile char rx_byte = '\0';

//================================================

// main - uart - send bytes

int main(void)

{

            unsigned char caldata1, caldata2;                  // Temp. storage for constants

            volatile unsigned int k = 0;

            unsigned char mbyte, temp;

            int count,n;

            unsigned char switches;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                

 

            WDTCTL = WDTPW + WDTHOLD;           // Stop watchdog timer

 

            wait(1000);                                         // give the crystal time to stabilize

 

            P1SEL  |= BIT0;                                 // ACLK

            P1SEL2 &= ~(BIT0);

            P1DIR  |= BIT0;

 

            P1SEL  |= BIT1;                                 // RX In

            P1SEL2 |= BIT1;

            P1REN |= BIT1;                                  // pullup/pulldown enabled

            P1OUT |= BIT1;

            P1DIR &= ~(BIT1);                           // In

 

            P1SEL  |= BIT2;                                 // TX Out

            P1SEL2 |= BIT2;

            P1DIR |= BIT2;

 

            P1SEL  &= ~(BIT3);                          // Out - for testing

            P1SEL2 &= ~(BIT3);

            P1DIR |= BIT3;

 

            P1SEL  |= BIT4;                                 // Out for SMCLK so we know it's working

            P1SEL2 &= ~(BIT4);

            P1DIR |= BIT4;

 

            P1SEL  &= ~(BIT5);                          // In  1 = furnace, 0=thermostat

            P1SEL2 &= ~(BIT5);

            P1REN |= BIT5;                                  // pullup/pulldown enabled

            P1OUT |= BIT5;                                 // pullup

            P1DIR &= ~(BIT5);                           // In

 

            P1DIR &= ~(BIT6);                           // In

            P1OUT |= BIT6;                                 // pullup

            P1SEL  &= ~(BIT6);

            P1SEL2 &= ~(BIT6);

            P1REN |= BIT6;                                  // pullup/pulldown enabled

 

            P1DIR &= ~(BIT7);                           // In - 60Hz phase

            P1OUT |= BIT7;                                 // pullup

            P1SEL  &= ~(BIT7);

            P1SEL2 &= ~(BIT7);

            P1REN |= BIT7;                                  // pullup/pulldown enabled

 

            switches = 0x00;

 

// Lock the DCO to the 32768 crystal - 1 MHz

              Set_DCO(DELTA_1MHZ);             // Set DCO and obtain constants

              caldata1 = DCOCTL;                       // for debugging

              caldata2 = BCSCTL1;

 

/*

Port 2

 

On the Furnace Adapter P2.5, P2.4, P2.3 are sent to the Thermostat Adapter and are output on Thermostat P2.2, P2.1, P2.0

 

On the Thermostat Adapter P2.5, P2.4, P2.3 are sent to the Furnace Adapter and are output on Furnace P2.2, P2.1, P2.0

 

  P2.5   In         Furnace=Diagnostic LED                   Thermostat=Call for Heat

  P2.4   In         Furnace=Flame Good LED                Thermostat=Call for Cool

  P2.3   In         Furnace= not used                              Thermostat=Auto/Fan

  P2.2   Out Furnace= Heat Relay                               Thermostat=Diagnostic LED

  P2.1   Out Furnace=Cool Relay                                Thermostat= Flame Good LED

  P2.0   Out      Furnace= Fan Relay                           Thermostat= not used

 

P2 In

            P2SEL  &= ~(BIT5|BIT4|BIT3);

            P2SEL2 &= ~(BIT5|BIT4|BIT3);

            P2REN  |= BIT5|BIT4|BIT3;               // pullup/pulldown enabled

            P2OUT  |= BIT5|BIT4|BIT3;              // pullup

            P2DIR  &= ~(BIT5|BIT4|BIT3);                    // In

 

P2 Out

            P2SEL  &= ~(BIT2|BIT1|BIT0);

            P2SEL2 &= ~(BIT2|BIT1|BIT0);

            P2DIR  |=  (BIT2|BIT1|BIT0);                        // Out

*/

 

// Initialize

            if(P1IN & BIT5) {P2OUT &= ~(BIT2|BIT1|BIT0);}            // furnace (relays) - reset to low

            else {P2OUT |= (BIT2|BIT1|BIT0);}             // thermostat (LEDs) - reset to high

 

            uartsetup_4800();

            uart_init();                                          // no interrupts for either RX or TX

 

// Main Loop

            while (1)                                 // main loop

            {

// send a byte

                        P1OUT |= BIT3;                                 // sync for 'scope

                        P1OUT &= ~(BIT3);

 

                        mbyte = 0;

 

                        if(P2IN & BIT5)  {mbyte |= BIT0;}

                        if(P2IN & BIT4)  {mbyte |= BIT1;}

                        if(P2IN & BIT3)  {mbyte |= BIT2;}

 

//                      mbyte = 0x05;                        // for testing

                        uart_send_byte(mbyte);

                        wait2();

 

// wait for our byte to be echoed

// At 4800 Baud it takes 2.1 ms to send a character so we will wait for the character

// to get sent and received.

                        rx_byte = 0;

                        for(k=17; k>0; k--)

                        {

                                    if(IFG2 & UCA0RXIFG)

                                    {

                                                rx_byte = UCA0RXBUF;                   // Get the received character

                                                break;

                                    }

                                    wait2();

                        }

 

                        if(rx_byte != mbyte)

                        {

                        // we had a data collision

                                    P1OUT |= BIT3;                                 // flag the error for 'scope

                                    if(P1IN & BIT5) {wait(6);}               // furnace waits for time 1

                                    else {wait(10);}                                  // thermostat waits for time 2

                                    P1OUT &= ~(BIT3);

                                    wait(2);

                        }

 

                        wait(2);

// end of waiting for and checking the echoed byte

 

// Check for incoming byte but timeout after 19 ms

            for(k=17; k>0; k--)

            {

                        if(IFG2 & UCA0RXIFG)

                        {

                                    rx_byte = UCA0RXBUF;                               // Get the received character

                                    break;

                        }

                        else {wait(2);}

            }          // end looking for received byte

 

            if(k != 0)                                             // we received a byte from the thermostat/furnace

            {

                        if(rx_byte & BIT0)  {P2OUT |= BIT2;}        // Call for Heat/Diagnostic LED

                        else {P2OUT &= ~BIT2;}

 

                        if(rx_byte & BIT1)  {P2OUT |= BIT1;}        // Call for Cooling/Flame Good LED

                        else {P2OUT &= ~BIT1;}

 

                        if(rx_byte & BIT2)  {P2OUT |= BIT0;}        // Auto-Fan/not used

                        else {P2OUT &= ~BIT0;}

            }

 

            if(P1IN & BIT5) {wait(1);}               // furnace

            else {wait(3);}                                                // thermostat

 

            }  // end main loop

}  // end main

//==================================

void wait(unsigned int time)              // 500 us

{

    volatile unsigned int i,j;

 

    for(i=time; i>0; i--)

    {

            for(j=48; j>0; j--);

            {

            }

    }

 

    return;

}

//=========================================================

// Low-Frequency Baud Rate Mode

// Read chapter 15.3.10 of msp430x2xxx user's guide for baud rate generation

void uartsetup_4800(void)

{

            P3SEL = 0x30;                       // P3.4,5 = USCI_A0 TXD/RXD, No need to set direction

            UCA0CTL1 |= UCSSEL_1;    // CLK = ACLK

            UCA0BR0 = 0x06;                 // 6 = INT(6.83), 32.768KHz/4800 = 6.8

            UCA0BR1 = 0x00;                                                                   //

            UCA0MCTL = UCBRS2 + UCBRS1 + UCBRS0;  // Modulation UCBRSx = 7 = round(0.83 * 8)

            UCA0CTL1 &= (~UCSWRST);                                              // ** Initialize USCI state machine

}

 

void uart_init(void)

{

            IE2 &= ~UCA0RXIE;       // default: Disable USCI_A0 RX interrupt

            IE2 &= ~UCA0TXIE;             // default: Disable USCI_A0 TX interrupt

}

 

// Sends a single byte out through UART

void uart_send_byte(unsigned char byte)

{

            while (!(IFG2&UCA0TXIFG));         // USCI_A0 TX buffer ready?

            UCA0TXBUF = byte;                         // TX -> RXed character

}

 

// USCI A0/B0 Transmit ISR

#pragma vector=USCIAB0TX_VECTOR

__interrupt void USCI0TX_ISR(void)

{

            IE2 &= ~UCA0TXIE;                         // Disable USCI_A0 TX interrupt

}

 

//==========================================================

void wait2()

{

volatile unsigned int i;

 

            for(i=0; i<48; i++){}

            return;

}

//========================================================

// This function came from Texas Instruments program msp430g2xx3_dco_flashcal.c

void Set_DCO(unsigned int Delta)            // Set DCO to selected frequency

{

  unsigned int Compare, Oldcapture = 0;

 

  BCSCTL1 |= DIVA_3;                        // ACLK = LFXT1CLK/8

  TACCTL0 = CM_1 + CCIS_1 + CAP;            // CAP, ACLK

  TACTL = TASSEL_2 + MC_2 + TACLR;          // SMCLK, cont-mode, clear

 

  while (1)

  {

    while (!(CCIFG & TACCTL0));          // Wait until capture occured

    TACCTL0 &= ~CCIFG;                      // Capture occured, clear flag

    Compare = TACCR0;                          // Get current captured SMCLK

    Compare = Compare - Oldcapture;     // SMCLK difference

    Oldcapture = TACCR0;                      // Save current captured SMCLK

 

    if (Delta == Compare)

      break;                                // If equal, leave "while(1)"

    else if (Delta < Compare)

    {

      DCOCTL--;                             // DCO is too fast, slow it down

      if (DCOCTL == 0xFF)            // Did DCO roll under?

        if (BCSCTL1 & 0x0f)

          BCSCTL1--;                        // Select lower RSEL

    }

    else

    {

      DCOCTL++;                             // DCO is too slow, speed it up

      if (DCOCTL == 0x00)              // Did DCO roll over?

        if ((BCSCTL1 & 0x0f) != 0x0f)

          BCSCTL1++;                        // Sel higher RSEL

    }

  }

  TACCTL0 = 0;                             // Stop TACCR0

  TACTL = 0;                                 // Stop Timer_A

  BCSCTL1 &= ~DIVA_3;           // ACLK is divide by 1

}

//=================================================================