Library AD5933 - Calibrate function Problem

Dear all,

We would like to make impedance measurements using the ad5933 chip. I downloaded a library "arduino-ad5933-master" by mjmeli.

We would like to make a small change though to the function to adapt it to our needs. We want to link the calibration to one button and the measurement to another.

So we entered the calibration code in the loop (using an “if loop“) linked to the state of the first button.

To carry out the measurement with the functions FrequencySweepEasy and FrequancySweepRaw, we used another “if loop” in the loop (sorry for this play on words) connected to the state of the second button. Up to here everything works!!

Since we need to display an average of the measurements of impedance we make, we tried to modify one of the two functions (FrequencySweepEasy) by making it return a value.

The code compiles but stops at the calibration step! Even if the measurement continues to be made. Obviously the impedance values ​​are infinite because the calibration has not been performed. Someone could tell me why?

Any help would be much appreciated.

Regards,

Stefania

Welcome to the forum.

Can you provide more information ? Links to the chip, the sketch, photo's, schematics, links to used modules, which Arduino board do you use, and so on.

Put a sketch between code-tags. Use the </> button or put the sketch between lines with three backslash-single-quotes.

```
Your sketch
```

Manufacturer page of the AD5933: https://www.analog.com/en/products/ad5933.html with datasheet.

It is a 12-bit Impedance Converter, Network Analyzer with I2C interface and it runs at 2.7 V to 5.5 V.

arduino-ad5933 by mjmeli: https://github.com/mjmeli/arduino-ad5933.

I think the code of the library is okay, but I can spot a few weak points.

Hi Koepel,

Thank you very much for your timely help!!

I studied the datasheet of the chip AD5933 from the AnalogDevice site. The link of the library is the one reported by you!
I am using an arduino UNO and AD5933 (plus two buttons and two LEDs) .
Below I report the modified sketch:

/*ad5933-test     Reads impedance values from the AD5933 over I2C and prints them serially.*/

#include <Wire.h>
#include "AD5933.h"

#define START_FREQ  (80000)
#define FREQ_INCR   (1000)
#define NUM_INCR    (40)
#define REF_RESIST  (10000) 

int a = 0; 

double gain[NUM_INCR+1];
int phase[NUM_INCR+1];


#include <LiquidCrystal_I2C.h>

#define LED_PIN 3

LiquidCrystal_I2C lcd(0x27, 20, 4); 

int ledPin1 = 9;  //LED Red
int ledPin2 = 10;  //LED Green
int ledStato1 = LOW;
int ledStato2 = LOW;

int pulsantePin1 = 11; //calibration button
int pulsantePin2 = 12; //measurement button

int pulsanteStato1 = LOW;
int pulsanteStato2 = LOW;

String riga1 = " Benvenuto, sono il ";
String riga2 = " tuo lettore TEER!";

String comandi[] = {"  ", "  Inserisci il   ", " bioreattore sulla ", " stazione di misura.", "   ", "    Premi 1   ","   per  calibrare", "    la TEER!",
                    "    ", "  Dopo premi 2  "," per  effettuare "," una nuova misura!"
                    };
                    
