Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Read 4 channel asynchronous #24

Closed
Mplex72 opened this issue Jul 1, 2021 · 88 comments
Closed

Read 4 channel asynchronous #24

Mplex72 opened this issue Jul 1, 2021 · 88 comments
Assignees
Labels
question Further information is requested

Comments

@Mplex72
Copy link

Mplex72 commented Jul 1, 2021

Hi ,

How can I read 4 channels asynchronus ?
The problem is the readout for each value see line below ;

 int16_t value = ADS.getValue(i); 

and gives the following error ; "invalid types 'int16_t {aka int}[int]' "

I have the followiing sketch to test ;

//

#include "ADS1X15.h"

ADS1115 ADS(0x48);
float f = 0;

void setup()
{
  Serial.begin(115200);
  Serial.println(__FILE__);
  Serial.print("ADS1X15_LIB_VERSION: ");
  Serial.println(ADS1X15_LIB_VERSION);

  ADS.begin();
  ADS.setGain(0);
  f = ADS.toVoltage();      // voltage factor
  ADS.requestADC(0);
}

void loop()
{
  if (ADS.isBusy() == false)
  {
    for (int i = 0; i < 4; i++) {
      int16_t value = ADS.getValue(i);
      ADS.requestADC(i);  // request a new one
      Serial.print("\tAnalog0: ");
      Serial.print(value[i]);
      Serial.print('\t');
      Serial.println(value[i] * f, 3);
    }
  }
  // simulate other tasks...
  delay(2000);
}

// -- END OF FILE --

Klass

@RobTillaart
Copy link
Owner

Hi Klass,

which platform do you use?
which version of the library?

Think you must remove the parameter i from the next line.

 int16_t value = ADS.getValue();

@Mplex72
Copy link
Author

Mplex72 commented Jul 1, 2021

Hi Rob,

I,m using Arduino 1.8.15 and your lastest ADS1115 lib
Compile for arduino Pro mini.

Now it,s accepted in the compiler ,

The question is now ;
I suppose it will get data blocks with the 4 data values the correct order ,but have to test it now.

first i = (value1) for the first channel to
fourth i = ((value4)) for the fourth channel

and also at the correct timing (all 4 within 3 millis would be good enough)

Regards,
Klass


`//

#include "ADS1X15.h"

int16_t value[4] = { 0, 0, 0, 0 };

ADS1115 ADS(0x48);
float f = 0;

void setup()
{
Serial.begin(115200);
Serial.println(FILE);
Serial.print("ADS1X15_LIB_VERSION: ");
Serial.println(ADS1X15_LIB_VERSION);

ADS.begin();
ADS.setGain(0);
f = ADS.toVoltage(); // voltage factor
ADS.requestADC(0);
}

void loop()
{
if (ADS.isBusy() == false)
{
for (int i = 0; i < 4; i++) {
value[i] = ADS.getValue();
ADS.requestADC(i); // request a new one
Serial.print("\tAnalog0: ");
Serial.print(value[i]);
Serial.print('\t');
Serial.println(value[i] * f, 3);
}
}
// simulate other tasks...
delay(500);
}

// -- END OF FILE --`

@RobTillaart
Copy link
Owner

array indices are counted from 0 to n-1 in C/C++ so in this program from 0..3

int16_t value[4] will have value[0] for the first channel, ... value[3] for the fourth channel

