/**
 * @file main.c
 * @brief Demo ADC12 single conversion on button press
 *
 * Press of a button initiates conversion on channel A0
 * of ADC12, which is connected to a potentiometer.
 * Result of the conversion is sent through USCI to PC.
 *
 * @date 2021
 * @author Marija Bezulj (meja@etf.bg.ac.rs)
 *
 * @version [1.0 @ 05/2021] Initial version
 */
#include <msp430.h> 
#include <stdint.h>

#define BR9600      (109)

#define BRS9600      (UCBRS_2)

/**
 * @brief Timer period
 *
 * Timer is clocked by ACLK (32768Hz).
 * We want ~5ms period, so use 163 for CCR0
 */
#define TIMER_PERIOD        (163)  /* ~5ms (4.97ms) */

/**
 * @brief Main function
 *
 * Peripheral initialization. USCI_A1 is used in UART mode
 * for transfer of ADC12 conversion result.
 */
int main(void)
{
    WDTCTL = WDTPW | WDTHOLD;       // Stop watchdog timer

    // Initialize UART
    P4SEL |= BIT4 | BIT5;           // enable P4.4 and P4.5 for UART

    UCA1CTL1 |= UCSWRST;            // set software reset

    UCA1CTL0 = 0;                   // no parity, 8bit, 1 stop bit
    UCA1CTL1 |= UCSSEL__SMCLK;      // use SMCLK = 1 048 576 Hz
    UCA1BRW = BR9600;              // BR = 109
    UCA1MCTL |=BRS9600 + UCBRF_0;  // BRS = 2 for 9600 bps

    UCA1CTL1 &= ~UCSWRST;           // release software reset

    // configure button S1
    P1REN |= BIT4;              // enable pull up/down
    P1OUT |= BIT4;              // set pull up
    P1DIR &= ~BIT4;             // configure P1.4 as in
    P1IES |= BIT4;              // interrupt on falling edge
    P1IFG &= ~BIT4;             // clear flag
    P1IE  |= BIT4;              // enable interrupt

    /* initialize Timer A0 */
    TA0CCR0 = TIMER_PERIOD;     // debounce period
    TA0CCTL0 |= CCIE;            // enable CCR0 interrupt
    TA0CTL |= TASSEL__ACLK;

    /* ADC12_A channel A0 init */
    P6SEL |= BIT0;              // set pin P6.0 as alternate function - A0 analog
                                // this is pot2 potentiometer
    ADC12CTL0 &= ~ADC12ENC;     // disable ADC before configuring
    /* 32 cycles for sampling, ref voltage is set by REF module, ADC ON */
    ADC12CTL0 |= ADC12SHT0_3 + ADC12ON;
    ADC12CTL1 |= ADC12SHP + ADC12SSEL_3; // start address ADC12MEM0, SC starts conversion
                                         // single channel single conversion, SMCLK clock
                                         // S&H pulse mode triggered by ADC12SC and
                                         // SAMPCON sourced from the sampling timer
    ADC12CTL2 &= ~ADC12RES_2;   // 8 bit conversion result
    ADC12MCTL0 |= ADC12INCH_0;   //reference AVCC and AVSS, channel A0
    ADC12CTL0 |= ADC12ENC;      // enable ADC12

    __enable_interrupt();           // GIE

    while(1){
        while ((ADC12IFG & ADC12IFG0) == 0); // wait for conversion to end
        UCA1TXBUF = ADC12MEM0;               // send the converted 8bit value to PC
    }
}

/**
 * @brief PORT1 ISR
 *
 * On button press send data using UART
 */
void __attribute__ ((interrupt(PORT1_VECTOR))) P1ISR (void)
{
    if ((P1IFG & BIT4) != 0)        // check if P1.4 flag is set
    {
        /* start timer */
        TA0CTL |= MC__UP;

        P1IFG &= ~BIT4;             // clear P1.4 flag
        P1IE &= ~BIT4;              // disable P1.4 interrupt
    }
}

/**
 * @brief TIMERA0 Interrupt service routine
 *
 * ISR debounces P1.4 and starts ADC12 single conversion
 */
void __attribute__ ((interrupt(TIMER0_A0_VECTOR))) CCR0ISR (void)
{
    if ((P1IN & BIT4) == 0) // check if button is still pressed
    {
        ADC12CTL0 |= ADC12SC;  // start ADC12 conversion
    }
    TA0CTL &= ~(MC0 | MC1); // stop and clear timer
    TA0CTL |= TACLR;
    P1IFG &= ~BIT4;         // clear P1.4 flag
    P1IE |= BIT4;           // enable P1.4 interrupt
    return;
}
