ADC readings conversion to Decimals

Go To Last Post
31 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello everyone,

in my setup >>external<< ADC (AD 7723) is connected via (16-Bit data-bus >>  DB0-DB16) to the AVR Device which is ATmega 2560. Each data-bit source has a dedicated port on ATmega. 

In my understanding I should read through 16 data-lines on AVR dedicated pins and then save all that in a 16 character array. But afterwards which ways exist to convert those array elements into decimal numbers to be able to work with them later on.  

 

 

work in progress...

Last Edited: Thu. Oct 25, 2018 - 10:15 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dave_Zeb. wrote:
save all that in a 16 character array.
?? Haven't a clue what you mean here??

 

Usually you have something like:

unti16_t adc_reading;

adc_reading = read_adc();

Of course it depends on the numeric range of the ADC but lets assume that at this stage the ADC has been read and adc_reading holds 12345. That is 0x3039 in hex. In binary 0b11000000111001. At this stage it's simply a pattern of 1s and 0s in 16 bits. If you later what to present this to a human on an LCD, UART or something you likely do something like:

char buff[20];

itoa(adc_reading, buff, 10);
UART_printstring(buff);

or maybe:

char buff[20];

sprintf(buff, "%d", adc_reading);
LCD_printstring(buff);

Either itoa() or sprintf()  will convert the numeric value in the variable to a srting of ASCII digits you can show to the shaved ape.

Last Edited: Mon. Oct 22, 2018 - 02:31 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello clawson 

adc_reading = read_adc();

     In "read_adc()" function, I must read those 16 x pins >>DB0->DB15, and then save them in a variable? Or array? Or buffer?. To make the problem easy I went back to arduino Due, although I don't like it. Because I try to minimize the sources of possible errors, which in my case are potentially everywhere. Sad but true, including the hardware setup, with external ADC and analog acquisition circuitry. I see no light at the end of a tunnel. Anyway, to cut it short. I wrote a naïve code in Arduino to read the data bits from ad7723 external ADC through 16 bit data-bus.  The Program is below:

//-------Preamble-----------------------------//

const int adc_db0 = 22;  // adc data-bus 
const int adc_db1 = 24;  // adc data-bus
const int adc_db2 = 26;  // adc data-bus
const int adc_db3 = 28;  // adc data-bus
const int adc_db4 = 30;  // adc data-bus
const int adc_db5 = 32;  // adc data-bus
const int adc_db6 = 34;  // adc data-bus
const int adc_db7 = 36;  // adc data-bus
const int adc_db8 = 38;  // adc data-bus
const int adc_db9 = 40;  // adc data-bus
const int adc_db10 = 42; // adc data-bus
const int adc_db11 = 44; // adc data-bus
const int adc_db12 = 46; // adc data-bus
const int adc_db13 = 48; // adc data-bus
const int adc_db14 = 50; // adc data-bus
const int adc_db15 = 52; // adc data-bus

int input_port;

uint16_t adc_readings;

const int clock_signal_port = 10; // ADC clock generation via PWM on Pin-10 1.0KHz; Due pin No 10 is attached to AD7723 CLKIN pin. 

//-------Functions----------------------------------//

uint16_t AD_7723_acquire(void){

          char data_buffer[20];

          int data_bit_0 = digitalRead(adc_db0);
          int data_bit_1 = digitalRead(adc_db1);
          int data_bit_2 = digitalRead(adc_db2);
          int data_bit_3 = digitalRead(adc_db3);
          int data_bit_4 = digitalRead(adc_db4);
          int data_bit_5 = digitalRead(adc_db5);
          int data_bit_6 = digitalRead(adc_db6);
          int data_bit_7 = digitalRead(adc_db7);
          int data_bit_8 = digitalRead(adc_db8);
          int data_bit_9 = digitalRead(adc_db9);
          int data_bit_10 = digitalRead(adc_db10);
          int data_bit_11 = digitalRead(adc_db11);
          int data_bit_12 = digitalRead(adc_db12);
          int data_bit_13 = digitalRead(adc_db13);
          int data_bit_14 = digitalRead(adc_db14);
          int data_bit_15 = digitalRead(adc_db15);

           //-----here I am completely stuck, no idea what to do with those data_bits (0-15) ---//        
  }

//-------inits-------------------------------------//