The async methods are implemented because reading an ADC sensor takes substantial time (read datasheet for details.
To understand the proper usage you should have a look at

https://github.com/RobTillaart/ADS1X15/blob/master/examples/ADS_continuous_4_channel/ADS_continuous_4_channel.ino
which shows how to read 4 channels as fast as possible .

Your example does request a next sample before it even checks if ADS.isBusy() == false
that must be done after every request

@RobTillaart RobTillaart self-assigned this Jul 2, 2021
@RobTillaart RobTillaart added the question Further information is requested label Jul 2, 2021
@Mplex72
Copy link
Author

Mplex72 commented Jul 2, 2021

Have changed the sketch quite a bit,
How can I get the sketch to read the four channels as fast as possible and THEN wait a second ?
now it waits a second after each sample.

//

#include "ADS1X15.h"

ADS1115 ADS(0x48);
float f = 0;
uint8_t channel = 0;
int16_t val[4] = { 0, 0, 0, 0 };

void setup()
{
  Serial.begin(115200);
  Serial.println(__FILE__);
  Serial.print("ADS1X15_LIB_VERSION: ");
  Serial.println(ADS1X15_LIB_VERSION);

  ADS.begin();
  ADS.setGain(0);
  ADS.setDataRate(3);
  f = ADS.toVoltage();      // voltage factor

  for (int i = 0; i < 4; i++)
  {
    ADS.requestADC(i);
  }
}

void loop()
{
//  handleConversion();
{
  for (int i = 0; i < 4; i++)
  {
    Serial.print(val[i]);
    Serial.print('\t');
    handleConversion();
  }
  Serial.println();
}
  delay(1000);
}



void handleConversion()
{
  if (ADS.isBusy() == false)
  {
    // save the value
    val[channel] = ADS.getValue();
    // request next channel
    channel++;
    if (channel >= 4) channel = 0;
    ADS.requestADC(channel);
  }
}



// -- END OF FILE --

@RobTillaart
Copy link
Owner

I updated your code tags so the code syntax is highlighted. (edit your post to see how it is done)

If you just want to read 4 channels and then wait for a second you do not need async calls.

something like this should be sufficient, (not tested)

#include "ADS1X15.h"

ADS1115 ADS(0x48);
float f = 0;
uint8_t channel = 0;
int16_t val[4] = { 0, 0, 0, 0 };

uint32_t lastTime = 0, now = 0;

void setup()
{
  Serial.begin(115200);
  Serial.println(__FILE__);
  Serial.print("ADS1X15_LIB_VERSION: ");
  Serial.println(ADS1X15_LIB_VERSION);

  ADS.begin();
  ADS.setGain(0);
  ADS.setDataRate(3);
  f = ADS.toVoltage();      // voltage factor
}


void loop()
{
  now = millis();
  if (now - lastTime >= 1000)
  {
    lastTime = now;
    for (int i = 0; i < 4; i++)
    {
      val[i] = ADS.readADC(i);
      Serial.print('\t');
      Serial.print(val[i]);
    }
    Serial.println();
  }


}

@RobTillaart
Copy link
Owner

Solved?

@Mplex72
Copy link
Author

Mplex72 commented Jul 5, 2021

I,m still strugling to get 4 channels properly working .
It looked so nice to let the adc1115 do his job at the background while the arduino is processing other sensors data.

I think I have to go back to the continues reading option and close this .
Thanks for the thelp
Klass

@RobTillaart
Copy link
Owner

If you can post your complete sketch I can have a quick look how to maximize throughput.

Which platform do you use?

@Mplex72
Copy link
Author

Mplex72 commented Jul 5, 2021

Hi ,
I use Arduino Pro Mini with CANbus but I can upgrade to Teensy
The following sketch uses 2 ADC units.
target is to use 4 modules and output 16 channels at 100hz but the code seems not fast enough.
I use a small capacitor over the analog inputs to smooth it a bit.
would prefer software averaging but that gives a lot more overhead.
I suppose the 128Hz speed on the adc is enough for this setup ?

#include "ADS1X15.h"
#include <elapsedMillis.h>

#include <mcp_can.h>
#include <SPI.h>

elapsedMillis ADSmillis1;

MCP_CAN CAN0(10);     // Set CS to pin 10

ADS1115 ADS0(0x48);
ADS1115 ADS1(0x49);


uint8_t channel = 0;
int16_t val[4] = { 0, 0, 0, 0 };

uint32_t lastTime = 0, now = 0;

void ADS0_read() {
  byte stmp[8] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};

  for (int i = 0; i < 4; i++)
  {
    val[i] = (ADS0.readADC(i) * 0.1875);
    Serial.print('\t');
    Serial.print(val[i]);
    stmp[ i * 2] = val[i] / 256;
    stmp[ i * 2 + 1] = val[i] % 256;
    // send data:  id = 0x70, standard frame, data len = 8, stmp: data buf
    CAN0.sendMsgBuf(0x70, 0, 8, stmp);
  }
  Serial.println();
}

void ADS1_read() {
  byte stmp[8] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};

  for (int i = 0; i < 4; i++)
  {
    val[i] = (ADS1.readADC(i) * 0.1875);
    Serial.print('\t');
    Serial.print(val[i]);
    stmp[ i * 2] = val[i] / 256;
    stmp[ i * 2 + 1] = val[i] % 256;
    // send data:  id = 0x70, standard frame, data len = 8, stmp: data buf
    CAN0.sendMsgBuf(0x71, 0, 8, stmp);
  }
  Serial.println();
}

void setup()
{
  Serial.begin(115200);
  Serial.println(__FILE__);
  Serial.print("ADS1X15_LIB_VERSION: ");
  Serial.println(ADS1X15_LIB_VERSION);

  // Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.
  if (CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_16MHZ) == CAN_OK) Serial.println("MCP2515 Initialized Successfully!");
  else Serial.println("Error Initializing MCP2515...");

  CAN0.setMode(MCP_NORMAL);   // Change to normal mode to allow messages to be transmitted


  ADS0.begin();
  ADS0.setGain(0);
  ADS0.setDataRate(4);

  ADS1.begin();
  ADS1.setGain(0);
  ADS1.setDataRate(4);
}


void loop()
{
  if (ADSmillis1 >= 1000)
  {
    ADS0_read();
  }
  if (ADSmillis1 >= 1100)
  {
    ADS1_read();
    ADSmillis1 = ADSmillis1 - 200;
  }
}

@RobTillaart
Copy link
Owner

Saw the code, I'll look at it tonight

@RobTillaart
Copy link
Owner

RobTillaart commented Jul 5, 2021

have a look at this (could not compile as I do not have all libraries.

what I did is read the ADS channels in pairs / parrallel
if all pairs are collected, I print them and then I send them
wait for a second,
request new pairs.

It is using the async interface as that allows me to request ADS1 right after ADS0 is started,
so they work effectively in parallel.

At least this way you can sample multiple ADS in parallel.

#include "ADS1X15.h"
// #include <elapsedMillis.h>

#include <mcp_can.h>
#include <SPI.h>

// elapsedMillis ADSmillis1;

MCP_CAN CAN0(10);     // Set CS to pin 10

ADS1115 ADS0(0x48);
ADS1115 ADS1(0x49);


uint8_t channel = 0;
int16_t val0[4] = { 0, 0, 0, 0 };
int16_t val1[4] = { 0, 0, 0, 0 };
int     idx = 0;

uint32_t lastTime = 0, now = 0;


void setup()
{
  Serial.begin(115200);
  Serial.println(__FILE__);
  Serial.print("ADS1X15_LIB_VERSION: ");
  Serial.println(ADS1X15_LIB_VERSION);

  // Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.
  if (CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_16MHZ) == CAN_OK) 
  {
    Serial.println("MCP2515 CAN0 Initialized Successfully!");
  }
  else Serial.println("Error Initializing MCP2515...");
  CAN0.setMode(MCP_NORMAL);   // Change to normal mode to allow messages to be transmitted

  ADS0.begin();
  ADS0.setGain(0);
  ADS0.setDataRate(4);

  ADS1.begin();
  ADS1.setGain(0);
  ADS1.setDataRate(4);

  ADS_request_all();
}


