ADC read issue

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

cross mob
MoSP_1672341
Level 1
Level 1
First like received

Hello,

I am using PSoC 4200M series (CY8C4247AZI-M485). I was trying to use the ADC. Just to get a feel for it, I uploaded the ADC_SAR_Seq_Die_Temp_PSoC4 example code in the PSoC creator 4.2 to check the measured voltage. When I ground the ADC pin the ADC does not read 0mV, instead it reads any value ranging from a few tens of mV to about 3-4V. However when I give it a voltage equal to the reference voltage (VDDA) it reads it properly. Can someone please guide me on what might be happening and how to fix it?

0 Likes
1 Solution
lock attach
Attachments are accessible only for community members.
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Hi,

That is a nice example code!

I did not know about "DieTemp", so I gave it a try.

Since you are using CY8C4247AZI-M485, I imagined that you are using

either CY8CKIT-044 or CY8CKIT-043.

To go with these board, I modified the schematic so that we can use KitProg UART.

schematic

001-schematic.JPG

CY8CKIT-044

IMG_3785.JPG

pin list

002-pin-list.JPG

Tera Term log when I moved the pot

000-TeraTerm-log.JPG

So the reading was from 0mV to 1024mV (actual VDD was 3.3V, with this)

Then I tried with CY8CKIT-043

IMG_3787.JPG

pin list (schematic was same)

004-pin-list-043.JPG

Tera Term log

003-TeraTerm-043.JPG

So, with my usage, both CY8CKIT-044 and CY8CKIT-043 printed out 0mV ~ 1024mV.

FYI, modified main.c

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

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

* File Name: main.c

*

* Version: 2.10

*

* Description:

*  Sequencing SAR ADC and DieTemp datasheet example project.

*

* Note:

*  Pin_Vin pin (P0[4]) must be connected to the GND.

*  UART_tx pin (P0[5]) must be connected to the pin (P12[6]) of J8 header.

*  Verify that J9 is connected to 5V.

*

* Hardware Dependency:

*  PSoC4 Pioneer kit

*

********************************************************************************

* Copyright 2013-2017, Cypress Semiconductor Corporation. All rights reserved.

* This software is owned by Cypress Semiconductor Corporation and is protected

* by and subject to worldwide patent and copyright laws and treaties.

* Therefore, you may use this software only as provided in the license agreement

* accompanying the software package from which you obtained this software.

* CYPRESS AND ITS SUPPLIERS MAKE NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,

* WITH REGARD TO THIS SOFTWARE, INCLUDING, BUT NOT LIMITED TO, NONINFRINGEMENT,

* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

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

#include <project.h>

#include <stdio.h>

/* ADC SAR sequencer component header to access Vref value */

#include <ADC_SAR_SEQ.h>

#define CH0_N              (0x00u)

#define TEMP_CH            (0x01u)

#define DELAY_1SEC          (1000u)

/* Get actual Vref. value from ADC SAR sequencer */

#define ADC_VREF_VALUE_V    ((float)ADC_SAR_SEQ_DEFAULT_VREF_MV_VALUE/1000.0)

volatile uint32 dataReady = 0u;

volatile int16 result[ADC_SAR_SEQ_TOTAL_CHANNELS_NUM];

volatile uint32 timer_delay = 0u;

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

void print(char *str)

{

    UART_UartPutString(str) ;

}

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

* Function Name: ISR_TIMER_LOC

*******************************************************************************

*

* Summary:

*  Handle Interrupt Service Routine. Source - TIMER.

*

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

CY_ISR(ISR_TIMER_LOC)

{

    timer_delay++;

  

    /* Measures temperature once per second */

    if(timer_delay > DELAY_1SEC)

    {

        /* Enables injection channel for next scan */

        ADC_SAR_SEQ_EnableInjection();

        timer_delay = 0u;

    }  

  

    /* Clears interrupt request from terminal count */

    PWM_ClearInterrupt(PWM_INTR_MASK_TC);

}

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

* Function Name: ADC_SAR_SEQ_ISR_LOC

*******************************************************************************

*

* Summary:

*  Handle Interrupt Service Routine. Source - ADC SAR Seq.

*

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

CY_ISR(ADC_SAR_SEQ_ISR_LOC)

