ADC interrupt halts / stops itself randomly

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
lock attach
Attachments are accessible only for community members.
OtGo_1311741
Level 3
Level 3
First like received First like given

Hi PSoC Community,

I'm working with the firmware of a product we will be launching soon.  We are using PSoC 4 (CY8C4245AZI-473) with internal clock set to 48 MHz and VCC to 5V.  I have enabled the ADC as hardware triggered so I can start a conversion manually using ADC_StartConvert() function.  This is the code for ADC initializing:

    ADC_Start();                                               // Starts ADC

    ADC_IRQ_StartEx(ADCINT_SERVICE);   // Function assigned to ADC interrupt

    ADC_EnableInjection();                             // Enable Inj channel for microcontroller temperature reading

    ADC_SetLimitMask(0);                               // Avoids limit values interrupt

    ADC_SetSatMask(0);                                 // Avoids saturation values interrupt

    ADC_StartConvert();                                // Start ADC conversions

This is the interrupt code:

CY_ISR(ADCINT_SERVICE)              // Sets flag indicating end of conversion

{

    uint32 intr_status;

    intr_status=ADC_SAR_INTR_REG;   // Reads interrupt flags from ADC

    if(intr_status&1)               // Masks all interrupt flags except end of conversion

    FlagAdc=1;                      // Indicates conversion ready

    ADC_SAR_INTR_REG=intr_status;   // Clear interrupt flags

}

This code goes inside main():

        if(FlagAdc)                     // Ha terminado una conversion del ADC?

        {

            FlagAdc=0;

            AdcWDT=0;

            adc_read(Conversions);  // Procesa las medidas capturadas por el ADC

        }

And this is the function to read the ADC conversions:

void adc_read(uint16 *Ptr)

{

    int16 TempAdc;        // Used to read ADC values

    uint8 AdcChannel;     //ADC channel

   

    if(Flag.MicroTempRead)      // Time to read microcontroller temperature?

    {

        Flag.MicroTempRead=0;

        Ptr[TM]=(uint16)(ADC_GetResult16(TM)/8);    // Reads microcontroller temperature

    }

   

    for(AdcChannel=0;AdcChannel<TM;AdcChannel++)   

    {  

        TempAdc=ADC_GetResult16(AdcChannel)/8;      // Gets average of each conversion

        if(TempAdc<0)                               // Negative values?

        TempAdc=0;                                  // Convert them to zero

        Ptr[AdcChannel]=(uint16)TempAdc;

    }

   

    if(Flag.MicroTempAsk)      // Ready for microcontroller temperature?

    {

        Flag.MicroTempAsk=0;

        ADC_EnableInjection();  // Enables injection channel for microcontroller temperature

        Flag.MicroTempRead=1;   // Indicates microcontroller temperature reading next time

    }

   

    ADC_StartConvert(); // Starts next conversions

}

The problem is that sometimes the conversions stops updating, like if the ADC end of conversion interrupt was suddenly disabled.  This happens randomly, the product could run nice for several hours and then the problem appears.  We have tested about ten units, but two of them shows this issue.  All of the other interrupts and functions (PWM, timer, Watchdog timer, I2C, UART, etc.) keeps running smoothly.

Question: What could cause the ADC interrupt EOC to stop without user consent?

Thanks for your help.

0 Likes
1 Solution

I read one note in TRM "If the injection channel is tailgating a scan (Injection channel tailgating is enabled by default), the EOS_INTR is raised in parallel to starting the injection channel conversion. The injection channel is not considered part of the scan. " This means EOS interrupt occur after completing a scan of all the enabled channels except INJ channel, INJ channel trigger INJ_EOC_INTR  interrupt when Injection channel end of conversion. So when FlagAdc=1, the INJ channel may still being in conversion.

111.JPG

View solution in original post

9 Replies
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Would be of some interest where the program stops. Probably FlagAdc (which needs to be declared volatile) is not set. This can happen as far as I can see due to a race condition in the main loop and the interrupt handler.

Bob

Hi Bob,

Thanks for replying.  This is the declaration of FlagAdc:

volatile uint8 FlagAdc=0;           // End of conversion of ADC

The program behaves as if after the last conversion, the interrupt never happens again.  The strange thing is that this problem shows very random.

I was wondering about maybe some stack overflow that could overwrite the value of FlagAdc. This is the memory usage:

Flash used: 30474 of 32768 bytes (93.0 %). Bootloader: 5376 bytes. Application: 24970 bytes. Metadata: 128 bytes.

SRAM used: 3028 of 4096 bytes (73.9 %). Stack: 1024 bytes. Heap: 0 bytes.

At first I used to have many variables declared inside main() but the compiler did not tell me the right amount of RAM used, so I put these as globlal variables and the usage changed from near 75% to 93%.  If other functions use static variables to keep values, could this cause a stack overflow and corrupt variable FlagAdc?

0 Likes

Static variables are not allocated on the stack. so no overflow by those.

Stack overflow: You may put an address breakpoint near top of stack

you can check FlagAdc for being out of range (> 1)

Bob

Hi Bob,

I have checked the stack usage as you said, it seems the problem is not related to stack overflow.  I'll try debugging inside the ADC interrupt to see if I can find a clue.

Thanks.

0 Likes
Vison_Zhang
Moderator
Moderator
Moderator
First comment on KBA 750 replies posted 250 sign-ins

Did you connect any hardware signal to SOC terminal of SARADC?  If it is possible the soc signal is asserted while SARADC is busy(), then the data in the result register interprets it as incorrect and the Component will be stalled.  So when your SARADC is stopped, is the last conversion result correct? You may try to check the busy state of ADC before trigger the next scan conversion and see what happened.

Hi xzng,

The SOC terminal of the ADC is tied to logic '0'.  The last result conversion is correct.  I'm using 6 channels and the injection channel. I start the conversions by software, using ADC_StartConvert(). I masked any other interrupt, except EOC. This is the sequence I use:

1. Start conversions

2. Work with functions in main

3. (Inside ISR) ADC interrupt? If it was EOC, activate FlagADC

4. (Inside main) FlagADC active? Clear FlagADC, reads conversions and start conversions again

5. Return to step 2

It looks like there is a moment where FlagADC is not set anymore. Unfortunately this happens very random and seldom.  I wonder, as you say, if maybe I'm triggering the start of conversion during a current conversion, the component would stop.  If so, how would be the procedure to restart the ADC normally?

Thanks.

0 Likes

I read one note in TRM "If the injection channel is tailgating a scan (Injection channel tailgating is enabled by default), the EOS_INTR is raised in parallel to starting the injection channel conversion. The injection channel is not considered part of the scan. " This means EOS interrupt occur after completing a scan of all the enabled channels except INJ channel, INJ channel trigger INJ_EOC_INTR  interrupt when Injection channel end of conversion. So when FlagAdc=1, the INJ channel may still being in conversion.

111.JPG

Hi xzng,

You are right, I was masking the injection EOC interrupt thinking that the EOS would do the same trick, but not.  I will modify the software to detect both interrupts separately (EOS and INJ EOC), read each conversion also separately and trigger the ADC with a timer giving enough time for total ADC conversion so the trigger does not collide with any conversion in progress.

I'll do some tests and let you know.

Thanks.

0 Likes

Hi everybody,

Several hours and no glitch, looks like the problem was solved.

Thanks!

0 Likes