void loop()
{
  while (ADS_read_all();  // we need to continue sampling.
  
  // we have all 8 values
  ADS_print_all();
  ADS_send_all();
  delay(1000);      // wait a second.
  ADS_request();
}


void ADS_request_all()
{
  ADS0.requestADC(idx);
  ADS1.requestADC(idx);
}


bool ADS_read_all() 
{
  // if both ADS are ready
  if ((ADS0.isBusy() == false) && (ADS1.isBusy() == false))
  {
    val0[idx] = ADS0.getValue(idx) * 0.1875;
    val1[idx] = ADS1.getValue(idx) * 0.1875;
    idx++;
    if (idx < 4)
    {
      ADS0.requestADC(idx);
      ADS1.requestADC(idx);
      return true;
    }
    return false;
  }
  return true; 
}


void ADS_print_all()
{
  // TIMESTAMP
  // Serial.print(millis());
  // Serial.print("\t");
  // PRINT ALL VALUES OF ADC0
  for (int i = 0; i < 4; i++)
  {
    Serial.print(val0[i]);
    Serial.print("\t");
  }
  // PRINT ALL VALUES OF ADC1
  for (int i = 0; i < 4; i++)
  {
    Serial.print(val1[i]);
    Serial.print("\t");
  }
  Serial.println();
}


void ADS_send_all()
{
  // SEND ALL VALUES OF ADC0
  byte stmp[8];
  for (int i = 0; i < 4; i++)
  {
    stmp[ i * 2] = val0[i] / 256;
    stmp[ i * 2 + 1] = val0[i] % 256;
    CAN0.sendMsgBuf(0x70, 0, 8, stmp);
  }
  // SEND ALL VALUES OF ADC1
  for (int i = 0; i < 4; i++)
  {
    stmp[ i * 2] = val1[i] / 256;
    stmp[ i * 2 + 1] = val1[i] % 256;
    CAN0.sendMsgBuf(0x71, 0, 8, stmp);
  }
}

you need to reset idx to 0; somewhere

@Mplex72
Copy link
Author

Mplex72 commented Jul 5, 2021

Wauw , complete different view on it , looking good.
This should be working ;
strange problem at line 75 see comment; no matching function for call to 'ADS1115::getValue(int&)'
following the sketch , ADS1 is setup and started ?
no error on the ADS1 request but then .....

Documents\Arduino\libraries\ADS1X15-master/ADS1X15.h:74:12: note: candidate expects 0 arguments, 1 provided
ADS1115_8ch_CAN_06:75:34: error: no matching function for call to 'ADS1115::getValue(int&)'
val1[idx] = ADS1.getValue(idx) * 0.1875;

#include "ADS1X15.h"
// #include <elapsedMillis.h>

#include <mcp_can.h>
#include <SPI.h>

// elapsedMillis ADSmillis1;

MCP_CAN CAN0(10);     // Set CS to pin 10

ADS1115 ADS0(0x48);
ADS1115 ADS1(0x49);


uint8_t channel = 0;
int16_t val0[4] = { 0, 0, 0, 0 };
int16_t val1[4] = { 0, 0, 0, 0 };
int     idx = 0;

uint32_t lastTime = 0, now = 0;


void setup()
{
  Serial.begin(115200);
  Serial.println(__FILE__);
  Serial.print("ADS1X15_LIB_VERSION: ");
  Serial.println(ADS1X15_LIB_VERSION);

  // Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.
  if (CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_16MHZ) == CAN_OK) 
  {
    Serial.println("MCP2515 CAN0 Initialized Successfully!");
  }
  else Serial.println("Error Initializing MCP2515...");
  CAN0.setMode(MCP_NORMAL);   // Change to normal mode to allow messages to be transmitted

  ADS0.begin();
  ADS0.setGain(0);
  ADS0.setDataRate(4);

  ADS1.begin();
  ADS1.setGain(0);
  ADS1.setDataRate(4);

  ADS_request_all();
}


void loop()
{
  while (ADS_read_all());  // we need to continue sampling.
  
  // we have all 8 values
  ADS_print_all();
  ADS_send_all();
  delay(1000);      // wait a second.
  ADS_request_all();
}


void ADS_request_all()
{
  ADS0.requestADC(idx);
  ADS1.requestADC(idx);
}


bool ADS_read_all() 
{
  // if both ADS are ready
  if ((ADS0.isBusy() == false) && (ADS1.isBusy() == false))
  {
    val0[idx] = ADS0.getValue(idx) * 0.1875;
    val1[idx] = ADS1.getValue(idx) * 0.1875;       // _**line 75 error  ;  no matching function for call to 'ADS1115::getValue(int&)'**_
    idx++;
    if (idx < 4)
    {
      ADS0.requestADC(idx);
      ADS1.requestADC(idx);
      return true;
    }
    return false;
  }
  return true; 
}


