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.

CCS/MSP430FR5969: CCS/MSP430FR5972 + ADC repeat-sequence (repeated autoscan) conversion

Part Number: MSP430FR5969
Other Parts Discussed in Thread: MSP430FR5972,

Tool/software: Code Composer Studio

CCS/MSP430FR5969: CCS/MSP430FR5972 + ADC

Unfortunately, it is difficult for me to switch from Atmel to MSP430FR5972 ...
I'm asking for help

I need to solve this problem:
1) The ADC should "repeat-sequence (repeated autoscan) conversion" A3->A12->A13->A14->A15->A3->A12..., bypassing the processor (no interrupts from ADC!!!).

2) Write values ​​from each channel to separate memory locations (ADC12MEMxx). I need 12 bits ADC.
3) Internal Ref=1.2V, should be powered from an internal clock source, the processor clock speed = 8MHz, ADC clock above = ~30kHz(from dividers).

How to program the ADC to this mode of operation?

I'm write:

...
while(REFCTL0 & REFGENBUSY);            // If ref generator busy, WAIT
REFCTL0 |= REFVSEL_0 | REFON;           // REFVSEL = Reference voltage level select. Select internal ref = 1.2V
                                        // REFON = Internal Reference ON
// Configure ADC12 === 200-ksps maximum conversion rate at maximum resolution of 12 bits
ADC12CTL0 = ADC12SHT0_2 | ADC12ON;
ADC12CTL0 &= ~ADC12ENC;                   //  conversion stop for configuration ADC

ADC12CTL0 = ADC12MSC+ADC12SHT0_0+ADC12RES__12BIT; // Turn on ADC12
ADC12CTL1 = ADC12PDIV_0+ADC12DIV_0+ADC12SHP+ADC12SHS_0+ADC12CONSEQ_3;  // repeated sequence

ADC12CTL3 = ADC12CSTARTADD_3; // Start from A3 to A15

ADC12MCTL3  = ADC12INCH_3+ADC12SHT0_0;                 // channel = A3
ADC12MCTL13 = ADC12INCH_13+ADC12SHT1_0;                // channel = A13
ADC12MCTL14 = ADC12INCH_14+ADC12SHT1_0;                // channel = A14
ADC12MCTL15 = ADC12INCH_15+ADC12SHT1_0+ADC12EOS;       // channel = A15

ADC12CTL0 |= ADC12ENC;                    // Enable conversions
ADC12CTL0 |= ADC12SC;                     // Start convn - software trigger


while(!(REFCTL0 & REFGENRDY));            // Wait for reference generator to settle

ADC12IER0 &= ~ADC12IE0;                   // Disable ADC interrupt
ADC12CTL0 |= ADC12ENC | ADC12SC;          // Sampling and conversion start
...

Is it correct ???

