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.

Msp430g2553 ADC clock division

Other Parts Discussed in Thread: MSP430G2553, MSP430WARE

dears "

i have msp430g2553 micro controller. which i want to make it run on 1 mega HZ clock from DCO which will be also the timer A clock.

and want my ADC clock to be 125 K HZ (125000 HZ) so i make the clock be from DCO and divide it by 8 as follows

void ADC_setup(){
    ADC10CTL0 = SREF_1 + ADC10SHT_2 + REFON + ADC10ON + ADC10IE+ADC10DIV_7;  // ADC10DIV_7 7 decimal mean 111 which mean divide by 8
 
    //enable_interrupt();
    TACCR0 = 30;                              // Delay to allow Ref to settle
      TACCTL0 |= CCIE;                          // Compare-mode interrupt.
      TACTL = TASSEL_2 | MC_1;                  // TACLK = SMCLK, Up mode.
      LPM0;                                     // Wait for delay.
      TACCTL0 &= ~CCIE;                         // Disable timer Interrupt
    //  __disable_interrupt();
}

and in main l make that

int main(void) {

    volatile int i = ADC10MEM ;

    WDTCTL = WDTPW | WDTHOLD;    // Stop watchdog timer

    BCSCTL1 = CALBC1_1MHZ;            // Set range   DCOCTL = CALDCO_1MHZ;
    BCSCTL2 &= ~(DIVS_3);            // SMCLK = DCO = 1MHz

}

the question here is ADC10DIV_7   mean divide the clock by 8    (1 MHZ / 8 = 125 KHZ) or it mean the number of division (1MHZ / 2 then (1MHZ / 2)/2 ......eight times )