void ADS_print_all()
{
  // TIMESTAMP
  // Serial.print(millis());
  // Serial.print("\t");
  // PRINT ALL VALUES OF ADC0
  for (int i = 0; i < 4; i++)
  {
    Serial.print(val0[i]);
    Serial.print("\t");
  }
  // PRINT ALL VALUES OF ADC1
  for (int i = 0; i < 4; i++)
  {
    Serial.print(val1[i]);
    Serial.print("\t");
  }
  Serial.println();
}


void ADS_send_all()
{
  // SEND ALL VALUES OF ADC0
  byte stmp[8];
  for (int i = 0; i < 4; i++)
  {
    stmp[ i * 2] = val0[i] / 256;
    stmp[ i * 2 + 1] = val0[i] % 256;
    CAN0.sendMsgBuf(0x70, 0, 8, stmp);
  }
  // SEND ALL VALUES OF ADC1
  for (int i = 0; i < 4; i++)
  {
    stmp[ i * 2] = val1[i] / 256;
    stmp[ i * 2 + 1] = val1[i] % 256;
    CAN0.sendMsgBuf(0x71, 0, 8, stmp);
  }
}

1. 

> 
> 
> > Here it is;
> > https://github.com/coryjfowler/MCP_CAN_lib
> 
> Is not supported in the library manager of the IDE unfortunately .



> 
> 
> > Here it is;
> > https://github.com/coryjfowler/MCP_CAN_lib
> 
> Is not supported in the library manager of the IDE unfortunately .

Wich one should it be ? for eventually better results ?

@RobTillaart
Copy link
Owner

RobTillaart commented Jul 5, 2021

which library is #include mcp_can
commented out the CAN bus stuff and this code compiles (after a few fixes)

#include "ADS1X15.h"
// #include <elapsedMillis.h>

// #include <mcp_can.h>
#include <SPI.h>

// elapsedMillis ADSmillis1;

// MCP_CAN CAN0(10);     // Set CS to pin 10

ADS1115 ADS0(0x48);
ADS1115 ADS1(0x49);


uint8_t channel = 0;
int16_t val0[4] = { 0, 0, 0, 0 };
int16_t val1[4] = { 0, 0, 0, 0 };
int     idx = 0;

uint32_t lastTime = 0, now = 0;


void setup()
{
  Serial.begin(115200);
  Serial.println(__FILE__);
  Serial.print("ADS1X15_LIB_VERSION: ");
  Serial.println(ADS1X15_LIB_VERSION);

//  // Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.
//  if (CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_16MHZ) == CAN_OK) 
//  {
//    Serial.println("MCP2515 CAN0 Initialized Successfully!");
//  }
//  else Serial.println("Error Initializing MCP2515...");
//  CAN0.setMode(MCP_NORMAL);   // Change to normal mode to allow messages to be transmitted

  ADS0.begin();
  ADS0.setGain(0);
  ADS0.setDataRate(4);

  ADS1.begin();
  ADS1.setGain(0);
  ADS1.setDataRate(4);

  ADS_request_all();
}


void loop()
{
  while (ADS_read_all());  // we need to continue sampling.
  
  // we have all 8 values
  ADS_print_all();
  ADS_send_all();
  delay(1000);      // wait a second.
  ADS_request_all();
}


void ADS_request_all()
{
  ADS0.requestADC(idx);
  ADS1.requestADC(idx);
}


bool ADS_read_all() 
{
  // if both ADS are ready
  if ((ADS0.isBusy() == false) && (ADS1.isBusy() == false))
  {
    val0[idx] = ADS0.getValue() * 0.1875;
    val1[idx] = ADS1.getValue() * 0.1875;
    idx++;
    if (idx < 4)
    {
      ADS0.requestADC(idx);
      ADS1.requestADC(idx);
      return true;
    }
    return false;
  }
  return true; 
}


void ADS_print_all()
{
  // TIMESTAMP
  // Serial.print(millis());
  // Serial.print("\t");
  // PRINT ALL VALUES OF ADC0
  for (int i = 0; i < 4; i++)
  {
    Serial.print(val0[i]);
    Serial.print("\t");
  }
  // PRINT ALL VALUES OF ADC1
  for (int i = 0; i < 4; i++)
  {
    Serial.print(val1[i]);
    Serial.print("\t");
  }
  Serial.println();
}


void ADS_send_all()
{
  // SEND ALL VALUES OF ADC0
  byte stmp[8];
  for (int i = 0; i < 4; i++)
  {
    stmp[ i * 2] = val0[i] / 256;
    stmp[ i * 2 + 1] = val0[i] % 256;
    // CAN0.sendMsgBuf(0x70, 0, 8, stmp);
  }
  // SEND ALL VALUES OF ADC1
  for (int i = 0; i < 4; i++)
  {
    stmp[ i * 2] = val1[i] / 256;
    stmp[ i * 2 + 1] = val1[i] % 256;
    // CAN0.sendMsgBuf(0x71, 0, 8, stmp);
  }
}


// -- END OF FILE --

@Mplex72
Copy link
Author

Mplex72 commented Jul 5, 2021

Here it is;

https://github.com/coryjfowler/MCP_CAN_lib

@Mplex72
Copy link
Author

Mplex72 commented Jul 5, 2021

Compiles but does not run,
it still seems to get stuck in the isBusy check

@RobTillaart
Copy link
Owner

you need to reset idx = 0 at some point.

@RobTillaart
Copy link
Owner

slightly modified version - without CAN bus stuff and some debug print statements.

Can you run it and post the output?

//
//    FILE: ADS_async_8_channel.ino
//  AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo (there are more ways to do this)
//    DATE: 2021-07-05
//     URL: https://github.com/RobTillaart/ADS1X15