Additional qwestions:
4) ADC12CTL0 and ADC12CTL01 and ADC12CTL3 - Are used as setting (the same) for all ADC channels?
5) ADC12MCTLхх - Are used as individual settings for each separate ADC channel?

  • Hi Alexander,

    Here is an example how to configure the MSP430FR5969 ADC12 to perform the sequence of measurements you are looking for.

    This code uses a simple software delay and manual start of conversion that samples about 4 times / second.

    You will need to setup a timer to trigger the ADC at your desired rate.  You can find example code for the timers and how to set the system clock to run at 8MHz in the CCS resouce explorer or TIREX from the web.

    #include <msp430.h>

    int results[5];

    int main(void)

    {

     WDTCTL = WDTPW | WDTHOLD;                 // Stop WDT

     // GPIO Setup

     P1OUT &= ~BIT0;                           // Clear LED to start

     P1DIR |= BIT0;                            // P1.0 output

     P1SEL1 |= BIT1;                           // Configure P1.1 for ADC

     P1SEL0 |= BIT1;

     // Configure the IO pins as ADC inputs

     P1SEL1 |= BIT3;

     P1SEL0 |= BIT3;

     P3SEL1 |= (BIT0 | BIT1 | BIT2 | BIT3);

     P3SEL0 |= BIT0;

     // Disable the GPIO power-on default high-impedance mode to activate

     // previously configured port settings

     PM5CTL0 &= ~LOCKLPM5;

     // By default, REFMSTR=1 => REFCTL is used to configure the internal reference

     while(REFCTL0 & REFGENBUSY);              // If ref generator busy, WAIT

     REFCTL0 |= REFVSEL_0 | REFON;             // Select internal ref = 1.2V

                                               // Internal Reference ON

     // Configure ADC12

     ADC12CTL0 = ADC12SHT0_2 | ADC12MSC | ADC12ON; // 16 ADC clock samples, Multiple sample and conversions

     ADC12CTL1 = ADC12SHP | ADC12CONSEQ_1;                     // ADCCLK = MODOSC; sampling timer

     ADC12CTL2 |= ADC12RES_2;                  // 12-bit conversion results

     ADC12IFGR0 = 0;

     ADC12IV = 0;

     ADC12IER0 = (ADC12IE15);                    // Enable ADC conv complete interrupt

     ADC12CTL3 = ADC12CSTARTADD_3; // Start from A3 to A15

     ADC12MCTL3  = ADC12VRSEL_1 | ADC12INCH_3;                 // channel = A3

     ADC12MCTL12 = ADC12VRSEL_1 | ADC12INCH_12;                // channel = A12

     ADC12MCTL13 = ADC12VRSEL_1 | ADC12INCH_13;                // channel = A13

     ADC12MCTL14 = ADC12VRSEL_1 | ADC12INCH_14;                // channel = A14

     ADC12MCTL15 = ADC12VRSEL_1 | ADC12INCH_15 | ADC12EOS;       // channel = A15

     _enable_interrupts();

     while(1)

     {

       __delay_cycles(200000);                    // Delay between conversions

       ADC12CTL0 |= ADC12ENC | ADC12SC;         // Sampling and conversion start

       __bis_SR_register(LPM0_bits + GIE);      // LPM0, ADC10_ISR will force exit

       __no_operation();                        // For debug only

     }

    }

    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)

    #pragma vector = ADC12_VECTOR

    __interrupt void ADC12_ISR(void)

    #elif defined(__GNUC__)

    void __attribute__ ((interrupt(ADC12_VECTOR))) ADC12_ISR (void)

    #else

    #error Compiler not supported!

    #endif

    {

     switch (__even_in_range(ADC12IV, ADC12IV_ADC12RDYIFG))

     {

       // Fall through if any of these interrupts occur

       case ADC12IV_ADC12IFG15:          // Vector 42:  ADC12MEM15

           results[0] = ADC12MEM3;

           results[1] = ADC12MEM12;

           results[2] = ADC12MEM13;

           results[3] = ADC12MEM14;

           results[4] = ADC12MEM15;

           // Toggle the LED

             P1OUT ^= BIT0;                      // P1.0 = 1

             __bic_SR_register_on_exit(LPM0_bits); // Exit active CPU

           break;

       default: break;

     }

    }

  • Perhaps non-obvious: To hook a timer trigger to the ADC, set ADC12SHS according to Data Sheet [SLASE66B] Table 6-16.
  • I clearly wrote: NO INTERRUPTIONS from ADC!

    Your example is just an example with interruptions from ADS!
    It does not suit me.
    I do not want and will not apply interrupts in working with ADC
    MSP430 has the ability to work with ADC without the use of interrupts, this greatly facilitates the work of calculators and gives me more resources.

    In the examples that are given for MSP430FR5969, and other "test cards", there are no examples(!!!) where the settings for the operation of ADCs are clearly described _without_ the use of interrupts.

    I need help specifically in the matter of how to set up the ADC operation mode _without_ interrupts.

    I've read the technical description many times, but it's written very hard to understand.  :-((
    I was looking for a "lecture" on this topic - but I found only "classics" with the use of interrupts :-(
    I do not understand why such an interesting mode of "work without interruptions" is practically not covered in the examples.
    MSP430 wins in performance and "the beauty of the code" precisely because of the use of "ADC without interrupts."

  • I'm write init code now:

    ----------------------

    // Start ADC init !
    
    while(REFCTL0 & REFGENBUSY);            // If ref generator busy, WAIT
    REFCTL0 |= REFVSEL_0 | REFON;           // REFVSEL = Reference voltage level select. Select internal ref = 1.2V
                                            // REFON = Internal Reference ON
    // Configure ADC12 === 200-ksps maximum conversion rate at maximum resolution of 12 bits
    ADC12CTL0 &= ~ADC12ENC;                   //  conversion stop for configuration ADC
    ADC12CTL0 = ADC12ON;
    //ADC12CTL1 = ADC12SHP;                     // ADCCLK = MODOSC; sampling timer
    
    ADC12CTL0 = ADC12MSC+ADC12SHT0_0+ADC12SHT1_0; // Turn on ADC12, extend sampling time
                                              // to avoid overflow of results
    ADC12CTL1 &= ~ADC12SHP;
    ADC12CTL1 &= ~ADC12SHS0;
    ADC12CTL1 &= ~ADC12SHS1;
    ADC12CTL1 &= ~ADC12SHS0;
    ADC12CTL1 &= ~ADC12SHP;
    ADC12CTL1 &= ~ADC12ISSH;
    ADC12CTL1 |= ADC12PDIV__64;                      // ADC12PDIV__64 == SMCLK/64
    ADC12CTL1 &= ~ADC12DIV_0;                        // ADC12_B clock divider == 000b = /1
    ADC12CTL1 |= ADC12CONSEQ_3;                      // ADC12CONSEQ_3 == 11b = Repeat-sequence-of-channels
    ADC12CTL1 |= ADC12SSEL_3;                        // select 11b = SMCLK
    
    ADC12CTL2 |= ADC12RES__12BIT;                    // ADC12_B resolution 10b = 12 bit (14 clock cycle conversion time)
    ADC12CTL2 &= ~ADC12DF;                           // ADC12_B data read-back format. Data is always stored in the binary unsigned format. == 0b = Binary unsigned
    ADC12CTL2 &= ~ADC12PWRMD;                        // Enables ADC low-power mode. 0b = Regular power mode where sample rate is not restricted
    
    ADC12CTL3 &= ~ADC12ICH0MAP;
    ADC12CTL3 &= ~ADC12ICH1MAP;
    ADC12CTL3 &= ~ADC12ICH2MAP;
    ADC12CTL3 &= ~ADC12ICH3MAP;
    ADC12CTL3 &= ~ADC12TCMAP;
    ADC12CTL3 &= ~ADC12BATMAP;
    
    ADC12CTL3 = ADC12CSTARTADD_3;                    // Start from A3 to A15
    
    ADC12MCTL3  = ADC12WINC+ADC12VRSEL1+ADC12INCH_3;       // channel = A3 - ADC input select; Vref=1.2V
    ADC12MCTL3 &= ~ADC12DIF;
    ADC12MCTL13 = ADC12WINC+ADC12VRSEL1+ADC12INCH_13;            // channel = A13 - ADC input select; Vref=1.2V
    ADC12MCTL13 &= ~ADC12DIF;
    ADC12MCTL14 = ADC12WINC+ADC12VRSEL1+ADC12INCH_14;            // channel = A14 - ADC input select; Vref=1.2V
    ADC12MCTL14 &= ~ADC12DIF;
    ADC12MCTL15 = ADC12WINC+ADC12VRSEL1+ADC12INCH_15+ADC12EOS;   // channel = A15 - ADC input select; Vref=1.2V
    ADC12MCTL15 &= ~ADC12DIF;
    
    ADC12IER0  &= ~0xFFFF;                     // All ADC interrupts disable!
    ADC12IER1  &= ~0xFFFF;                     // All ADC interrupts disable!
    ADC12IER2  &= ~0x00FF;                     // All ADC interrupts disable!
    ADC12IFGR0 &= ~0xFFFF;                     // All ADC interrupts disable!
    ADC12IFGR1 &= ~0xFFFF;                     // All ADC interrupts disable!
    ADC12IFGR2 &= ~0x00FF;                     // All ADC interrupts disable!
    ADC12IV    &= ~0xFFFF;                     // All ADC interrupts disable!
    
    ADC12CTL0 |= ADC12SC;                     // Start convn - software trigger
    ADC12CTL0 |= ADC12ENC;                    // Enable conversions
    
    while(!(REFCTL0 & REFGENRDY));            // Wait for reference generator to settle
    
    //  end ADC init !
    

    ..................

    Test program:

    void main(void) {
    
    float fUadc;
    char string_U[8];
    
    __delay_cycles(1000000);
        LCD_init();
    __delay_cycles(1000000);
        lcd_clear();
    __delay_cycles(1000000);
    
          for(;;) {
    
    __delay_cycles(1000000);
    
              lcd_gotoxy(0,0);
              fUadc=ADC12MEM13;         // V = ...
              sprintf(string_U, "%5.2f", fUadc);
             lcd_gotoxy(0,0); lcd_puts(string_U);
    
    __delay_cycles(1000000);
              lcd_gotoxy(1,0);
              lcd_puts("== ADC ==");
    
    __delay_cycles(1000000);
              lcd_clear();
    
          }
    } // main

    ...

    all function  lcd_**** -- this is my own "small lib", it's work exelent.

    ...

    ...and ADC dont work !  :-(((

  • Init Pin's for ADC:

    ....

     P1SEL1 |= (BIT0+BIT1+BIT2+BIT3); // Configure P1.0---P1.3 for ADC
     P1SEL0 |= (BIT0+BIT1+BIT2+BIT3);
    
     P9SEL1 |= (BIT4+BIT5+BIT6+BIT7); // Configure P9.4---P9.7 for ADC
     P9SEL0 |= (BIT4+BIT5+BIT6+BIT7);
    

    ....

    is correct?

  • Hi Alexander,
    I have not used the ADC with DMA, but that is definitely what you want to do. Have you looked at the DMA examples to see if they include some ADC setup? This thread might have some good examples for you: e2e.ti.com/.../337572

    Hope this helps,
    Paul
  • dear Paul

    I write programs for different microcontrollers since 1988 :)
    still in the former USSR, now I in Ukraine.
    And I have long wanted to switch to MSP430 for my products, precisely because architecture reminds me of my favorite PDP-11, in assembly language I wrote programs in 1988.
    Unfortunately, the English language is not native to me, so it's probably hard for me to explain my thoughts here.

    So, in the MSP430 there is already a ready-made ADC module, which does not need to separately connect the DMA. The ADC is already "laying out" its data in the "autoscan" mode, not using (!) The "central processor".
    ADC12MEM1 .......... ADC12MEM15, as an example.
    It is wonderful! This greatly saves the resources (running time) of the "central processor".

    All that is required from the programmer, this will set up the "autoscan" ADC mode and then, inside its program, simply use the constructions of the form:
    MyIntUsample=ADC12MEM1;
    This is a great opportunity! :)
    Yes, this is an asynchronous mode, while your program "slips" (skips) the individual ADC measurements, but in my program "a spoon is only needed for dinner"(Data is only needed when I come for them, and I will not wait - I'll take what was the freshest), that is, I need the metering data only when I turned to them myself, and not when " the ADC data is ready. "
    When programming the "real-time" system, which I have been working on for the last 10 years, I use the philosophy of an "event-driven system", which allows some liberties and an asynchronous "flow of measurement" with respect to the "decision-making flow".

    That's why I'm so important mode "autoscreen" without the use of interrupts.

    for event-driven systems, the autoscan ADC offers unique capabilities, and I do not understand why this mode is not practically reflected in the examples for the MSP430. :-(((

  • Based on inspection, your original code looks like it would do what you wanted (CONSEQ=3 + MSC=1 + IE=0). What did it do when you ran it? (I'm finding it harder to read your second version, but I do see that in that one you're setting ENC and SC out of order.)

    Without interrupts, you won't know when the samples (ADC12MEMx) are updated, but maybe they'll be updating fast enough that it doesn't matter -- you can just pluck the values out of the MEMx when you want them.

    One possible refinement: The ADC will be converting according to MCTL3 (CSTARTADD_3) through MCTL15 (EOS), including MCTL4-12, which will sample from INCH_0 since you haven't set anything. This is harmless, but a bit wasteful. At some point you might want to set MCTL4/MEM4 for INCH_13, MCTL5 for INCH_14, and so on, so you do only the 4 conversions you want rather than 13 of them.
  • Thanks for the answer.
    1)
    (CONSEQ = 3 + MSC = 1 + IE = 0).
    when I started it all, the data from the ADC12MEM13 is always 118.00 (floating point) regardless whether I send 2V test to the input of the ADC or not - "hardware" is OK, I've rechecked all the tracks on the PC board a hundred times.

    2)
    set up ENC and SC not in order? The manual clearly states: that bits are not set if ADC12ENC = 1; // conversion stop for configuration.
    So, I must first make ADC12ENC = 0; then make all the settings of the registers, and then already ADC12ENC = 1;
    Am I wrong ?

    3)
    Yes, Without interrupts, I do not know when the samples (ADC12MEMx) will be updated, but, on the operation of my device, I'm sure (and this is laid down in the design) that they will be updated fairly quickly (up to 3-5 times faster than I want to read ), I "take out" the values ​​from MEMx whenever I want, and it suits me.

    4)
    The ADC will convert according to MCTL3 (CSTARTADD_3) via MCTL15 (EOS), including MCTL4-12 - yes, I know it, and I will rework the circuit board so that all my ADCs are "in a row" - to "start" and "end" was without a miss and there was no time lost.
    I am ready now for the fact that it will be idle to run MCTL4-12.
    Speed ​​allows it.

    Now it is important for me to start the ADC in operation.
    it's unclear why it does not work, although all the settings are done correctly ...
    :(

    I checked my program on the test MSP430FR5969 - also does not work :(
    Please help me...
  • I'm getting a bit confused about what code you're actually running.

    Your original code appears to be using ENC correctly. The main() function you posted doesn't appear to be doing any ADC12 initialization at all. That main() also isn't stopping the Watchdog -- which runs automatically in the MSP430 -- so your MCU may be resetting every half-second or so.

    Side point:
    > ADC12MCTL3 = ADC12INCH_3+ADC12SHT0_0; // channel = A3
    The SHT0 bits are in CTL0 (where you're also setting them), not in the MCTLs. In this case, since SHT=0, it's harmless, but you're also (implicitly) setting VRSEL=0, which requests Vcc, not VREF, as a reference. This is a numerical, not an operational thing.
    I suggest:
    > ADC12MCTL3 = ADC12INCH_3+ADC12VRSEL_1; // channel = A3, VREF
  • Here is the latest version of my code.
    please see if everything is correct?

    ...

    #include <msp430fr5972.h>
    #include <float.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <stdint.h>
    
    // int _system_pre_init(void)
    void _system_pre_init(void)
    {
    /* Insert your low-level initializations here */
     WDTCTL = WDTPW + WDTHOLD;  // Stop Watchdog timer
    
    __disable_interrupt();  // Это специальная команда!  Это не прерывание.
    
     PM5CTL0 &= ~LOCKLPM5;           // Disable the GPIO power-on default high-impedance mode
                                     // to activate previously configured port settings
    // Clock System Setup
     CSCTL0_H = CSKEY >> 8;                    // Unlock CS registers
    
     CSCTL1 = 0;
     CSCTL1 |=  DCOFSEL_6;                     // Set DCO setting for 8MHz --- установка частоты 8_Мгц
    
     CSCTL2 = 0;
     CSCTL2 |= SELA__LFMODCLK;        // 010b = LFMODCLK  (ACLK == MODOSC/128)
     CSCTL2 |= SELS__DCOCLK;          // 011b = DCOCLK
     CSCTL2 |= SELM__DCOCLK;          // 011b = DCOCLK
    
     CSCTL3 = 0;
     CSCTL3 |= DIVA__2;      // ACLK source divider. Divides the frequency of the ACLK clock source. 001b = /2
     CSCTL3 &= ~DIVS__1;      // SMCLK source divider. Divides the frequency of the SMCLK clock source. 000b = /1
     CSCTL3 &= ~DIVM__1;      // MCLK source divider. Divides the frequency of the MCLK clock source. 000b = /1
    
     CSCTL4 = 0;
     CSCTL4 |= HFXTOFF;      // 1b = HFXT is off if it is not used as a source for ACLK, MCLK, or SMCLK
     CSCTL4 &= ~VLOOFF;      // VLO off. This bit turns off the VLO. 0b = VLO is on
     CSCTL4 &= ~SMCLKOFF;    // SMCLK off. This bit turns off the SMCLK. 0b = SMCLK on
     CSCTL4 |= LFXTOFF;      // 1b = LFXT is off if it is not used as a source for ACLK, MCLK, or SMCLK
    
     // CSCTL5 ???
     // CSCTL6 ???
    
     CSCTL0_H = 0;                             // Lock CS registers
    
    
    // === Init inputs ADC ===
     P1SEL0 = P1SEL1 = 0;
     P1SEL1 |= (BIT0+BIT1+BIT2+BIT3); // Configure P1.0---P1.3 for ADC
     P1SEL0 |= (BIT0+BIT1+BIT2+BIT3);
    
     P9SEL0 = P9SEL1 = 0;
     P9SEL1 |= (BIT4+BIT5+BIT6+BIT7); // Configure P9.4---P9.7 for ADC
     P9SEL0 |= (BIT4+BIT5+BIT6+BIT7);
    
    // ...
    
    // By default, REFMSTR=1 => REFCTL is used to configure the internal reference
    
    while(REFCTL0 & REFGENBUSY);            // If ref generator busy, WAIT
    
    REFCTL0 |= REFVSEL_0 | REFON;           // REFVSEL = Reference voltage level select. Select internal ref = 1.2V
                                                                         // REFON = Internal Reference ON
    
    while(!(REFCTL0 & REFGENRDY));            // Wait for reference generator to settle
    
    
    // Configure ADC12 === up to 200-ksps maximum conversion rate at maximum resolution of 12 bits
    ADC12CTL0 = 0;                          //  conversion stop for configuration ADC
    ADC12CTL0 = ADC12ON;
    
    // e2e.ti.com/.../659772
    
    ADC12CTL0 = 0;
    ADC12CTL0 = ADC12ON+ADC12MSC+ADC12SHT0_0+ADC12SHT1_0;         // Turn on ADC12
    
    ADC12CTL1 = 0;
    ADC12CTL1 = ADC12PDIV__64+ADC12SSEL_3+ADC12CONSEQ_3;      // Predivide by 64, SMCLK, Use sampling 0b = SAMPCON , repeated sequence
    
    ADC12CTL3 = ADC12CSTARTADD_3;                       // Start from A3 to A15
    
    ADC12MCTL3  = ADC12VRSEL_1 + ADC12INCH_3;           // channel = A3  - ADC input select; Vref=1.2V
    ADC12MCTL13 = ADC12VRSEL_1 + ADC12INCH_13;          // channel = A13 - ADC input select; Vref=1.2V
    ADC12MCTL14 = ADC12VRSEL_1 + ADC12INCH_14;          // channel = A14 - ADC input select; Vref=1.2V
    ADC12MCTL15 = ADC12VRSEL_1 + ADC12INCH_15;          // channel = A15 - ADC input select; Vref=1.2V
    ADC12IFGR0 = 0;                             // Disable interrupt
    ADC12CTL0 |= ADC12ENC;                    // Enable conversions
    ADC12CTL0 |= ADC12SC;                     // Start convn - software trigger
    
    //  End init ADC -------------------------------------------
    
    __bis_SR_register(GIE);
    
    __enable_interrupt();
    
    } // end preinit
    
    void main(void) {
    
    float fUadc;
    char string_U[8];
    
         __delay_cycles(1000000);
        LCD_init();
         __delay_cycles(1000000);
        lcd_clear();
         __delay_cycles(1000000);
    
          for(;;) {
             __delay_cycles(1000000);
    
              lcd_gotoxy(0,0);
    
              fUadc=ADC12MEM13;         // UAcontr
    //          ADC12MEM13=0;
              sprintf(string_U, "%5.2f", fUadc);
             lcd_gotoxy(0,0); lcd_puts(e_8prob);  // put 8 " " (space) to LCD
             lcd_gotoxy(0,0); lcd_puts(string_U);
    
             fUadc=ADC12MEM3;         // Ucontr
    //         ADC12MEM3=0;
             sprintf(string_U, "%5.2f", fUadc);
            lcd_gotoxy(1,0); lcd_puts(e_8prob);  // put 8 " " (space) to LCD
            lcd_gotoxy(1,0); lcd_puts(string_U);
    
    
           __delay_cycles(1000000);
              lcd_clear();
    
          }
    
    } // main

    ...
    Now, as a result of
    I see the same value on the LCD, instead of the changing numbers.
    Where was I wrong again?

    Question: if I did not put ADC12EOS, then the sequence will be processed by itself from the initial address to the end?
    I do not quite understand - ADC12EOS leads to a stop of "scan cycles" in general?

  • I'm pretty sure (ref CCS CC User Guide SLAU132R sec. 6.9.1) that _system_pre_init should return a value. Depending on the result, it may or may not complete library initialization. Your function supplies a random return value.

    More generally, I'm not sure it's a good idea to put this kind of code into pre_init:
    1) The C runtime environment is only partially set up.
    2) By the time you get to the (automatic) breakpoint at main, this code is already done, so you don't get a before/after.
    3) If you misspell the name (I don't think you did), I expect your function won't get called and you won't know the difference.

    Outside of that, based on inspection, I don't see anything obviously wrong. I don't have your equipment, so I can't try it myself.

    At this point, I would be pausing the program in the debugger and checking all the registers I thought I set to make sure they're right. I would also be checking the IFG registers to see if any conversions had executed at all. (The MEMx registers are not necessarily 0 after Reset.)
    -----------------
    I suggest setting EOS on MCTL15, but that's not your trouble. Without it (similar to MCTL4-12), the ADC will keep converting up through MEM31 then cycle back to MEM0. This generates unneeded activity, but is otherwise harmless. This is described in the flow chart in the FR5 User Guide (SLAU367O) Fig 34-11. There's a lot of useful information in that Figure.
  • Bruce
    it does not matter at all, I apply MAIN () or pre-init.
    I wrote and so and so the ADC does not work anyway.
    Do not be distracted by this - help me set up the ADC

    You can check the work of my code if you have a "test board" MSP430FR5969
    MSP430FR5969 and MSP430FR5972 are almost identical, except for the memory size.

    The ADC and Timers works the same there.

    Thank you for your help

  • Alexander, Bruce did recommend a next step... Inspect all of the registers. But that can't be done with all of your code in the system pre init function.
    I understand there is a language difference, but your statement "Do not be distracted by this - help me set up the ADC" comes across as unfriendly. Bruce has already done a lot of work to help you set up the ADC!

    Best of luck. I hope the solution is found soon!
    Paul
  • Dear Sir!

    I apologize in advance, but English is not my native language.
    I'm pretty good (I think) I know "technical English" but Google translator sometimes gives me such "designs" that I do not know how to translate.
    Therefore, please do not be offended if any of my words seemed to you harsh.

    I wanted to say that the "initialization of libraries", the CCS-compiler has nothing to do with it.
    The question is that in the ADC setup itself for the mode that I want, it has an error somewhere.
  • But it does matter. If you insert a pre_init function into the library, it needs to be done correctly. Yours isn't.

    I don't have suitable equipment here because I have a Day Job. And I have to get back to work now.
  • I think you need to put ADC12CTL1:ADC12SHP back in. [Ref FR5 User Guide (SLAU367O) Fig 34-11.]
  • With the changes I suggested (and adapting the pins), it appears to run fine on an FR5994. It looks like I'm getting about 200sps.
  • Exelent! :-)
    ...but may be 200Ksps ?

    Last qwestion is: Whot a 1.2v referense?

    ADC12VRSEL (in manual --- Table 34-9. ADC12MCTLx Register Description )
    0000b = VR+ = AVCC, VR- = AVSS
    0001b = VR+ = VREF buffered, VR- = AVSS
    0010b = VR+ = VeREF-, VR- = AVSS
    0011b = VR+ = VeREF+ buffered, VR- = AVSS
    0100b = VR+ = VeREF+, VR- = AVSS
    0101b = VR+ = AVCC, VR- = VeREF+ buffered
    0110b = VR+ = AVCC, VR- = VeREF+
    0111b = VR+ = VREF buffered, VR- = VeREF+
    1000b = Reserved
    1001b = VR+ = AVCC, VR- = VREF buffered
    1010b = Reserved
    1011b = VR+ = VeREF+, VR- = VREF buffered
    1100b = VR+ = AVCC, VR- = VeREF-
    1101b = VR+ = VREF buffered, VR- = VeREF-
    1110b = VR+ = VeREF+, VR- = VeREF-
    1111b = VR+ = VeREF+ buffered, VR- = VeREF-

    Where is 1.2v ref ????
    I think is a
    0011b = VR+ = VeREF+ buffered, VR- = AVSS
    or
    0001b = VR+ = VREF buffered, VR- = AVSS
    ???

    In manual DONT written :
    ...
    34.2.3 Voltage References
    The ADC12_B module may use an on-chip shared reference module that supplies three selectable
    voltage levels of 1.2 V, 2.0 V, and 2.5 V (see the reference module for proper configuration details ?????) to
    supply VR+ and VR-. These reference voltages may be used internally and externally on pin VREF+ if
    REFOUT=1. Alternatively, external references may be supplied for VR+ and VR- through pins
    VREF+/VeREF+ and VeREF-. The ADC12_B module reference selection is through the ADC12VRSEL
    bits. For pin flexibility VR+ and VR- are not restricted to VeREF+ and VeREF- respectively. Care must be
    taken that ADC12VRSEL does not conflict with REFOUT bit settings as only one buffer is available for
    internal reference with REFOUT=1 or ADC12_B module reference when external reference with internal
    buffer is selected . So if REFOUT=1, VeREF+ buffered should not be selected with ADC12VRSEL = 0x3,
    0x5, or 0xF.
    ....

    Where is internal 1.2v ref ????
    "reference module for proper configuration details" ????? Where is ?
    SLAU367O - do not have this...

    Please...
  • Hi Alexander,
    See "Chapter 33 REF_A" starting on page 858 for configuring the internal voltage reference. (In the same document you refer to: www.ti.com/.../slau367o.pdf)

    Thanks,
    Paul
  • I express my gratitude to all of you.

    The ADC worked as I wanted

    (I still have to work hard without interrupting Timer B, but this is my other question in another topic :-)

    Here is the working code - maybe someone will be interested in applying it in their development.

    ...

    #include <msp430fr5972.h>
    
    // int _system_pre_init(void)
    void _system_pre_init(void)
    {
     WDTCTL = WDTPW + WDTHOLD;  // Stop Watchdog timer
    
    __disable_interrupt();  // Это специальная команда!  Это не прерывание.
    
    //WDTCTL = WDTPW | WDTTMSEL | WDTSSEL_2 | WDTIS_5;       // VLOCLK, 1s interrupts --- таймер запущен   <-=================  _wdt_01.c
    // WDTCTL = WDTPW | WDTTMSEL | WDTSSEL_0 | WDTIS_3;        // SMCLK, 0.524sek interrupts --- таймер запущен
    // WDTCTL = WDTPW | WDTTMSEL | WDTSSEL_0 | WDTIS_2;        // SMCLK, 1.049sek interrupts --- таймер запущен
     //SFRIE1 |= WDTIE;                          // Enable WDT interrupt   <---- это надо сделать только после настроек всех частот проца и делителей частоты!
    
     PM5CTL0 &= ~LOCKLPM5;           // Disable the GPIO power-on default high-impedance mode
                                     // to activate previously configured port settings
    // Clock System Setup
     CSCTL0_H = CSKEY >> 8;                    // Unlock CS registers
    // CSCTL0 = CSKEY;                    // Unlock CS registers
    
     CSCTL1 = 0;
     //CSCTL1 &= ~DCORSEL;                       // DCO range select. Set DCO setting for 8MHz --- установка частоты 8_Мгц
     CSCTL1 |=  DCOFSEL_6;                     // Set DCO setting for 8MHz --- установка частоты 8_Мгц
    
     //CSCTL2 = SELA__LFMODCLK | SELS__DCOCLK | SELM__DCOCLK;  // Set SMCLK = MCLK = DCO
     CSCTL2 = 0;
     CSCTL2 = SELA__LFMODCLK + SELS__DCOCLK + SELM__DCOCLK;
     //CSCTL2 |= SELA__LFMODCLK;        // 010b = LFMODCLK  (ACLK == MODOSC/128)
     //CSCTL2 |= SELS__DCOCLK;          // 011b = DCOCLK
     //CSCTL2 |= SELM__DCOCLK;          // 011b = DCOCLK
    
    
     //CSCTL3 = DIVA__2 | DIVS__1 | DIVM__1;   // Set dividers to 2-1-1
     CSCTL3 = 0;
     CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1;   // Set dividers to 1-1-1
     //CSCTL3 |= DIVA__1;      // ACLK source divider. Divides the frequency of the ACLK clock source. 001b = /2
     //CSCTL3 |= DIVS__1;      // SMCLK source divider. Divides the frequency of the SMCLK clock source. 000b = /1
     //CSCTL3 != DIVM__1;      // MCLK source divider. Divides the frequency of the MCLK clock source. 000b = /1
    
     CSCTL4 = 0;
     CSCTL4 = HFXTOFF + VLOOFF + LFXTOFF;
     //CSCTL4 |= HFXTOFF;      // 1b = HFXT is off if it is not used as a source for ACLK, MCLK, or SMCLK
     //CSCTL4 |= VLOOFF;       // VLO off. This bit turns off the VLO. 0b = VLO is on
     //CSCTL4 &= ~SMCLKOFF;    // SMCLK off. This bit turns off the SMCLK. 0b = SMCLK on
     //CSCTL4 |= LFXTOFF;      // 1b = LFXT is off if it is not used as a source for ACLK, MCLK, or SMCLK
    
     // CSCTL5 ???
     // CSCTL6 ???
    
     CSCTL0_H = 0;                             // Lock CS registers
    
    // ...
    
    // === Input pin for ADC ===
     P1SEL0 = P1SEL1 = 0;
     P1SEL0 |= (BIT0+BIT1+BIT2+BIT3); // Configure P1.0---P1.3 for ADC
     P1SEL1 |= (BIT0+BIT1+BIT2+BIT3);
    
     P9SEL0 = P9SEL1 = 0;
     P9SEL0 |= (BIT4+BIT5+BIT6+BIT7); // Configure P9.4---P9.7 for ADC
     P9SEL1 |= (BIT4+BIT5+BIT6+BIT7);
    
    //  Start init ADC --------------------------------------------------------------------------
    
    while(REFCTL0 & REFGENBUSY);            // If ref generator busy, WAIT
    REFCTL0 |= REFVSEL_0 | REFON;           // REFVSEL = Reference voltage level select. Select internal ref = 1.2V
                                            // REFON = Internal Reference ON
    while(!(REFCTL0 & REFGENRDY));            // Wait for reference generator to settle
    
    // Configure ADC12 ===
    
    ADC12CTL0 = 0;                          //  conversion stop for configuration ADC
    ADC12CTL0 = ADC12ON+ADC12MSC+ADC12SHT0_0+ADC12SHT1_0;         // Turn on ADC12, extend sampling time
    
    ADC12CTL1 = 0;
    ADC12CTL1 = ADC12PDIV__4+ADC12DIV_2+ADC12SSEL_3+ADC12SHS_0+ADC12SHP+ADC12CONSEQ_3;      // Predivide by 4+2, SMCLK, Use sampling 0b = SAMPCON , repeated sequence
    // 1Mhz inp.freq ADC == 71428,57 sps! 4629,63 замеров в сек. (с 3 по 15 канал перебором)
    
    ADC12CTL2 = 0;
    ADC12CTL2 |= ADC12RES__12BIT;                    // ADC12_B resolution 10b = 12 bit (14 clock cycle conversion time)
    
    ADC12CTL3 = ADC12CSTARTADD_3;                    // Start from A3 to A15
    
    ADC12MCTL3  = 0;
    ADC12MCTL3  = ADC12VRSEL_3 + ADC12INCH_3;           // channel = A3  - ADC input select; Vref=1.2V
    ADC12MCTL13 = 0;
    ADC12MCTL13 = ADC12VRSEL_3 + ADC12INCH_13;          // channel = A13 - ADC input select; Vref=1.2V
    ADC12MCTL14 = 0;
    ADC12MCTL14 = ADC12VRSEL_3 + ADC12INCH_14;          // channel = A14 - ADC input select; Vref=1.2V
    ADC12MCTL15 = 0;
    ADC12MCTL15 = ADC12VRSEL_3 + ADC12INCH_15 + ADC12EOS;          // channel = A15 - ADC input select; Vref=1.2V
    ADC12IFGR0 = 0;                             // Disable interrupt
    //ADC12CTL0 |= ADC12ENC;                    // Enable conversions
    //ADC12CTL0 |= ADC12SC;                     // Start convn - software trigger
    ADC12CTL0 |= ADC12SC | ADC12ENC;            // Start conversions + Enable conversions
    
    //  End setup ADC ----------------------------------------------------------------------
    
    // ...
    
    __bis_SR_register(GIE);
    } //void _system_pre_init(void)
    

    ...

    Thanks again!

  • My arithmetic says you might approach 70ksps before your clock goes out of spec. This also assumes that your sensors deal well with a 4-clock (<1usec) integration time (SHT0=SHT1=0); some do, some don't. But if you're only picking out 1 sample each second -- or, more generally, displaying the value for a human on an LCD -- it's not clear what you gain from a higher sample rate.

    "Alternatively, external references may be supplied for VR+ and VR- through pins VREF+/VeREF+ and VeREF-." I.e. VeREF refers to an "e"xternal pin. Since you don't have that -- or at least didn't mention it-- Dennis Lehman (and I) recommended VRSEL=1.

    If you don't have a copy of the FR5 User Guide (SLAU367O) I strongly recommend it:
    www.ti.com/.../slau367o.pdf
  • Dear Bruce!

    1) Thank you, you express the right fears, but you do not see my whole "iron" scheme before the ADC. last Friday I drove out the work of my scheme in real work and I liked the results.
    I make the decision of the scheme work according to the ADC data from 100 to 300 times per second, and the output on the LCD "for the person", yes, occurs about once a second.
    I have already written that this is an "event-driven system" with an asynchronous mode of parallel operation of individual parts and the allowed "slippage" of measurements regarding "decision-making".
    So the result that I now got me quite satisfied.

    2) I use (only) an internal reference voltage.
    SLAU367O ---- Figure 34-1. ADC12_B Block Diagram
    "...ADC12VRSEL selects the internal reference for the ADC..."
    and:
    Table 34-9. ADC12MCTLx Register Description

    ADC12VRSEL --- 0001b = VR+ = VREF buffered, VR- = AVSS
    that's right?

    ...

    REFCTL0 |= REFVSEL_0 | REFON;           // REFVSEL = Reference voltage level select. Select internal ref = 1.2V
    ...

    ADC12MCTL3  = ADC12VRSEL_1 + ADC12INCH_3;           // channel = A3  - ADC input select; Vref=1.2V
    ...

    that's right?

**Attention** This is a public forum