any help will  appreciated .thanks in advance

  • Hi Amir,

    After looking at your code, I've noticed a few bugs:

    1. ADC10DIV_7 needs to be set in register ADC10CTL1, not ADC10CTL0
    2. You need to specify the clock provided to the ADC by modifying the ADC10SSELx bits in ADC10CTL1
      1. Currently it defaults to ADC10OSC which runs between 3.7MHz and 6.3MHz

    To answer your original question, ADC10DIV_7 means the clock provided to the ADC is divided by 8. To make you code do what you'd like remove ADC10_DIV7 from the ADC10CTL0 register setup and add this line:

    ADC10CTL1 |= ADC10DIV_7 + ADC10SSEL_2 ;  // Set ADC source clock to MCLK (1MHz) and divide by 8 = 125kHz

    Also, take a look at the MSP430Ware examples provided in the TI resource explorer through Code Composer Studio. There are a wide range of ADC examples present there to help you get started. 

    Best regards, 
    Caleb Overbay

  • HI Caleb '
    Thanks a lot . your answer is appreciated .

    I have anther question about the timer clock . the code i use as follows

    CCTL0 = CCIE; // CCR0 interrupt enabled
    CCR0 = 80 ;
    TACTL = TASSEL_2 + MC_1; // SMCLK, upmode

    _BIS_SR(LPM0_bits + GIE); // Enter LPM0 w/ interrupt


    #pragma vector=TIMER0_A0_VECTOR
    __interrupt void timerA0ISR(void)
    {
    read_signal();
    }


    Is that code correct as i am using the timer interrupt every 80 cycle to excite the function( read_signal)

    thanks in advance .
  • Hi Amir, 

    Your timer code looks good and should perform as you've described. However, I strongly suggest not calling functions within an ISR. Instead, set a flag within the ISR and wake from LPM0, then in your main loop, react to that flag being set. MSP430 Software Coding Techniques describes this approach well.

    Again, I recommend taking a look at the examples in MSP430Ware. It contains a wealth of examples, including one that performs very similarly to the code you've posted above. 

    Best regards, 

    Caleb Overbay

  • Hi celeb '
    I don't know how to thank you for that great support and your time.

    after your modification now i can read adc signal as the rang i expect . but for some reasons i can't read the full data sent ( transmitter send infrared signal) .
    By the way i have that code works well by avr atmega family . so i think the main problem in the different adc registers between msp430 family and atmega family.
    the code i use as follows .

    void ADC_setup(){
    ADC10CTL0 = SREF_1 + ADC10SHT_2 + REFON + ADC10ON + ADC10IE ;

    ADC10CTL1 |= ADC10DIV_7 + ADC10SSEL_2 ; // Set ADC source clock to MCLK (1MHz) and divide by 8 = 125kHz
    }

    void conversion_start(void){

    ADC10AE0 &= ~(0x07) ; //clearing enabled channels
    ADC10CTL1 = INCH_1; // input A1
    ADC10AE0 |= 0x02; // PA.1 ADC option select
    ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start
    }

    int conversion_read(void){

    while( ADC10IFG < 0) ; // adc flag that mean finish conversion equal to " while(bit_is_set(ADCSRA, ADSC)); " in avr

    return ADC10MEM ; // ADC10MEM register equal adc register in avr
    }

    i have great Doubt in that two lines of code
    ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start
    and
    while( ADC10IFG < 0) ; // adc flag that mean finish conversion

    thanks in advance .

  • Hi Amir,

    What do you mean when you say you "cant read full data sent"?

    Also, I see you are setting the ADC registers with '=' instead of '|='. This can be a problem, especially in your conversion_start function where you set the value of ADC10CTL1 you are erasing all the other data previously written to that register (ie ADC10DIV_7 + ADC10SSEL_2).

    Again, I strongly urge you to take a look at the MSP430Ware examples in CCS. More specifically, the msp430g2x33_adc10_01.c.

    Best regards,
    Caleb Overbay
  • Hi caleb '
    Hope you are doing well .

    I can't read the full data mean that can't receive the sent message .
    Your modification is appreciated .
    Also i have get look on the examples on CCS about ADC . but i need to set function for ADC start conversion and anther function for read conversion after complete the conversion i found that in the examples by using the ADC interrupt which i don't need to use as following

    #include <msp430.h>


    int main(void)
    {

    WDTCTL = WDTPW + WDTHOLD; // Stop WDT
    ADC10CTL0 = SREF_1 + ADC10SHT_2 + REFON + ADC10ON + ADC10IE;
    __enable_interrupt(); // Enable interrupts.
    TACCR0 = 30; // Delay to allow Ref to settle
    TACCTL0 |= CCIE; // Compare-mode interrupt.
    TACTL = TASSEL_2 | MC_1; // TACLK = SMCLK, Up mode.
    LPM0; // Wait for delay.
    TACCTL0 &= ~CCIE; // Disable timer Interrupt
    __disable_interrupt();
    ADC10CTL1 = INCH_1; // input A1
    ADC10AE0 |= 0x02; // PA.1 ADC option select
    P1DIR |= 0x01; // Set P1.0 to output direction

    for (;;)
    {
    ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start
    __bis_SR_register(CPUOFF + GIE); // LPM0, ADC10_ISR will force exi


    if (ADC10MEM < 305) // ADC10MEM = A1 > 0.2V?
    P1OUT &= ~0x01; // Clear P1.0 LED off
    else
    P1OUT |= 0x01; // Set P1.0 LED on
    }
    }

    // ADC10 interrupt service routine
    #pragma vector=ADC10_VECTOR
    __interrupt void ADC10_ISR (void)
    {
    __bic_SR_register_on_exit(CPUOFF); // Clear CPUOFF bit from 0(SR)
    }

    #pragma vector=TIMER0_A0_VECTOR
    __interrupt void ta0_isr(void)
    {
    TACTL = 0;
    LPM0_EXIT; // Exit LPM0 on return
    }


    There in any way else to say that the conversion has complete so i can read the next sent data.
    By the way i search and fount that
    while( (ADC10CTL1 & ADC10BUSY) );

    are that is flag to say that conversion has complete .

    Thanks in advance .
  • Hi Amir, 

    When you say "sent message" are you referring to the ADC conversion completion? It sounds like you're not detecting when this conversion is complete. Am I correct?

    Now regarding the code you've posted above, inside the main loop, it signals the start of an ADC conversion and goes to a LPM meaning the CPU stops executing code. Once the ADC finishes it's conversions, its ISR wakes the CPU back up where it immediately reads the ADC conversion result.

    Is there a reason you don't want to use this interrupt based approach? In regards to needing to have a start conversion function, the conversion is started with this line of code:

    ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start

    You could create a function and put just that line of code in it if you wanted.

    Also, in the MSP430Ware example above, the reading of the result occurs in the ADC interrupt service routine with this line of code:

    if (ADC10MEM < 305) // ADC10MEM = A1 > 0.2V?

    By reading the AC10MEM register, you are reading the result of the conversion. 

    To me, it seems the example does everything you need it to. Am I missing something?

    Best regards, 
    Caleb Overbay

  • Hi Amir,

    Have you made any progress on this issue?

    Best regards,
    Caleb Overbay

**Attention** This is a public forum