#include "ADS1X15.h"


ADS1115 ADS0(0x48);
ADS1115 ADS1(0x49);

int16_t val0[4] = { 0, 0, 0, 0 };
int16_t val1[4] = { 0, 0, 0, 0 };
int     idx = 0;


void setup()
{
  Serial.begin(115200);
  Serial.println(__FILE__);
  Serial.print("ADS1X15_LIB_VERSION: ");
  Serial.println(ADS1X15_LIB_VERSION);

  ADS0.begin();
  ADS1.begin();
  idx = 0;
  ADS_request_all();
}


void loop()
{
  Serial.println(__FUNCTION__);
  // wait until all is read...
  while (ADS_read_all());

  // we have all 8 values
  ADS_print_all();

  delay(1000);      // wait a second.
  ADS_request_all();
}


void ADS_request_all()
{
  Serial.println(__FUNCTION__);
  ADS0.requestADC(idx);
  ADS1.requestADC(idx);
}


bool ADS_read_all()
{
  if (ADS0.isBusy() || ADS1.isBusy()) return true;
  Serial.print("IDX:\t");
  Serial.println(idx);
  val0[idx] = ADS0.getValue();
  val1[idx] = ADS1.getValue();
  idx++;
  if (idx < 4)
  {
    ADS_request_all();
    return true;
  }
  idx = 0;
  return false;
}


void ADS_print_all()
{
  Serial.println(__FUNCTION__);
  // TIMESTAMP
  // Serial.print(millis());
  // Serial.print("\t");
  // PRINT ALL VALUES OF ADC0
  for (int i = 0; i < 4; i++)
  {
    Serial.print(val0[i]);
    Serial.print("\t");
  }
  // PRINT ALL VALUES OF ADC1
  for (int i = 0; i < 4; i++)
  {
    Serial.print(val1[i]);
    Serial.print("\t");
  }
  Serial.println();
}

// -- END OF FILE --

@Mplex72
Copy link
Author

Mplex72 commented Jul 6, 2021

It compiles,
It display LOOP as last output on serial monitor;

\Documents\Arduino\ADS1115_8ch_CAN_06__test1\ADS1115_8ch_CAN_06__test1.ino
ADS1X15_LIB_VERSION: 0.3.1
ADS_request_all
loop

@RobTillaart
Copy link
Owner

mmmm , please replace setup()

void setup()
{
  Serial.begin(115200);
  Serial.println(__FILE__);
  Serial.print("ADS1X15_LIB_VERSION: ");
  Serial.println(ADS1X15_LIB_VERSION);

  ADS0.begin();
  ADS1.begin();
  Serial.println(ADS0.isConnected());
  Serial.println(ADS1.isConnected());

  idx = 0;
  ADS_request_all();
}

@Mplex72
Copy link
Author

Mplex72 commented Jul 6, 2021

output

Documents\Arduino\ADS1115_8ch_CAN_06__test1\ADS1115_8ch_CAN_06__test1.ino
ADS1X15_LIB_VERSION: 0.3.1
1
0
ADS_request_all
loop

@RobTillaart
Copy link
Owner

So device ADS1115 ADS1(0x49); is not visible, think you need to check wiring and address lines .

@Mplex72
Copy link
Author

Mplex72 commented Jul 6, 2021

sorry , yes its right , now 1 item on it.
In 5 minutes 2 connected

@RobTillaart
Copy link
Owner

Which country are you from? (just interested where my libs go to, I'm from the Netherlands)

@RobTillaart
Copy link
Owner

Here it is;

https://github.com/coryjfowler/MCP_CAN_lib

Is not supported in the library manager of the IDE unfortunately .

@Mplex72
Copy link
Author

Mplex72 commented Jul 6, 2021

Not that far away :-) near Zwolle,

Sorry , have to combine 2 new ADC for testing again , previous units not at hand
back in half an hour

@Mplex72
Copy link
Author

Mplex72 commented Jul 6, 2021

This is working

//
//    FILE: ADS_async_8_channel.ino
//  AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo (there are more ways to do this)
//    DATE: 2021-07-05
//     URL: https://github.com/RobTillaart/ADS1X15


#include "ADS1X15.h"


ADS1115 ADS0(0x48);
ADS1115 ADS1(0x49);

int16_t val0[4] = { 0, 0, 0, 0 };
int16_t val1[4] = { 0, 0, 0, 0 };
int     idx = 0;


void setup()
{
  Serial.begin(115200);
  Serial.println(__FILE__);
  Serial.print("ADS1X15_LIB_VERSION: ");
  Serial.println(ADS1X15_LIB_VERSION);

  ADS0.begin();
  ADS1.begin();
  Serial.println(ADS0.isConnected());
  Serial.println(ADS1.isConnected());

  idx = 0;
  ADS_request_all();
}


void loop()
{
  Serial.println(__FUNCTION__);
  // wait until all is read...
  while (ADS_read_all());

  // we have all 8 values
  ADS_print_all();

  delay(1000);      // wait a second.
  ADS_request_all();
}


void ADS_request_all()
{
  Serial.println(__FUNCTION__);
  ADS0.requestADC(idx);
  ADS1.requestADC(idx);
}


bool ADS_read_all()
{
  if (ADS0.isBusy() || ADS1.isBusy()) return true;
  Serial.print("IDX:\t");
  Serial.println(idx);
  val0[idx] = ADS0.getValue();
  val1[idx] = ADS1.getValue();
  idx++;
  if (idx < 4)
  {
    ADS_request_all();
    return true;
  }
  idx = 0;
  return false;
}