void setup() {
  
  Serial.begin(9600);
  Serial.print ("------- AD_7723 test program--------");
  
  for(input_port = 22; input_port < 53; input_port ++ ){

       pinMode(input_port, INPUT_PULLUP);
    }
       pinMode(clock_signal_port, OUTPUT);
  
  Serial.print("----GPIO Congfig-----");
  Serial.print("-----Inits End-------");
  }

  void loop(){

        analogWrite(clock_signal_port, 100); // ADC clock Generator 1.0KHz
        AD_7723_acquire();
        Serial.print(adc_readings, DEC);
        Serial.print("\n");
  }

  At the moment I am sure about two things:

   1. instrumentation amplifiers do provide the suitable analog voltage at the (V+/ V-) inputs of the ADC, checked with the scope the upper signal 135 Hz.

   2. While probing the output pins of the ADC, directly on the ADC, shows that there is some data transfer going on, the lower signal. I guess......

 

 

So that's the hole story behind all this trouble of mine.

 

Hope you guys can put some light into this.

 

 

work in progress...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hint: db0 = 1,db1 =2, db2 = 4,db3 =8 ...........
something like if (digitalRead(adc-db0)) value+=1;

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Please no! This process of reading one bit at a time is painful to look at!

Using digitalRead, well known for its slowness, by the time you reach the last bit, the first one probably already has a different reading.

You need to figure out what are the actual AVR ports that are connected to the ADC and read them directly. A pin diagram of the Arduino Mega will help.

Also, the ADC has a DRDY signal to warn the MCU about new data available. You need to wait for that before reading a value.

 

edit: you should use only 2 AVR ports for the serial interface, each port has 8 pins. I suggest that you connect ADC D0-D7 to PORTA (Arduino Mega pins 22-29 in ascending order) and ADC D8-D15 to PORTC (Arduino Mega pins 37-30 in descending order).

 

If you have no idea what I'm going on about, please say so and I'll try to be more clear.

Last Edited: Mon. Oct 22, 2018 - 08:58 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

The ATmega 2560 is connected back to circuitry as you proposed. What are next steps? 

by the way, I even have got a tri-state buffer latch here, tho it is smaller in size, it has just 6 input terminals, so in case we use them, we have to connect all three, to support the 16 bit bus.

 

work in progress...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Let's start over a bit...

 

What do you intend to accomplish adding a very fast $50 external ADC, parallel, to an AVR8 application?  Lessee, a 600Hz sine wave has 600 cycles per second, right?  How many samples do you intent to take for each cycle?  If you answer "10" then any reproduction/analysis will be coarse.  If you say "100" then where are you going to put all the sample results?  When are you going to find the processor cycles to do anything with it?

 

As mentioned, you don't read/stor a bit at a time.  With your described setup you would do it a port at a time.

 

Now, let's consider atomic access for a bit.  The datasheet does mention latch/buffer.  But given the above speed considerations I'd think a /DRDY monitor would suffice.

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

at this stage, it is highly needed/essential to read data from AD7723. That will show that the analog circuitry functions properly. Something like 16 Bit, 200-500 ksps or lesser resolution would be enough, no need to kick-it at full speed. I'm feeding a sine wave 1.0 KHz to analog circuitry and would be nice to see AD 7723 data in serial monitor, showing the mentioned sine wave without any issues.

If its successful at this, then later on, the AVR will be supported by E2PROM arrays to store the data acquired from AD7723. In my understanding the DRDY has to have a dedicated port connection, which has to be monitored with interrupt to signal the AVR to read the 16 bit data port?

 

work in progress...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dave_Zeb. wrote:
Something like 16 Bit, 200-500 ksps

If you are designing-in a $50 part, there must be a reason besides "must use".

 

Again, re-read what I posted, and tell what you intend to do with these readings.  You want to get a 16-bit sample, two bytes, every few microseconds.  Assuming you get them into a pair of AVR registers, what are you going to do with them in the remaining microsecond or so?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you are designing-in a $50 part, there must be a reason besides "must use".

The ADC samples the output of the sensor (aka thermocouple). It is important later-on (in further steps) to sample with max resolution 1.2 MSPS, 16Bit, because the changes the thermocouple registers are very fast in µs time domain, so that nothing is missed.

and tell what you intend to do with these readings

they will be fed into a PID controller. But again, we could dump-down the sampling so that AVR wins some cycles to process data. It would be so brilliant if AVR will present data from ADC into serial at that's more than enough to say that analog circuitry works just fine hehe.

work in progress...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How int he name of all that is holy is a 16..20..32MHz AVR going too keep up with 1.2Msps? Set aside the fact that you only have 10..20 cycles per sample to read/process the data where in the name of God are you going to put them in a micro with 1..16K of SRAM.

 

