This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP430FR2355: MSP430FR2355 MULTIPLE CHANNEL ADC WITH TIMER TRIGGER not working

Part Number: MSP430FR2355
Other Parts Discussed in Thread: MATHLIB

Hello all,

Iam trying to use the ADC of my MSP430FR2355 LAUNCHPAD to sample the outputs of two SAC i.e. SAC0 & SAC2 using TIMER TRIGGER.

According to User Guide of launchpad, OA0 out can be connected internally to ADC Input & OA20 out needs to be connected to ADC input externally.

I've followed the examples and try writing the below code as shown 

 /*******************SAC0 configurations ******************/
	             P1SEL0 |=   BIT1|BIT2 ;             // Select  P1.2 P1.1 AS OA0 OUTPUT OA0- PIN function
	             P1SEL1 |=  BIT1| BIT2 ;             // Select  P1.2  OA0- PIN function

	             SAC0DAC = DACSREF_1;                        // Select 2.5V int Vref as DAC reference
	               SAC0DAT = 2048;                         // Set SAC DAC data to 1.25V
	               SAC0DAC |= DACEN;                         // Enable DAC
	             SAC0OA |= NMUXEN | PMUXEN | PSEL_1 | NSEL_0; //Select positive INPUT AS DAC and negative pin input AS external
	          //  SAC0PGA |= MSEL_0;                          // INVERTING PGA MODE
	             SAC0OA &= ~OAPM;                            // Select HIGH speed and HIGH power mode
	             SAC0OA |= SACEN + OAEN;                     // Enable SAC and OA

	             /****************SAC2 configurations AS INVERTING PGA************/
	                                     P3SEL0 |= BIT1    ;             // Select P3.1   OA2 OUTPUT function
	                                     P3SEL1 |= BIT1    ;             // Select P3.1   OA2 OUTPUT function

	                                      SAC2DAC = DACSREF_1;                       // Select 2.5V int Vref as DAC reference
	                                      SAC2DAT = 2048;                         // DAC TO PROVIDE BIAS FOR AMPLIFIER
	                                      SAC2DAC |= DACEN;                         // Enable DAC
	                                     SAC2OA |= NMUXEN | PMUXEN | PSEL_1 | NSEL_1;//Select positive INPUT AS DAC and negative pin input AS O/P of OA0
	                                     SAC2PGA |= GAIN0 + GAIN2 + MSEL_3;    // Set inverting PGA mode with Gain=16
	                                     SAC2OA &= ~OAPM;                           // Select HIGH speed and HIGH power mode
	                                     SAC2OA |= SACEN | OAEN; // Enable SAC and OA
/***********ADC CONFIGURATION***********/ ADCCTL0 &= ~ADCENC; // Disable ADC ADCCTL0 |= ADCSHT_4 | ADCMSC | ADCON; //0000010010010010; 64 ADCLK CYCLES, MSC BIT HIGH, ADC ON ADCCTL1 |= ADCSHP | ADCSHS_1 | ADCCONSEQ_1|ADCSSEL_1; //0000010010010010; ADCCTL2 &= ~ADCRES; //CLEAR RESOLUTION ADCCTL2 |= ADCRES_2; //12 BIT RESOLUTION ADCMCTL0 |= ADCSREF_1|ADCINCH_1|ADCINCH_3; // OA0 OUTPUT AS A1 ADC INPUT ,VR+= VREF+, ALSO OA2 OUPUT EXTERNALLY CONNECTED TO A3 ADC INPUT ADCIE |= ADCIE0; // ENABLE CONVERSION COMPLETE INTERRUPT __enable_interrupt(); // enable maskables /******************** Configure Timer ******************/ TB0CTL = TBSSEL__ACLK + TBCLR; //ACLK & Reset timer TB0CCTL1 = OUTMOD_2; // TOGGLE & RESET TB0CCTL0 = CCIE; //INTERRUPT ENABLE TB0CCR0 = 31; //SAMPLING RATE 512 SPS TB0CCR1 = 10; //Allow plenty of time for the signal to become stable before sampling TB0CTL |= MC_1; // UP MODE ADCCTL0 |= ADCENC; // ENABLE CONVERSION & START CONVERSION While(1) { } // ADC interrupt service routine written outside main function #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector=ADC_VECTOR __interrupt void ADC_ISR(void) #elif defined(__GNUC__) void __attribute__ ((interrupt(ADC_VECTOR))) ADC_ISR (void) #else #error Compiler not supported! #endif { ADCIFG &= ~ADCIFG0; // CLEAR INTERRUPT FLAG } // Timer B0 interrupt service routine outside main fucntion #pragma vector=TIMER0_B0_VECTOR __interrupt void Timer0_B0_ISR(void) { x = ADCMEM0; Y= ADCMEM0; }

