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.

TM4C1231H6PM: ADC Digital Comparator output

Part Number: TM4C1231H6PM

Trigger ADC Digital Comparator by timer in every 1ms

#define ADC_SEQUENCE_NUMBER 3

void adc_comparator_config(void) {
    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
    SysCtlPeripheralReset(SYSCTL_PERIPH_ADC0);

    GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_0);
    GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_2);
    GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_2, GPIO_PIN_2);

    //
    // Disable the sequence.
    //
    ADCSequenceDisable(ADC0_BASE, ADC_SEQUENCE_NUMBER);
    ADCSequenceDisable(ADC0_BASE, 0);
    ADCIntClear(ADC0_BASE, ADC_SEQUENCE_NUMBER); // Clear any interrupts

    //
    // Reconfigure and enable the sequence.
    //
    ADCSequenceConfigure(ADC0_BASE, ADC_SEQUENCE_NUMBER,
                         ADC_TRIGGER_TIMER, 3);
    ADCSequenceStepConfigure(ADC0_BASE, ADC_SEQUENCE_NUMBER, 0,
                             ADC_CTL_CH7 | ADC_CTL_END | ADC_CTL_IE | ADC_CTL_CMP7);
	ADCSequenceEnable(ADC0_BASE, ADC_SEQUENCE_NUMBER);

    // Reset the ADC comparator
    ADCComparatorReset(ADC0_BASE, ADC_CTL_CH7, true, true);
    ADCComparatorIntClear(ADC0_BASE, ADC_SEQUENCE_NUMBER);
    
    // Configure the ADC comparator
    ADCComparatorConfigure(ADC0_BASE, ADC_CTL_CMP7,
                           ADC_COMP_INT_HIGH_ALWAYS);
    ADCComparatorRegionSet(ADC0_BASE, ADC_CTL_CH7, 1024, 3600); // High threshold = 3600mV
    ADCComparatorIntEnable(ADC0_BASE, ADC_SEQUENCE_NUMBER);
    
    // Register the interrupt handler
    IntMasterEnable();
    ADCIntRegister(ADC0_BASE, ADC_SEQUENCE_NUMBER, adc_comparator_int_handler);
    ADCIntEnable(ADC0_BASE, ADC_SEQUENCE_NUMBER);
    IntEnable(INT_ADC0SS3);

}

// Once interrupt trigger, get the ADC value and print.
void adc_comparator_int_handler(void) {
    ADCComparatorIntClear(ADC0_BASE, ADC_SEQUENCE_NUMBER);
    uint32_t pui32ADC0Value[8] = {0};
    ADCSequenceDataGet(ADC0_BASE, ADC_SEQUENCE_NUMBER, pui32ADC0Value);
    printf("ADC value: %d", pui32ADC0Value[0]);
}

