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.

TM4C123GH6PGE: qs-logger Example Source Code ADC Questions

Part Number: TM4C123GH6PGE
Other Parts Discussed in Thread: TM4C1236D5PM, INA301, TM4C123GH6PM, INA198

Hello, Bob

Bob said> Using the 64 pin part with VADC connected to VREFP, let's use a reference voltage of 3.30V.

I have been designing circuit and PCB artwork for a while, but parts supply was delayed due to the corona virus.

I wanted to apply VREFP 3.3V in the source code, so I saw the ADCReferenceSet ( ) function in the SW-TM4C-DRL-UG documentation.

But there is no procedural way to change 3.3V ,  also looked at the registers inside the Datasheet but didn't find.

TM4C1236D5PM (64 Pin) without VREFP, VDDA (Min 2.97 Nom 3.3 Max 3.63) 3.3V power supply.

Q1> How do I modify the source code to change 3.3V?

[ Acquire.c/AcquireInit ( ) ]

   ADCReferenceSet(ADC0_BASE, ADC_REF_EXT_3V);

   ADCReferenceSet(ADC1_BASE, ADC_REF_EXT_3V);

[ adc.h ]

#define ADC_REF_EXT_3V         0x00000001 // External 3V reference

Best Regards,

Jame,Shin

  • For the 64 pin device VDDA and VREFP are tied together. It is not necessary to call ADCReferenceSet(). Your reference voltage will be the voltage applied between the VDDA and GNDA pins. That voltage must be between 2.97V and 3.63V. Use whatever voltage that is in your ratiometric calculations. 

  • (Fig 1.)   Souce Code

    FPULazyStackingEnable();     // floating-point Enable

    uint32_t   adc_volt;

    uint32_t pui32ADC0Value[1];

    uint32_t ui32Current;

    .

    unsigned int uiValue;

    float fAmp;

    .

    .

    .

    // ============================================================

       /*1*/   ADCSequenceDataGet(ADC0_BASE, 0, pui32ADC0Value);

                adc_volt=(pui32ADC0Value[0]* 4096) / 819;

                UARTprintf("\nCH0 Voltage = %d.%d V  \n",adc_volt/1000, adc_voltl%1000); // Display the CH0/AIN0 (PE3)

    // ============================================================ 

      /*2*/    ADCSequenceDataGet(ADC1_BASE, 0, pui32ADC0Value);  // Display the CH23/AIN23(PP0)

                ui32Current = (pui32ADC0Value[0] * 200) / 273;

                UARTprintf("CH23 ADC Value = %d  \n",ui32Current);

    // ----------------------------------------------------------------------------------------------------

      /*3*/   ADCSequenceDataGet(ADC1_BASE, 0, pui32ADC0Value);  // Display the CH23/AIN23(PP0)

               ui32Current = (pui32ADC0Value[0] * 200) / 273;

               UARTprintf("CH23 Current = %d.%d mA \n",ui32Current/10,ui32Current%10);

    // ----------------------------------------------------------------------------------------------------

      /*4*/   ADCSequenceDataGet(ADC1_BASE, 0, pui32ADC0Value);  // Display the CH23/AIN23(PP0)

               ui32Current = (pui32ADC0Value[0] * 200) / 273;

               UARTprintf("CH23 Current = %d.%04d A \n",ui32Current/1000,ui32Current%1000);

    // ---------------------------------------------------------------------------------------------------

      /*5*/   ADCSequenceDataGet(ADC1_BASE, 0, &uiValue);  // Display the CH23/AIN23(PP0)

               fAmp =  (float)uiValue *0.01 *100*3.0/4096.0;

               UARTprintf("Float Current = %f \n",fAmp);

    ========================================================================================

    Hello, Bob

    Bob said> Suggest a real floating point calculation method

    float fAmp;

    unsigned int value;

    ...

    ADCSequenceDataGet(ADC0_BASE,3,&value);

    fAmp = (float)value / 0.01 * 100.0 * 3.30 / 4096.0;

    /*5 */ case : Compile warning: “ single-precision operand implicitly converted to double-precision”

    - A warning occurred with (float) type cast Operator

    - The result is displayed as ERROR from the real type output assignment operator %f.

    Q1> Output format specifiers for UARTprintf () and usnprintf () data types do not have  % f

           So either Log Messge or OLED Display will output ERROR

           What output method does the “n.nn” expression with a real calculation?  

    Q2> /*4*/ Case : When the current calculation was done using the conventional decimal calculation method, the current unit was forcibly find in (mA) to (A).

           The ADC = 134 value is the gain 100 V / V applied on the INA189 device.

           When ADC / 10 is calculated through the output function, it becomes 13.4 mA.

           I want is 0.0134 A.

           However, the calculation result of "% d.%d", 134/1000, 134%1000 is 0.134.

           Forced the addition of 0 to change the %04d format specifier to 0.0134.

          Is this the right way?  and  Please advise.

    Best Regards,

    Jame,Shin

  • As documented in "C:\ti\TivaWare_C_Series-2.1.4.178\docs\SW-TM4C-UTILS-UG-2.1.4.178.pdf", the UARTprintf function does not support %f. This is done to reduce the size of the code. Your solution #4 is a good solution. 

  • Hello Bob,

    Thanks you for your answer.

    The 32bit Tiva MCU can calculate floating point operations.

    However, is it the conclusion that the OLED display and the Log Message cannot be output in real type?

    I feel a contradiction.

    Q1>   Is there any way to output the result of a real floating point calculation?

    The Tiva MCUs can't output real values, so the previous Ti development team seems to have calculated them mathematically(greatest common divisor).

    - gcd(3000, 4095) = 15, 3000/15 = 200 and 4096/15 = 273.066.

    - (3000/4096) / (18Khom / 123kohm) ≒ 4100/819

        (Equation)

    ui32Current = (ui32Current * 200) / 273;

    ui32Millivolts = (g_pui32ADCData[ui8Idx] * 4100) / 819;

    Inferring the story from the previous post, I think:

    Best Regards,

    Jame,Shin

  • Hi James,

    Jame shin said:
    Q1>   Is there any way to output the result of a real floating point calculation?

    I think you are not understanding how these numbers are represented in a computer. The TM4C is capable of doing floating point computations (ANSI/IEEE Std 754-2008). The issue you are seeing is that the OLED display displays ANSI strings. You must convert the float to an ANSI string. The UARTPrintf() function does not support that conversion. You can use the sprintf() function to convert the floating point number to a string and then use UARTPrintf() to print that string.

    Or, you can convert the floating point number to two integers, (the integer part and the decimal part) and print them both as you did in case #4 above. The results are the same, but this method can save you code size.

  • Hello Bob.

    I have a question about the coding from the qs-logger example.

    - ProcessDataItem( ) Function.

    for(ui8Idx = ADCSEQ_CURRENT;

               ui8Idx < (ADCSEQ_CURRENT + NUM_CURRENT_SAMPLES); ui8Idx++)

           {

               ui32Current += g_pui32ADCData[ui8Idx];

           }

           ui32Current /= NUM_CURRENT_SAMPLES;

    - AcquireStart( ) Function.

       MAP_ADCSequenceDataGet(ADC1_BASE, 0, g_pui32ADCData);

    Q1> Capture one ADC values from the ADCSequenceDataGet () function.

           I don't known how each 7th sampling data is input from g_pui32ADCData [6] to g_pui32ADCData [12].

         Please explain what source code is being used.

    Best Regards,

    Jame,Shin

  • I am not sure I understand your question. The function ADCSequenceDataGet() returns the number of samples available in that sequence. Since sequence 0 is being used for both ADC0 and ADC1, the maximum number of samples returned is 8 (sequence 0 has a FIFO size of 8). The number of samples is also defined by the calls to ADCSequenceStepConfigure() in the function AquireInit() of the file acquire.c in line 1286. The loop configures "NUM_ADC_CHANNELS" (13). The first 8 are configured in sequence 0 of ADC0, then next 5 are in sequence 0 of ADC1.

  • Hello Bob.

    I didn't have a clear question. Sorry.

    Table 13-2. Samples and FIFO Depth Sequencers In the Data Sheet

    SS0: 8 , SS1: 4 , SS2:4 , SS3: 1

    Q1> What is the ADCSequenceStepConfigure () parameter ui32Step about?

           If the meaning of the step is sampling number and the range is min 1  to  max 8 means.

               e.g) ADCSequenceStepConfigure(ADC1_BASE, 0, 7, ADC_CTL_CH23 | ADC_CTL_IE | ADC_CTL_END);

           If the meaning of step means the number of analog input 0 ~ 23 (AIN0 ~ AIN23).

              e.g) ADCSequenceStepConfigure(ADC1_BASE, 0, 23, ADC_CTL_CH23 | ADC_CTL_IE | ADC_CTL_END);

          

    Q2> The FIFO value of ADC1 SS0 is saved as the index of each array name.

            I didn't find any source code to save as below.  Please explain your advice.

           g_pui32ADCData[6] = ADC sample1 Current Value ……….. g_pui32ADCData[12] = ADC sample 7 Current Value

          

               ADCSequenceDataGet(ADC1_BASE, 0, g_pui32ADCData[6]);

               ADCSequenceDataGet(ADC1_BASE, 0, g_pui32ADCData[7]);

               ADCSequenceDataGet(ADC1_BASE, 0, g_pui32ADCData[8]);

               ADCSequenceDataGet(ADC1_BASE, 0, g_pui32ADCData[9]);

               ADCSequenceDataGet(ADC1_BASE, 0, g_pui32ADCData[10]);

               ADCSequenceDataGet(ADC1_BASE, 0, g_pui32ADCData[11]);

               ADCSequenceDataGet(ADC1_BASE, 0, g_pui32ADCData[12]);

    Q3> Why did you sample it 7 times, as shown in Table 13-2, at maximum SS0: 8 samples ?

    Best Regards,

    Jame,Shin

  • Jame shin said:
    Q1> What is the ADCSequenceStepConfigure () parameter ui32Step about?

    The sequences can do multiple conversions when started, one after the other. Sequence 0, up to 8 conversions, sequences 1 and 2 up to 4 and sequence 3 only one. For sequences 0, 1 and 2, the step is configuring which channels to convert. They are done in order of step, 0, 1, 2 ...

    Jame shin said:

    Q2> The FIFO value of ADC1 SS0 is saved as the index of each array name.

            I didn't find any source code to save as below.

    The code example you cite is not correct. The code to read the ADC after all conversion are made is in lines 671 and 672 of acquire.c (original example). 

        //
        // Retrieve the data from all ADC sequencers
        //
        MAP_ADCSequenceDataGet(ADC0_BASE, 0, &g_pui32ADCData[0]);
        MAP_ADCSequenceDataGet(ADC1_BASE, 0, &g_pui32ADCData[8]);
    

    The function ADCSequenceDataGet() returns all of the values in the FIFO. Since ADC0 was configured for 8 samples and ADC1 was configured for 5, the first call fills g_pui32ADCData[0] - [7], the second call fills g_pui32ADCData[8] - [12] 

  • #1. AcquireInit ( )

       {

            for(ui32Chan = 0; ui32Chan < NUM_ADC_CHANNELS; ui32Chan++)

           // for( ui32Chan =0; ui32Chan < 13 ; ui32Chan++)

            ..

           // Configure the sequence step

           MAP_ADCSequenceStepConfigure(ui32Base, ui32Seq, ui32Chan % 8, ui32ChCtl);

             // ui32Chan : 0 ,1 ,2 ,3 ,4 ,5 ,6 ,7, ( ADC0 , Seq=0)

            //                    8 ,9 ,10 ,11 ,12         (ADC1, Seq =0) 

         .. 

         }

    #2. ADC0SS0Handler( )

         {

             …

            MAP_ADCSequenceDataGet(ADC0_BASE, 0, &g_pui32ADCData[0]);

            MAP_ADCSequenceDataGet(ADC1_BASE, 0, &g_pui32ADCData[8]);

           ..

         }

    #3. ProcessDataItems ( )

         {

           ..  

             for(ui8Idx = ADCSEQ_CURRENT; ui8Idx < (ADCSEQ_CURRENT + NUM_CURRENT_SAMPLES); ui8Idx++)

           // for (ui8Idx = 6 ; ui8Idx < 13 ; ui8Idx++)

                {

                  ui32Current += g_pui32ADCData[ui8Idx];

                }

           ui32Current /= NUM_CURRENT_SAMPLES;     // ui32Current = ui32Current / 7 , ( [6],[7],[8],[9],[10],[11],[12])

            ..

         }

    Hello Bob.

    I did not pass the desired question due to lack of expression. Sorry.

    Bob Said> The code to read the ADC after all conversion are made is in lines 671 and 672 of acquire.c

    Q1> Configure the # 1 sequence step and save the ADC value from the FIFO as # 2 in two variables: & g_pui32ADCData [0] and & g_pui32ADCData [8].

       # 3 calculates the sampling average to reduce the error.

       But I don't know how the values of g_pui32ADCData [6] ~ g_pui32ADCData [12] are filled.

       Please explain in detail.

    Best Regards,

    Jame,Shin

  • ADC0 is configured to convert 8 channels in this order: CHAN_USER0, CHAN_USER1, CHAN_USER2, CHAN_USER3, CHAN_EXTTEMP, CHAN_INTTEMP, CHAN_CURRENT, CHAN_CURRENT. Notice that the last two conversions are of the same channel, CHAN_CURRENT (ADC23). 

    The function 

      MAP_ADCSequenceDataGet(ADC0_BASE, 0, &g_pui32ADCData[0]);

    reads all 8 channels results, storing them in g_pui32ADCData[0] through g_pui32ADCData[7]. 

    ADC1 is configured to read CHAN_CURRENT (ADC23) 5 times. The function

      MAP_ADCSequenceDataGet(ADC1_BASE, 0, &g_pui32ADCData[8]);

    reads all 5 results and stores them in g_pui32ADCData[8] through g_pui32ADCData[12]. 

    Now g_pui32ADCData[6] through g_pui32ADCData[12] contain 7 readings of CHAN_CURRENT (ADC23).

  • Bob Crosby said:
    Now g_pui32ADCData[6] through g_pui32ADCData[12] contain 7 readings of CHAN_CURRENT (ADC23).

    Had poster enabled "8 such readings" a simple "Unsigned Addition followed by 3 (proper) Shifts Right" would escape the necessity to divide.   (to compute the 'average.')

    It may be that, "More time spent optimizing the current sensor's design & implementation" trumps, "beating the sensor to death!"   (in the "misguided attempt" to enhance accuracy.)   

    There is (little ... i.e. NO guarantee) that even "clustering" 100 or so (inaccurate) sensor readings will enhance "ACCURACY!"    (although "apparent sensor precision" will improve.)

    This classic drawing nicely illustrates:   (crack staff notes that "Deviation from the reference" denotes accuracy - "clustering denotes precision.")

  • Hello Bob.

    The assembled board is coming in and testing.

    I have a question that I learned from the previous Post.

    In [Figure 1], the previous R2 value is 18K.

    Bob said that by lowering the voltage per bit to the ratio of resistance, I changed it to the same value because it had precision.

    The ADCReferenceSet () function does not require you to set VREFP.

    Q1> The + 5V_EXT input port supplies 4.95V and the ADC result is 4.4V ~ 4.45V.

           So 4.95 – 4.45 = 0.5V difference occurs.

         How can I calibrate ? (VREFP 3.3V is not applied.)

          

         ui32Volt=(pui32ADC0Value[0]* 4100) / 819;

    Of course, as you answered, I stopped real type calculations and their results because of an error in the character change.

    float fVolt;

    unsigned int value;

    ...

    ADCSequenceDataGet(ADC0_BASE,3,&value);

    fVolt = (float)value * 2.0 * 3.30 / 4096.0

     

    Q2> + 5V_INT Input port is + 1.5V. Why is ADC output value of PE2 / AIN1 pin 4.53V?

             I don't know why. Please check if the configuration source code is wrong.

    Main( )

    {

       ...........

       char pcVoltBuffer[6];

       char pcCurrBuffer[6];

      uint32_t pui32ADC0Value[2]; 

      uint32_t ui32Volt;

      uint32_t ui32Current;

      ……

       SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);

       SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC1);

       SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);

       SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD)

    GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3|GPIO_PIN_2);      

    GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_1|GPIO_PIN_0);

       ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_PROCESSOR, 0);  

       ADCSequenceConfigure(ADC1_BASE, 0, ADC_TRIGGER_PROCESSOR, 0);

       ADCSequenceStepConfigure(ADC0_BASE, 0, 2, ADC_CTL_CH0|ADC_CTL_CH6|ADC_CTL_IE|ADC_CTL_END);

       ADCSequenceStepConfigure(ADC1_BASE, 0, 2, ADC_CTL_CH1|ADC_CTL_CH7|ADC_CTL_IE|ADC_CTL_END);

       ADCSequenceEnable(ADC0_BASE, 0);

       ADCSequenceEnable(ADC1_BASE, 0);

       IntMasterEnable();

      while(1)

      {

             …….

               ADCProcessorTrigger(ADC0_BASE, 0);

              ADCProcessorTrigger(ADC1_BASE, 0);

             while(!ADCIntStatus(ADC0_BASE, 0, false) && !ADCIntStatus(ADC1_BASE, 0, false) )

              {

              }

           ADCIntClear(ADC0_BASE, 0);

           ADCIntClear(ADC1_BASE, 0)

           ......

           // PE[3]/AIN0, Volt ( ADC0 )

           ADCSequenceDataGet(ADC0_BASE, 0, &pui32ADC0Value[0]);

           ui32Volt=(pui32ADC0Value[0]* 4100) / 819;

           usnprintf(pcVoltBuffer, 5, "%u.%u ", ui32Volt/1000,ui32Volt%1000);

           ......

         // PD[1]/AIN6, Curr (ADC0)

           ui32Current = (pui32ADC0Value[1] * 200) / 273;

           usnprintf(pcCurrBuffer, 5, "%u.%04u ", ui32Current/1000,ui32Current%1000);

           .....

         // PE[2]/AIN1, Volt ( ADC1 )

           ADCSequenceDataGet(ADC1_BASE, 0, &pui32ADC0Value[0]);  

           ui32Volt=(pui32ADC0Value[0]* 4100) / 819;  

           usnprintf(pcVoltBuffer, 5, "%u.%u ", ui32Volt/1000,ui32Volt%1000);

        

           ......

         // PD[0]/AIN7, Curr ( ADC1 )

           ui32Current = (pui32ADC0Value[1] * 200) / 273;

           usnprintf(pcCurrBuffer, 5, "%u.%04u ", ui32Current/1000,ui32Current%1000);

           ......

        }

    }

    Bob Said > The measurement can be no more accurate than 1/2 of a bit (quantization error).

                   Scaling the input voltage to make the smallest mV/bit gives you the smallest quantization error.

    Q3> [Figure 1] I applied R1: 150K, R2: 150K same as Block Diagram

    The ADC measured voltage value at PE3 / AIN0 pin is 15.4 to 15.5V.

     Input voltage of + 5V_EXT input port is 4.97V. 

    How can I change the source code below?  

    ui32Volt=(pui32ADC0Value[0]* 4100) / 819;

    Best Regards,
    Jame,Shin

  • Hello Bob,

    I still don't know <Q1> and <Q2> of the previous post.

    In the meantime, debugging is as follows.  (R2 value is 18K.)

    This is an addition to the previous Q2.

    Q2-1> Why are the ADC0 and ADC1 values similar to the data copied from the specified sample sequencer output FIFO to the memory resident buffer?

    // 5.02V power supply. No load.     (ADC0)

    ADC0: PE3 / AIN0 (CH0): +EXT voltage measurement,   PD1 / AIN6 (CH6): +EXT current measurement

    // 1.54V power supply. No load.   (ADC1)

    ADC1: PE2 / AIN1 (CH1): +INT voltage measurement,   PD0 / AIN7 (CH7): +INT current measurement

    ADCSequenceStepConfigure(ADC0_BASE, 0, 2, ADC_CTL_CH0|ADC_CTL_CH6|ADC_CTL_IE|ADC_CTL_END);
    ADCSequenceStepConfigure(ADC1_BASE, 0, 2, ADC_CTL_CH1|ADC_CTL_CH7|ADC_CTL_IE|ADC_CTL_END);
         …
    
    ADCSequenceDataGet(ADC0_BASE, 0, &pui32ADC0Value[0]);   //  1st Break Point.
        …
    ADCSequenceDataGet(ADC1_BASE, 0, &pui32ADC0Value[0]);   // 2nd Break Point.
       …

    However, I set two break points and checked the values with the pui32ADC0Value [0] debugging tool.

    (1st Break Point.)

    // ADC0

    pui32ADC0Value[0] : 0x0000.038C -> D’908,       pui32ADC0Value[1] : 0x 0000.001C -> D’28

         (908 * 4100) / 819 = 4545                 (28 * 200) / 273 = 20

                         Result = 4.54 V                                             Result = 0.0020 A                                    

    // ADC1

           pui32ADC0Value[0] : 0x0000.038C -> D’908,       pui32ADC0Value[1] : 0x 0000.000A -> D’10

           (908 * 4100) / 819 = 4545                 (10 * 200) / 273 = 7

                           Result = 4.54 V                                            Result = 0.0007 A

    (1st & 2nd Break Point.)

    // ADC1

           pui32ADC0Value[0] : 0x0000.0006 -> D’6,       pui32ADC0Value[1] : 0x 0000.000A -> D’10

            (6 * 4100) / 819 = 30                 (10 * 200) / 273 = 7

                        Result = 0.03 V                                             Result = 0.0007 A

    Q3> ADCSequenceDataGet (ADC1_BASE, 0, & pui32ADC0Value [0]) How can I correct the other states?

           My guess is that ADC1 responds with a time delay.

    Best Regards,
    Jame,Shin

  • While it is beyond the scope of my support to debug your code for you, if you want me to take a closer look at your code, please provide the complete project by using the Code Composer Studio "File" -> "Export" feature and then attach the created .zip file to this thread.

  • Hello Bob,

    Thanks for the suggestion. By the way I use Keil Tools uVision.

    The progress is slow, but I will solve the problem with my efforts.

    In the previous poster, I asked the parameters of the ADCSequenceStepConfigure () function.

    ui32Step I think my understanding is wrong as an answer to the detailed function.

    •  ADC0 : PE3/AIN0, CH0 ( Volt Measure) , PD1/AIN6 , CH6 (Current Measure)

                            Setting  :  ADCSequenceStepConfigure(ADC0_BASE, 0, 2

                                                                            ADC_CTL_CH0 | ADC_CTL_CH6 | ADC_CTL_IE | ADC_CTL_END);

    • ADC1 : PE2/AIN1, CH1 ( Volt Measure) , PD0/AIN7, CH7 (Current Measure)

                            Setting  :ADCSequenceStepConfigure(ADC1_BASE, 0, 2,

                                                                             ADC_CTL_CH1 | ADC_CTL_CH7 | ADC_CTL_IE | ADC_CTL_END);

    In the above configuration,

    Sending to the memory resident buffer by SS_FIFOn 32 bit unit at the beginning of the starting address of pui32ADC1Value as many as the specified number of ui32step Isn't it the number of times to send from the designated ADC channel ?  (If you want to do the following, how do you implement the source)

    ADCSequenceDataGet(ADC0_BASE, 0, &pui32ADC0Value[0]);     // ui32Step = 2

      i.e) PE3 / AIN0, CH0 -> pui32ADC0Value[0] ,     PD1/AIN6   -> pui32ADC0Value[1]

    ADCSequenceDataGet(ADC1_BASE, 0, &pui32ADC1Value[0]);   // ui32Step = 2

     i.e) PE2 / AIN1 ,CH1 -> pui32ADC1Value[0], PD0 / AIN7,CH7 -> pui32ADC1Value[1]

    Only ADC1's ADC capture value is incorrect for pui32ADC1Value [0] & [1].

    There is also this way. Please give me a checklist.

    Best Regards,

    Jame,Shin

  • When you configure the steps of an ADC sequence, you specify only one channel on each step. Here are the two lines of code that configure ADC0, sequence 0 step 0 for channel 0 and step 1 for channel 6. After channel 6 is converted, then an interrupt flag is set.

        ADCSequenceStepConfigure(ADC0_BASE,0u,0u,ADC_CTL_CH0);
        ADCSequenceStepConfigure(ADC0_BASE,0u,1u,ADC_CTL_CH6 | ADC_CTL_END | ADC_CTL_IE);
    

    Likewise to configure ADC1, sequence 0 step 0 for channel 1 and step 1 for channel 7, use this code:

        ADCSequenceStepConfigure(ADC1_BASE,0u,0u,ADC_CTL_CH1);
        ADCSequenceStepConfigure(ADC1_BASE,0u,1u,ADC_CTL_CH7 | ADC_CTL_END | ADC_CTL_IE);
    

    Now in the interrupt routine (or after the interrupt flag is set) when you call ADCSequencDataGet() you should get the two conversion results copied to the buffer pointed to by *pui32Buffer parameter (third parameter).

  • Hello Bob,

    ADCSequenceStepConfigure () has been solved  parameters and setting procedures.

    Thank you for your warm and whole touch of my misunderstanding.

    [1]  The actual input supply voltage to the measurement port is 4.99V.

           The calculated measured ADC value range is 4.49 ~ 4.56V.

           ADC capture error range occurs.

          4.99 V - (4.49 ~ 4.56)V = 0.5V ~ 0.43V

    [2] Below , in the previous post,

         I did not set the answer to the 64Pin MCU setting question and

        suggested a floating point real-type calculation method in another way.

        However, I tried real type calculation, but I couldn't because of lack of program skills.

        Also, D-CAP 0.1uF was applied very near to VDDA Pin.

    // Select the external reference for greatest accuracy.

    ADCReferenceSet(ADC0_BASE, ADC_REF_EXT_3V);

    (Suggested calculation method (3.3V))

    fVolt = (float)value * 2.0 * 3.30 / 4096.0;

    Q1> How can I change the contents below Integer calculation? ( for ADC VREFP(VDDA) 3.3V)

            ui32Volt=(pui32ADC1Value[0]* 4100) / 819;

           ui32Current = (pui32ADC1Value[1] * 200) / 273;

    Best Regards,

    Jame,Shin

  • 1) If the measured value is not matching the value at the analog input pin by 10%, that it a lot. Double check you measurements of the voltage at the analog input pin and the voltage at VREEFA+ and VREFA- (pins 8 and 9). If the problem is noise it is best to clean up the signal. Using hardware sample averaging can help.

    2) If the offset is because of differences in the resistor divider or the reference voltage, you can modify the 4100/819 value to compensate. If the calculated value is 10% low, increase the numerator by 10% (4100 becomes 4510). Try checking at several voltages to verify that the gain offset is linear.

  • Hello Bob,

    Thanks for the two answers in the previous post.

    As you told me, I did a 10% correction.

    And for accuracy, the hardware sample averaging was applied through ADCHardwareOversampleConfigure () function.

    However, I have confirmed some really strange results.

    e.g) ADCHardwareOversampleConfigure(ADC0_BASE, 2)

           ADCHardwareOversampleConfigure(ADC1_BASE, 2)

    ADC 0: Volt1 ADC 1: Volt 2 is measured. And it sends data to UART0, 3, 5 of MCU.

    The two ADC values read the desired proximity values.

    However, if only UART0 sends data to the MCU, the ADC value drops significantly at any moment.

    In ADC0 and ADC1 modules, the ADC value captured in sequence 0 in ADC0 module is changed from 0x386 to 0x1B.

    Specifically, it becomes 0x386 (4.96V) and 0x1B (0.14V). And it cannot be restored.

    When I test it, it, it can be restored very occasionally.

    Q1> I don't know why. What is the problem?

         And if the parameter ui32Factor is set to 4, the frequency of occurrence is less than 2.

    Q2> Is there a correct way to set the function?

           Removing the use of the ADCHardwareOversampleConfigure function does not cause any problems.

           However, it decreases accuracy.

    Best Regards,
    Jame,Shin

  • Sorry, I do not know what is going on in your code. Can you export your latest project to a .zip file and attach it to this thread?

  • Hello Bob,

    thank you for reply.

    As I said before, I use the Keil Project,  but you want is known as the CCS Project.

    Thanks for the help. I will solve it with my efforts.

    Below is a brief reduction of the source code.

    If don't use ADCHardwareOversampleConfigure () function, there is no problem.

    That is, ADC values are normal in ADC0 and ADC1 modules even when data is received from UART0, 3, and 5.

    However, if ADCHardwareOversampleConfigure () functions are declared, only the ADC0 module reads the ADC value near 0.

    Q1> Is the function(ADCHardwareOversampleConfigure) procedural declaration method wrong?

    Q2> How about giving me a checklist?

    Best Regards,
    Jame,Shin

    Main()
    
    {
    ..... SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0); SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC1); ...... GPIOPinTypeADC(….) ... ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_PROCESSOR, 0); ADCSequenceConfigure(ADC1_BASE, 0, ADC_TRIGGER_PROCESSOR, 0); ADCSequenceStepConfigure(ADC0_BASE, 0u, 0u, ADC_CTL_CH0); ADCSequenceStepConfigure(ADC0_BASE, 0u, 1u, ADC_CTL_CH6|ADC_CTL_IE|ADC_CTL_END); ADCSequenceStepConfigure(ADC1_BASE, 0u, 0u, ADC_CTL_CH1); ADCSequenceStepConfigure(ADC1_BASE, 0u, 1u, ADC_CTL_CH7|ADC_CTL_IE|ADC_CTL_END); ..... // hardware sample averaging ADCHardwareOversampleConfigure(ADC0_BASE, 2); ADCHardwareOversampleConfigure(ADC1_BASE, 2); ADCSequenceEnable(ADC0_BASE, 0); ADCSequenceEnable(ADC1_BASE, 0); ADCIntClear(ADC0_BASE, 0); ADCIntClear(ADC1_BASE, 0); IntMasterEnable(); While(1) { if( g_bSerialTerminal ) { ADCProcessorTrigger(ADC0_BASE, 0); ADCProcessorTrigger(ADC1_BASE, 0); while(!ADCIntStatus(ADC0_BASE, 0, false) && !ADCIntStatus(ADC1_BASE, 0, false) ) { } ADCIntClear(ADC0_BASE, 0); ADCIntClear(ADC1_BASE, 0); .. ADCSequenceDataGet(ADC0_BASE, 0, &pui32ADC0Value[0]); .... if( ...) { ........ } ADCSequenceDataGet(ADC1_BASE, 0, &pui32ADC1Value[0]); .... if( ...) { ........ } …. } // if (g_bSerialTerminal) end .... if(UART0_RX ) { …. }; if(UART3_RX ) { …. }; if(UART5_RX ) { …. }; …. } // while(1) end } // main end

    
    
  • I don't see a problem with your call to ADCHardwareOversampleConfigure(). I do see an issue with your loop waiting for both ADC's to complete, but not sure is that is relevant to the issue you are seeing. 

              while(!ADCIntStatus(ADC0_BASE, 0, false) && !ADCIntStatus(ADC1_BASE, 0, false) )
               {
    
               }
    

    should be:

              while(!ADCIntStatus(ADC0_BASE, 0, false) || !ADCIntStatus(ADC1_BASE, 0, false) )
               {
    
               }
    

    You want to wait while ADC0 "or" ADC1 is not ready. 

  • Greetings,

    If not mistaken - poster's code insures an "Early & Illegal" EXIT from the "while loop" - guaranteeing flawed ADC data readings!

    Yet - there exists, "more than a simple code-error here" - poster has notably, "Invited in Errors" by rejecting "KISS!"    Had "KISS" been employed (both) ADC Modules would have been read "in turn" (sequentially) - and the potential for such "And-Or Logic Error" eliminated!    Only after that, "Eased & proper, sequenced reading" - should the attempt to (likely) "add elegance" (via the addition of logic) have been made.   In so doing - "KISS" would have (immediately) detected that code-error!

    Poster's other (highly unusual) issue:

    ADC 0: Volt1 ADC 1: Volt 2 is measured. And it sends data to UART0, 3, 5 of MCU.
    The two ADC values read the desired proximity values.
    However, if only UART0 sends data to the MCU, the ADC value drops significantly at any moment.   [cb1: this REALLY demands far greater detailing - careful use of language]

    Such issue leads to:

    • what is (really) meant by, "Sends data to the MCU?"   Are "multiple MCUs" in play here?    As the ADC is contained w/in the MCU - what "Sending to the MCU" can possibly be required? 
    • is this a "Single Board Anomaly?"   Are forum helpers to be presented w/a (problem set) - unique to one & only one board?   (which could be caused by "anything" - (i.e. failing: board, assembly, component etc!)   Multiple board testing provide the key advantage of, "A-B (even) A-B-C board comparison" - famed for speeding/easing diagnostics!
    • code reveals that UART0 is the first  w/in the sequence UART0, 3, 5.   Changing that sequence (i.e. to UART5, 3, 0) add insight!
    • is the ADC result known (& confirmed) prior to being passed to UART0?   (is that not the ONLY way to confirm that such change is (really) occurring?)
    • should the (just above) prove true - AND (only) UART0 yields such issue - might UART0 and/or its "line driver" (if any) and/or "load" prove suspect?    (this is suspected to be a "language issue" - as the likelihood of (any) UART being able to "Impact an ADC conversion (or result)" should "ONLY" be possible if (both) that ADC Conversion & UART operation overlap!)   (i.e. the UART & follow-on circuitry draw sufficient current to alter "VDDA" and/or "Spike" the ADC input...)

    Engineering 101 "Alive & Well..."    Is not the MCU (almost only), "Along for the ride?"

  • Hello Bob,

    Problem solved. Thank you.

    I understood the problem with completion as many as the number of samplings set in ADCHardwareOversampleConfigure ().

    Q1> However, if ADC0 waits for ADC1, does the ADC data disappear?

            I am not sure why both are waiting for ADC conversion to complete.

            The ADC0 was tired of waiting and be perversity . ( I feel)

            I don't know why AND (&&) needs to change OR (||).

    Best Regards,
    Jame,Shin

  • In your code example each ADC converter is running independently. You started ADC0 first, and then ADC1. You wrote the loop to wait for them to be finished as: wait while both ADC0 AND ADC1 are busy. Since ADC0 started first, it will finish first. You will exit the while loop, but ADC1 is not ready yet. If instead the wait while loop is written as wait while ADC0 or ADC1 is busy, you will not exit the while loop until both ADCs have completed their conversions.

  • Hello Bob,

    I've tested on ADC average values

    ADCHardwareOversampleConfigure () function does not work.

    Q1> It is not displayed with hardware sample averaging.  Why is that ?

            1 case> ADCHardwareOversampleConfigure () function not declared.

                          ADC value measure :   4.16, 4.96, 4.98, 4.99, 5.0, 5,11, 5.5V

            2 cases> ADCHardwareOversampleConfigure () sampling 2x, function declaration.

                           ADC value measure : 4.16, 4.96, 4.98, 4.99, 5.0, 5,11, 5.17, 5.5V

            3 cases> ADCHardwareOversampleConfigure () sampling 4x, function declaration.

                            ADC value measure : 4.16, 4.95, 4.98, 4.99, 5.0, 5,11, 5.5V

    Best Regards,
    Jame, Shin

  • Those values look good to me. What are you expecting? Using hardware oversampling should not make any noticeable difference unless the signal is noisy.

  • Greetings,

    Might it be that the (inverse) "!ADCIntStatus" and the parameter "false" - unduly "Cloud this code issue?"

    It is believed that (both) original poster and (follow-on) readers may benefit from "simplification."

    while(!ADCIntStatus(ADC0_BASE, 0, false) && !ADCIntStatus(ADC1_BASE, 0, false) )

    {
    }

    may be replaced w/the vastly simplified:

    while(a && b)
    {
    }

    where "a = !ADCIntStatus(ADC0_BASE, 0, false) & b = !ADCIntStatus(ADC1_BASE, 0, false)" - - thus the "negative logic - so much in-play here - is removed.

    It is then far simpler to note that the "while function persists" (i.e. "waits" for both conversions to complete) only while (both) a & b are logically true.  As soon as one - or both - prove "untrue" - the while loop is exited.   (which is "not" what poster wanted) & results in the "Early & Illegal" exit - identified by vendor's Bob & cb1 crüe...)   Negative logic - even when encountered w/in vendor API - should be treated w/"Great care, caution & precision!" 

  • Hello My justice friend Cb1,

    Thanks for your posting.

    Cb1 Said> ... (inverse) "!ADCIntStatus" and the parameter "false" - unduly "Cloud this code issue?“

              A> TM4C-DRL-UG documented below.

                  False set “raw interrupt status”. and This function returns the interrupt status for the specified sample sequence.

                  First, when ADC0 is converted, it becomes True, and then waits in the While statement until ADC1 becomes True,

                  and then exits the loop.

                 By the way, why does ADC0 lose the ADC value?

                 And if ADC0 and ADC1 modules want to work at the same time, how do you code the source code? 

                 e.g)  ADCSequenceDataGet(ADC0_BASE, 0, &pui32ADC0Value[0]) &&

                         ADCSequenceDataGet(ADC1_BASE, 0, &pui32ADC1Value[0])

    Deep Kiss Standard Ver.

    Best Regards,
    Jame, Shin

  • Greetings,

    Staff (flying under the restrictive Chicago "virus" weather) is "on the way."    (& pretend that they "need" my feeb guidance.)   Must be quick...

    You wrote, "By the way, why does ADC0 lose the ADC value?"   That's beyond curious - did I not ask (earlier) for deeper detail?    (i.e. you need to far better explain if you've tested for that value PRIOR to sending it to the (murderous) UART_0!

    Also, "And if ADC0 and ADC1 modules want to work at the same time, how do you code the source code?"

    Vendor Bob - months past - provided "Just that Solution!"    (kicked cb1's rear - even though cb1 provided his 'standard' thousand-yard stare...)

    To Bob's credit - he (alone) noted that a "Timer may "Jointly  TRIGGER (both) ADC0 & ADC1" - something which the entire cb1 crüe had (never) even considered!    (unfortunately - that's not the first - nor last time - of such "unknowing ... thousand yards - you know!"

    Staff (this time - & (this time only) offers up:   (from PDL User Guide - more "reading" - less posting...)

    4.2.2.27 ADCSequenceConfigure
    Configures the trigger source and priority of a sample sequence.

    Prototype:
    void
    ADCSequenceConfigure(uint32_t ui32Base,
    uint32_t ui32SequenceNum,
    uint32_t ui32Trigger,
    uint32_t ui32Priority)

    Parameters:
    ui32Base is the base address of the ADC module.
    ui32SequenceNum is the sample sequence number.
    ui32Trigger is the trigger source that initiates the sample sequence; must be one of the ADC_TRIGGER_∗ values.
    ui32Priority is the relative priority of the sample sequence with respect to the other sample sequences.

    Description:
    This function configures the initiation criteria for a sample sequence. Valid sample sequencers range from zero to three; sequencer zero captures up to eight samples, sequencers one and two capture up to four samples, and sequencer three captures a single sample. The trigger condition and priority (with respect to other sample sequencer execution) are set.
    The ui32Trigger parameter can take on the following values:

    ADC_TRIGGER_PROCESSOR - A trigger generated by the processor, via the ADCProcessorTrigger() function.
    ADC_TRIGGER_COMP0 - A trigger generated by the first analog comparator; configured with ComparatorConfigure().
    ADC_TRIGGER_EXTERNAL - A trigger generated by an input from the Port B4 pin.
    ADC_TRIGGER_TIMER - A trigger generated by a timer; configured with TimerControlTrigger().    (that left for you - some effort required!)

    BTW - unless I'm "thicker than my usual" this morning - you did not indicate if my (young) staff's past "Code Simplification" (via the elimination of the ADC's test using "Negative Logic") helped your understanding!    They'll "beat me up" w/out your "closing that loop."   (did their work help?)    (even before they "Did your job for you, today!)

  • Hello justice Cb1,

    Thanks for the answer.

    I am noon on Sunday.

    Don't be in the backroom.

    Have a good weekend.

    Best Regards,
    Jame, Shin

  • Jame shin said:
    Don't be in the backroom.

    Thank you - always appreciated.

    Now we "aspire" (i.e. hope for) one day - a back-room.   Presently we operate from a "Back-Room (behind) yet another Back-Room."   One of our office windows looks out on the "Great Lake!"   (Lake Michigan - one of 5 - U.S. Great Lakes)   All remaining windows (gloriously) display a (neighboring) brick wall.   We invest our funds in: Staff, Instrumentation, Assembly Equipment, latest/greatest components & "Less than luxurious, commercial real estate..."

    The (unusual) claim that, "Passing a just converted ADC value to UART_0 - (alone) causes the great degradation of that ADC value" -  surely warrants custom analysis - from within a well equipped (dare we say) "Back-Room."   Further - should your (assumed) SINGLE Board prove "sunlight sensitive" - Staff/I may just know of a suitable "Diagnostic Space!"    (i.e. just as soon as the sun escapes the eastern horizon...)

  • Hello Bob,

    I learn a lot from you. thank you.

    Bob Said> What are you expecting? Using hardware oversampling should not make any noticeable difference unless the signal is noisy.

    Q1> I understand by turning on the ADC to call the hardware average function to reduce the deviation between high and low values.

    So in Case2 & Case3 with hardware average x2, x4 based on Case1> in the previous post, the deviation did not decrease.

    My point of view is the same as Case 1 vs Case 2 & 3, so there is no improvement. Am I misunderstanding?

    Q2> I am not sure exactly what is below. Please explain.

    SW_DRL : “enabling 4x oversampling reduces the throughput of a 250 k samples/second ADC to 62.5 k samples/second. “

    Bob Said> typically we refer to the sampling frequency as how often you sample, not the inverse of the sample time.

    Q2-1> “250 k samples / second ADC to 62.5 k samples / second.” In SW_DRL document. what do you mean ?

             (1M sample / s) / 4 = 250 k sample /s OK. I don't know why 62.5Ksps divides 250Ksps by 4 again.

    Q2-2> When x4, (max) 1M sample / second divided by 4 is 250 K sample / second.

     ADC SSFIFO captures the ADC value 4 times, I understand that the four ADC values calculate the hardware average.

    What is the capture time of 1 from 4 ADCs?

    Maybe TC (ADC Conversion time 1 us) / 4 = 0.25us?

    Q2-3> TS (Sampling Time 250ns) becomes 1us by dividing the unit time (1 second) of the analog input signal by 1Mhz (sample frequency) by the sampling frequency.

    i.e) 1us / 250ns = 4, Does this mean 4 samplings per unit time?

    So, in conclusion, how long is 250 ns (0.25 us) to sample one out of all four samplings?

       - Q2-2 and Q2-3 have similar questions.

    Best Regards,
    Jame, Shin

  • Jame shin said:

    Q1> I understand by turning on the ADC to call the hardware average function to reduce the deviation between high and low values.

    So in Case2 & Case3 with hardware average x2, x4 based on Case1> in the previous post, the deviation did not decrease.

    My point of view is the same as Case 1 vs Case 2 & 3, so there is no improvement. Am I misunderstanding?

    Perhaps I misunderstood the data you presented. Are these successive values measuring a DC voltage? Did you change the order, or are they in the order in which they were taken. If you already sorted these results, could this be that your input signal is varying? If this is the order that the samples were taken, the resulting value is constantly increasing. This can be caused by insufficient sample time. However, using hardware averaging will also compensate for insufficient sampling time, and we see no difference. Since your circuit uses unity gain amplifiers, it should be very low input resistance. 

    Jame shin said:

    Q2-2> When x4, (max) 1M sample / second divided by 4 is 250 K sample / second.

     ADC SSFIFO captures the ADC value 4 times, I understand that the four ADC values calculate the hardware average.

    What is the capture time of 1 from 4 ADCs?

    Maybe TC (ADC Conversion time 1 us) / 4 = 0.25us?

    The ADC module is clocked by the 16MHz PIOSC. Each conversion takes 16 clock cycles. A single conversion then takes 1uS. If you do 4x hardware averaging, the ADC does four conversions, averages them and then stores the average as a single entry in the FIFO. It takes 4uS to create the one FIFO result.

    Jame shin said:

    Q2-3> TS (Sampling Time 250ns) becomes 1us by dividing the unit time (1 second) of the analog input signal by 1Mhz (sample frequency) by the sampling frequency.

    The sample time is 4 ADC clocks, or 250nS. The conversion time is 12 ADC clocks or 750nS. The total time to sample and convert is 1uS. The sample rate (when in continuous mode) is one sample every 1uS, or 1M samples/S. With 4x hardware averaging, you get results every 4uS, or 250K samples/second.

  • Hello Bob,

    Bob Said> Are these successive values measuring a DC voltage?

                A> DC + 5V is continuously measured in an infinite loop.

    Bob Said> Did you change the order, or are they in the order in which they were taken.

                   If you already sorted these results, could this be that your input signal is varying?

              A> I have read the ADC value on the OLED display with my eyes, so it is not in order.

    Bob Said> This can be caused by insufficient sample time.

             A> Measure the voltage and current of ports B1 and B2 in an infinite loop. i.e) ADC0: B1 Port, ADC1: B2 Port

                   And UART0,1,2,3,5,7 Rx pins receive data from the Rx pin to handle interrupts.

                   Of course, if you don't receive data from all UART Rx pins, the ADC Capture value quickly appears on the display.

                  However, when receiving data from all UART Rx pins, the ADC Capture value appears slowly on the display.

    Q1> All UART baud rates are 115200 bps. It is 8.68us / 1bit transmission speed.

           Capture the voltage and current on the ADC0 module at the same time.

         The next ADC1 module then captures voltage and current.

         From the previous post, I understood that the sampling conversion time is 4us.

         By the way, hardware oversampling x 2 is 2us.

         So, 4us + 2us = 6us time, MCU occupancy time occurs.

         Subtract the 1 bit transmission time of UART and the occupancy time of ADC MCU.

         The difference is 8.68us – 6us = 2.68us.

         The data sheet explains “fast interrupt processing: always 12 cycles”.

         So if the processing time in the ISR routine is 100 cycles enough.

           MCU System Clock 50Mhz (20ns / 1cycle).

           20ns x 100 cycle = 2us.

           Therefore, the ISR processing time of 2us x 6 UARTs is 12us.

          In conclusion, 2.68us – 12us = -9.32us is insufficient.

           Is the above calculation correct?

    Q2> How can I know if the hardware average function works?

           If the above Q1 calculation is -9.32us , what should I do?

    Best Regards,
    Jame, Shin

  • Sorry, your calculations do not make sense to me. Without seeing your entire code, I can only speculate. What I think you are doing is using a software trigger to do ADC conversions and then sending the ASCII results to a display using a UART. You are also processing receive data from other UARTs. Yes, since you are not using interrupts, the frequency at which you will update the display is a function of your CPU overhead. In this case, how much time you spend receiving and processing data from the other UARTs. You are probably spending most of your time waiting for the ADC or waiting for a UART. You should be using interrupts instead.

    Start with an overall plan. Which things need to be done immediately, and which can wait. How often do you need to update the display? Will people be able to see the numbers if updated more often than twice a second? You can achieve this by using a timer to generate an interrupt every 500mS. In that interrupt routine start the ADC conversions, but don't wait. Use an ADC complete interrupt to start the transmission to the display. If you need to send more than 8 characters to update the display (the UART FIFO is 8 characters deep) use the UART TXIS interrupt to send additional characters as the FIFO empties.

    I am not sure what you are doing in the UART RX interrupts for UARTs 0,1,2,3,5,7. You should not be doing any data processing. You should empty the receive FIFO, set any flags for processing data in the main routine and then exit. You main loop would then just be to check flags and do the required data processing.

    While this may be more than you are ready to take on, these issues are often addressed by using a real-time operating system like TIRTOS. 

    The TM4C123 also supports nested interrupts in case that is necessary. At some point, you may exceed the computational power of the TM4C123 CPU and somethings will be missed or delayed. I doubt you are at that point.

  • Hello Bob,

    I have a question, so please ask for advice and explanation.

    Previous post , Bob said> 

    Therefore the FADC (ADC clock) is 16 times faster than the maximum sample rate. 

    In most application the sample rate is even slower. If the source is a high impedance, the sample time must be increased.

    If more than one channel is to be converted, the sample rate for each channel is divided among the channels converted.

    Q1> If need to convert 4 channels to ADC, what if you don't want the sample rate to be divided by the converted channel?

          i.e) If you want to use TC (ADC conversion Time) 1us for each channel, what should you do?

    Q2> Is there any device with TC 1us for each channel among all MCUs in Ti?

    Q3> If there are 4 input channels, if you want 1us instead of TC = 1us / 4ch = 250ns,

             is FADC (conversion clock frequency) 64Mhz (when ADC 12bit, 16Mhz * 4 = 64)?

            i.e) Is it Ts (ADC Sample time) 1us? Therefore, the ADC input capacitor charge discharge time will be 1us?

    Q4> What would be better to select a device in condition of Q1 to Q3?

    Best Regards,
    Jame,Shin

  • Sample Rate & Social Distancing Greetings,

    Jame shin said:
    If you want to use TC (ADC conversion Time) 1us for each channel, what should you do?

    Clarifications (may) assist Vendor Bob's "tireless" efforts in your behalf:

    • How do you justify your pursuit of "1µS or bust" for TC?    Are all 4 of your analog signals expected to require that conversion rate - based upon normal sampling theorem - operating upon such signals?
    • Should that prove the case (believed doubtful) - as earlier mentioned by my staff w/in this (lengthy) thread - you may employ an MCU Timer to "Trigger (both) ADC modules simultaneously" - which divides the number of channels to be converted  by two - thus "Doubling your conversion rate!"    (How have you LOST such fact?)
    • Thus - should you (additionally) deploy a 2nd (identical) MCU - and Timer trigger each as described - you can (possibly) "tease out" a 1µS conversion rate - across "all four" of your channels!

    Jame shin said:
    Is there any device with TC 1us for each channel among all MCUs in Ti?

    Again - "your" suggested solution (employ another (non-other MCU) is unlikely to prove optimal.    This vendor (& others) produce "far more variety" of discrete (external) ADC ICs than MCUs.    Your search will reveal devices w/(both) higher resolution & faster conversion times.    Certain of these (higher resolution) ADCs may allow one to "trade" even faster conversions at the "cost" of (some) resolution - yet still meet your stated (yet nowhere justified) requirement... 

  • I am having problems understanding your questions because you are using some terms incorrectly. Let me define three terms:

    TC - Time of conversion. For the TM4C parts the minimum conversion time is 1uS. That is how long it takes the ADC to digitize one analog value.

    Ts - ADC sample time, This is the time that the ADC uses to charge the sample capacitor. For the TM4C the minimum sample time is 250nS. The sample time is part of the time of conversion. 250nS of sample and 750nS of actual conversion.

    SR - Sample rate. This is the number of times a channel is converted per second. If only converting one channel and doing it continuously, the sample rate is the inverse of the time of conversion or, for the TM4C, 1M samples/s

    If you need to convert four ADC channels at a sample rate of 1M samples/second, you cannot do that with the TM4C ADC. To convert four channels will take four 1uS conversion times, so each channel would be sampled once every 4uS. That would give a sample rate of 250K Samples/second.

    There are two ADCs on the TM4C23 device. Each one can convert a single channel at a sample rate of 1M samples/second. You can use external ADC chips. Here is a place to start looking: http://www.ti.com/data-converters/adc-circuit/overview.html

  • Hello Bob,

    Earlier w/in this (seam bursting) thread my staff noted that "you" had earlier advised that a "Timer Trigger" can operate upon (both) of the MCU's ADC modules - thus potentially (near) doubling the "grouped ADC" conversion rate!   (Yet not the sampling rate - which remains fixed - as you've just noted.)

    Poster has "missed" the fact that (only) Continuous Conversion can achieve the highest potential conversion rate - and that the "necessary processing of the ADC data" - reduces the overall (i.e. effective) conversion rate achieved.  

    Somehow staff recalls a, "Horseman w/sharpened Lance - charging against a windmill" - w/suspect results...

  • Hello Bob,

    Thanks for the clarification of the terms.

    The price of an individual ADC is expensive for me.

    Previous post, Bob Said>

    During the sample time, a switch is open and the voltage on the ADC input pin charges (or discharges) an internal sample and hold capacitor.

    The simple answer is that 4 ADC clocks is the fastest time that this ADC converter will allow. But in some designs 4 ADC clocks (250nS) may not be enough.

    Bob Said> Ts - ADC sample time, This is the time that the ADC uses to charge the sample capacitor.

    Q1> Does it only need 4 ADC clock to charge the capacitor?

           Why does capacitor discharges not include TS (ADC sample time)?

           i.e)  (time constant) t = RC, I understand that if the input impedance is large, 4 ADC clock is not enough.

    Bob Said> There are two ADCs on the TM4C23 device. Each one can convert a single channel at a sample rate of 1M samples/second.

    Q2> Are the ADC0: 2 channels, ADC1: 2 channels per 2 ADC modules as shown below?

         The module of ADC0 is TC: 2uS and FCONV: 500Ksps

         The module of ADC1 is TC: 2us and FCONV: 500Ksps

        So, all 4 channels are TC: 4uS and FCONV: 250Ksps. I understand. 

        When two ADC modules are triggered, TC and FCONV values?

    Q3> Is it possible to set the timer as below, or do I need to start the timer by adding the timer source code?

         ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_TIMER , 0);

         ADCSequenceConfigure(ADC1_BASE, 0, ADC_TRIGGER_TIMER , 0);

    Q4> Could you explain the details below?  ( I didn't understand what cb1 said.)

    cb1 Said> "Timer Trigger" can operate upon (both) of the MCU's ADC modules - thus potentially (near) doubling the "grouped ADC" conversion rate!   (Yet not the sampling rate - which remains fixed - as you've just noted.)    ........ reduces the overall (i.e. effective) conversion rate achieved. 

    Best Regards,
    Jame,Shin

  • Jame shin said:
    Q1> Does it only need 4 ADC clock to charge the capacitor?

    As you point out, it is a function of the input impedance. 

    Q2: The two ADC converters operate independently and can operate at the same time. Therefore with each ADC converting two channels the effective conversion rate is 500K samples per second for each of the four inputs.

    Jame shin said:
    Q3> Is it possible to set the timer as below, or do I need to start the timer by adding the timer source code?

    No, the timer must also be configured. If you want the maximum conversion rate, you don't need the timer, but just use continuous conversions.

  • Hello,

    Is there room here for a differing (& more inclusive) opinion?

    Bob Crosby said:

    Q2: The two ADC converters operate independently and can operate at the same time. Therefore with each ADC converting two channels the effective conversion rate is 500K samples per second for each of the four inputs.

    Jame shin
    Q3> Is it possible to set the timer as below, or do I need to start the timer by adding the timer source code?

    Our group has experimented & confirmed that by, "Triggering both ADC modules from the same "Trigger Source" - the effective ADC conversion rate CAN be Doubled!    May that "conversion rate Doubling" receive vendor blessing/approval?   (this enhanced triggering method was 1st noted here by Agent Bob.)

    Indeed "continuous conversions" (achieved via parameter "ADC_TRIGGER_ALWAYS") can maximize the conversion rate - yet at the "COST of Breaking Synchronization between the two ADC Modules!"    And - the Timer Trigger, "ADC_TRIGGER_TIMER" can (also) easily achieve maximum conversion rate - while maintaining ADC module Sync!

    Our small group has found that, "Timer Triggered Conversions" provide greatly improved (management) of the ADC Conversions.    (i.e. conversions may be halted when a solenoid (or other noise source) is to be activated/released or when the "constant over-write of an 'ADC results buffer' proves undesirable" - which is a known (yet unwanted) byproduct of  continuous conversions!)

    The use of "Timer Triggered (Synchronized) Conversions" by (each) ADC module appears to come closest to meeting this user's objective.

  • CB1,

    Yes, I agree on all of the points you made above. 

  • Hello Bob,

    Bob Siad> No, the timer must also be configured. If you want the maximum conversion rate, you don't need the timer, but just use continuous conversions.

    Q1> “but just use continuous conversions. “ this mean in my case only ADC continuous conversion without time to receive data from UART 0,1,2,3,5,7?

    Q2> Is the source code correct by setting the timeout to trigger the timer on two ADC modules? If there is something wrong, please touch it.

    Previous post, Bob Siad>    How often do you need to update the display?      

                                               You can achieve this by using a timer to generate an interrupt every 500mS.

                                               Will people be able to see the numbers if updated more often than twice a second?

    Q3> I understand the words you previously advised. However, in my case, when the threshold current value (0.7Amp) or more flows, the state reaction time must be fast.   So the timer load value was 50ms(blow source Code 0x26259F) . Could you please let me know if there is a better way?

    Best Regards,
    Jame,Shin

    Main() 
    {
        ..... 
    
      // Enable the Timer0 peripheral	
         SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    
      // Wait for the Timer0 module to be ready.	
        while(!SysCtlPeripheralReady(SYSCTL_PERIPH_TIMER0))
        {
        }
    
        // Initialize timer A count up in time mode
           TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC _UP);
    
      // Set the count time for the the periodic  timer (TimerA).
      //  Timer clock =  system clock  50Mhz , Tc= 20ns ,
      //   Count = 50ms / 20ns = 2,500,000, 
      //   HEX conversion  =  2,500,000 - 1  = 2,499,999 (0x26259F)
      //
         TimerLoadSet(TIMER0_BASE, TIMER_A, 0x26259F);
    
    
      // Enable the timer can cause ADC trigger event.
         TimerADCEventSet(TIMER0_BASE, TIMER_ADC_TIMEOUT_A)
    
      // Enable the timers.
         TimerEnable(TIMER0_BASE, TIMER_A);
    
      //  ADC Settings
         …..
    
       ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_TIMER , 0);
       ADCSequenceConfigure(ADC1_BASE, 0, ADC_TRIGGER_TIMER , 0);
        …..
    
       IntEnable(INT_TIMER0A);
    
       IntMasterEnable(); 
    
    
    
        While(1)
        {
           ….
          if(g_bSerialTerminal) 
          { 
              ADCProcessorTrigger(ADC0_BASE, 0);
              ADCProcessorTrigger(ADC1_BASE, 0); 
    
              while(!ADCIntStatus(ADC0_BASE, 0, false)  | |  !ADCIntStatus(ADC1_BASE, 0, false) ) 
              { 
              }
     
              ADCIntClear(ADC0_BASE, 0); 
              ADCIntClear(ADC1_BASE, 0); 
               .... 
              ADCSequenceDataGet(ADC0_BASE, 0, &pui32ADC0Value[0]); 
               .... 
    	  ui32Current = (pui32ADC0Value[1] * 1378) / 273;
    
              if(ui32Current > 7000) 
              { 
               ........ 
              } 
              ADCSequenceDataGet(ADC1_BASE, 0, &pui32ADC1Value[0]);
               .... 
    	 ui32Current = (pui32ADC0Value[1] * 1378) / 273;
             if(ui32Current > 7000) 
             {
               ........ 
             }
           ........ 
           } // if (g_bSerialTerminal)  end
    
         .... 
        if(UART0_RX ) { …. };
        if(UART1_RX ) { …. }; 
        if(UART2_RX ) { …. };
        if(UART3_RX ) { …. };
        if(UART5_RX ) { …. }; 
        if(UART7_RX ) { …. };
         ......
     
        } // while(1) end 
    
    } // main end
    

    // TIMERA , timeout , Interrupt ISR
     void Timer0AIntHandler(void)
    {				
        TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
        TimerIntEnable((TIMER0_BASE, TIMER_TIMA_TIMEOUT);
    		
    }
    

  • Can this thread (soon) reach to 100 postings ... Greetings,

    Had you really intended to employ TWO (different) ADC Triggers?     (Perhaps that's possible - yet unlikely.)

    First:  

    ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_TIMER , 0);
    ADCSequenceConfigure(ADC1_BASE, 0, ADC_TRIGGER_TIMER , 0);


    then followed by:

    ADCProcessorTrigger(ADC0_BASE, 0);
    ADCProcessorTrigger(ADC1_BASE, 0);

  • Jame shin said:
    Q1> “but just use continuous conversions. “ this mean in my case only ADC continuous conversion without time to receive data from UART 0,1,2,3,5,7?

    Actually, the continuous conversions do not interfere with receiving data on a UART. Both can happen simultaneously. However, you may not have enough CPU time to process both the continuous conversions and the received data.

    Jame shin said:
    Q2> Is the source code correct by setting the timeout to trigger the timer on two ADC modules?

    Answered by CB1 (Thank you CB1!)

    Jame shin said:
    Q3> I understand the words you previously advised. However, in my case, when the threshold current value (0.7Amp) or more flows, the state reaction time must be fast.   So the timer load value was 50ms(blow source Code 0x26259F) . Could you please let me know if there is a better way?

    Have you considered using a current sensor with an integrated comparator such as the INA301. Use the ALERT pin to generate an interrupt in the over-current condition for a fast response.

    http://www.ti.com/product/INA301

  • Hello,

    Vendor's Bob earlier noted that you should be mindful of the, "Time humans require to process Displayed Data."   My small group remains concerned that you seek to:

    • Update your (very small) OLED    (500mS period (2 updates/Sec) should be your fastest update rate - especially for a tiny OLED!

    and

    • monitor system current draw

    via the (same) Timer-based Trigger.

    My group has substantial experience (both) w/Displays & Current Monitoring & Measurement.    Your use of the MCU's ADC to Monitor & Measure Current presents serious weaknesses!   (ADC alone proves both "too slow" & "too subject to disruption" - thus adds much Risk!)      

    Bob's suggestion of a "far faster" (dedicated to task) current sensor IC  removes (both) of the ADC's current monitor/measure liabilities...  (Note too that "certain" members of the INA (current sense) family include "Integrated Sense Resistors" - yielding improved accuracy & pcb size reduction...

    Further - you need to develop a, "Strategy to deal with such Over-Currents."   Some over-currents may be "transient" (very brief) & may be resolved by your (briefly) "Shutting Down" those MCU tasks demanding maximum current.   In more severe cases - you may "Increase that shut-down period" - and/or "Reset your system" - yet if the over-current persists - you may have to fully disable your small system... In all cases - the far faster (and assured) response (INA) suggested by Bob - maximizes the prevention of "System Damage!"

  • Hello Bob,

    I tried to touch the correct source code in the reduced source code for triggering the ADC timer, but there is a problem.

    Bob Said> "Answered by CB1 (Thank you CB1!) "

    It stops at the source code below.

    e2e.ti.com/.../3313455

    // Wait for conversion to be completed.

    while(!ADCIntStatus(ADC0_BASE, 0, false) || !ADCIntStatus(ADC1_BASE, 0, false) )

    {

    }

    //

    // Clear the ADC interrupt flag.

    ADCIntClear(ADC0_BASE, 0);

    ADCIntClear(ADC1_BASE, 0);

    Q1> How do I change the source code correctly?

    Best Regards,
    Jame,Shin