Seems like you may have picked the wrong micro for the job.

Last Edited: Mon. Oct 22, 2018 - 11:03 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't think you will need the latch, reading the value will take just 2 AVR cycles.

So, now you connect DRDY to some other free pin and wait for it to go low with a while loop for example.

Then you read port A and port C with something like:

 

    ADClow = PINA;
    ADChigh = PINC;
    ADCval = ADClow | (ADChigh << 8);

 

You will have your 16 bit ADC reading in the ADCval variable, so now you just need to scale it to the actual voltage value.

 

edit: but yeah, the AVR will not have time to process the ADC value in 10-20 cycles.

Last Edited: Mon. Oct 22, 2018 - 11:04 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oh no. I really need/must have to run the setup with AVR. Can  I clock the ADC with external clock source to 100 KHz=?, should be possible,  and then it becomes like a ATmege328 ADC onboard, which runs at 250KHz=? yes/no.

Would this be an option?= okay, if not ATmega2560, what about Arduino Due? it runs at 84 MHz.

work in progress...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Arduino Due is not an AVR, it's an ARM.

What is the MCU supposed to do with the value, anyway? Send it trough serial? It will take a while to transmit the value even at maximum baud rate, although this is done by a peripheral so it doesn't take a lot of CPU time.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why, in the world, are you sampling a  thermocouple at speeds like that. Thermocouples are NOT noted for high speed operation! If you add a thermocouple interface IC with cold-junction correction, then you are probably down to a bandwidth of a few hundred Hertz! Are you blasting it with a short-pulse laser or something?

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

Last Edited: Tue. Oct 23, 2018 - 01:08 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dave_Zeb. wrote:

Oh no. I really need/must have to run the setup with AVR. Can  I clock the ADC with external clock source to 100 KHz=?, should be possible,  and then it becomes like a ATmege328 ADC onboard, which runs at 250KHz=? yes/no.

The answer is NO.....

I think you missed a bit......

If you would have had a look at the datasheet, YES the ADC peripheral clock frequency can be 250KHz, with lowered performance/output accuracy... ( typ good is 50K - 200K)

But it takes the ADC a minimum of 13 clock cycles to perform 1 conversion, so actually you should be rather happy if you do 20K conversions per second.

 

Now I would like to see how you are going to do 1.2MSPS with an 8bit avr running at 20MHz.... Then redo the math for 16MHz as the mega2560 will do that max.....

I will start... with the AVR running at 16MHz and you need 1.2MSPS you have about 13 CPU clock cycles to do the fetch and do what you need to do with it.......

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Something similar. Thermocouples, if they are small enough one can easily measure high speed transitions etc. in materials, for example. What transitions are happening in polymers, are they endothermic or exothermic. All sorts of good stuff. 

thermocouple interface IC with cold-junction correction

 are very slow and mostly, one cannot expose those IC's to extreme temperatures like 200K or -50K

work in progress...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

so the program ended up looking like this:

 

#include <binaryMacro.h>
#include <macros.h>
#include <pinDefines.h>
#include <portpins.h>
#include <USART.h>


//-------------------------------Preamble----------------------------//

const int data_ready_port = 38;   //data ready signaling
const int ADC_clock_gen_port = 2; // ADC CLKIN from ATmega 2560
uint16_t ADC_data;                // ADC data

//-------------------------------Functions----------------------------//

 uint16_t init_AD7723(void){
       
         uint8_t ADC_lowbyte;       // 1/2 ADC data-bus
         uint8_t ADC_highbyte;      // 1/2 ADC data-bus

        while (data_ready_port == 0){

               ADC_lowbyte = PINA;
               ADC_highbyte = PINC;
               ADC_data = ADC_lowbyte | (ADC_highbyte<<8);

                return(ADC_data);
          }
  }
//-------------------------------Inits----------------------------//

 void setup (){

      Serial.begin(115200);
      Serial.print("//------------ AD-7723 test program ------------//");

      for(int pinX = 22; pinX < 39 ; pinX ++){

          pinMode(pinX, INPUT_PULLUP);
        }
          pinMode(ADC_clock_gen_port, OUTPUT); // clock signal output via PWM.
  }
//-------------------------------Event Loop----------------------------//

 void loop(){
          analogWrite(ADC_clock_gen_port, 50);   
          init_AD7723();
          Serial.print(ADC_data);
          Serial.print("\n");  
  }