// Enable hw timer to trigger the ADC in every 1ms
void hw_timer_init()
{
    SysCtlPeripheralEnable(SYSCTL_PERIPH_WTIMER1);

    TimerDisable(WTIMER1_BASE, TIMER_A);

    TimerConfigure(WTIMER1_BASE, TIMER_CFG_A_PERIODIC);
    TimerLoadSet(WTIMER1_BASE, TIMER_A, SysCtlClockGet() / 1000 * 1);
    TimerControlTrigger(WTIMER1_BASE, TIMER_A, true);
    TimerEnable(WTIMER1_BASE,TIMER_A);

}
Problem statement: ADC digital Comparator interrupt status is not set (ADCComparatorIntStatus(ADC0_BASE)).
Q1. How to get/calculate ADC Digital Comparator value(read value from which register)? (I would like to make sure that the ADC value is higher than 3600 mV)
Q2. Is the ADC Digital Comparator configuration correct?
Q3. How to make sure that the interrupt trigger due to the ADC value is higher than threshold?
Please help to clarify the problems. Thanks for your time and help.
Regards,
Suraj Pramanik
  • Hi Suraj,

      In your code I don't see you enable PortD if you want to use PD0 for AIN7. You should have the below line of code. 

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);

  • Additional comments for your code. 

    You wrote the below code. ADC_CTL_CMP7 does not need to go with ADC_CTL_CH7. There is no strict one to one mapping here. You could have use ADC_CTL_CMP0 as the comparator for ADC_CTL_CH7 or another channel. With that said, using ADC_CTL_CMP7 is ok here. Just wanted to clarify there is no hard association between ADC_CTL_CMP7 and ADC_CTL_CH7. 

    ADCSequenceStepConfigure(ADC0_BASE, ADC_SEQUENCE_NUMBER, 0,
    ADC_CTL_CH7 | ADC_CTL_END | ADC_CTL_IE | ADC_CTL_CMP7);

    You wrote the below code. You are supposed to provide the bit-mapped interrupts status to clear, not ADC_SEQUENCE_NUMBER which is 3 all the time. Please refer to peripheral driverlib user's guide. 


    ADCComparatorIntClear(ADC0_BASE, ADC_SEQUENCE_NUMBER);


    You wrote below line. You need to be aware that it is the conversion values that the the comparator is comparing against, not the voltage. When you input 3600, this does NOT mean 3600mV but rather a ADC conversion value. Since ADC is 12 bit and suppose the VDDA is 3.3V, 3600 would mean 3.3 * (3600 / 4096) = 2.9V. Is that what you really want? It is your application. You will need to figure what is the upper limit you want to trigger an interrupt. 

     
    ADCComparatorRegionSet(ADC0_BASE, ADC_CTL_CH7, 1024, 3600); // High threshold = 3600mV

  • Hello Charles, 
    Thanks for pointing it out about the ADCComparatorIntClear function usage. Now I am pretty clear how to calculate the higher threshold value. 

    I have a further question about the interrupt configurations. When I dump the 

    HWREG(ADC0_BASE + ADC_O_IM) register, I see the value is 0x80008(bit 3 and bit 19 are set). 

    Is it okay to set two different interrupt setting? 
    I can get interrupt from the ADC Int setting, however cannot see any interrupt from the digital comparator.
  • HWREG(ADC0_BASE + ADC_O_IM) register, I see the value is 0x80008(bit 3 and bit 19 are set). 

    Is it okay to set two different interrupt setting? 
    I can get interrupt from the ADC Int setting, however cannot see any interrupt from the digital comparator.

    Hi,

      Can you remove ADC_CTL_IE? Does that make a difference?

  • No. If I remove this, the interrupt callback function (adc_comparator_int_handler) never execute. 

  • Hi,

    Is it okay to set two different interrupt setting? 
    I can get interrupt from the ADC Int setting, however cannot see any interrupt from the digital comparator.
    HWREG(ADC0_BASE + ADC_O_IM) register, I see the value is 0x80008(bit 3 and bit 19 are set). 

    I think in your case it should be ok to enable both  both DCONSS3 and MASK3 bits in ADCIM register. The reason is that you are routing the input value to the digital comparator. The input value will not be saved in the FIFO. In your ISR, you should not expect to read the ADC value but instead check if DCONSS3 is set. If it is set, it means the upper threshold is detected. 

    If both bit 3 and 19 are set then it means it detects that your input channel is higher than COMP1 threshold. 

      Can you show your settings for ADC_DCCTL7 and aDC_DCCMP7 registers?

  • Hi, 

      My name is Kevin, college of Suraj, for test purpose I used a condition looks like should generate interrupt no matter which ADC value was

      ADC_DCCTL7:  0x14  -> enable interrupt and triggered when mid band condition meets

      ADC_DCCMP7: 0xFFF0000 -> COMP1= 4095 and COMP0 = 0

      We can get interrupt whenever SS3 finished the conversion, however, the digital comparator interrupt never shown.

      We also check the

      ADC_SSOP3: 0x1 -> connect ADC output to comparator

      ADC_SSDP3: 0x07 -> connect to comparator 7

      Just wonder if you could provide us a script of register setting or sample code to enable digital comparator interrupt at mid band condition?

      We hope to see digital comparator interrupt occurs first, thank you very much! 

       

  • Hi,

      Please refer to the below two errata and apply the workarounds. 

  • Hi Charles,

      Thanks for your quick response, I think these are what we need.