void ADS_print_all()
{
  Serial.println(__FUNCTION__);
  // TIMESTAMP
  // Serial.print(millis());
  // Serial.print("\t");
  // PRINT ALL VALUES OF ADC0
  for (int i = 0; i < 4; i++)
  {
    Serial.print(val0[i]);
    Serial.print("\t");
  }
  // PRINT ALL VALUES OF ADC1
  for (int i = 0; i < 4; i++)
  {
    Serial.print(val1[i]);
    Serial.print("\t");
  }
  Serial.println();
}

// -- END OF FILE --`

@Mplex72
Copy link
Author

Mplex72 commented Jul 6, 2021

serial output

s\Documents\Arduino\ADS1115_8ch_CAN_06__test1\ADS1115_8ch_CAN_06__test1.ino
ADS1X15_LIB_VERSION: 0.3.1
1
1
ADS_request_all
loop
IDX: 0
ADS_request_all
IDX: 1
ADS_request_all
IDX: 2
ADS_request_all
IDX: 3
ADS_print_all
1752 1944 3015 3023 2915 2923 2930 2919
ADS_request_all
loop
IDX: 0
ADS_request_all
IDX: 1
ADS_request_all
IDX: 2
ADS_request_all
IDX: 3
ADS_print_all
1753 1953 3001 3050 2915 2928 2915 2925
ADS_request_all
loop
IDX: 0
ADS_request_all
IDX: 1
ADS_request_all
IDX: 2
ADS_request_all

@Mplex72
Copy link
Author

Mplex72 commented Jul 6, 2021

Stop further test ,
need to debug something first !

@Mplex72
Copy link
Author

Mplex72 commented Jul 7, 2021

it are zero values from the voltage divider

@RobTillaart
Copy link
Owner

voltage divider?

@Mplex72
Copy link
Author

Mplex72 commented Jul 7, 2021

its the zero value drifting around (16th bit is minus signal)

@Mplex72
Copy link
Author

Mplex72 commented Jul 7, 2021

this is voltage 5volt on ADC1 channel 3

35378	25	25	19	19	-1	-1	-2	-2	
ADS_request_all
loop
IDX:	0
ADS_request_all
IDX:	1
ADS_request_all
IDX:	2
ADS_request_all
IDX:	3
ADS_print_all
36387	28	28	20	20	-1	-1	-3	-3	
ADS_request_all

@Mplex72
Copy link
Author

Mplex72 commented Jul 7, 2021

5volt signal on ADC2 channel2

ADS_request_all
loop
IDX:	0
ADS_request_all
IDX:	1
ADS_request_all
IDX:	2
ADS_request_all
IDX:	3
ADS_print_all
131359	-2	-2	0	0	11117	11117	0	0```

with the isbusy check working 

```cpp

