Post Go back to editing

ADC problem about ADUC7061

I post this problem in chinese version, but the china engineer can't give correct answer. So i want to post it here to found an more senior engineer. 

As you know, ADC1~ADC5 are single function port. but ADC6~ADC9 are mutil-function prots.

The SPI/I2C and analog can be changed.

I write code to sample analog signle from ADC4 and ADC8, ADC 4 is connected to ADC8 together.

But when i read, value from ADC4 is correct, but data from ADC8 is not correct.

When the voltage is 0.67V around. the value from ADC4 is 0x004xxxxx, but value from ADC8 is about 0x000005xx.

When i change the voltage, value from ADC8 will not change, or chage slightly. for example, 0x5ff, 0x5fe.

When i change another device(CPU chip), the value will be 0x606, 0x607.

I  deduce:

there are some bug in device. and the codes to initiate ADC1 need special sequence.

the Datasheed does not tell me what is sequence, the special sequence, so i get wrong result.

I can't find example code how to use adc6~adc9,  will anyone give correct resolution?

thanks.

I post my code here:

int main()
{
volatile signed long s;
signed char N = -1;
char Err = 0;
float fN = 0;

PLLKEY1 = 0xaa;
PLLCON = 0x00;
PLLKEY2 = 0x55;

POWKEY1 = 0x1;
POWCON0 = 0x38; // Set core to max CPU speed of 10.24Mhz
POWKEY2 = 0xF4;

POWKEY3 = 0x76;
POWCON1 = 0x024;
POWKEY4 = 0xB1;

DACCON = 0x0013;
DACDAT = 0x04ff0000;


while(1)
{

ADCCFG = 0x84;
ADCFLT = 0x8083;

GP0CON0 = 0x00000000; //p0.0~p0.4 gpio
GP0PAR = 0x0f; //01110
GP0DAT = 0x10100000;

GP0KEY1 = 0x7;
GP0CON1 = 0x1; // adc
GP0KEY2 = 0x13;

ADC0CON = 0;
ADC1CON = 0x878c;;

s = ADCSTA;
s = ADC0DAT;
s = ADC1DAT;
//////////
ADCMDE = 0x83;
////
ADC1CON = 0x8004 | 0x0480;//ch 8
//ADC1CON = 0x800c | 0x0300;//ch 4

s = ADC1DAT;
s = ADCSTA;
ADCMDE = 0x82;
do
{
s = ADCSTA;
if (s & 0x2000) //adc1cerr
{
Err |= 1; //over range
}
} while(!(s & 0x2));

s = ADC1DAT;
ADCMDE = 0x83;

//3. exit adc
ADCMDE = 0x83; //idle
ADCFLT = 0x80ff;
ADC1CON = 0x78c; //internally shorted

GP0CON0 = 0x00001011; //back to spi
GP0PAR = 0x04;
GP0DAT = 0x10100000;

GP0KEY1 = 0x7;
GP0CON1 = 0x0; // exit adc
GP0KEY2 = 0x13;
}
}

