Hello,
In the code below, I am trying to use Timer A to trigger ADC conversion every one second. I have multiple sensors in my converter, so I am trying to use the timer for sensing the non-critical signals every one second. There are other sensors that need to be included in the code, but for now I am trying to see if I can execute the main code, trigger ADC signal in the timer ISR every one second and during the rest of the time run the main loop. However, my code is not returning to main. Is just goes into the ADC and timer ISRs.
I am using single channel ADC conversion and I did try exiting from the ISR in both ADC and timer ISRs but none of them seem to work. The GetADC function sets the input channel and enables the ADC ISR and the timer ISR calls this function every 1 second. How can I make this work or is there a better way of implementing this? Thank you.
/*
* CSHTEG code
* Firehiwot Gurara - July 2021
* main.c
* used MSP430F51x2_adc10_10.c for configuring ADC and DMA
* Robert Erickson's code for configuring PWM (ecee.colorado.edu/.../main.c)
*/
#include <msp430.h>
#include <stdint.h>
#include <math.h>
//define functions
void SetVcoreUp (unsigned int level);
void SetPWM (unsigned int tbuck, unsigned int tboost);
void SetDuty_Buck (unsigned int dbuckH, unsigned int dbuckL);
void SetDuty_Boost (unsigned int dboost, unsigned int dboostL);
void SetADC ();
void SetDMA();
void OffBuck(unsigned int dH, unsigned int dL);
void OffBoost(unsigned int dH, unsigned int dL);
void OnBattery();
void OffBattery();
#define T_buck 200 // period of buck stage - 200MHz/500kHz (desired freq)=400
#define T_boost 200 // // period of boost stage
unsigned int ADC_Result[6]; // 10-bit ADC conversion result array
unsigned int Iin_temp; // 10-bit ADC conversion result array
unsigned int Vin_temp; // 10-bit ADC conversion result array
unsigned int Vbat_temp; // 10-bit ADC conversion result array
unsigned int Ibat_temp; // 10-bit ADC conversion result array
unsigned int Vout_temp; // 10-bit ADC conversion result array
unsigned int Iout_temp; // 10-bit ADC conversion result array
unsigned int Vbuck_temp;
unsigned int flag;
unsigned int REdge1, FEdge2, FEdge_IN1, FEdge_IN2; // Variables to hold timer capture values
unsigned int F_EDGE, dt;
unsigned int Vin_min=260; // 5V is the minimum input voltage
unsigned int Vin_minABS=180; // ~4V - prevents current flowing back to TEGs (buck stage)
unsigned int i; // Declare counter variable
volatile unsigned int D_buckH,D_buckL ; // buck duty cycle
volatile unsigned int D_boostH,D_boostL; // boost duty cycle
volatile unsigned int bat_State; // battery switch state
void main(void) {
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
// Configure PWM channels
/*
P1SEL |= BIT7; // Set P1.7 to output direction - High BUCK
P1DIR |= BIT7;
P2SEL |= BIT0; // Set P2.0 to output direction - Low BUCK
P2DIR |= BIT0;
P2SEL |= BIT2; // Set P2.2 to output direction - High BOOST
P2DIR |= BIT2;
P2SEL |= BIT3; // Set P2.3 to output direction - Low BOOST
P2DIR |= BIT3;
*/
// configure ADC pins
PMAPPWD = 0x02D52; // Enable Write-access to modify port mapping registers
PMAPCTL = PMAPRECFG; // Allow reconfiguration during runtime
//P1MAP0|= PM_ANALOG; // Modify all PxMAPy registers - A0 - Iin
P1MAP1|= PM_ANALOG; // Modify all PxMAPy registers - A1 - Vout_buck
P1MAP2|= PM_ANALOG; // Modify all PxMAPy registers - A2 - Vout
P1MAP3|= PM_ANALOG; // Modify all PxMAPy registers - A3
P1MAP4|= PM_ANALOG; // Modify all PxMAPy registers - A4 - Vbat
P1MAP5|= PM_ANALOG; // Modify all PxMAPy registers - A5 - Iout
P3MAP5|= PM_ANALOG; // Modify all PxMAPy registers - A8 - Ibat
//P3MAP6|= PM_ANALOG; // Modify all PxMAPy registers - A7 - Vin
P2MAP2|= PM_TD1_1;
P2MAP3|= PM_TD1_2;
P2MAP0|= PM_TD0_2;
P1MAP7|= PM_TD0_1;
P1SEL |=BIT7+BIT5+BIT4+BIT3+BIT2+BIT1; // setting the port mapping register PxMAPy to PM_ANALOG together with PxSEL.y=1 when applying analog signals
//P3SEL |=BIT5+BIT6;
P2SEL |= BIT0+BIT2+BIT3;
P2DIR |= BIT0+BIT2+BIT3;
P1DIR |= BIT7;
P1OUT |= 0x00; // Set P1.0 LED on
P1DIR |= BIT0;
P3SEL &= (~BIT0); // Set P3.0 to GPIO and to output direction - BAT_GD_EN
P3DIR |= BIT0;
P2SEL &= (~BIT6); // Set P2.6 as GPIO and to output direction - Vgate BAT
P2DIR |= BIT6;
P3DIR |= BIT6; // P3.6/TA0.1 output
P3SEL |= BIT6; // Output TA0.1 ADC trigger signal
PMAPPWD = 0; // Disable Write-Access to modify port mapping registers by writing incorrect key
// Increase Vcore setting to level3 to support fsystem=25MHz
// NOTE: Change core voltage one level at a time.
SetVcoreUp (0x01);
SetVcoreUp (0x02);
SetVcoreUp (0x03);
// Initialize DCO to 25MHz
__bis_SR_register(SCG0); // Disable the FLL control loop - set SCG0
UCSCTL0 = 0x0000; // Set lowest possible DCOx, MODx
UCSCTL1 = DCORSEL_7; // Select DCO range 4.6MHz-88MHz operation
UCSCTL2 = FLLD_1+762; // Set DCO Multiplier for 25MHz
// (N + 1) * FLLRef = Fdco
// (762 + 1) * 32768 = 25MHz
// Set FLL Div = fDCOCLK/2
__bic_SR_register(SCG0); // Enable the FLL control loop - clear SCG0
// 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 25 MHz / 32,768 Hz = 781250 = MCLK cycles for DCO to settle
//__delay_cycles(781250);
__delay_cycles(782000);
// setup ADC
ADC10CTL1 |= ADC10SHP+ADC10SHS_1; // ADCCLK = MODOSC; sampling SIGNAL is sourced from the sampling timer
ADC10CTL2 |= ADC10RES; // 10-bit conversion results
ADC10MCTL0|= ADC10SREF_1; // Select ADC channel; USE VR+ = VREF and VR- = AVSS
// Configure internal reference
ADC10CTL0 |= ADC10SHT_2 + ADC10ON; // ADC10ON, Sample&Hold=16 ADC clks - ADC10SHT_2=2*256
while(REFCTL0 & REFGENBUSY); // If ref generator busy, WAIT
REFCTL0 |= REFVSEL_2+REFON; // Select internal ref = 2.5V
// Internal Reference ON
__delay_cycles(75); // Delay (~4us) for Ref to settle -ADC10 sample & convert = (32+13)*2/SMCLK = 90/SMCLK = 75us
ADC10IE |= ADC10IE0; // Enable ADC conv complete interrupt
SetPWM(T_buck, T_boost);
D_buckH = 53;
D_buckL = 54;
D_boostH = 148;
D_boostL = 149;
__delay_cycles(100); // Delay between sequence convs
// Configure Timer (TA0.1 - see device specific d/s) -> ADC conversion trigger
TA0CCR0 = 16384-1; // PWM Period
TA0CCR1 = 16384-1; // PWM Period
TA0CCTL1 = OUTMOD_4 + CCIE; // TACCR1 toggle;
TA0CTL = TASSEL_1 + MC_1 + TACLR; // ACLK, up mode
while (1){
if (Vin_temp>=Vin_min){
OffBattery();
__delay_cycles(100); // Delay between sequence convs
SetDuty_Buck (D_buckH, D_buckL);
}
else if(Vin_temp<Vin_min & Vin_temp>=Vin_minABS){
// turn off buck stage
//P1OUT &= ~0x01; // Clear P1.0 LED off
OffBuck(0,0);
__delay_cycles(100); // Delay between sequence convs
OnBattery();
__delay_cycles(100); // Delay between sequence convs
// turn on the boost stage
SetDuty_Boost(D_boostH, D_boostL);
}
else if (Vin_temp<Vin_minABS)
{
//P1OUT |= 0x01; // Set P1.0 LED on
OffBuck(0,0);
__delay_cycles(100); // Delay between sequence convs
OffBoost(0,0);
__delay_cycles(100); // Delay between sequence convs
OffBattery();
}
__bis_SR_register(LPM0_bits + GIE); // Enter LPM3, enable interrupts
}
}
// Timer A0 interrupt service routine
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=TIMER0_A1_VECTOR
__interrupt void Timer_A(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(TIMER0_A0_VECTOR))) Timer_A (void)
#else
#error Compiler not supported!
#endif
{
flag=5;
GetADC(flag);
TA0CTL = 0; // Clear Timer_A control registers
__bic_SR_register_on_exit(CPUOFF); // Clear CPUOFF bit from 0(SR)
}
// ADC10 interrupt service routine
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(ADC10_VECTOR))) ADC10_ISR (void)
#else
#error Compiler not supported!
#endif
{
switch(__even_in_range(ADC10IV,12))
{
case 0: break; // No interrupt
case 2: break; // conversion result overflow
case 4: break; // conversion time overflow
case 6: break; // ADC10HI
case 8: break; // ADC10LO
case 10: break; // ADC10IN
case 12:
//ADC10IFG &= ~ADC10INIFG; // Clear interrupt flag
//TD0CTL0 &= ~MC_1; // Turn off Timer
ADC10CTL0 &= ~ADC10ENC;
if (flag==0)
Iin_temp= ADC10MEM0;
else if (flag==1)
Vbuck_temp= ADC10MEM0;
else if (flag==2)
Vout_temp= ADC10MEM0;
else if (flag==4)
Vbat_temp= ADC10MEM0;
else if (flag==5)
Iout_temp= ADC10MEM0;
else if (flag==7)
Vin_temp= ADC10MEM0;
else if (flag==8)
Ibat_temp= ADC10MEM0;
//__bic_SR_register_on_exit(LPM0_bits);
break; // Clear CPUOFF bit from 0(SR)
default: break;
}
}
// functions
void GetADC(int ADC_chan){
if (ADC_chan==0){ // Iin
ADC10MCTL0|= ADC10INCH_0; //Select ADC channel; USE VR+ = VREF and VR- = AVSS
}
else if (ADC_chan==1){ // Vout_buck
ADC10MCTL0|= ADC10INCH_1; //Select ADC channel; USE VR+ = VREF and VR- = AVSS
}
else if (ADC_chan==2){ // Vout
ADC10MCTL0|= ADC10INCH_2; //Select ADC channel; USE VR+ = VREF and VR- = AVSS
}
else if (ADC_chan==4){ // Vbat
ADC10MCTL0|= ADC10INCH_4; //Select ADC channel; USE VR+ = VREF and VR- = AVSS
}
else if (ADC_chan==5){ // Iout
ADC10MCTL0|= ADC10INCH_5; //Select ADC channel; USE VR+ = VREF and VR- = AVSS
}
else if (ADC_chan==7){ // Vin
ADC10MCTL0|= ADC10INCH_7; //Select ADC channel; USE VR+ = VREF and VR- = AVSS
}
else if (ADC_chan==8){ // Ibat
ADC10MCTL0|= ADC10INCH_8; //Select ADC channel; USE VR+ = VREF and VR- = AVSS
}
else {
//error
}
while (ADC10CTL1 & BUSY); // Wait if ADC10 core is active
ADC10CTL0 |= ADC10ENC + ADC10SC; // Sampling and conversion ready -- triggers the ADC interrupt
}