ADC Read using interrupt issue

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

cross mob
RaSh_3782726
Level 3
Level 3
10 replies posted 10 questions asked 5 replies posted

Hi all,

I want to make adc read using Interrupt.

But when i debug the code the isr loop call. and did not goes into for(;;) loop.

so the value is not getting.

Here is the code.

CY_ISR(ADC_SAR_2_ISR_LOC)

{

        result = CY_GET_REG16(ADC_SAR_2_SAR_WRK0_PTR);

        dataReady = 1u;

}

int main()

{

    LCD_Start();

    CyGlobalIntEnable; /* Enable all interrupts by the processor. */

    ADC_SAR_2_Start();

    ADC_SAR_2_IRQ_StartEx(ADC_SAR_2_ISR_LOC);

    ADC_SAR_2_StartConvert();

 

  for(;;)

    {

       

        /* Show ADC2 result on LCD*/

        if(dataReady != 0u)

        {

           res1 = ADC_SAR_2_CountsTo_Volts(result);

                   LCD_Position(0u, 0u);

                LCD_PrintString("ADC_Output");

                LCD_ClearDisplay();

                LCD_Position(1u, 2u);

                LCD_PrintNumber(res1);

                LCD_Position(1u, 5u);

                LCD_PrintString("v");

                dataReady = 0u;

        }

               

    }

}

0 Likes
1 Solution
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Hi,

I think that you need to clear interrupt flag inside the ISR,

otherwise ISR will be called repeatedly.

I modified your code as below and tested with CY8CKIT-059

and at least program flow seems to be working.

Note: As I don't have LCD, I used UART instead.

change USE_LCD to 1 for your system.

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

#include "project.h"

#include <stdio.h>

#define USE_LCD 0

#if !USE_LCD

    char str[128] ; /* print buffer */

#endif

volatile int dataReady = 0u ;

uint16_t result = 0 ;

CY_ISR(ADC_SAR_2_ISR_LOC)

{

    ADC_SAR_2_IRQ_ClearPending() ;

    result = CY_GET_REG16(ADC_SAR_2_SAR_WRK0_PTR);

    dataReady = 1u;

}

int main()

{

    float res1 = 0.0 ;

   

#if USE_LCD

    LCD_Start();

#else

    UART_Start() ;

#endif

    CyGlobalIntEnable; /* Enable all interrupts by the processor. */

    ADC_SAR_2_Start();

    ADC_SAR_2_IRQ_StartEx(ADC_SAR_2_ISR_LOC);

    ADC_SAR_2_StartConvert();

  for(;;)

    {

        /* Show ADC2 result on LCD*/

        if(dataReady != 0u)

        {

           res1 = ADC_SAR_2_CountsTo_Volts(result);

#if USE_LCD

                   LCD_Position(0u, 0u);

                LCD_PrintString("ADC_Output");

                LCD_ClearDisplay();

                LCD_Position(1u, 2u);

                LCD_PrintNumber(res1);

                LCD_Position(1u, 5u);

                LCD_PrintString("v");

#else

            sprintf(str, "ADC_Output %d.%02d V\n",

                (int)res1, ((int)(res1 * 100) % 100)) ;

            UART_PutString(str) ;

#endif

            dataReady = 0u;

        }            

    }

}

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

moto

View solution in original post

2 Replies
KyTr_1955226
Level 6
Level 6
250 sign-ins 10 likes given 50 solutions authored

I'm unsure what the problem exactly is.  Are you saying you can't get to your main for(;;) loop because it's not leaving the ISR?  Do you mean you're never getting dataready = 1 or result is not reading the result register properly?

Are result and dataReady declared as volatile?  Any value that you're going to change in an ISR should be declared volatile to ensure the compiler doesn't just assume and optimize incorrectly.  It will basically force the variable to be read before any time it is used rather than assuming it already knows the value.

I'd also recommend not pulling your value from the ADC inside the interrupt.  Set a flag then pull the value into your result variable inside your main for(;;) loop.  That way you can safely use ADC_IsEndConversion() to determine when your conversion has actually finished and ensure you aren't reading until then.  It also minimizes code inside your interrupt.

if (dataReady){

     while (!ADC_IsEndConversion(ADC_RETURN_STATUS){};

     result = ADC_GetResult16();

     dataReady = 0;

}

MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Hi,

I think that you need to clear interrupt flag inside the ISR,

otherwise ISR will be called repeatedly.

I modified your code as below and tested with CY8CKIT-059

and at least program flow seems to be working.

Note: As I don't have LCD, I used UART instead.

change USE_LCD to 1 for your system.

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

#include "project.h"

#include <stdio.h>

#define USE_LCD 0

#if !USE_LCD

    char str[128] ; /* print buffer */

#endif

volatile int dataReady = 0u ;

uint16_t result = 0 ;

CY_ISR(ADC_SAR_2_ISR_LOC)

{

    ADC_SAR_2_IRQ_ClearPending() ;

    result = CY_GET_REG16(ADC_SAR_2_SAR_WRK0_PTR);

    dataReady = 1u;

}

int main()

{

    float res1 = 0.0 ;

   

#if USE_LCD

    LCD_Start();

#else

    UART_Start() ;

#endif

    CyGlobalIntEnable; /* Enable all interrupts by the processor. */

    ADC_SAR_2_Start();

    ADC_SAR_2_IRQ_StartEx(ADC_SAR_2_ISR_LOC);

    ADC_SAR_2_StartConvert();

  for(;;)

    {

        /* Show ADC2 result on LCD*/

        if(dataReady != 0u)

        {

           res1 = ADC_SAR_2_CountsTo_Volts(result);

#if USE_LCD

                   LCD_Position(0u, 0u);

                LCD_PrintString("ADC_Output");

                LCD_ClearDisplay();

                LCD_Position(1u, 2u);

                LCD_PrintNumber(res1);

                LCD_Position(1u, 5u);

                LCD_PrintString("v");

#else

            sprintf(str, "ADC_Output %d.%02d V\n",

                (int)res1, ((int)(res1 * 100) % 100)) ;

            UART_PutString(str) ;

#endif

            dataReady = 0u;

        }            

    }

}

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

moto