{

    uint32 intr_status;

    uint32 range_status;

    /* Read interrupt status registers */

    intr_status = ADC_SAR_SEQ_SAR_INTR_MASKED_REG;

    /* Check for End of Scan interrupt */

    if((intr_status & ADC_SAR_SEQ_EOS_MASK) != 0u)

    {

        /* Read range detect status */

        range_status = ADC_SAR_SEQ_SAR_RANGE_INTR_MASKED_REG;

        /* Verify that the conversion result met the condition Low_Limit <= Result < High_Limit  */

        if((range_status & (uint32)(1ul << CH0_N)) != 0u)

        {

            /* Read conversion result */

            result[CH0_N] = ADC_SAR_SEQ_GetResult16(CH0_N);

            /* Set PWM compare from channel0 */

            PWM_WriteCompare(result[CH0_N]);

        }  

        /* Clear range detect status */

        ADC_SAR_SEQ_SAR_RANGE_INTR_REG = range_status;

        dataReady |= ADC_SAR_SEQ_EOS_MASK;

    }  

    /* Check for Injection End of Conversion */

    if((intr_status & ADC_SAR_SEQ_INJ_EOC_MASK) != 0u)

    {

        result[TEMP_CH] = ADC_SAR_SEQ_GetResult16(TEMP_CH);

        dataReady |= ADC_SAR_SEQ_INJ_EOC_MASK;

    }  

    /* Clear handled interrupt */

    ADC_SAR_SEQ_SAR_INTR_REG = intr_status;

}

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

* Function Name: main

********************************************************************************

*

* Summary:

*

* Parameters:

*  None.

*

* Return:

*  None.

*

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

int main()

{

    int16 res = 0;

    int32 temperature;

    char  uartLine[250];

    int16 ADCCountsCorrected;

    /* Initialize the UART */

    UART_Start();

    print("\r\n") ; // UART_PutCRLF();

    print("\r\n") ; // UART_PutCRLF();

    // UART_PutString("Starting temperature measurement...");

    print("Starting temperature measurement...");

    print("\r\n") ; // UART_PutCRLF();

  

    PWM_Start();

    PWM_TriggerCommand(PWM_MASK, PWM_CMD_START);

    /* Init and start sequencing SAR ADC */

    ADC_SAR_SEQ_Start();

    ADC_SAR_SEQ_StartConvert();

    /* Enable interrupt and set interrupt handler to local routine */

    ADC_SAR_SEQ_IRQ_StartEx(ADC_SAR_SEQ_ISR_LOC);

  

    /* Init interrupt from timer to measure the temperature rarely */

    ISR_TIMER_StartEx(ISR_TIMER_LOC);

    CyGlobalIntEnable;

    for(;;)

    {

        /* When conversion of sequencing channels has completed */

        if((dataReady & ADC_SAR_SEQ_EOS_MASK) != 0u)

        {

            /* Get voltage, measured by ADC */

            dataReady &= ~ADC_SAR_SEQ_EOS_MASK;

            res = ADC_SAR_SEQ_CountsTo_mVolts(CH0_N, result[CH0_N]);

        }  

      

        /* When conversion of the injection channel has completed */

        if((dataReady & ADC_SAR_SEQ_INJ_EOC_MASK) != 0u)

        {

            dataReady &= ~ADC_SAR_SEQ_INJ_EOC_MASK;

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

            * Adjust data from ADC with respect to Vref value.

            * This adjustment is to be done if Vref is set to any other than

            * internal 1.024V.

            * For more detailed description see Functional Description section

            * of DieTemp P4 datasheet.

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

            ADCCountsCorrected = (int16)(result[TEMP_CH]*(((float)ADC_VREF_VALUE_V/1.024)));

          

            temperature = DieTemp_CountsTo_Celsius(ADCCountsCorrected);

            /* Print temperature value to UART */

            sprintf(

                    uartLine, "Temperature value: %dC",

                    (int16) temperature

                    );

            print(uartLine) ;  // UART_PutString(uartLine);

            print("\r\n") ;    // UART_PutCRLF();

          

            /* Print voltage value to UART */

            sprintf(

                uartLine, "ADC measured voltage: %dmV",

                (uint16) res

                );

          

            print(uartLine) ;  // UART_PutString(uartLine);

            print("\r\n") ;    // UART_PutCRLF();

        }

    }

}