I tried putting breakpoint in ADC ISR but it never comes inside ADC ISR. Timer ISR is working but X& Y both values are always 1. Both SAC are working as I have check the SAC output on Oscilloscope.
Where am I doing it wrong?
  • I tried putting breakpoint in ADC ISR but it never comes inside ADC ISR. Timer ISR is working but X& Y both values are always 1. Both SAC are working as I have check the SAC output on Oscilloscope.Where am I doing it wrong?

  • Hello Sumit,

    Check your ADCSHS configuration. According to Table 6-22 in the datasheet, ADCSHS_1 means an RTC event will trigger the ADC which you're probably not using.

    You may want to consider using ADCSHS_2 to use the TB1.1B trigger source. You're using TB0 but could change your code to use TB1. If you use this trigger method, you don't need a Timer ISR.

    As an alternative, you could use ADCSHS_0 and then set the software trigger (ADCSC) in your Timer ISR. Then, you could read ADCMEM0 in the ADC ISR.

    Hope this helps.

    Regards,

    James

  • Hello James,

    I've tried changing the ADCSHS REGISTER TO ADCSHS_2 and changed timer to TIMERB1 but still no result for ADC. Actually Iam trying to implement a pulse oximeter design &  want to sample the ADC at 1000 samples per second and read the OA0 & OA2 Output . I'am switching two LED'S inside Timer ISR   Inside the TIMER ISR I check Which LED is on  and switch off the other LED. After switiching the LED'S I want to read the output of the LED which was ON. Below is the code. Based on ADC Output i need to adjust the DAC Voltage which further adjust the LED Intensity.

     /***********ADC CONFIGURATION***********/
    
    	             ADCCTL0 &= ~ADCENC;                       // Disable ADC
    	           ADCCTL0 |= ADCSHT_4 | ADCMSC | ADCON;  //0000010010010010; 64 ADCLK CYCLES, MSC BIT HIGH, ADC ON
    
    	           ADCCTL1 |= ADCSHP | ADCSHS_2 | ADCCONSEQ_3|ADCSSEL_1;   //0000010010010010;
    	           ADCCTL2 &= ~ADCRES; //CLEAR RESOLUTION
    	           ADCCTL2 |= ADCRES_2; //12 BIT RESOLUTION
    	           ADCMCTL0 |= ADCSREF_1|ADCINCH_1|ADCINCH_3; // OA0 OUTPUT AS A1 ADC INPUT ,VR+= VREF+, ALSO OA2 OUPUT EXTERNALLY CONNECTED TO A3 ADC INPUT
    	           ADCIE |= ADCIE0; // ENABLE CONVERSION COMPLETE INTERRUPT
    	           __enable_interrupt(); // enable maskables
    
    
    	           /******************** Configure Timer ******************/
    
    	           TB1CTL = TBSSEL__ACLK + TBCLR; //ACLK & Reset timer
    	           TB1CCTL1 = OUTMOD_2; // TOGGLE & RESET
    	           TB1CCTL1  = CCIE; //INTERRUPT ENABLE
    	           TB1CCR0 = 31; //SAMPLING RATE 512 SPS
    	           TB1CCR1 = 10; //Allow plenty of time for the signal to become stable before sampling
    	           TB1CTL |= MC_1; // UP MODE
    	           ADCCTL0 |= ADCENC|ADCSC; // ENABLE CONVERSION & START  CONVERSION
    
    // Timer A0 interrupt service routine
    #pragma vector=TIMER1_B1_VECTOR
    __interrupt void Timer1_B1_ISR(void)
    
    {
    
    
    int i;
    
     if((SAC1OA & SACEN)) //  CHECK IF IR LED IS ON
    
     {
    
         SAC1OA &= ~SACEN; //DISABLE IR LED SAC.
         SAC1DAC &= ~DACEN; // Disable IR LED DAC
         P2OUT |= BIT2; //2.2 =1 // TURN ON vsled
         SAC3OA |= SACEN; //ENABLE VS LED SAC.
         SAC3DAC |= DACEN;//ENABLE VS LED DAC
         SAC3DAT =  vs_LED_level;
         SAC2DAT = vs_dc_offset;
         P2OUT &= ~BIT0; //2.0 =0  turn off ir led
    
    
         is_IR = 0;                          // IR LED OFF
    
         ir_sample = ADCMEM0;              // Read the IR LED results
         i = ADCMEM0;
                                                     // Enable the next conversion sequence.
                                                     // The sequence is started by TB1
                 ADCCTL0 &= ~ADCENC;
                 ADCCTL0 |= ADCENC;
                 ADCCTL0 |= ADCSC;
    
                 ir_heart_signal = ir_filter(i); // Filter away 50/60Hz electrical pickup and 100/120Hz room lighting optical pickup
                 ir_heart_ac_signal = ir_heart_signal - dc_estimator(&ir_2nd_dc_register, ir_heart_signal);  // Filter away the large DC component from the sensor
    
                 /* Bring the IR signal into range through the second opamp */
                         if (i >= 4095)
                         {
                             if (ir_dc_offset > 100)
                                 ir_dc_offset--;
                         }
                         else if (i < 100)
                         {
                             if (ir_dc_offset < 4095)
                                 ir_dc_offset++;
                         }
    
                         sq_ir_heart_ac_signal += (mul16(ir_heart_ac_signal, ir_heart_ac_signal) >> 10);
    
                         if (ir_sample > FIRST_STAGE_TARGET_HIGH || ir_sample < FIRST_STAGE_TARGET_LOW)
    
                                {
                             if (ir_sample > FIRST_STAGE_TARGET_HIGH)
                                       {
                                           if (ir_sample >= FIRST_STAGE_TARGET_HIGH_FINE)
                                               ir_LED_level -= FIRST_STAGE_STEP;
                                           else
                                               ir_LED_level -= FIRST_STAGE_FINE_STEP;
                                                                       // Clamp to the range of the DAC
                                           if (ir_LED_level < 0)
                                               ir_LED_level = 0;
                                       }
                                       else
                                       {
                                           if (ir_sample < FIRST_STAGE_TARGET_LOW_FINE)
                                               ir_LED_level += FIRST_STAGE_STEP;
                                           else
                                               ir_LED_level += FIRST_STAGE_FINE_STEP;
                                                                       // Clamp to the range of the DAC
                                           if (ir_LED_level > 4095)
                                               ir_LED_level = 4095;
                                       }
                                }
                         /* Track the beating of the heart */
                                 heart_signal_sample_counter++;
                                 if (pos_edge)
                                 {
                                     if (edge_debounce < 120)
                                     {
                                         edge_debounce++;
                                     }
                                     else
                                     {
                                         if (ir_heart_ac_signal < -200)
                                         {
                                             edge_debounce = 0;
                                             pos_edge = 0;
                                           //  display_pulse(0);
                                         }
                                     }
                                 }
                                 else
                                 {
                                     if (edge_debounce < 120)
                                     {
                                         edge_debounce++;
                                     }
                                     else
                                     {
                                         if (ir_heart_ac_signal > 200)
                                         {
                                             edge_debounce = 0;
                                             pos_edge = 1;
                                             //display_pulse(1);
                                            // display_correcting(1, 0);
                                             if (++heart_beat_counter >= 3)
                                             {
                                                 log_heart_signal_sample_counter = heart_signal_sample_counter;
                                                 log_sq_ir_heart_ac_signal = sq_ir_heart_ac_signal;
                                                 log_sq_vs_heart_ac_signal = sq_vs_heart_ac_signal;
                                                 heart_signal_sample_counter = 0;
                                                 sq_ir_heart_ac_signal = 0;
                                                 sq_vs_heart_ac_signal = 0;
                                                 heart_beat_counter = 0;
                                               //  _BIC_SR_IRQ(LPM0_bits);
                                                                     // Do a dummy wake up roughly
                                                                     // every 2 seconds
                                             }
                                         }
                                     }
                                 }
    
    
     }
    
    
    
     else
     {
              SAC3OA &= ~SACEN; //DISABLE VS LED SAC.
              SAC3DAC &= ~DACEN; // Disable VS LED DAC
              P2OUT |= BIT0; //2.0 = 1
              SAC1OA |= SACEN; //ENABLE IR LED SAC.
              SAC1DAC |= DACEN;//ENABLE IR LED DAC
              SAC1DAT = ir_LED_level;
              SAC2DAT = ir_dc_offset;
    
              P2OUT &= ~BIT2; //2.2 =0
    
    
              is_IR = 1;                          // IR LED ON
    
                 vs_sample = ADCMEM0;              //Read the visible LED results
                 i = ADCMEM0;
    
                                                     //Enable the next conversion sequence.
                                                     //The sequence is started by TB1
                 ADCCTL0 &= ~ADCENC;
    
                 ADCCTL0 |= ADCENC;
                 ADCCTL0 |= ADCSC;
    
    
                                                     //Filter away 50/60Hz electrical
                                                     //pickup, and 100/120Hz room
                                                     //lighting optical pickup */
                 vs_heart_signal = vs_filter(i);
                                                     //Filter away the large DC
                                                     //component from the sensor */
                 vs_heart_ac_signal = vs_heart_signal - dc_estimator(&vs_2nd_dc_register, vs_heart_signal);
    
                /* Bring the VS signal into range through the second opamp */
                 if (i >= 4095)
                 {
                     if (vs_dc_offset > 100)
                         vs_dc_offset--;
                 }
                 else if (i < 100)
                 {
                     if (vs_dc_offset < 4095)
                         vs_dc_offset++;
                 }
    
                 sq_vs_heart_ac_signal += (mul16(vs_heart_ac_signal, vs_heart_ac_signal) >> 10);
    
                 if (vs_sample > FIRST_STAGE_TARGET_HIGH || vs_sample < FIRST_STAGE_TARGET_LOW)
    
    
                 {
                     /* We are out of the target range */
                   //  display_correcting(1, 1);
                     if (vs_sample > FIRST_STAGE_TARGET_HIGH)
                     {
                         if (vs_sample >= FIRST_STAGE_TARGET_HIGH_FINE)
                             vs_LED_level -= FIRST_STAGE_STEP;
                         else
                             vs_LED_level -= FIRST_STAGE_FINE_STEP;
                         if (vs_LED_level < 0)
                             vs_LED_level = 0;
                     }
                     else
                     {
                         if (vs_sample < FIRST_STAGE_TARGET_LOW_FINE)
                             vs_LED_level += FIRST_STAGE_STEP;
                         else
                             vs_LED_level += FIRST_STAGE_FINE_STEP;
                         if (vs_LED_level > 4095)
                             vs_LED_level = 4095;
                     }
                 }
    
     }
    }
    
    // ADC interrupt service routine
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=ADC_VECTOR
    __interrupt void ADC_ISR(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(ADC_VECTOR))) ADC_ISR (void)
    #else
    #error Compiler not supported!
    #endif
    
    {
        ADCIFG &= ~ADCIFG0; // CLEAR INTERRUPT FLAG
        SAC1DAT = 0; //TURN OFF BOTH LED'S
        SAC3DAT = 0;
        // Turn OFF the H-Bridge completely
        if(is_IR)                               // If IR LED was ON in TA0 ISR
             P2OUT |= BIT2;                        // P2.2 = 1
           else                                    // Else if VS LED ON in TA0 ISR
             P2OUT |= BIT0;                        // P2.0 = 1
    
    }
    

    kindly help me in resolving the issue.

  • My SAC OA2O Output from SPO2 Sensor is shown below. I need ADC to read this as per the shown timing diagram. To Achieve this I've written the code shown above in my post but ADC data is always 1. I've been following TI Document slaa897 & slaa458 

  • 1) Don't fetch ADCMEM0 in the timer ISR. Fetch it in the ADC ISR (as James suggested). The timer ISR is called a long time (~2ms) before the ADC has a result ready.

    2) ADCINCH is a number, not a bit field. (So (ADCINCH_1|ADCINCH_3) == ADCINCH_3.) An ADC sequence steps from INCH down to 0, in this case A3-A2-A1-A0. Each ADC interrupt provides one of those. It is up to you to keep track of which one. It's usually easiest to just keep a global (cyclic) counter variable.

    3) Each conversion is taking you (64+15)/32768 = 2.4ms, and you're doing 4 of them = 9.6ms, so that's a roughly 100Hz sample rate. Your timer is triggering every (31+1)/32768 = 1ms, i.e. much faster than the ADC can convert. I suggest you adjust this so the timer triggers at the correct rate (but see (4) below). [Unsolicited: Do you really need a 2ms S/H time? That's a long time. I would expect the SAC output to be very low impedance.]

    4) With CONSEQ=3 and MSC=1, your timer trigger is being ignored (after the very first trigger). Ordinarily I would say go back to CONSEQ=1, but I won't in this case. Since your intended sample rate (and S/H time) will keep the ADC running more or less constantly anyway, keep CONSEQ=3 but set MSC=0. With that setting, each trigger will start one new conversion, but the ADC will still cycle the channels. And you still have some control over the sample rate (by adjusting TB1CCR0).

  • Hello Bruce,

    Thanks for your reply and helping me understand MCU Working better. I changed the clock of ADC to MODCLK which is 5MHz by Setting ADCSSEL_0. So then My one conversion would take (64+15)/5000000 = 15.8us . I've changed the INCH number to INCH1 as my OA0 Output is internally connected to ADC Input A1 & OA2 Output is externally connected on A0 (PIN 3.1 CONNECTED TO PIN 1.0 ON LAUNCHPAD). Thus my two channel conversion would take ~32us. Even if my TIMER ISR is coming after every 1ms the TB1CCR1 = 10 means my ADC will be triggered & get my converted result of both channels well before 1ms .

    Its The TB1CCR1 which is triggering the ADC right?  Still my code is not going inside the ADC ISR. I don't understand why? I tried your suggestion of keeping CONSEQ3 & MSC =0 but not working.

    Do I have to configure any clock inside the main function?  I hope ACLK & MODCLK Have default values of 32768Hz & 5Mhz 

    I've attached my complete code . 

    int main(void)
    {
    
        double f1;
                   int x;
                  int y;
    	WDTCTL = WDTPW | WDTHOLD;	// stop watchdog timer
    	
    	// Setup GPIO
    
        // Configure ADC A0 pin
        P1SEL0 |= BIT0;
        P1SEL1 |= BIT0;
    
    	           P2DIR |= BIT0 + BIT2;                   // P2.0 and P2.2 o/p direction -
    	                                                   // drives NPN transistors in H-Bridge
    	           P2OUT &= ~BIT0;
    	           P2OUT &= ~BIT2;
    
    	           PM5CTL0 &= ~LOCKLPM5;
    
    	           // Configure reference module
    	             PMMCTL0_H = PMMPW_H;                    // Unlock the PMM registers
    	             PMMCTL2 = INTREFEN | REFVSEL_2;         // Enable internal 2.5V reference
    	             while(!(PMMCTL2 & REFGENRDY));          // Poll till internal reference settles
    
    
    
    
    	            /*******************SAC0 configurations as TIA******************/
    	             P1SEL0 |=   BIT1|BIT2 ;             // Select  P1.2 P1.1 AS OA0 OUTPUT OA0- PIN function
    	             P1SEL1 |=  BIT1| BIT2 ;             // Select  P1.2  OA0- PIN function
    
    	             SAC0DAC = DACSREF_1;                        // Select 2.5V int Vref as DAC reference
    	               SAC0DAT = 2048;                         // Set SAC DAC data to 2.5V
    	               SAC0DAC |= DACEN;                         // Enable DAC
    	             SAC0OA |= NMUXEN | PMUXEN | PSEL_1 | NSEL_0; //Select positive INPUT AS DAC and negative pin input AS PHOTODIODE
    	          //  SAC0PGA |= MSEL_0;                          // INVERTING PGA MODE
    	             SAC0OA &= ~OAPM;                            // Select HIGH speed and HIGH power mode
    	             SAC0OA |= SACEN + OAEN;                     // Enable SAC and OA
    
    	             /****************SAC2 configurations AS INVERTING PGA************/
    	                                     P3SEL0 |= BIT1    ;             // Select P3.1   OA2 OUTPUT function
    	                                     P3SEL1 |= BIT1    ;             // Select P3.1   OA2 OUTPUT function
    
    	                                      SAC2DAC = DACSREF_1;                       // Select 2.5V int Vref as DAC reference
    	                                      SAC2DAT = 0;                         // DAC TO PROVIDE BIAS FOR AMPLIFIER
    	                                      SAC2DAC |= DACEN;                         // Enable DAC
    	                                     SAC2OA |= NMUXEN | PMUXEN | PSEL_1 | NSEL_1;//Select positive INPUT AS DAC and negative pin input AS O/P of OA0
    	                                     SAC2PGA |= GAIN0 + GAIN2 + MSEL_3;    // Set inverting PGA mode with Gain=16
    	                                     SAC2OA &= ~OAPM;                           // Select HIGH speed and HIGH power mode
    	                                     SAC2OA |= SACEN | OAEN; // Enable SAC and OA
    
    	             /****************SAC0 configurations AS INVERTING PGA************/
    	                         /*P1SEL0 |= BIT1 | BIT2 | BIT3;             // Select P1.1 P1.2 P1.3 OA0 function
    	                          P1SEL1 |= BIT1 | BIT2 | BIT3;             // Select P1.1 P1.2 P1.3 OA0 function
    	                         SAC0DAC = DACSREF_1;                       // Select 2.5V int Vref as DAC reference
    	                         SAC0DAT = 819;                         // Set SAC DAC data to 0.5V
    	                         SAC0DAC |= DACEN;                         // Enable DAC
    	                         SAC0OA = NMUXEN + PMUXEN + PSEL_1 + NSEL_1;//Select positive INPUT AS DAC and negative pin input AS PHOTODIODE
    	                         SAC0PGA |= GAIN0 + GAIN2 + MSEL_0;    // Set inverting PGA mode with Gain=16
    	                         SAC0OA &= ~OAPM;                           // Select HIGH speed and HIGH power mode
    	                         SAC0OA |= SACEN | OAEN; // Enable SAC and OA*/
    
    	             /*******************SAC2 configurations as TIA******************/
    
    	            /* P3SEL0 |= BIT1 | BIT2 | BIT3;             // Select P3.1 P3.2 P3.3 OA2 function
    	             P3SEL1 |= BIT1 | BIT2 | BIT3;             // Select P3.1 P3.2 P3.3 OA2 function
    	             SAC2DAC = DACSREF_1;                       // Select 2.5V int Vref as DAC reference
    	             SAC2DAT = 819;                         // Set SAC DAC data to 0.5V
    	             SAC2DAC |= DACEN;                         // Enable DAC
    	             SAC2OA = NMUXEN + PMUXEN + PSEL_1 + NSEL_0;//Select positive INPUT AS DAC and negative pin input AS PHOTODIODE
    	             SAC2PGA |= MSEL_0;
    
    	              SAC2OA |= SACEN + OAEN; // Enable SAC and OA*/
    
    
    
    	                          /******************SAC3 configurations AS DAC OUTPUT********************/
    	                          P3SEL0 |= BIT6|BIT5   ;           // Select P3.6 AS OA3-VE P3.5  OA3O function
    	                          P3SEL1 |= BIT6|BIT5  ;         //  OA is used as buffer for DAC
    
    	                          SAC3DAC = DACSREF_1;                       // Select 2.5V int Vref as DAC reference
    	                          SAC3DAT = 3340;                         // Set SAC DAC data to 2.5V
    	                          SAC3DAC |= DACEN;                         // Enable DAC
    	                          SAC3OA = NMUXEN + PMUXEN + PSEL_1 + NSEL_0;//Select DAC MODE
    	                          SAC3PGA |= MSEL_1;                       // Set OA AS BUFFER MODE
    	                          SAC3OA &= ~OAPM;                           // Select HIGH speed and HIGH power mode
    	                          SAC3OA |= SACEN | OAEN; // Enable SAC and OA
    
    	                          /*******************SAC1 configurationsAS DAC OUTPUT**********************/
    	                          P1SEL0 |= BIT6|BIT5  ;            // SelectP1.6 AS OA1-VE P1.5  OA1O function
    	                          P1SEL1 |= BIT6|BIT5 ;          //  OA is used as buffer for DAC
    
    	                         SAC1DAC = DACSREF_1;                       // Select 2.5V int Vref as DAC reference
    	                         SAC1DAT = 3340;                         // Set SAC DAC data to INTIAL VALUE OF 2.5V
    	                         SAC1DAC |= DACEN;                         // Enable DAC
    	                         SAC1OA = NMUXEN + PMUXEN + PSEL_1 + NSEL_0;//Select DAC MODE
    	                         SAC1PGA |= MSEL_1;                       // Set OA AS BUFFER MODE
    	                         SAC1OA &= ~OAPM;                           // Select HIGH speed and HIGH power mode
    	                        SAC1OA |= SACEN | OAEN; // Enable SAC and OA
    
    	                        // Set initial values for the LED brightnesses
    	               ir_LED_level = 1300; //1300
    	               vs_LED_level = 1450;//1450
    
    	                        /***********ADC CONFIGURATION***********/
    
    	             ADCCTL0 &= ~ADCENC;                       // Disable ADC
    	           ADCCTL0 |= ADCSHT_4|ADCMSC|ADCON;  //0000010010010010; 64 ADCLK CYCLES, MSC BIT , ADC ON
    	           ADCCTL1 |=  ADCSHP|ADCSHS_2 | ADCCONSEQ_3|ADCSSEL_0; //5 Mhz clock
    	          // ADCCTL1 |= ADCSHP | ADCSHS_2 | ADCCONSEQ_3|ADCSSEL_1;   //0000010010010010;
    	           ADCCTL2 &= ~ADCRES; //CLEAR RESOLUTION
    	           ADCCTL2 |= ADCRES_2; //12 BIT RESOLUTION
    	           ADCMCTL0 |= ADCINCH_1|ADCSREF_1; // OA0 OUTPUT AS A1 ADC INPUT ,VR+= VREF+, ALSO OA2 OUPUT EXTERNALLY CONNECTED TO A0 ADC INPUT
    	           ADCIE |= ADCIE0; // ENABLE CONVERSION COMPLETE INTERRUPT
    	           ADCCTL0 |= ADCENC|ADCSC; // ENABLE CONVERSION & START  CONVERSION
    	         //  __enable_interrupt(); // enable maskables
    
    
    	           /******************** Configure Timer ******************/
    
    	           TB1CTL = TBSSEL__ACLK + TBCLR; //ACLK & Reset timer
    	           TB1CCTL1 = OUTMOD_4; // TOGGLE & RESET
    	           TB1CCTL1  = CCIE; //INTERRUPT ENABLE
    	           TB1CCR0 =  31; //SAMPLING RATE 512 SPS
    	           TB1CCR1 = 10; //Allow plenty of time for the signal to become stable before sampling
    	           TB1CTL |= MC_1; // UP MODE
    
    
    	while(1)
    	{
    	    __bis_SR_register(LPM0_bits | GIE);
    
    	    /* Heart Rate Computation */
    	           f1 = 60.0*512.0*3.0/(float)log_heart_signal_sample_counter;
    	           heart_rate = f1;
    	          // display_number(heart_rate, 3, 3);
    	           heart_rate_LSB = heart_rate & 0x00FF;
    
    	           /* SaO2 Computation */
    	           x = log_sq_ir_heart_ac_signal/log_heart_signal_sample_counter;
    	           y = log_sq_vs_heart_ac_signal/log_heart_signal_sample_counter;
    	           Ratio = (unsigned int) (100.0*log(y)/log(x));
    	           if (Ratio > 66)
    	             SaO2 = Lookup[Ratio - 66];        // Ratio - 50 (Look-up Table Offset) - 16 (Ratio offset)
    	           else if (Ratio > 50)
    	             SaO2 = Lookup[Ratio - 50];        // Ratio - 50 (Look-up Table Offset)
    	           else
    	             SaO2 = 100;
    	          // display_number(SaO2, 7, 3);
    	           SaO2_LSB = SaO2 & 0x00FF;
    
    	}
    
    //	return 0;
    }
    
    // Timer B1 interrupt service routine
    #pragma vector=TIMER1_B1_VECTOR
    __interrupt void Timer1_B1_ISR(void)
    
    {
    
    
    int i;// declared outside main
    
     if((SAC1OA & SACEN)) //  CHECK IF IR LED IS ON
    
     {
    
         SAC1OA &= ~SACEN; //DISABLE IR LED SAC.
         SAC1DAC &= ~DACEN; // Disable IR LED DAC
         P2OUT |= BIT2; //2.2 =1 // TURN ON vsled
         SAC3OA |= SACEN; //ENABLE VS LED SAC.
         SAC3DAC |= DACEN;//ENABLE VS LED DAC
         SAC3DAT =  vs_LED_level;
         SAC2DAT = vs_dc_offset;
         P2OUT &= ~BIT0; //2.0 =0  turn off ir led
    
    
         is_IR = 0;                          // IR LED OFF
    
         ir_sample = ADC_Result[0];              // Read the IR LED results
         i = ADC_Result[1];
                                                     // Enable the next conversion sequence.
                                                     // The sequence is started by TB1
                // ADCCTL0 &= ~ADCENC;
                // ADCCTL0 |= ADCENC |ADCSC;
                // ADCCTL0 |= ADCSC;
    
                // ir_heart_signal = ir_filter(i); // Filter away 50/60Hz electrical pickup and 100/120Hz room lighting optical pickup
                // ir_heart_ac_signal = ir_heart_signal - dc_estimator(&ir_2nd_dc_register, ir_heart_signal);  // Filter away the large DC component from the sensor
    
                 /* Bring the IR signal into range through the second opamp */
                         if (i >= 4095)
                         {
                             if (ir_dc_offset > 100)
                                 ir_dc_offset--;
                         }
                         else if (i < 100)
                         {
                             if (ir_dc_offset < 4095)
                                 ir_dc_offset++;
                         }
    
                       //  sq_ir_heart_ac_signal += (mul16(ir_heart_ac_signal, ir_heart_ac_signal) >> 10);
    
                         if (ir_sample > FIRST_STAGE_TARGET_HIGH || ir_sample < FIRST_STAGE_TARGET_LOW)
    
                                {
                             if (ir_sample > FIRST_STAGE_TARGET_HIGH)
                                       {
                                           if (ir_sample >= FIRST_STAGE_TARGET_HIGH_FINE)
                                               ir_LED_level -= FIRST_STAGE_STEP;
                                           else
                                               ir_LED_level -= FIRST_STAGE_FINE_STEP;
                                                                       // Clamp to the range of the DAC
                                           if (ir_LED_level < 0)
                                               ir_LED_level = 0;
                                       }
                                       else
                                       {
                                           if (ir_sample < FIRST_STAGE_TARGET_LOW_FINE)
                                               ir_LED_level += FIRST_STAGE_STEP;
                                           else
                                               ir_LED_level += FIRST_STAGE_FINE_STEP;
                                                                       // Clamp to the range of the DAC
                                           if (ir_LED_level > 4095)
                                               ir_LED_level = 4095;
                                       }
                                }
                         /* Track the beating of the heart */
                                 heart_signal_sample_counter++;
                                 if (pos_edge)
                                 {
                                     if (edge_debounce < 120)
                                     {
                                         edge_debounce++;
                                     }
                                     else
                                     {
                                         if (ir_heart_ac_signal < -200)
                                         {
                                             edge_debounce = 0;
                                             pos_edge = 0;
                                           //  display_pulse(0);
                                         }
                                     }
                                 }
                                 else
                                 {
                                     if (edge_debounce < 120)
                                     {
                                         edge_debounce++;
                                     }
                                     else
                                     {
                                         if (ir_heart_ac_signal > 200)
                                         {
                                             edge_debounce = 0;
                                             pos_edge = 1;
                                             //display_pulse(1);
                                            // display_correcting(1, 0);
                                             if (++heart_beat_counter >= 3)
                                             {
                                                 log_heart_signal_sample_counter = heart_signal_sample_counter;
                                                 log_sq_ir_heart_ac_signal = sq_ir_heart_ac_signal;
                                                 log_sq_vs_heart_ac_signal = sq_vs_heart_ac_signal;
                                                 heart_signal_sample_counter = 0;
                                                 sq_ir_heart_ac_signal = 0;
                                                 sq_vs_heart_ac_signal = 0;
                                                 heart_beat_counter = 0;
                                               //  _BIC_SR_IRQ(LPM0_bits);
                                                                     // Do a dummy wake up roughly
                                                                     // every 2 seconds
                                             }
                                         }
                                     }
                                 }
    
    
     }
    
    
    
     else
     {
              SAC3OA &= ~SACEN; //DISABLE VS LED SAC.
              SAC3DAC &= ~DACEN; // Disable VS LED DAC
              P2OUT |= BIT0; //2.0 = 1
              SAC1OA |= SACEN; //ENABLE IR LED SAC.
              SAC1DAC |= DACEN;//ENABLE IR LED DAC
              SAC1DAT =  ir_LED_level;
              SAC2DAT = ir_dc_offset;
    
              P2OUT &= ~BIT2; //2.2 =0
    
    
              is_IR = 1;                          // IR LED ON
    
                 vs_sample = ADC_Result[0];              //Read the visible LED results
                 i = ADC_Result[1];
    
                                                     //Enable the next conversion sequence.
                                                     //The sequence is started by TB1
             //    ADCCTL0 &= ~ADCENC;
    
               //  ADCCTL0 |= ADCENC|ADCSC;
    
    
    
                                                     //Filter away 50/60Hz electrical
                                                     //pickup, and 100/120Hz room
                                                     //lighting optical pickup */
                // vs_heart_signal = vs_filter(i);
                                                     //Filter away the large DC
                                                     //component from the sensor */
                // vs_heart_ac_signal = vs_heart_signal - dc_estimator(&vs_2nd_dc_register, vs_heart_signal);
    
                /* Bring the VS signal into range through the second opamp */
                 if (i >= 4095)
                 {
                     if (vs_dc_offset > 100)
                         vs_dc_offset--;
                 }
                 else if (i < 100)
                 {
                     if (vs_dc_offset < 4095)
                         vs_dc_offset++;
                 }
    
                 //sq_vs_heart_ac_signal += (mul16(vs_heart_ac_signal, vs_heart_ac_signal) >> 10);
    
                 if (vs_sample > FIRST_STAGE_TARGET_HIGH || vs_sample < FIRST_STAGE_TARGET_LOW)
    
    
                 {
                     /* We are out of the target range */
                   //  display_correcting(1, 1);
                     if (vs_sample > FIRST_STAGE_TARGET_HIGH)
                     {
                         if (vs_sample >= FIRST_STAGE_TARGET_HIGH_FINE)
                             vs_LED_level -= FIRST_STAGE_STEP;
                         else
                             vs_LED_level -= FIRST_STAGE_FINE_STEP;
                         if (vs_LED_level < 0)
                             vs_LED_level = 0;
                     }
                     else
                     {
                         if (vs_sample < FIRST_STAGE_TARGET_LOW_FINE)
                             vs_LED_level += FIRST_STAGE_STEP;
                         else
                             vs_LED_level += FIRST_STAGE_FINE_STEP;
                         if (vs_LED_level > 4095)
                             vs_LED_level = 4095;
                     }
                 }
    
     }
    }
    
    // ADC interrupt service routine
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=ADC_VECTOR
    __interrupt void ADC_ISR(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(ADC_VECTOR))) ADC_ISR (void)
    #else
    #error Compiler not supported!
    #endif
    
    {
        switch(__even_in_range(ADCIV,ADCIV_ADCIFG))
            {
                case ADCIV_NONE:
                    break;
                case ADCIV_ADCOVIFG:
                    break;
                case ADCIV_ADCTOVIFG:
                    break;
                case ADCIV_ADCHIIFG:
                    break;
                case ADCIV_ADCLOIFG:
                    break;
                case ADCIV_ADCINIFG:
                    break;
                case ADCIV_ADCIFG:
                    ADC_Result[s] = ADCMEM0;
                                                    if(s == 0)
                                                    {
                                                      //  __bic_SR_register_on_exit(LPM0_bits);
                                                        SAC1DAT = 0; //TURN OFF BOTH LED'S
                                                        SAC3DAT = 0;//
                                                          // Turn OFF the H-Bridge completely
                                                        if(is_IR)                               // If IR LED was ON in TA0 ISR
                                                         P2OUT |= BIT2;                        // P2.2 = 1
                                                          else                                    // Else if VS LED ON in TA0 ISR
                                                        P2OUT |= BIT0;                        // P2.0 = 1
                                                        // Set P1.2 LED on
                                                    }
                                                    else
                                                    {
                                                        s--;
                                                    }
    
    
                                      ADCIFG = 0;
                    break;                                           // Clear CPUOFF bit from 0(SR)
                default:
                    break;
            }
    
    
    
    
       // ADCIFG &= ~ADCIFG0; // CLEAR INTERRUPT FLAG
    
    }
    
    int16_t ir_filter(int16_t sample)
    {
        static int16_t buf[32];
        static int offset = 0;
        int32_t z,test;
        int i;
                                                //Filter hard above a few Hertz,
                                                //using a symmetric FIR.
                                                //This has benign phase
                                                //characteristics */
        buf[offset] = sample;
        z = mul16(coeffs[11], buf[(offset - 11) & 0x1F]);
        for (i = 0;  i < 11;  i++)
            z += mul16(coeffs[i], buf[(offset - i) & 0x1F] + buf[(offset - 22 + i) & 0x1F]);
        offset = (offset + 1) & 0x1F;
        return  z >> 15;
    }
    
    int16_t vs_filter(int16_t sample)
    {
        static int16_t buf[32];
        static int offset = 0;
        int32_t z;
        int i;
    
                                                //Filter hard above a few Hertz,
                                                //using a symmetric FIR.
                                                //This has benign phase
                                                //characteristics */
        buf[offset] = sample;
        z = mul16(coeffs[11], buf[(offset - 11) & 0x1F]);
        for (i = 0;  i < 11;  i++)
            z += mul16(coeffs[i], buf[(offset - i) & 0x1F] + buf[(offset - 22 + i) & 0x1F]);
        offset = (offset + 1) & 0x1F;
        return  z >> 15;
    }
    int16_t dc_estimator(register int32_t *p, register int16_t x)
    {
        /* Noise shaped DC estimator. */
        *p += ((((int32_t) x << 16) - *p) >> 9);
        return (*p >> 16);
    }

  • ok , I got the solution. I used TB0 to switch the LED'S & TB1.1 For ADC Conversion. Now the ADC is reading the values correctly.

    I wanted to ask one more thing. In my code Iam getting an error of unresolved sysmbols remain for mul16 function. The document SLAA458 has a mul16 assembler file. How can I include this assembler file in my code or do I need to include any mathlib for this? mul16 is used inside filter code.

  • If it's a .asm file, I think you can just copy it into your project and CCS will figure it out. But this looks like a .s43 file, which is IAR assembly, which as I recall is somewhat different from TI assembly. But you can try it, and see what you get.

    At first glance, it does look like a 16x16->32 multiplication function.("int32_t mul16(register int16_t x, register int16_t y)"). Maybe it was included since the FG437 doesn't have a hardware multiplier. But the FR2355 does, and the compiler is pretty good about using it. If the .s43 file doesn't work, maybe just define your own "mul16(x,y) {return(x*y);}"

**Attention** This is a public forum