Parents
  • Hi,

    You mentioned that CH4 is working while CH8 is not but looking at the configuration below, there is another difference. You bypass both buffer when reading from CH4. Can you try to bypass the buffer when using CH8 as well? This is just to check if we have an issue with the buffer. 

    ADC1CON = 0x8004 | 0x0480;//ch 8
    //ADC1CON = 0x800c | 0x0300;//ch 4

    Also, I think the lines below can be skipped.

    GP0CON0 = 0x00000000; //p0.0~p0.4 gpio
    GP0PAR = 0x0f; //01110
    GP0DAT = 0x10100000;

     

    regards,

    Mark

  • I have checked it for several weeks,

    In facts, the ADC is correct. the reason to make wrong data of ADC is that the DAC will not work when P0 is configured as analogue input. the DAC will not ouput linear voltage.

    Finally, when USE jlink, device works correctly after programming, but will not work correctly after reset again by power off and on.

    when use ULINK, device work incorrectly after programming, but it will work in debug mode, run or step by step. if the devcei is resetted again by poweroff/on, the devcei will not work correctly again.

  • Hi,
    I have gone through the code and added some comments to it. I will suggest to disable the SPI/I2C blocks when converting from ADC. Also please take note of the device selection on your compiler, use ADuC7061 instead of ADuC7060. What compiler are you using?

    int main()
    {
    volatile signed long s;
    signed char N = -1;
    char Err = 0;
    float fN = 0;

    PLLKEY1 = 0xaa;
    PLLCON = 0x00;
    PLLKEY2 = 0x55;

    POWKEY1 = 0x1;
    POWCON0 = 0x38; // Set core to max CPU speed of 10.24Mhz
    POWKEY2 = 0xF4;

    POWKEY3 = 0x76;
    POWCON1 = 0x024; --> Please use 0x020 this if using ADC6 to 9
    POWKEY4 = 0xB1;

    DACCON = 0x0013;
    DACDAT = 0x04ff0000;


    while(1)
    {

    GP0CON0 = 0x00000000; //p0.0~p0.4 gpio
    GP0PAR = 0x0f; //01110
    GP0DAT = 0x10100000;

    GP0KEY1 = 0x7;
    GP0CON1 = 0x1; // adc
    GP0KEY2 = 0x13;

    ADCCFG = 0x84; -->Moved after GPIO CFG
    ADCFLT = 0x8083;
    ADC0CON = 0;
    ADC1CON = 0x878c; --> This is an internal short to ADC3. Are you measuring ADC3 intentionally?

    s = ADCSTA;
    s = ADC0DAT;
    s = ADC1DAT;
    //////////
    ADCMDE = 0x83; //idle mode
    ////
    ADC1CON = 0x8004 | 0x0480;//ch 8 -> Measuring from CH8, is ADC5 biased with 0.1V?
    //ADC1CON = 0x800c | 0x0300;//ch 4 -> Measuring from CH4, is ADC5 biased with 0.1V? Note the gain difference

    s = ADC1DAT;
    s = ADCSTA;
    ADCMDE = 0x82;

    do
    {
    s = ADCSTA;
    if (s & 0x2000) //adc1cerr
    {
    Err |= 1; //over range
    }
    } while(!(s & 0x2));

    s = ADC1DAT;
    ADCMDE = 0x83; //idle

    //3. exit adc
    ADCMDE = 0x83; //idle
    ADCFLT = 0x80ff;
    ADC1CON = 0x78c; //internally shorted

    GP0CON0 = 0x00001011; //back to spi
    GP0PAR = 0x04;
    GP0DAT = 0x10100000;

    GP0KEY1 = 0x7;
    GP0CON1 = 0x0; // exit adc
    GP0KEY2 = 0x13;
    }


  • void DelayMs(long d)
    {
    long i, j;
    for (j=0; j<d; j++)
    {
    for (i=0; i<900; i++)
    {
    //T2CLRI = 0x55;
    }
    }
    }
    void SetDacInmv(signed short mV)
    {
    signed long v;
    signed long vdac;
    v = mV;
    vdac = (v * 4095) / 1200; //by Vdd=2.5V
    vdac <<= 16;
    if (vdac > 0xfff0000)
    {
    vdac = 0xfff0000;
    }
    DACCON = 0x10;
    DACDAT = vdac;
    }

    int main()
    {
    SetDacInmv(0);
    while(1)
    {
    // T2CLRI = 0x55;
    GP0KEY1 = 0x7;
    GP0CON1 = 0x1;
    GP0KEY2 = 0x13;
    SetDacInmv(1200);
    DelayMs(5);
    SetDacInmv(600);
    DelayMs(5);

    SetDacInmv(0);
    DelayMs(5);
    GP0KEY1 = 0x7;
    GP0CON1 = 0x0;
    GP0KEY2 = 0x13;
    SetDacInmv(1200);
    DelayMs(5);
    SetDacInmv(600);
    DelayMs(5);

    SetDacInmv(0);
    DelayMs(10);
    }
    }

  • These codes are too complex.

    you can check code following. it is simple.

  • Hi, 
    I have been debugging this using the EVAL-ADUC7061MKZ and I am not seeing any issue. I enabled both ADCs using AIN8 for ADC1 and AIN2 for ADC0. You can see the UART result from the screenshot vs the input voltage. 

    The square wave in the image is the DAC output, I am toggling between 0V (Zero scale) and 0.6V (Midscale) and I am not seeing any spikes in the output. The image was captured after power cycle. 




    My full code is below for reference:

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

    Author : ADI - Apps www.analog.com/AduC7060

    Date : November 2007

    File : ADC1_Cont.c

    Hardware : ADuC706x

    Description : This Simple ADC1 example shows how to initialize the Auxiliary ADC for
    continuous sampling using a Single-Ended inputs.
    *************************************************************************************************/
    // Bit Definitions
    #define BIT0 0x01
    #define BIT1 0x02
    #define BIT2 0x04
    #define BIT3 0x08
    #define BIT4 0x10
    #define BIT5 0x20
    #define BIT6 0x40
    #define BIT7 0x80
    #define BIT8 0x100
    #define BIT9 0x200
    #define BIT10 0x400
    #define BIT11 0x800
    #define BIT12 0x1000
    #define BIT13 0x2000
    #define BIT14 0x4000
    #define BIT15 0x8000


    #include<aduc7060.h>
    # include "stdio.h"
    # include "string.h"

    volatile unsigned char bSendResultToUART = 0; // Flag used to indicate ADC1 resutl ready to send to UART
    unsigned char szTemp[16] = ""; // Used to store ADC1 result before printing to UART
    unsigned char ucTxBufferEmpty = 0; // Used to indicate that the UART Tx buffer is empty
    volatile unsigned long ulADC1Result = 0; // Variable that ADC1DAT is read into in ADC1 IRQ
    volatile unsigned long ulADC0Result = 0; // Variable that ADC1DAT is read into in ADC0 IRQ

    void DelayMs(long d)
    {
    long i, j;
    for (j=0; j<d; j++)
    {
    for (i=0; i<900; i++)
    {
    //T2CLRI = 0x55;
    }
    }
    }

    int main(void)
    {
    unsigned char i = 0;
    unsigned char j = 0;
    unsigned char nLen = 0;

    float lsb10r9 = 143.0511; // 10^9 G

    POWKEY1 = 0x1;
    POWCON0 = 0x78; // Set core to max CPU speed of 10.24Mhz
    POWKEY2 = 0xF4;

    GP0KEY1 = 0x7;
    GP0CON1 = 0x1;
    GP0KEY2 = 0x13;

    GP0CON0 = 0x00000000; //p0.0~p0.4 gpio
    GP0PAR = 0x0f; //01110
    GP0DAT = 0x10100000;

    // Initialize the UART for 9600-8-N
    GP1CON = BIT0 + BIT4; // Select UART functionality for P1.0/P1.1
    COMCON0 = BIT7; // Enable access to COMDIV registers
    COMDIV0 = 0x21; // Set baud rate to 9600.
    COMDIV1 = 0x00;

    COMCON0 = BIT0 + BIT1 + BIT2;
    COMIEN0 = BIT0 + BIT1; // Enable UART interrupts when Rx full and Tx buffer empty.

    // DAC configuration
    DACCON = 0 + // range AVdd/AGND
    BIT4; // Disable clearing of DACDAT + DAC is updated with falling edge of core clock

    // Configure ADC1 for continuous conversions, 1khz, ADC4 input
    ADCMSKI = BIT1; // Enable ADC1 result ready interrupt source
    ADCFLT = 0x7; // Chop off, 1Khz samping rate, SF = 7. No averaging
    ADCMDE = BIT0; // Continuous Conversion mode, Normal mode
    ADC0CON = BIT8 + BIT7 // ADC0 input channel 6 in Single-Ended mode.
    + BIT15; // Auxiliary-ADC Enabled
    // Also, Int reference,

    ADC1CON = BIT10 + BIT7 // ADC1 input channel 6 in Single-Ended mode.
    + BIT15; // Auxiliary-ADC Enabled
    // Also, Int reference,
    ADCCFG = 0;
    IRQEN = BIT10 + BIT11; // Enable ADC1 and UART interrupts
    bSendResultToUART = 0;

    while (1)
    {

    if (bSendResultToUART == 1) // Is there an ADC1 result ready for UART transmission?
    {
    DACDAT = 0x8000000;
    DelayMs(10);

    sprintf ( (char*)szTemp, "ADC0 Result: %f\r",ulADC0Result*lsb10r9/1000000000 );// Send the ADC1 Result to the UART
    nLen = strlen((char*)szTemp);
    for ( i = 0 ; i < nLen ; i++ ) // loop to send ADC1 result
    {
    COMTX = szTemp[i];
    ucTxBufferEmpty = 0;
    while (ucTxBufferEmpty == 0)
    {
    }
    }
    }


    DACDAT = 0x0000000;
    DelayMs(10);

    sprintf ( (char*)szTemp, "ADC1 Result: %f\r",ulADC1Result*lsb10r9/1000000000 );// Send the ADC1 Result to the UART
    nLen = strlen((char*)szTemp);
    for ( i = 0 ; i < nLen ; i++ ) // loop to send ADC1 result
    {
    COMTX = szTemp[i];
    ucTxBufferEmpty = 0;
    while (ucTxBufferEmpty == 0)
    {
    }
    }
    }
    }

    void IRQ_Handler(void) __irq
    {
    unsigned long IRQSTATUS = 0;
    unsigned char ucCOMIID0 = 0;

    IRQSTATUS = IRQSTA; // Read off IRQSTA register
    if ((IRQSTATUS & BIT11) == BIT11) //UART interrupt source
    {
    ucCOMIID0 = COMIID0;
    if ((ucCOMIID0 & 0x2) == 0x2) // Transmit buffer empty
    {
    ucTxBufferEmpty = 1;
    }
    }

    if ((IRQSTATUS & BIT10) == BIT10) //If ADC1 interrupt source
    {
    ulADC0Result = ADC0DAT; // Read ADC0 conversion result
    ulADC1Result = ADC1DAT; // Read ADC1 conversion result
    bSendResultToUART = 1;
    }
    }

  • hi, ramos,

    I have checked your code, it is wrong;

    ADC0CON = BIT8 + BIT7 // ADC0 input channel 6 in Single-Ended mode.
    + BIT15; // Auxiliary-ADC Enabled

    You use ADC0 to read channel6, it is wrong. ADC0 can't be used to read channel6~9. you can see datasheet.

    if you set BIT8+BIT7, the channel is not channel6, it is channel Vref+ and Vref-.

    Data reading by ADC0 is not output of DAC, it is voltage of Vref+ and Vref-.

    So wave in your picture and data from UART are wrong.

    They are fake.

  • Hi,
    In this example, I am using 2 ADCs at the same time.

    ADC0 measures from ADC2/ADC5 by setting ADC0CON = BIT8 + BIT7. I realized the comment there is wrong but on my board, I am forcing  voltage to ADC2 that is why I am reading the correct value. See screen shot from the datasheet below



    In my setup, I did not connect the DAC output to ADC input. I think this is the reason why you're getting a bad measurement. The ADC is probably loading the DAC. Do you have other circuit connected to your DAC? Can you disconnect the DAC from ADC and any other connection and re-run your code? 

  • sorry, ADC0CON = BIT8 + BIT7 set channel 2, not Vref+ and Vref-. I miss one bit;

    The test result of romas really validate the dac don't work correctly.

    As you see, midscale of Vref=1.2V is 0.6V

    midscale of Ver=2.5 is 1.25V

    You can see, the voltage 1.0v is hard to explain.

    romas said, it is little higher than 0.9V when he set DATDAT = 0xc000000.

    But if device works correctly, the output is very precise, error will not be so large.

    I compute here:

    when DATDAT = 0xc000000

    DAC output will be 0.9 when Vref = 1.2

    DAC output will be 1.85 when Vref = 2.5.

    In fact, if you want to output 1.0V, the devider should not be an integer because of prime number.

    I belive there is something wrong, perhaps romas can check it again

     

  • I just connect ADC4 and DAC together, and there is no other components.

    The spike you said generate because DAC output wrong leven when GP0CON1 = 0x0 change to GP0CON1 = 0x1. 

    with the same DACDAT the DAC will generate different voltage.

    You said you seen correct output, but why will not you to swap GP0CON1 = 0x0 and GP0CON1 = 0x1?

    It is easy to validate. I have give you good code, it is very easy to do this.

    I don't know why you insiste test code like that.

    In your code, it is very hard to identify what is relation between ADC1 ADC0, and Vref, and 0.6, 0.9, 1.0.

    All are in chaos.

  • The sps is 1k, from the code, bSendResultToUART = 1 always, it is not been cleared.

    so, when the DelayMs finish, the UART will report at once.

    from the code, you will find ADC1 should be constant, if  DACDAT = 0x0000000, ADC1 should be 0V, if DACDAT = 0x8000000; ADC1 should be 0.6V, constant, not swinging from 0 to 0.6V

    This is because ulADC1Result will be overwritten when DelayMs();

    another thing is:

    The result is 0.59V, if the ADC1 is used to sample DAC ouput, the error will not be so large, 0.59 give a error over/around 1%. It is not possible.

  • DACDAT = 0x8000000;
    DelayMs(10);

    sprintf ( (char*)szTemp, "ADC0 Result: %f\r",ulADC0Result*lsb10r9/1000000000 );

    this is because the ulADC0Result is used for the first report, and ulADC0Result  is used for the second report.

    So any value of ADC0 or ADC1 will be constant ( not considering noise), they will not swing.

    And you will find adc0 is about 1.0V. the value is wrong.

Reply
  • DACDAT = 0x8000000;
    DelayMs(10);

    sprintf ( (char*)szTemp, "ADC0 Result: %f\r",ulADC0Result*lsb10r9/1000000000 );

    this is because the ulADC0Result is used for the first report, and ulADC0Result  is used for the second report.

    So any value of ADC0 or ADC1 will be constant ( not considering noise), they will not swing.

    And you will find adc0 is about 1.0V. the value is wrong.

Children