I am not sure about CLKIN generation with ATmega2560 port No2, with analogWrite() function, any better ideas ? as mentioned by " meslomp " above to setup decent clock cycle at about 20K?

It looks like with this program in serial is nothing but a single "0" in a row.frown

 

work in progress...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

-50K is 50 below absolute zero with K meaning Kelvin. Somehow i think you mean C for Celsius. Two very different men.

Not sure how data_ready_port is going to work for you. I think you missed a digitalRead call.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
const int data_ready_port = 38;
  while (data_ready_port == 0)

 

This will be always false. You need to read the pin and wait until it goes to zero.

 

edit: well, let me show you the mistakes:

 

 /* uint16_t */ void init_AD7723(void){

         uint8_t ADC_lowbyte;       // 1/2 ADC data-bus
         uint8_t ADC_highbyte;      // 1/2 ADC data-bus

        while (digitalRead(data_ready_port) == HIGH) ; /*{*/ // this is just a wait loop for data ready low

               ADC_lowbyte = PINA;
               ADC_highbyte = PINC;
               ADC_data = ADC_lowbyte | (ADC_highbyte<<8);

                //return(ADC_data); you don't need to return the value if you are using a global variable
          /*}*/ this code is outside the wait loop
  }

 

I've used Arduino stuff in the wait loop, but this is just for clarity. You can't use digitalRead in performance critical applications, you need to learn how to access the ports directly.

Last Edited: Tue. Oct 23, 2018 - 12:21 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Can we see your schematic? I don't understand your code at all. What are the MODE0 and MODE1 bits on pins 7/8 set to? If you are using in parallel (MODE0:1 not 00) then you seem to be ignoring the state of DRDY ??

 

BTW why is the function that apparently reads the ADC called initAD7723() - very misleading! 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Decided to do everything properly ^_^

-------------------------------------------

 

-  "Timer-1" is used for the clock generation of the "AD-7723, CTC mode / 500 KHz"

-  The "Mode-1/Mode-2" pins are connected to 5 Volts >> parallel interface

-  "UNI" connected to Ground for Bipolar operation

- "XTAL_OFF" is tied HIGH.

- "CLKIN" is connected to AVR/ATmega(2560)  PB5 >>> OC1A

- for everything else please see the schematics.

 

After all I considered to use Teensy 3.6 which I have here, but then it looks like that it does not have 5 Volt tolerant GPIO, so now the ATmega2560 is only chance.

 

and the program I have rewritten is this:

//----------------- Preamble ----------------- //
#include <avr/io.h>
#include <util/delay.h>
#include <avr/power.h>
#include <interrupt.h>
#include <Hardware_Connections_Bay.h>
#include <In_Lining_Functions.h>
#include <USART.h>

#define COUNTER_VALUE    1

uint8_t ADC_lowbyte, ADC_highbyte;
uint16_t ADC_data;

//----------------- Initializations ----------------- //
int main (void){

    initUSART(); // start USART
    init_Timer_1(); // start Timer-1
    L_L_AD_7723_N1_DDR = 0x00; // makes sure we're in input mode / high byte PORT DDR
    L_H_AD_7723_N1_DDR = 0x00; // makes sure we're in input mode / low byte PORT DDR
    L_AD_7723_N1_CLKIN_sig_DDR| = (1 << L_AD_7723_N1_CLKIN_lock); // clock signal port setup for output mode
    printString("//---- bla bla  v. N-1----//");
}
//----------------- Event loop ----------------- //

 while(1){

        get_ADC_data();
        printString("left amplifier ADC results = ");
        printWord(ADC_data);
        printString("\r\n");

        return(0);
 }

the headers:


// ------ No1 Left AD-7723 data-bus GPIO ------ //

//---------- low byte ------------//
#define   L_L_AD_7723_N1_DDR        DDRE
#define   L_L_AD_7723_N1_PORT      PORTE
#define   L_L_AD_7723_N1_PIN        PINE

#define   L_N1_DB0                 PE0
#define   L_N1_DB1                 PE1
#define   L_N1_DB2                 PE2
#define   L_N1_DB3                 PE3
#define   L_N1_DB4                 PE4
#define   L_N1_DB5                 PE5
#define   L_N1_DB6                 PE6
#define   L_N1_DB7                 PE7

//---------- high byte -----------//
#define   L_H_AD_7723_N1_DDR         DDRH
#define   L_H_AD_7723_N1_PORT       PORTH
#define   L_H_AD_7723_N1_PIN         PINH