double valori[NUM_INCR+1]  ; 
double somma = 0;
float media; 
void setup(void)
{
       
      lcd.init(); 
  lcd.backlight(); 
  pinMode(LED_PIN, OUTPUT); 
  analogWrite(LED_PIN, 50);
 
  //SCRITTA DI BENVENUTO
      lcd.clear();
      lcd.setCursor(0, 0); 
      lcd.print(riga1); 
      lcd.setCursor(0, 2); 
      lcd.print(riga2); 
   
    delay(100);

      pinMode (ledPin1, OUTPUT);
      pinMode (ledPin2, OUTPUT);
      pinMode (pulsantePin1, INPUT);
      pinMode (pulsantePin2, INPUT);
      digitalWrite(ledPin1, ledStato1);
      digitalWrite(ledPin2, ledStato2);

//INIZIALIZZAZIONE DI AD5933 

 // Begin I2C
  Wire.begin();

  // Begin serial at 9600 baud for output
  Serial.begin(9600);
  Serial.println("AD5933 Test Started!");

  // Perform initial configuration. Fail if any one of these fail.
  if (!(AD5933::reset() &&
        AD5933::setInternalClock(true) &&
        AD5933::setStartFrequency(START_FREQ) &&
        AD5933::setIncrementFrequency(FREQ_INCR) &&
        AD5933::setNumberIncrements(NUM_INCR) &&
        AD5933::setPGAGain(PGA_GAIN_X1)))
        {
            Serial.println("FAILED in initialization!"); 
            digitalWrite (ledPin1, HIGH);   //led rosso ACCESO
            while (true) ; // led rosso che si accende
        }
        else {
          Serial.println("Initialization ok!");
          digitalWrite (ledPin2, HIGH);  //led verde ACCESO
          a =! a; //inverto il valore di a
          lcd.clear();
          lcd.setCursor(0, 2); 
          lcd.print(" Inizializzazione ok  ");
          delay(100);
          }
           lcd.clear();
           delay(100);
           
//SCRITTURA DI INIZIO SUL LCD
if (a == 1){
  
          for ( int c = 0; c <3; c++){
                        
              for (int i = 0 ; i < 4; i ++) {
                          
                   lcd.setCursor(0, i); 
                   lcd.print(comandi[i+c*4]);
                    delay(1000);
                   }           
                   lcd.clear();
              }   
       a =! a;
       digitalWrite(ledPin2, LOW);  //led verde SPENTO
  
      }
}
void loop()
{
//PRIMO PULSANTE - PULSANTE DI CALIBRAZIONE
   pulsanteStato1 = digitalRead(pulsantePin1);
Serial.print(digitalRead(pulsantePin1));
     if (pulsanteStato1 == HIGH){

        // Perform calibration sweep - 
   if (AD5933::calibrate(gain, phase, REF_RESIST, NUM_INCR+1)) {
                Serial.println("Calibrated!");

        
                 lcd.clear();
                 lcd.setCursor(0, 2); 
                 lcd.print("Calibrazione ok!"); 
                 }
            else{
               Serial.println("Calibration failed...");
                
                 lcd.clear();
                 lcd.setCursor(0, 1); 
                 lcd.print("Calibrazione Failed!");
              } 
    
    }     
    delay(100);
    

       //PULSANTE 2 - MISURA
      pulsanteStato2 = digitalRead(pulsantePin2);

     if (pulsanteStato2 == HIGH){
                     
                   lcd.clear();       
                   lcd.setCursor(0, 1); 
                   lcd.print("Sto eseguendo misura");
                    delay(1000);
        
              Stefy(valori);
   
                    delay(5000);
                    
                  //lcd.print(somma);
                  media = somma / NUM_INCR+1;
           
                   lcd.clear();       
                   lcd.setCursor(0, 2); 
                   lcd.print("La misura è:");
                   lcd.setCursor(0, 3);
                   lcd.print(media);


           // inizio funzione raw
                   lcd.clear();       
                   lcd.setCursor(0, 1); 
                   lcd.print("Sto eseguendo misuraE");
                    delay(1000);
        
               frequencySweepRaw();
               
                   lcd.clear();       
                   lcd.setCursor(0, 3); 
                   lcd.print("La misura è:");
                   //lcd.print(media);
                    delay(5000);
              }           
        
  delay(100);    
}