/* [] END OF FILE */

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

moto

View solution in original post

0 Likes
2 Replies
lock attach
Attachments are accessible only for community members.
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Hi,

That is a nice example code!

I did not know about "DieTemp", so I gave it a try.

Since you are using CY8C4247AZI-M485, I imagined that you are using

either CY8CKIT-044 or CY8CKIT-043.

To go with these board, I modified the schematic so that we can use KitProg UART.

schematic

001-schematic.JPG

CY8CKIT-044

IMG_3785.JPG

pin list

002-pin-list.JPG

Tera Term log when I moved the pot

000-TeraTerm-log.JPG

So the reading was from 0mV to 1024mV (actual VDD was 3.3V, with this)

Then I tried with CY8CKIT-043

IMG_3787.JPG

pin list (schematic was same)

004-pin-list-043.JPG

Tera Term log

003-TeraTerm-043.JPG

So, with my usage, both CY8CKIT-044 and CY8CKIT-043 printed out 0mV ~ 1024mV.

FYI, modified main.c

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

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

* File Name: main.c

*

* Version: 2.10

*

* Description:

*  Sequencing SAR ADC and DieTemp datasheet example project.

*

* Note:

*  Pin_Vin pin (P0[4]) must be connected to the GND.

*  UART_tx pin (P0[5]) must be connected to the pin (P12[6]) of J8 header.

*  Verify that J9 is connected to 5V.

*

* Hardware Dependency:

*  PSoC4 Pioneer kit

*

********************************************************************************

* Copyright 2013-2017, Cypress Semiconductor Corporation. All rights reserved.

* This software is owned by Cypress Semiconductor Corporation and is protected

* by and subject to worldwide patent and copyright laws and treaties.

* Therefore, you may use this software only as provided in the license agreement

* accompanying the software package from which you obtained this software.

* CYPRESS AND ITS SUPPLIERS MAKE NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,

* WITH REGARD TO THIS SOFTWARE, INCLUDING, BUT NOT LIMITED TO, NONINFRINGEMENT,

* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

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

#include <project.h>

#include <stdio.h>

/* ADC SAR sequencer component header to access Vref value */

#include <ADC_SAR_SEQ.h>

#define CH0_N              (0x00u)

#define TEMP_CH            (0x01u)

#define DELAY_1SEC          (1000u)

/* Get actual Vref. value from ADC SAR sequencer */

#define ADC_VREF_VALUE_V    ((float)ADC_SAR_SEQ_DEFAULT_VREF_MV_VALUE/1000.0)

volatile uint32 dataReady = 0u;

volatile int16 result[ADC_SAR_SEQ_TOTAL_CHANNELS_NUM];

volatile uint32 timer_delay = 0u;

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

void print(char *str)

{

    UART_UartPutString(str) ;

}

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

* Function Name: ISR_TIMER_LOC

*******************************************************************************

*

* Summary:

*  Handle Interrupt Service Routine. Source - TIMER.

*

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

CY_ISR(ISR_TIMER_LOC)

{

    timer_delay++;

  

    /* Measures temperature once per second */

    if(timer_delay > DELAY_1SEC)

    {

        /* Enables injection channel for next scan */

        ADC_SAR_SEQ_EnableInjection();

        timer_delay = 0u;

    }  

  

    /* Clears interrupt request from terminal count */

    PWM_ClearInterrupt(PWM_INTR_MASK_TC);

}

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

* Function Name: ADC_SAR_SEQ_ISR_LOC

*******************************************************************************

*

* Summary:

*  Handle Interrupt Service Routine. Source - ADC SAR Seq.

*

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

CY_ISR(ADC_SAR_SEQ_ISR_LOC)