#define   H_N1_DB0                 PH0
#define   H_N1_DB1                 PH1
#define   H_N1_DB2                 PH2
#define   H_N1_DB3                 PH3
#define   H_N1_DB4                 PH4
#define   H_N1_DB5                 PH5
#define   H_N1_DB6                 PH6
#define   H_N1_DB7                 PH7

// ------ No1 Left AD-7723 control-bus GPIO ------ //

#define   L_AD_7723_N1_CLKIN_sig_DDR         DDRB
#define   L_AD_7723_N1_CLKIN_sig_PORT       PORTB
#define   L_AD_7723_N1_CLKIN_sig_PIN         PINB

#define   L_AD_7723_N1_CLKIN_lock             PB5
#define   L_AD_7723_N1_DRDY_lock              PB0

     and finally the Functions

    


/** \brief init_Timer_1 Function sets-up the on-board 16-Bit Timer/Counter-1 for waveform
 *  generation. It is running in CTC mode with output on PB5 port/OC1A.
 *  The OC1A/PB5 toggles each time through. Which generates 500 KHz clock signal.
 * \param takes no parameters
 * \param takes no parameters
 * \return nothing
 */

static inline void init_Timer_1(void){

    TCCR1B| = (1 << WGM12)|(1 << CS11);  // Timer-1/16 Bit in CTC mode and clock prescaler set div/8
    TCCR1A| = (1 << COM1A0); // toggle OCR1A on compare match
     OCR1A| = COUNTER_VALUE; // waveform output frequency 500 KHz
}

/** \brief get_ADC_data Function call uses [AVR's] 2 x PORT E/H banks 2 x 8-Bits
 *  to read the 16-Bit data-bus from the AD-7723 external Analog-Digital-Converter.
 *  The 16-Bit value is then saved in variable.
 * \param takes no argument
 * \param takes no argument
 * \return nothing, saves the value in ADC_data
 */

static inline void get_ADC_data(void){

    while((L_AD_7723_N1_CLKIN_sig_PIN & (1 << L_AD_7723_N1_DRDY_lock )) == 1){

            ADC_lowbyte = L_L_AD_7723_N1_PIN;
            ADC_highbyte = L_H_AD_7723_N1_PIN;
            ADC_data = ADC_lowbyte | (ADC_highbyte << 8);
          }
}

    sorry for this long post, but looks like there is no other way.

 

work in progress...

Last Edited: Tue. Oct 23, 2018 - 11:05 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That wait loop is still confusing you, I see. Fortunately, avr-libc has a ready made macro for this kind of situations.

So replace this:

while((L_AD_7723_N1_CLKIN_sig_PIN & (1 << L_AD_7723_N1_DRDY_lock )) == 1){

            ADC_lowbyte = L_L_AD_7723_N1_PIN;
            ADC_highbyte = L_H_AD_7723_N1_PIN;
            ADC_data = ADC_lowbyte | (ADC_highbyte << 8);
          }

with this:

loop_until_bit_is_clear(L_AD_7723_N1_CLKIN_sig_PIN, L_AD_7723_N1_DRDY_lock);
ADC_lowbyte = L_L_AD_7723_N1_PIN;
ADC_highbyte = L_H_AD_7723_N1_PIN;
ADC_data = ADC_lowbyte | (ADC_highbyte << 8);

 

edit: and what about ADC pins RD and CS? The datasheet says they need to be low for reading parallel data.