// Easy way to do a frequency sweep. Does an entire frequency sweep at once and
// stores the data into arrays for processing afterwards. This is easy-to-use,
// but doesn't allow you to process data in real time.
void frequencySweepEasy( ) { //DOUBLE
    // Create arrays to hold the data
    int real[NUM_INCR+1], imag[NUM_INCR+1];

    // Perform the frequency sweep
    if (AD5933::frequencySweep(real, imag, NUM_INCR+1)) {
      // Print the frequency data
      int cfreq = START_FREQ/1000;

      for (int i = 0; i < NUM_INCR+1; i++, cfreq += FREQ_INCR/1000) { 
        // Print raw frequency data
        Serial.print(cfreq);
        Serial.print(": R=");
        Serial.print(real[i]);
        Serial.print("/I="); 
        Serial.print(imag[i]); 

        // Compute impedance 
        double magnitude = sqrt(pow(real[i], 2) + pow(imag[i], 2));
     
        double impedance = 1/(magnitude*gain[i]);
        Serial.print("  |Z|=");
        Serial.println(impedance);     
      }
      Serial.println("Frequency sweep complete!"); 
          
    } else {
      Serial.println("Frequency sweep failed...");
    }
}

//NUOVA FUNZIONE
void Stefy( double valori[] ) { 
    // Create arrays to hold the data
    int real[NUM_INCR+1], imag[NUM_INCR+1];
          
    // Perform the frequency sweep
    if (AD5933::frequencySweep(real, imag, NUM_INCR+1)) {
      // Print the frequency data
      int cfreq = START_FREQ/1000;

      for (int i = 0; i < NUM_INCR+1; i++, cfreq += FREQ_INCR/1000) { 
        // Print raw frequency data
        Serial.print(cfreq);
        Serial.print(": R=");
        Serial.print(real[i]);
        Serial.print("/I="); 
        Serial.print(imag[i]); 

        // Compute impedance 
        double magnitude = sqrt(pow(real[i], 2) + pow(imag[i], 2));
      
        double impedance = 1/(magnitude*gain[i]);
        Serial.print("  |Z|=");
        Serial.println(impedance);

                    valori [i] = impedance;
                    somma = somma + valori[i];
   
      }
      Serial.println("Frequency sweep complete!"); 
      //return somma;        
          
    } else {
      Serial.println("Frequency sweep failed...");
    }
}




// Removes the frequencySweep abstraction from above. This saves memory and
// allows for data to be processed in real time. However, it's more complex.
void frequencySweepRaw() {
    // Create variables to hold the impedance data and track frequency
    int real, imag, i = 0, cfreq = START_FREQ/1000;

    // Initialize the frequency sweep
    if (!(AD5933::setPowerMode(POWER_STANDBY) &&          // place in standby
          AD5933::setControlMode(CTRL_INIT_START_FREQ) && // init start freq
          AD5933::setControlMode(CTRL_START_FREQ_SWEEP))) // begin frequency sweep
         {
             Serial.println("Could not initialize frequency sweep...");
         }

    // Perform the actual sweep
    while ((AD5933::readStatusRegister() & STATUS_SWEEP_DONE) != STATUS_SWEEP_DONE) {
        // Get the frequency data for this frequency point
        if (!AD5933::getComplexData(&real, &imag)) {
            Serial.println("Could not get raw frequency data...");
        }

        // Print out the frequency data
        Serial.print(cfreq);
        Serial.print(": R=");
        Serial.print(real);
        Serial.print("/I=");
        Serial.print(imag);

        // Compute impedance
        double magnitude = sqrt(pow(real, 2) + pow(imag, 2));
        double impedance = 1/(magnitude*gain[i]);
        Serial.print("  |Z|=");
        Serial.println(impedance);

        // Increment the frequency
        i++;
        cfreq += FREQ_INCR/1000;
        AD5933::setControlMode(CTRL_INCREMENT_FREQ);
    }

    Serial.println("Frequency sweep complete!");

    // Set AD5933 power mode to standby when finished
    if (!AD5933::setPowerMode(POWER_STANDBY))
        Serial.println("Could not set to standby...");
}

(1)

The global variable is called "valori" and the parameter is also called "valori":

double valori[NUM_INCR + 1];
void Stefy(double valori[])

Can you give one of them an other name ? Then the compiler knows which one to use.

(2)

Have you changed the file "AD5933.cpp" to remove #include <Math.h> ?
I got a warning so I removed it.

(3)

