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.

MSP430F5438A: ADC12 timer trigger

Part Number: MSP430F5438A

Hello,

I am trying to collect data from the following optical dust sensor:

According to page 5 of the datasheet, I generated the correct PWM signal using timer A for input PIN 3 of the sensor and observed the signal in my oscilloscope. Now at the same page Figure 2, they talked about the output pulse sample timing. Anyone can help me understand how should I set up my ADC12 for this? Few queries regarding this:

1. Should my sample and hold time be 0.28ms?

2. If so then should I wait for next  0.04ms + 9.68ms to collect my next ADC value as the input pulse needs that much time to arrive?

3. If 1 and 2 are correct, how can I set up my ADC for this? 

Thanks,

Row

 

  • Hello Rowshon,

    I won't comment on the specifics of the sensor you are looking at, but this application seems similar to a general smoke detector application. Please see the following resources that could potentially help you out on your application. The devices are different, but the general principle will be the same.

    Lot's of design resources linked at the bottom of this blog:
    e2e.ti.com/.../designing-a-smoke-detector-with-the-smart-analog-combo-in-the-msp430fr2355

    Smoke Detector App note:
    http://www.ti.com/lit/slaa335

    You will most likely need to implement a Timer triggered ADc sampling as well. Please see the following link for example code for your device that exhibits this. Please look at example DMA04. It shows how to configure ADC for a Timer trigger, although with the added complication of DMA usage to move said ADC sample.
    dev.ti.com/.../
  • As I read this, your MCU generates the sensor activation (LED) pulse, with a recommended duty of 0.32ms out of 10ms. It is then recommended that you sample the voltage level as late as possible before your pulse goes low (and at least 0.28ms from the pulse start) such that it completes before the pulse goes low. That gives you <= 40usec (0.040ms) to do the conversion.

    [If that's not how it works, ignore the rest of this.]

    A conversion can certainly be done in <= 40usec, just choose an appropriate (SHT + 13)*ADCCLK.

    I don't see how you'll do the coordination with a single CCR. I suggest using a second CCR set to compare-match (SHT+13)*ADCCLK in time before the pulse CCR, and use that to trigger the ADC. You'll need to survey the available ADC triggers (SHS settings) in the data sheet, and pick a timer that also has a pin output. The ADC trigger OUTMOD should be Set/Reset and the pulse should be Reset/Set.

    [I've probably made it sound complicated, but it's more arithmetic than code.]
  • Hello,
    Thanks for the response. So I wrote the code below. Now the problem is I'm getting zero all the time. Not sure if the problem with timer and ADC setup or something conceptual. What I am doing is Set a timer to generate a PWM for the sensor input. Another timer to trigger my ADC12 exactly at the same time the sensor getting the activation pulse. In my ADC12 I set the sample and hold time around 0.26ms (Couldn't able to set it at 0.28ms which is recommended). Then I am sending the ADC data through UART sothat I can check my ADC value (using tera term to see the vaules). I.m not efficient in msp coding that's why didn't use ISR just not deal with additional complicacy.

    My Code:
     

    #include <msp430.h>
    
    volatile unsigned char volt [5];
    volatile unsigned int in_value;
    
    void clock_setup (void);
    void clock_setup (void)
    {
    P11DIR |= BIT0;
    P11SEL |= BIT0; // ACLK
    P11DIR |= BIT1;
    P11SEL |= BIT1; // MCLK
    P11DIR |= BIT2;
    P11SEL |= BIT2; // SMCLK
    P2DIR |= BIT7;
    P2SEL |= BIT7; // ADC12 CLK
    }
    
    void init_serial (void);
    void init_serial (void)
    {
    P5SEL |= 0xC0; // 5.6 and 5.7 for TX/RX- UCA1
    UCA1CTL1 |= UCSWRST;
    UCA1CTL1 |= UCSSEL_1; //32768 Hz
    UCA1BR0 = 03; // Baudrate 9600
    UCA1BR1 = 0x00;
    UCA1MCTL = 0x06; // Modulation Sx=3, Fx= 0
    UCA1CTL0 = 0x00;
    UCA1CTL1 &= ~UCSWRST; // In operation mode
    
    }
    
    void ADC_value (int);
    void ADC_value (int ADC_Data)
    {
    volatile char x=3;
    volt [3] = volt [2] = volt [1] = volt [0] = 0x30;
    while (ADC_Data > 0)
    {
    volt [x] = (ADC_Data%10)| 0x30; // Separating unit digit
    ADC_Data = ADC_Data/10; // rest of the digit than last digit
    x--;
    }
    volt [4] = '\0';
    }
    
    void Send_Serial (void);
    void Send_Serial (void)
    {
    volatile char i=0;
    while (volt[i] != '\0')
    {
    UCA1TXBUF = volt[i];
    
    while (UCA1STAT & UCBUSY);
    i++;
    }
    UCA1TXBUF = 0x0a;
    while (UCA1STAT & UCBUSY);
    UCA1TXBUF = 0x0d;
    while (UCA1STAT & UCBUSY);
    
    }
    
    
    int main(void)
    {
    clock_setup();
    init_serial ();
    
    WDTCTL = WDTPW + WDTHOLD; // Stop WDT
    P8DIR |= BIT6; // P8.6 output
    P8SEL |= BIT6; // P8.6 options select
    P1DIR |= BIT1;
    P1DIR |= BIT1;
    
    // Generating PWM for Sensor input PIN 3
    TA1CCR0 = 10617-1; // PWM Period
    TA1CCTL1 = OUTMOD_7; // CCR1 reset/set
    TA1CCR1 = 10286; // CCR1 PWM duty cycle --> Get a 0.32ms low pulse out of 10ms, goes low at 9.68ms
    TA1CTL = TASSEL__SMCLK + MC__UP + TACLR; // SMCLK, up mode, clear TAR
    
    // Configure Timer0_A3 to periodically trigger the ADC12
    TA0CCR0 = 10617-1; // PWM Period
    TA0CCTL1 = OUTMOD_3; // TACCR1 set/reset
    TA0CCR1 = 10286; // TACCR1 PWM Duty Cycle--> triggers ADC12 at 9.68ms which is at the same time the sensor got a low input 
    TA0CTL = TASSEL__SMCLK + MC__UP + TACLR; // SMCLK, up mode, clear TAR
    
    P6SEL |= BIT7; //ADC in
    ADC12CTL0 = ADC12SHT0_8 + ADC12ON; // Sampling time ((256+13)/(ADC_CLK)=0.26ms around not able to get 0.28ms recommended by sensor datasheet), ADC12 on
    ADC12CTL1 = ADC12SHP + ADC12SHS_1; // Use sampling timer + MCLK
    ADC12MCTL0 = ADC12INCH_7;
    
    
    while (1)
    {
    ADC12CTL0 &= ~ADC12SC;
    ADC12CTL0 |= ADC12SC + ADC12ENC;
    while (ADC12CTL1 & ADC12BUSY)
    in_value = ADC12MEM0 & 0x0FFF;
    P1OUT ^= BIT1;
    ADC_value (in_value);
    Send_Serial ();
    }
    
    }



    I am attaching the arduino version (Found in Web) of the code also for this sensor. I'm trying to implement same thing in msp430. I tested the code and it works perfect for sensor. I'm attaching this if by any chance I explained anything wrong about the sensor in my statring post.
    Arduino code version:

    int sensePin = A0;
    int ledPin = 9;
    
    int Tsampling = 280;
    int Tdelta = 40;
    int Tsleep = 9680;
    
    float outVo = 0;
    float sigVolt = 0;
    float dustLevel = 0;
    
    void setup(){
    Serial.begin(9600);
    pinMode(ledPin,OUTPUT);
    }
    
    void loop(){
    digitalWrite(ledPin,LOW); 
    delayMicroseconds(Tsampling);
    
    outVo = analogRead(sensePin); 
    
    delayMicroseconds(Tdelta);
    digitalWrite(ledPin,HIGH); 
    delayMicroseconds(Tsleep);
    
    sigVolt = outVo * (3.3 / 1024);
    
    dustLevel = 0.17 * sigVolt - 0.1;
    
    Serial.print("Measured Signal Value (0-1023): ");
    Serial.print(outVo);
    
    Serial.print(" Voltage: ");
    Serial.print(sigVolt);
    
    Serial.print(" Dust Density Level: ");
    Serial.println(dustLevel);
    
    delay(1000);
    }



    Hope any of you can help me understand what am I doing wrong!

    Thanks,
    Row

  • Hello Row,

    When posting code onto the forum, please use the code formatting tool marked by the </> button. This tool can be located by clicking the "Insert Code, Attatch Files, and more" link on the bottom right hand side of the Reply menu. The Code Formatting Tool allows the code to be easily read and can help you get support faster on the forums. I've modified your previous post to reflect the use of the tool.

    I would highly recommend to taking the time to switch to a interrupt driven approach here as it will make your job timing this together easier. You may need to up your MCLK speed here as well in order to do all you need to do in the time frames you have. It seems you are running at the default 1MHz speed.
  • Setting both CCR1 values to be the same(10286) will trigger the ADC at the beginning of the pulse, which has two concerns:

    1) You don't want the sampling capacitor to be integrating over that long rise time (nom. 230us), you want to snapshot it, and only after it levels at its high value.
    2) You're using ADC12SSEL_0=ADC12OSC, which runs at about 4.8MHz, so your conversion time is (roughly) (256+13)/4.8=54usec. That means your conversion is complete before the signal (per Fig 2) has risen much.

    I suggest you reduce your sampling time to say 64 clocks (SHT0_4) which within ADC12OSC tolerance is still less than 19usec. Then subtract your 40usec from the pulse-off time i.e. set TA0CCR1 = 10617-1.06*40 (I assume that 1.06 is your measured SMCLK correction).

    Thus the pulse starts 10286 ticks into the cycle, then the ADC triggers at 10575 ticks, then the ADC runs until about 10595 ticks, then the pulse ends at 10617 ticks. You may end up fine-tuning these, but I think it's about right.
    ------------
    I agree with Jace that you'll probably end up with an interrupt driven structure. The problem you face is that the usual method for polling the ADC waits for ADCBUSY to go low, but you don't know when it goes high. (I suspect that's part of why you're seeing 0s.)

    For the moment, you might get away with a two phase poll: wait for ADCBUSY to go high, then low:
    > while ((ADC12CTL1 & ADCBUSY) == 0) /*EMPTY*/; // Wait for it to start
    > while ((ADC12CTL1 & ADCBUSY) != 0) /*EMPTY*/; // Wait for it to end

    There's no value in setting SC. Set ENC=1 before the loop and then just let the timer trigger cycle.
    ------------
    Using two timers isn't ideal, but I agree that the SHS choices in the F5438A don't make it easy. Using two timers will result in a slight asynchrony (fixed offset), but for now the numbers above have plenty of slop. Long term you might try moving to TB0, which has both an external pin and an ADC trigger (SHS=3).

**Attention** This is a public forum