Last Edited: Tue. Oct 23, 2018 - 11:56 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
 while((L_AD_7723_N1_CLKIN_sig_PIN & (1 << L_AD_7723_N1_DRDY_lock )) == 1){

will never be true.

 

drdy_lock is PB5 which is 0x20. Thus the result of the AND will either be 0 or 0x20, but never 1. Remove the ==1 and the IF will test for 0 or not zero.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

just a question on the schematic....

 

 

What will happen if the left amp has a bit higher gain than in your ideal world, and the right one has a slightly lower gain than in you ideal world?

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, I don't understand why so many amplifiers are used. You are supposed to reference the thermocouple negative wire to ground with a high value resistor:

Since the negative input will be at GND, the instrumentation amplifier can do all the amplification by itself, it doesn't need a differential step.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

RD and CS are tied >> LOW<< so that the data interface is always outputting.

static inline void get_ADC_data(void){

    if((L_AD_7723_N1_CLKIN_sig_PIN & (1 << L_AD_7723_N1_DRDY_lock ))){

            ADC_lowbyte = L_L_AD_7723_N1_PIN;
            ADC_highbyte = L_H_AD_7723_N1_PIN;
            ADC_data = ADC_lowbyte | (ADC_highbyte << 8);
          }
}

so this is rewritten with all the comments taken into account. We test if the mentioned  "L_AD_7723_N1_DRDY_lock" bit is cleared?, and if it is then code in brackets is executed. 

(ADC_highbyte << 8);

this left shift is done for getting rid of padding=?  and transform the variable to 8 bit?

 

Also there is an issue with AVR (ATmega 2560), I do not have a TQFP to DIP adapter here in my lab. to melt it down into something usable. But on the other hand I found another brand new AVR which is ATmega644 device and it is in DIP package. 

So as far as it runs at 16-20 MHz, and has enough pins, it doesn't really matter whether it is ATmega 2560 or ATmega644 right=?, so can I use the ATmega644 instead?

 

this one for me would be much easy to setup, then the TQFP cpu soldering and stuff.

 

 

work in progress...

Last Edited: Thu. Oct 25, 2018 - 10:08 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In my ideal world ^_^). gain is set via the first OP-amp in signal chain. But I am using a separate high-precision  power supply with reference for output for analog circuitry. If that makes sense, although I see some stuff which would like to discuss here.

 

work in progress...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
    if((L_AD_7723_N1_CLKIN_sig_PIN & (1 << L_AD_7723_N1_DRDY_lock ))){

            ADC_lowbyte = L_L_AD_7723_N1_PIN;
            ADC_highbyte = L_H_AD_7723_N1_PIN;
            ADC_data = ADC_lowbyte | (ADC_highbyte << 8);
          }

This in not what you want. This code will read ADC data if L_AD_7723_N1_DRDY_lock happens, by mere chance, to be  >>HIGH<< when the function is called.

 

First mistake: DRDY is active low. So, you want to read data when it's zero, not one.

 

Second mistake: When you call the data reading function, DRDY can be in any state, you don't know. If it's >>HIGH<<, you can't read data yet. You need to wait until DRDY goes >>LOW<<.

An "if" statement doesn't wait, so you need a wait loop like this:

    while((L_AD_7723_N1_CLKIN_sig_PIN & (1 << L_AD_7723_N1_DRDY_lock ))){
        // just wait here, doing nothing, while DRDY is >>HIGH<< (data not available)
    }
    // DRDY has gone >>LOW<<, exiting the wait loop
    // Now we can read valid data
    ADC_lowbyte = L_L_AD_7723_N1_PIN;
    ADC_highbyte = L_H_AD_7723_N1_PIN;
    ADC_data = ADC_lowbyte | (ADC_highbyte << 8);

 

Another way is to connect the DRDY pin to an external interrupt of the AVR. Normally, AVRs have 2 types of externally triggered interrupts, the basic one is the "pin change interrupt" that triggers on any change. You don't want this here, you want to interrupt only on falling edges of DRDY. The advanced ones are called "external interrupt" (rather unfortunately, as "pin change" are also external interrupts...) and can be programmed to trigger only on the falling edge.

In this case, you write an ISR (interrupt service routine) instead of the get_ADC_data() function. This is a function that is called automatically when the interrupt condition is met, asynchronously from the main program.

It will update the ADC data constantly without the main program being aware. This means the "ADC_data" variable would have to be made volatile, and also read atomically.

 

 

Finally, the most difficult and possibly most optimized way would be to take advantage of the fact that you are clocking the ADC from the MCU. This means they are synchronized, so in principle, you know exactly when is the right time to read data. You could trigger an interrupt right before DRDY would go low, to hide ISR latency. I'm not even sure it could be done in C, it would require quite a lot of skill and perfect synchronization easier to achieve in assemblyfrown

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

let me try the already discussed option with function call  "get_ADC_data()" just to see if everything works, later on, I will write a code to use the hardware interrupts as you mentioned. 

From datasheet on AVR which is ATmega-644P, it's max clock speed is 20 Mhz, I have here an external crystal which is 22.3 Mhz something....., would it be fine if I use this oscillator or it has to be exactly 20Mhz=? and which capacitor options would be wise to connect with it=?

 

work in progress...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My experiments with random crystals show that it will probably work... the capacitors, probably something in the 6-20 pF range will do.

Sometimes the crystal will lock to a sub-harmonic, I have somewhere a 27MHz crystal that tends to lock to 1/3 frequency (9Mhz) when I put it on an AVR.

 

But in your final product, if this is not just for educational purposes, you should use a proper recommended crystal!