The compiler about the SRAM usage:

Global variables use 1476 bytes (72%) of dynamic memory, leaving 572 bytes for local variables. Maximum is 2048 bytes.

I think it should be okay, but I'm not sure.

Could you make normal text string for the text and print them in a normal way ?

const char *comandi[3][4] =
{
  { 
    "  ", 
    "  Inserisci il   ", 
    " bioreattore sulla ", 
    " stazione di misura.", 
  },
  {    
    "   ", 
    "    Premi 1   ", 
    "   per  calibrare", 
    "    la TEER!",
  },
  {
    "    ", 
    "  Dopo premi 2  ", 
    " per  effettuare ", 
    " una nuova misura!"
  }
};

In the for-loop, you get this:

      for (int i = 0 ; i < 4; i ++)
      {
        lcd.setCursor(0, i);
        lcd.print(comandi[c][i]);    // <-----------
        delay(1000);

Please turn riga1 and riga2 into normal texts as well:

char *riga1 = " Benvenuto, sono il ";
char *riga2 = " tuo lettore TEER!";

The F() macro reduces the usage of SRAM.
Use them only for the 'Serial' port and not for the 'lcd' display. Some LCD libraries do not support the F() macro.

Serial.println(F("AD5933 Test Started!"));
Serial.println(F("Initialization ok!"));
Serial.println(F("Calibrated!"));
and so on

Then I get:

Global variables use 1144 bytes (55%) of dynamic memory

Try if you can match that.

(4)

In the Arduino IDE (not the beta version), press Ctrl+T
Then put every indent, every comma, every space correct. Use the same style throughout the whole sketch.

(5)

Do you know what variable "a" is doing ? I don't.

(6)

You were not supposed to split the sketch into three parts for this forum. Put the whole sketch between code tags.

```
The whole sketch
```

(7)

I give it 40% chance that the memory usage was the problem. If the problem is not gone, can you show the output of the Serial Monitor, to check where it stopped.

(8)

Is everything powered with 5V ? Both the display and the AD5933 ?

Hi Koepel,

Thank you very much for your timely help again!! I try to answer your points…

(1)

I change the global variable "valori" and the parameter "valori" with two different names!

(2)

I haven’t changed the file "AD5933.cpp" to remove #include <Math.h> because it didn't ask me to.

(3)

I really think it was a problem of SRAM usage. I modified the controls according to your suggestions.

(4)

I inserted proper IDE formatting

(5)

the variable "a" is used to retrieve the string “comandi” only if the initialization was successful. Do you think there could be a better way?

(6)

Sorry if I divided the sketch into three parts, but I'm a beginner and I couldn't load it all in full

(8)

Yes, everything is powered with 5V ( Both the display and the AD5933)

Thanks again very much!!

Stefania

(4)

Do you dare to show the new sketch :wink:

(5)

This will stop the sketch when the initialization was wrong: while (true) ;
That means that the variable "a" has no use.
If you want a variable to tell if the initialization was okay, then give it a good name: "initSuccess" or something like that.

You could even make it a bool variable. A bool variable can be used on its own as a condition of a if-statement.

bool initSuccess;

if ( ...)
  initSuccess = true;
else
  initSuccess = false;

if (initSuccess)        // <--- check a 'bool' variable
{
  ...
}

(8)

Good. Then there is no voltage conflict on the I2C bus.

The I2C bus needs pullup resistors. I suppose that the display has already pullup resistors. If you use short wires (don't use flat ribbon cable) then it is okay. You might have to add extra pullup resistors.

The while loop doesn't convince me too much. I changed for the variable name "a" to following your suggestion. This is the sketch:

/*
ad5933-test- Reads impedance values from the AD5933 over I2C and prints them serially.
*/

#include <Wire.h>
#include "AD5933.h"

#define START_FREQ  (80000)
#define FREQ_INCR   (1000)
#define NUM_INCR    (40)
#define REF_RESIST  (10000) //resistenza di calibrazione inserita 10kOhm

double gain[NUM_INCR+1];
int phase[NUM_INCR+1];

int initSuccess = 0; 

#include <LiquidCrystal_I2C.h>

#define LED_PIN 3

LiquidCrystal_I2C lcd(0x27, 20, 4); 

int ledPin1 = 9; //LED ROSSO
int ledPin2 = 10; //LE VERDE
int ledStato1 = LOW;
int ledStato2 = LOW;

int pulsantePin1 = 11; //calibration button
int pulsantePin2 = 12; //measurement button

int pulsanteStato1 = LOW;
int pulsanteStato2 = LOW;

String riga1 = " Benvenuto, sono il ";
String riga2 = " tuo lettore TEER!";

const char *comandi[3][4] =
{
  { 
     "  Inserisci il   ", 
    " bioreattore sulla ", 
    " stazione di misura.", 
    "    "
  },
  {    
    "    Premi 1   ", 
    "    per  calibrare", 
    "    la TEER!",
    "   "
  },
  {
    
    "    Dopo premi 2  ", 
    "    per  effettuare ", 
    "    una misura!",
    "    "
  }
};

double valori[NUM_INCR + 1]  ; 
double somma = 0;
float media; 

//fine inizializzione schermo e pulsanti

void setup(void)
{
      
  lcd.init(); 
  lcd.backlight(); 
  pinMode(LED_PIN, OUTPUT); 
  analogWrite(LED_PIN, 50);
 
      lcd.clear();
      lcd.setCursor(0, 0); 
      lcd.print(riga1);
      lcd.setCursor(0, 2); 
      lcd.print(riga2); 
   
    delay(2000);

      pinMode (ledPin1, OUTPUT);
      pinMode (ledPin2, OUTPUT);
      pinMode (pulsantePin1, INPUT);
      pinMode (pulsantePin2, INPUT);
      digitalWrite(ledPin1, ledStato1);
      digitalWrite(ledPin2, ledStato2);

 // Begin I2C
  Wire.begin();

  // Begin serial at 9600 baud for output
  Serial.begin(9600);
  Serial.println("AD5933 Test Started!");

  // Perform initial configuration. Fail if any one of these fail.
  if (!(AD5933::reset() &&
        AD5933::setInternalClock(true) &&
        AD5933::setStartFrequency(START_FREQ) &&
        AD5933::setIncrementFrequency(FREQ_INCR) &&
        AD5933::setNumberIncrements(NUM_INCR) &&
        AD5933::setPGAGain(PGA_GAIN_X1)))
        {
            Serial.println("FAILED in initialization!"); 
            digitalWrite (ledPin1, HIGH);   
            while (true) ; // led rosso che si accende
        }
        else {
          Serial.println(F("Initialization ok!"));
          digitalWrite (ledPin2, HIGH); 
          
          initSuccess =! initSuccess;
          lcd.clear();
          lcd.setCursor(0, 1); 
          lcd.print(" Inizializzazione ok  ");
          delay(2000);
          }
           lcd.clear();
           delay(100);
           
//SCRITTURA DI INIZIO SUL Lcd
if (initSuccess == 1){
  
          for ( int c = 0; c <3; c++){
                        
              for (int i = 0 ; i < 4; i ++) {
                          
                   lcd.setCursor(0, i);
                   lcd.print(comandi[c][i]);
                    delay(1000);
                   }           
                   lcd.clear();
              }   
       initSuccess =! initSuccess;
       
       digitalWrite(ledPin2, LOW);  
      }
                 
                   lcd.setCursor(0, 1);
                   lcd.print("  #1  Calibrazione");
                   lcd.setCursor(0, 2);
                   lcd.print("   #2  Misura");
                   
      
}

void loop()
{

   pulsanteStato1 = digitalRead(pulsantePin1);

     if (pulsanteStato1 == HIGH){

        // Perform calibration sweep - 
   if (AD5933::calibrate(gain, phase, REF_RESIST, NUM_INCR+1)){ 
                Serial.println(F("Calibrated!"));
        //SCRIVO ANCHE SULLO SCHERMO
                 lcd.clear();
                 lcd.setCursor(0, 1); 
                 lcd.print("  Calibrazione ok!"); 
                 }
            else{
               Serial.println(F("Calibration failed..."));
                 //SCRIVO ANCHE SULLO SCHERMO
                 lcd.clear();
                 lcd.setCursor(0, 1); 
                 lcd.print("Calibrazione Failed!");
              }
               delay(2000);
               lcd.clear();
               lcd.setCursor(0, 1);
               lcd.print("  #1  Calibrazione");
               lcd.setCursor(0, 2);
               lcd.print("   #2  Misura"); 
    
    }     
    delay(100);
        
      pulsanteStato2 = digitalRead(pulsantePin2);

     if (pulsanteStato2 == HIGH){
                     
                   lcd.clear();       
                   lcd.setCursor(0, 1); 
                   lcd.print("   Sto eseguendo ");
                   lcd.setCursor(0, 2); 
                   lcd.print("   la misura..");
                    delay(1000);
        
              frequencySweepRaw(valori);
                  
                   delay(5000);
                    
                   media = somma / (NUM_INCR+1);
                   Serial.println(media);
           
                   lcd.clear();       
                   lcd.setCursor(0, 1); 
                   lcd.print("  La misura e':");
                   lcd.setCursor(0, 2); 
                   lcd.print("    ");
                   lcd.print(media);


               delay(2000);
               lcd.setCursor(0, 1);
               lcd.print("  #1  Calibrazione");
               lcd.setCursor(0, 2);
               lcd.print("  #2  Misura"); 

                   
              }           
               
  delay(100);    
}


// Removes the frequencySweep abstraction from above. This saves memory and
// allows for data to be processed in real time. However, it's more complex.
void frequencySweepRaw( double val[] ) {
    // Create variables to hold the impedance data and track frequency
    int real, imag, i = 0, cfreq = START_FREQ/1000;

    // Initialize the frequency sweep
    if (!(AD5933::setPowerMode(POWER_STANDBY) &&          // place in standby
          AD5933::setControlMode(CTRL_INIT_START_FREQ) && // init start freq
          AD5933::setControlMode(CTRL_START_FREQ_SWEEP))) // begin frequency sweep
         {
             Serial.println("Could not initialize frequency sweep...");
         }

    // Perform the actual sweep
    while ((AD5933::readStatusRegister() & STATUS_SWEEP_DONE) != STATUS_SWEEP_DONE) {
        // Get the frequency data for this frequency point
        if (!AD5933::getComplexData(&real, &imag)) {
            Serial.println("Could not get raw frequency data...");
        }

        // Print out the frequency data
        Serial.print(cfreq);
        Serial.print(": R=");
        Serial.print(real);
        Serial.print("/I=");
        Serial.print(imag);

        // Compute impedance
        double magnitude = sqrt(pow(real, 2) + pow(imag, 2));
        double impedance = 1/(magnitude*gain[i]);
        Serial.print("  |Z|=");
        Serial.println(impedance);
                    
                    valori [i] = impedance;
                    somma = somma + valori[i];

        // Increment the frequency
        i++;
        cfreq += FREQ_INCR/1000;
        AD5933::setControlMode(CTRL_INCREMENT_FREQ);
    }

    Serial.println("Frequency sweep complete!");

    // Set AD5933 power mode to standby when finished
    if (!AD5933::setPowerMode(POWER_STANDBY))
        Serial.println("Could not set to standby...");
}

You did not press Ctrl+T in the Arduino IDE 1.8.15 (it might work in the newest Beta version as well).
Please do that and then fix all the indents, put every space, every comma, every empty line at the right place, and use the same style for the text throughout the whole sketch.
You don't have to do that for me, but for yourself.
When the code is looking good, the structure of the code can be seen at the first glance.

The example sketch was just an demonstration. You might have to make changes.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.