{

    uint32 intr_status;

    uint32 range_status;

    /* Read interrupt status registers */

    intr_status = ADC_SAR_SEQ_SAR_INTR_MASKED_REG;

    /* Check for End of Scan interrupt */

    if((intr_status & ADC_SAR_SEQ_EOS_MASK) != 0u)

    {

        /* Read range detect status */

        range_status = ADC_SAR_SEQ_SAR_RANGE_INTR_MASKED_REG;

        /* Verify that the conversion result met the condition Low_Limit <= Result < High_Limit  */

        if((range_status & (uint32)(1ul << CH0_N)) != 0u)

        {

            /* Read conversion result */

            result[CH0_N] = ADC_SAR_SEQ_GetResult16(CH0_N);

            /* Set PWM compare from channel0 */

            PWM_WriteCompare(result[CH0_N]);

        }  

        /* Clear range detect status */

        ADC_SAR_SEQ_SAR_RANGE_INTR_REG = range_status;

        dataReady |= ADC_SAR_SEQ_EOS_MASK;

    }  

    /* Check for Injection End of Conversion */

    if((intr_status & ADC_SAR_SEQ_INJ_EOC_MASK) != 0u)

    {

        result[TEMP_CH] = ADC_SAR_SEQ_GetResult16(TEMP_CH);

        dataReady |= ADC_SAR_SEQ_INJ_EOC_MASK;

    }  

    /* Clear handled interrupt */

    ADC_SAR_SEQ_SAR_INTR_REG = intr_status;

}

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

* Function Name: main

********************************************************************************

*

* Summary:

*

* Parameters:

*  None.

*

* Return:

*  None.

*

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

int main()

{

    int16 res = 0;

    int32 temperature;

    char  uartLine[250];

    int16 ADCCountsCorrected;

    /* Initialize the UART */

    UART_Start();

    print("\r\n") ; // UART_PutCRLF();

    print("\r\n") ; // UART_PutCRLF();

    // UART_PutString("Starting temperature measurement...");

    print("Starting temperature measurement...");

    print("\r\n") ; // UART_PutCRLF();

  

    PWM_Start();

    PWM_TriggerCommand(PWM_MASK, PWM_CMD_START);

    /* Init and start sequencing SAR ADC */

    ADC_SAR_SEQ_Start();

    ADC_SAR_SEQ_StartConvert();

    /* Enable interrupt and set interrupt handler to local routine */

    ADC_SAR_SEQ_IRQ_StartEx(ADC_SAR_SEQ_ISR_LOC);

  

    /* Init interrupt from timer to measure the temperature rarely */

    ISR_TIMER_StartEx(ISR_TIMER_LOC);

    CyGlobalIntEnable;

    for(;;)

    {

        /* When conversion of sequencing channels has completed */

        if((dataReady & ADC_SAR_SEQ_EOS_MASK) != 0u)

        {

            /* Get voltage, measured by ADC */

            dataReady &= ~ADC_SAR_SEQ_EOS_MASK;

            res = ADC_SAR_SEQ_CountsTo_mVolts(CH0_N, result[CH0_N]);

        }  

      

        /* When conversion of the injection channel has completed */

        if((dataReady & ADC_SAR_SEQ_INJ_EOC_MASK) != 0u)

        {

            dataReady &= ~ADC_SAR_SEQ_INJ_EOC_MASK;

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

            * Adjust data from ADC with respect to Vref value.

            * This adjustment is to be done if Vref is set to any other than

            * internal 1.024V.

            * For more detailed description see Functional Description section

            * of DieTemp P4 datasheet.

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

            ADCCountsCorrected = (int16)(result[TEMP_CH]*(((float)ADC_VREF_VALUE_V/1.024)));

          

            temperature = DieTemp_CountsTo_Celsius(ADCCountsCorrected);

            /* Print temperature value to UART */

            sprintf(

                    uartLine, "Temperature value: %dC",

                    (int16) temperature

                    );

            print(uartLine) ;  // UART_PutString(uartLine);

            print("\r\n") ;    // UART_PutCRLF();

          

            /* Print voltage value to UART */

            sprintf(

                uartLine, "ADC measured voltage: %dmV",

                (uint16) res

                );

          

            print(uartLine) ;  // UART_PutString(uartLine);

            print("\r\n") ;    // UART_PutCRLF();

        }

    }

}

/* [] END OF FILE */

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

moto

0 Likes

Hey this is awesome! Thanks a lot for the quick reply. I am using CY8CKIT-043. I just tried your code with the pot. It's working fine. But looks like a sudden jump from 0-5V seems to have some settling time. Other than that I think I was having some loose connection. So I rigged up a GPCB and tried it with the pot. And it properly measure a 0 when grounded.