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.

ADC Digital comparator problem

Hello (( LM4F232H5QD  board

First, I want to read the ADC value, and then send it to digital comparator.
Second, if the value is above the HighRef then interrupt.

A counter is set to count how many times it interrupts.

I want to use hysteris always mode, high band operation , and the region is 40 to 60 mV

There are two problems

1)  How I set ulLowRef and ulHighRef

2) Where can I add interrupt and counter? When the voltage is  beyond the region, it will interrupt and the counter will work.

Here's my code (GPIO port D pin6 as input)

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

SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC1);
        
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
     
GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_6);
        
ADCSequenceConfigure(ADC1_BASE, 1, ADC_TRIGGER_COM1, 0);
        
ADCComparatorConfigure(ADC1_BASE, 1, ADC_COMP_TRIG_HIGH_HALWAYS);
        
ADCComparatorRegionSet(ADC1_BASE, 1,  ulLowRef, ulHighRef);

ADCSequenceStepConfigure(ADC1_BASE, 1, 0, ADC_CTL_CH5| ADC_CTL_IE | ADC_CTL_END);

ADCSequenceEnable(ADC1_BASE, 1);

ADCIntClear(ADC1_BASE, 1);

while(1) {

     ADCProcessorTrigger(ADC1_BASE, 1);
     while(!ADCIntStatus(ADC1_BASE,1, false));
     ADCSequenceDataGet(ADC1_BASE,1, ulADC1_Value);  }

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

  • It looks to me like your real issue is using Interrupts with the ADC -- the rest you can do.

    See my post here.

    http://e2e.ti.com/support/microcontrollers/stellaris_arm_cortex-m3_microcontroller/f/473/t/212263.aspx

    That should show you how to read values from the ADC using interrupts and send them via the UART to a PC. That should get you started if you can modify that program to work with your processor.

    hth

  • Jeff,

    You can set ulLowRef and ulHighRef by converting your 40 to 60 mV bound values to their equivalent ADC values. The formula is ADC value = mV value * 4096 / (range of analog reference voltage in mV). The range of analog reference voltage will be either VDDA - GNDA or VREFA+ - VREFA-, depending on if you are using the ADC in single-ended or differential mode. Section 13.3.4.1 and 13.3.5 of the datasheet will have more information about converting ADC values to mV.

    As for the interrupts, Dave's post is a good start. If you are using a IDE other than CCS, remember that you will need to make a startup.s file specific to your IDE.

  • Hello, Dave Robinson and

    The main problem for me is that I am not sure whether my ADC comparator code is right or not, and I found no comparator demo.

    Obviously, my code is wrong because there's nothing show on my LED monitor. I'm confused by it.

    here's my code, I have modified it but still not working at all.

  • Perhaps you should step through your code using the debugger. Perhaps what it does may surprise you.

  • Hi Jeff,

    Reading your code reveals some problems:

    ADC1 is configured with the function ADCSequenceStepConfig(...ADC_CTL_CMP0...) -  but reading the comments above this functions in adc.c file in driverlib folder you can find out this:

    "note: If the Digital Comparator is present and enabled using the ADC_CTL_CMP0 through ADC_CTL_CMP7 selects, the ADC sample is NOT written into the ADC sequence data FIFO",

    so it is obvious that later reading with ADCSequenceDataGet(ADC1_BASE...) will not give you useful values.

    Also you have two interrupt routines for ADC1; which one is inserted into interrupt vectors table?

    Next, in the ADC1Seq1IntHandler you have used usprintf and GrStringDraw - take care since these can be longer than expected - you are the only one who knows how fast your signals are so there is the possibility that you miss some interrupts - remove these functions from that place, use flags or direct actions with the watched signal(s).

    Last: make a habit to read before use the comments in driverlib routines, at least until you know these better. Make coding phase the last one.

    Petrei. 

  • Thanks Petrei !!

    Sorry for my careless about two interrupt routines and data get from ADC1.

    So, how  could get useful data from digital comparator?

    The voltage input to GPIO and go through ADC, and then comparator work.

    I want my board does nothing when the input is below the region, and a counter counts how many times the voltage is beyond the region, but I have no idea about what's wrong my code for digital comparator.

    Without using ADCSequenceDataGet(ADC1_BASE...) , how can I modify my code when using ADC comparator?

    Petrei said:

    Next, in the ADC1Seq1IntHandler you have used usprintf and GrStringDraw - take care since these can be longer than expected - you are the only one who knows how fast your signals are so there is the possibility that you miss some interrupts - remove these functions from that place, use flags or direct actions with the watched signal(s).

    This is how I detect the comparator is working or not. I want the screen to show how many times it interrupted.

    Anyways, it's bad , so I'll change it. Thanks !!

    Still trying now. Thanks a lot Prtrei, your suggest is so useful.!!

    Here's my code link (on-line reading) http://chopapp.com/#sdla397g

    It's colorful, much easier to read. If you worry about the security about the link, do not open it. I also upload the modified code.

  • Hi,

    I don't know the details of your project - what I can tell you further at this stage is to take care of sampling rate of ADC1 - you set it to TRIGGER_ALWAYS - this means the sample rate is 4 micro-seconds (and of coarse writing to the graphic display inside the interrupt will mask out many other interrupts)- try to lower it - (use sampling theorem, even some low-pass filtering) - and you will succeed. 

    Petrei

  • Hi,

    I finally finish it.

    First, I added wrong interrupt handler to the vector table.

    Second, although the Digital Comparator is present and enabled using the ADC_CTL_CMP0 through ADC_CTL_CMP7 selects, the ADC sample is NOT written into the ADC sequence data FIFO, it still need to write "ADCSequenceDataGet(ADC1_BASE,0, ulADC1_Value);" in while(1) loop for digital comparator.

    I also changed the ways to detect how many times it interrupted.

    Here'e the code:

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

    #include "inc/lm4f232h5qd.h"
    #include "utils/ustdlib.h"
    #include "inc/hw_types.h"
    #include "inc/hw_ADC.h"
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/adc.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/gpio.h"
    #include "grlib/grlib.h"
    #include "drivers/cfal96x64x16.h"

    //*****************************************************************************
    //
    // Global variable to count the number of digital comparator interrupts.  This
    // variable is not needed for the proper operation of the ADC or digital
    // comparators.
    //
    //*****************************************************************************
    unsigned long g_ulNumOfInt;

    //*****************************************************************************
    //
    // Global variable to count the number of digital omparator interrupts that
    // have been triggered.  This variable is not needed for the proper operation
    // of the ADC or digital comparators.
    //
    //*****************************************************************************
    unsigned long g_ulDCIntStatus;

    //*****************************************************************************
    //
    // The error routine that is called if the driver library encounters an error.
    //
    //*****************************************************************************
    #ifdef DEBUG
    void
    __error__(char *pcFilename, unsigned long ulLine)
    {
    }
    #endif


    //*****************************************************************************


    #define SEQUENCER 1
            tContext sContext;
        char cText[8];

    //*****************************************************************************

    void
    ADC1Seq0IntHandler(void)
    {
        //
        // Read the digital comparator interrupt status register.  This global
        // variable will keep track of which digital comparator triggered the
        // interrupt.
        //
        g_ulDCIntStatus = ADCComparatorIntStatus(ADC1_BASE);

        //
        // Clear all of the digital comparator interrupt bits.  We do this because
        // more than one digital comparator interrupt may have been triggered this
        // interrupt.
        //
        ADCComparatorIntClear(ADC1_BASE, 0x0F);

        //
        // Increment the variable that keeps track of how many interrupts have
        // been triggered.
        //
        switch (g_ulDCIntStatus)
            {
                    case 0x01:
                            g_ulNumOfInt++;
                            break;
                    default:
                            break;
            }
    }


    //*****************************************************************************


    int main(void)
    {
        volatile unsigned long ulLoop;
            
        unsigned long ulADC1_Value[4];
        
        //
        // Enable ADC
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC1);
            

          //
          // Enable GPIO Port .
          //
          SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOP);

        //
        // Configure GPIO pins as ADC input channels.
        //
        GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_5);

        //
        // Enable processor interrupts.
        //
        IntMasterEnable();

        //
        // Enable the ADC sample sequence 0 interrupt on the processor (NVIC).
        //
        IntEnable(INT_ADC1SS0);
            
        //
        // Configure sequencer for trigger.
        //
        ADCSequenceConfigure(ADC1_BASE, 0, ADC_TRIGGER_ALWAYS, 0);

        //
        // Configure ADC 0 to use Hardware Over Sampling Ciruit.
        //
        ADCHardwareOversampleConfigure(ADC0_BASE, 64);

        //  
        // Sample ADC channels in single ended mode & configure an interrupt flag
        // when sample is done. Configure the last step to cause an interrupt when
        // it is complete
            
        ADCSequenceStepConfigure(ADC1_BASE, 0, 0, ADC_CTL_CH22 | ADC_CTL_CMP0);
        ADCSequenceStepConfigure(ADC1_BASE, 0, 1, ADC_CTL_CH22 | ADC_CTL_END);
            
        //
        // Enable sample sequence.
        //
        ADCSequenceEnable(ADC1_BASE, 0);
            
        //
        // Configure ADC Comparator 0
        //
        ADCComparatorConfigure(ADC1_BASE, 0, ADC_COMP_INT_LOW_HONCE);
        ADCComparatorRegionSet(ADC1_BASE, 0, 300, 400);
            
            g_ulNumOfInt = 0;
            
            ADCComparatorReset(ADC1_BASE, 0, true, true);
            ADCComparatorIntEnable(ADC1_BASE,0);
            
            //==============================================================   

        while(1)
        {
                
                //
                // Read ADC Value.
                //
                ADCSequenceDataGet(ADC1_BASE,0, ulADC1_Value);
                    
                //
                // Display how many times it interrupted on screen .
                //
                usprintf(cText, " %d    ", g_ulNumOfInt);
                GrStringDraw(&sContext, cText, -1, 45, 55, 1);
                    
            //
            // This function provides a means of generating a constant length
            // delay.  The function delay (in cycles) = 3 * parameter.  Delay
            // 250ms arbitrarily.
            //
            SysCtlDelay(SysCtlClockGet() / 20);

            //
            // Flush any cached drawing operations.
            //
            GrFlush(&sContext);
        }
    }