bool ADS_read_all()
{
 // if (ADS0.isBusy() || ADS1.isBusy()) return true;
  Serial.print("IDX:\t");
  Serial.println(idx);
  val0[idx] = ADS0.getValue();
  val1[idx] = ADS1.getValue();
  idx++;
  if (idx < 4)
  {
    ADS_request_all();
    return true;
  }
  idx = 0;
  return false;

@Mplex72
Copy link
Author

Mplex72 commented Jul 7, 2021

This is the output with a normal read (ADS-read) from the lib
voltage dider active.

Analog0: -1	-0.000
	Analog1: 92	0.017
	Analog2: 11095	2.080
	Analog3: 10	0.002

	Analog0: 4	0.001
	Analog1: 91	0.017
	Analog2: 11098	2.081
	Analog3: 7	0.001

	Analog0: 3	0.001
	Analog1: 89	0.017
	Analog2: 11133	2.088
	Analog3: 6	0.001

	Analog0: 3	0.001
	Analog1: 90	0.017
	Analog2: 11110	2.083
	Analog3: 12	0.002

@RobTillaart
Copy link
Owner

I do not understand your last 6 post.

Is the problem solved now?

@Mplex72
Copy link
Author

Mplex72 commented Jul 12, 2021

Hi Rob,

Having problems with the read buffers ,
when running the sketch with real data it does not refresh the buffers.
no faults when compiling and don,t know it,s software or hardware related yet.
still puzzling to get it working as this should.

Take some time so close this for now ?

Klass

@RobTillaart
Copy link
Owner

RobTillaart commented Jul 12, 2021

I have ordered 4x 1115 + 4x 1015, expect them Wednesday.
So if time permits I can recreate the setup (without can-bus) later this week.

@Mplex72
Copy link
Author

Mplex72 commented Jul 12, 2021

Would be fine to have this working .
it is a pretty efficient method

@RobTillaart
Copy link
Owner

The sensors are in, I had my soldering moment so made this setup

4x_ADS1115

@RobTillaart
Copy link
Owner

With the green wire (GND) on the right I checked every input and reading 4 ADS1115 in parallel works.

//
//    FILE: ADS_async_8_channel.ino
//  AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo reading two ADS1115 modules in parallel
//    DATE: 2021-07-05
//     URL: https://github.com/RobTillaart/ADS1X15


// Note all IO with the sensors are guarded by an isConnected()
// this is max robust, in non critical application one may either
// cache the value or only verify it in setup (least robust).
// Less robust may cause the application to hang - watchdog reset ?


#include "ADS1X15.h"


ADS1115 ADS0(0x48);
ADS1115 ADS1(0x49);
ADS1115 ADS2(0x4A);
ADS1115 ADS3(0x4B);

int16_t val0[4] = { 0, 0, 0, 0 };
int16_t val1[4] = { 0, 0, 0, 0 };
int16_t val2[4] = { 0, 0, 0, 0 };
int16_t val3[4] = { 0, 0, 0, 0 };
int     idx = 0;


void setup()
{
  Serial.begin(115200);
  Serial.println(__FILE__);
  Serial.print("ADS1X15_LIB_VERSION: ");
  Serial.println(ADS1X15_LIB_VERSION);

  ADS0.begin();
  ADS1.begin();
  ADS2.begin();
  ADS3.begin();
  Serial.println(ADS0.isConnected());
  Serial.println(ADS1.isConnected());
  Serial.println(ADS2.isConnected());
  Serial.println(ADS3.isConnected());
  idx = 0;
  ADS_request_all();
}


void loop()
{
  Serial.println(__FUNCTION__);
  // wait until all is read...
  while (ADS_read_all());

  // we have all 8 values
  ADS_print_all();

  delay(1000);      // wait a second.
  ADS_request_all();
}


void ADS_request_all()
{
  // Serial.println(__FUNCTION__);
  if (ADS0.isConnected()) ADS0.requestADC(idx);
  if (ADS1.isConnected()) ADS1.requestADC(idx);
  if (ADS2.isConnected()) ADS2.requestADC(idx);
  if (ADS3.isConnected()) ADS3.requestADC(idx);
}


bool ADS_read_all()
{
  if (ADS0.isConnected() && ADS0.isBusy()) return true;
  if (ADS1.isConnected() && ADS1.isBusy()) return true;
  if (ADS2.isConnected() && ADS2.isBusy()) return true;
  if (ADS3.isConnected() && ADS3.isBusy()) return true;
  //Serial.print("IDX:\t");
  //Serial.println(idx);
  if (ADS0.isConnected()) val0[idx] = ADS0.getValue();
  if (ADS1.isConnected()) val1[idx] = ADS1.getValue();
  if (ADS2.isConnected()) val2[idx] = ADS2.getValue();
  if (ADS3.isConnected()) val3[idx] = ADS3.getValue();
  idx++;
  if (idx < 4)
  {
    ADS_request_all();
    return true;
  }
  idx = 0;
  return false;
}


void ADS_print_all()
{
  // Serial.println(__FUNCTION__);
  // TIMESTAMP
  Serial.println(millis());

  // PRINT ALL VALUES OF ADC0
  for (int i = 0; i < 4; i++)
  {
    Serial.print(val0[i]);
    Serial.print("\t");
  }
  // PRINT ALL VALUES OF ADC1
  for (int i = 0; i < 4; i++)
  {
    Serial.print(val1[i]);
    Serial.print("\t");
  }
  Serial.println();
  // PRINT ALL VALUES OF ADC2
  for (int i = 0; i < 4; i++)
  {
    Serial.print(val2[i]);
    Serial.print("\t");
  }
  // PRINT ALL VALUES OF ADC3
  for (int i = 0; i < 4; i++)
  {
    Serial.print(val3[i]);
    Serial.print("\t");
  }
  Serial.println();
}

// -- END OF FILE --

@RobTillaart
Copy link
Owner

Output

ADS1X15_LIB_VERSION: 0.3.1
1
1
1
1
loop
62
2904	2946	3044	2850	2924	2979	3065	2880	
2883	2934	-1	2917	2902	2973	3047	2946	
loop
1122
2880	2950	3021	2942	2893	2970	3035	2999	
2874	2935	-1	2996	2910	2955	3021	3041	
loop
2183
2903	2925	2985	3023	2941	2937	3002	3067	
2914	2911	-1	3052	2950	2925	2987	3101	

The -1 is where I connected GND.

A loop takes 1061 millis of which 1000 is a delay, so total time = 61/62 millis
==> requesting + reading of 4 x 4 analog channels takes (rounded) 64 millis
==> 16 milliseconds for 4 devices in parallel.

@RobTillaart
Copy link
Owner

RobTillaart commented Jul 13, 2021

Made a PR with two new examples including the above.

@Mplex72
Copy link
Author

Mplex72 commented Jul 13, 2021

THAT IS FAST !
You,ve extracted the maximum out of this IC

@Mplex72
Copy link
Author

Mplex72 commented Jul 13, 2021

Now do some crashtest but so far it seems perfectly stable , great , really great.
I think this issue is closed as far as I can see ?

@Mplex72
Copy link
Author

Mplex72 commented Jul 13, 2021

with the code in the push release not all values show zero.
otherwise working perfect.

the code above with separate constructors is ok

1057
0	65534	0	0	
1	65533	65535	1	
1	65534	0	0	
0	65534	65535	0	

1057
1	65534	65535	0	
3	65534	0	0	
0	65533	0	0	
2	65535	65535	0	

1056
65535	65534	0	65535	
2	65534	0	65534	
1	65535	65535	1	
0	65534	65535	0	

1057
2	65534	0	1	
1	65534	0	65535	
0	65534	65535	0	
0	65534	65535	0	

@RobTillaart
Copy link
Owner

Note that the value should be a 16 bit signed int ==>15 bits + sign

65535 is just an unsigned way to write -1 (and that is close to zero last time I looked)

@RobTillaart
Copy link
Owner

Tweaked the code a bit and I got a few millis of

loop
1049
3181	2787	3028	3068	3241	2744	3026	3100	
-1	2850	2848	3330	3229	2873	2908	3301	

49 / 4 =~ 12 milliseconds per 4 samples (but the code looks not nice)

@Mplex72
Copy link
Author

Mplex72 commented Jul 13, 2021

Yers I know that its zero but in the logs it looking very eratic.
May I see the fast code ?
Is it with serial output after each 4 samples ?

@RobTillaart
Copy link
Owner

RobTillaart commented Jul 13, 2021

May I see the fast code ?

changed it already, It did 2 things

  • cache the ADSx.isBusy() in a bool. So it removed an I2C handshake if not all were ready.
  • it retrieved the values as soon as possible

Need to recreate it.

MY current test uses the variation below uses the assumption that as ADS3 is started last, it will also be finished last.

bool ADS_read_all()
{
  //  if (ADS0.isBusy()) return true;
  //  if (ADS1.isBusy()) return true;
  //  if (ADS2.isBusy()) return true;

  if (ADS3.isBusy()) return true;
  val0[idx] = ADS0.getValue();
  val1[idx] = ADS1.getValue();
  val2[idx] = ADS2.getValue();
  val3[idx] = ADS3.getValue();

  //Serial.print("IDX:\t");
  //Serial.println(idx);

  idx++;
  if (idx < 4)
  {
    ADS_request_all();
    return true;
  }
  idx = 0;
  return false;
}

it scores 1054

@RobTillaart
Copy link
Owner

Also quite stable at 1056

bool ADS_read_all()
{
  if (ADS0.isBusy()) return true;
  val0[idx] = ADS0.getValue();     // fetch value as soon as possible.
  if (ADS1.isBusy()) return true;
  val1[idx] = ADS1.getValue();
  if (ADS2.isBusy()) return true;
  val2[idx] = ADS2.getValue();
  if (ADS3.isBusy()) return true;
  val3[idx] = ADS3.getValue();

  //Serial.print("IDX:\t");
  //Serial.println(idx);

  idx++;
  if (idx < 4)
  {
    ADS_request_all();
    return true;
  }
  idx = 0;
  return false;
}

With extra administration of the status per device the performance could be squeezed a bit more.
However it would become quite complex and you still have to wait until the slowest device has made the 4 scans.

@RobTillaart
Copy link
Owner

To speed up the code you might add these 4 lines in setup() after the connected test

  ADS0.setDataRate(7);
  ADS1.setDataRate(7);
  ADS2.setDataRate(7);
  ADS3.setDataRate(7);

default dataRate = 4, 7 is fastest, but 7 allows more noise, so depending on the quality of your signals increasing the dataRate improves the performance.

A datarate of 4 gives 128 samples / second = 8 millisecond per sample.
As we do 4 samples the theoretical minimum == 4x 8 = 32.
Add to it the duration of the calls of request(), isBusy() and getValue() (e.g. 3x12 x 0.5 ms ??? => 18 ms makes 50 millis
==> so 56 millis is not bad at all.

@Mplex72
Copy link
Author

Mplex72 commented Jul 13, 2021

It is pretty maxed out this way !
The ADC is just slower as I was aware of because I didn,t read/understand it fully .
I had it already on rate(6) and I have a capacitor on it to smooth the signal a little.

getting the 16bytes to the CANbus takes also 50 millis .... not able to find a faster way.

@RobTillaart
Copy link
Owner

RobTillaart commented Jul 13, 2021

getting the 16bytes to the CANbus takes also 50 millis .... not able to find a faster way.

Mind you, you have 16 values of 2 bytes each...

You need to read every detail of the data sheet to see what is possible.
And then find a good / efficient library that can get the most from the IC used.

However the ADS part, think we can close this issue.

@Mplex72
Copy link
Author

Mplex72 commented Jul 13, 2021

indeed for the 32 bytes.

Yes , case closed thanks to your hard work ,
thank you .

@Mplex72 Mplex72 closed this as completed Jul 13, 2021
@RobTillaart
Copy link
Owner

RobTillaart commented Jul 13, 2021

a last look at your canbus code, gave a few ideas how to optimize it

void ADS0_read() 
{
  byte stmp[32];    // assume 16 x 2 
  uint8_t idx = 0;

  for (uint8_t i = 0; i < 16; i++)
  {
    //  assume all values are in val[] array by the above code
    //  val[i] = val[i] * 0.1875;  //  ==> 0.1875 * 3 /16 
    //  ==>     x = x * 3/ 16  = x * 1/8 + x * 1/16
    // ==>       x = x /8 + x /16;
    // ==>      x/16    ==  x/8 /2 !!
    uint16_t temp = val[i] / 8;      // no floating point math needed, and compiler can optimize division of powers of 2 !!
    val[i] = temp + temp / 2;

    // stmp[ i * 2] = val[i] / 256;
    // stmp[ i * 2 + 1] = val[i] % 256;
    // you split the data in 2 bytes here
    // furthermore the index of smtp is "a lot of math" which can be simplified as we just need the next element.

    stmp[idx++] = val[i] / 256;        // power of 2 will be optimized.
    stmp[idx++] = val[i] & 0xFF;    // just do bit masking instead of % division - compiler might do that too?

    // send data:  id = 0x70, standard frame, data len = 32, stmp: data buf
    CAN0.sendMsgBuf(0x70, 0, 32, stmp);
  }
}

Get the idea?


however filling the array may not be the time consuming part....

@RobTillaart
Copy link
Owner

last note - you still could try the ADS1015 (which is faster) and the MCP3208 if you need extra speed (and less resolution)

GIven that the data is roughly divided by 4 when sending over the CAN bus a 12 bit conversion could be good enough..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants