Can a library break Teensy's serial port settings?

Biff

Active member
Hello all,

I've created a sketch to read some outputs from an analog-to-digital converter. I've chosen the AD7124, from Analog Devices, and found a well-reviewed library online from EpsilonRT : https://github.com/epsilonrt/ad7124.

I uploaded the sketch to my board (a homebrew board with Teensy 3.2 parts, plus the aforementioned AD7124). All is well - I can read the desired ports, plus the device ID. BUT... if I power-cycle the board, the serial port produces inaccurate AD7124 values - all static values of -2 and -2.5. I probed all SPI signals, including CSS, and they are still toggling; also, serial port is still indicated correctly in the Arduino app. I tried loading a separate, un-related sketch, and it works OK, even after a power cycle.

So, is my sketch faulty, or perhaps this library is working some evil on the serial port settings?

Many thanks!
---------------------------------------

Here's my ultra-short sketch:

Code:
const int CSS = 15;      // uC  pin 15 Teensy 3.2

Ad7124Chip adc;         // create an object

long value;
double voltage;

void setup()  {

  delay(1000);
  SPI.begin();

  Serial.begin(115200);
  
  Serial.println("AD7124 VM");
  
  pinMode(CSS,OUTPUT);
  digitalWrite(CSS,HIGH);

  adc.begin(CSS);
  adc.setConfig (0, Ad7124::RefInternal, Ad7124::Pga1, true);
  adc.setChannel (0, 0, Ad7124::AIN3Input, Ad7124::AIN0Input);
  adc.setAdcControl (Ad7124::ContinuousMode, Ad7124::FullPower, true);

}
void loop() {
  value = adc.read (0);                                                  // Ch 0 defined above in setChannel
  voltage = Ad7124Chip::toVoltage (value, 1, 2.5, true);  //value, gain, vref, bipolar boolean
  Serial.println(voltage, 3);
  value = adc.getRegister (AD7124_ID_REG);
  Serial.print("Dev ID ");
  Serial.println(value);

  delay(2000);
}
 
Last edited by a moderator:
Taking an educated shot in the dark, but my bet is that you just need a delay before adc.begin. When you upload code, the ADC is sitting there powered for a long time before it starts receiving commands from the Teensy. During a power cycle, the Teensy may boot well before the ADC and start trying to issue commands before the ADC is ready. I'm surprised the library author doesn't have any output from the begin method to indicate success or failure. Also, data sheets for sensors usually have time to wait between powering the board and trying to communicate with it, you could look that up and use that for a delay value.
 
Thanks for the suggestion brtaylor; you'll see in my sketch code, line 6, that I already have a 1 second delay in place. Do you think the ADC needs more than a second to initialize?
 
For a quick attempt to answer the original question, a library or any other code running on Teensy can disrupt USB communication. Every Teensy is made with a pushbutton dedicated to entering programming mode, because the normal & automatic way using USB communication can fail if code on Teensy is interfering with USB.

The most common way is keeping interrupts disabled. Buffer overflows or other memory corruption which overwrite variables used by the USB code are rare, but have come up. Other uncommon issues like shutting off the USB hardware or staying in sleep modes, are not common but theoretically possible.

But what exactly is meant by "break Teensy's serial port settings" isn't clear to me. The traditional settings, like serial baud rate, aren't actually used for communication. They're just sent from your PC to variables on the Teensy side. Your program can read them, but usually you would only do that if you're making a USB-Serial converter where you read the baud rate software on the PC side intended and then you configure one of Teensy's real not-USB serial ports with that baud rate. Memory corruption from a buggy library could possibly overwrite that stored baud rate number, but it wouldn't affect the actual communication between your PC and Teensy, because native USB speed is always used. The serial settings are just parameters meant for programs to read if they want to know the settings the PC side sent.

Whether this answer helps, I have no idea. I'm guessing probably not. But just wanted to try to answer the original question.
 
Another way of putting this conundrum: Immediately after uploading the sketch, everything works fine. Arduino's serial monitor accurately shows this:

1.75
Dev ID 4


The 1.75 changes accordingly if I adjust the ADC input voltage.
If I pull the power cord for a few seconds and re-connect it, serial monitor shows

-2.5
-2


Only way to fix this (at least temporarily) is to re-upload the sketch.

Maybe suggesting Teensy's serial port settings are broke is incorrect, but since I still measure all the SPI hardware signals changing in the same manner, whether the serial readings are correct or not, I thought serial port might be a potential culprit.
 
Sorry I may be wrong, but I am wondering if the issue is really an issue with Serial?

That is if I am not mistaken, the chip connects using SPI.

Often times a difference between uploading new and powering up, is if you have code like if (!Serial) ;
hanging if you don't open a Serial terminal.

But sounds like you are receiving some data, but garbage.

Which sounds more like your chip is not properly initialized or there is an issue with SPI? Or???

As mentioned one of the first things I would do is to check each of your adc calls to see if they have return values and print those out.
And see if they succeed and are the same values between uploading new code or just powering up.

Other things that might be interesting to look at include things like:

Are there other IO pins connected to the teensy, what are the states of them? i.e. how is this hooked up.

I assume the ADC chip is connected to something the produces analog... Is it(they) something that takes a while to startup? Is there an issue of power up sequence where they cause power issues as everything is starting up at same time?

Maybe try adding more delays between commands:
Code:
  adc.begin(CSS);
  adc.setConfig (0, Ad7124::RefInternal, Ad7124::Pga1, true);
  adc.setChannel (0, 0, Ad7124::AIN3Input, Ad7124::AIN0Input);
  adc.setAdcControl (Ad7124::ContinuousMode, Ad7124::FullPower, true);

Like what happens if you add a delay(250);
between each of the calls above.
 
Kurt, thanks for your suggestions. Details:
When I print out the Return values, I see all zeroes immediately after code upload (and the Teensy performs as expected). If I power-cycle the system, I see "-2" for all the Return values, and the Teensy outputs degrade to the previously mentioned "-2" and "-2.5" values.

Adding a 250mS delay after each setup function produced no differences.

The board does have other devices on the SPI bus. I added a code segment to pull all of their CS high (inactive). No differences observed.

New code is below.

Code:
#include <ad7124.h>
#include <SPI.h>
#include <arduino.h>

const int CSS = 15;      // uC pin 2 Teensy 4, pin 15 Teensy 3.2
const int FPGA = 30; 
const int fram = 23;
const int flash = 10;
const int vrdac = 0;

Ad7124Chip adc;         // create an object

long value;
double voltage;
int trial = 0;         //debug tracker

void setup()  {

  delay(1000);
  SPI.begin();

  Serial.begin(115200);
  
  pinMode(FPGA,OUTPUT);       //de-assert unused CS, FRAM, VRDAC and Flash
  digitalWrite(FPGA,HIGH);
  pinMode(fram, OUTPUT);
  digitalWrite(fram,HIGH);
  pinMode(flash,OUTPUT);
  digitalWrite(flash,HIGH);
  pinMode(vrdac,OUTPUT);
  digitalWrite(vrdac,HIGH);

  
  Serial.println("AD7124 VM");
  
  pinMode(CSS,OUTPUT);
  digitalWrite(CSS,HIGH);
  delay(250);
  
  trial = adc.begin(CSS);
  Serial.print("begin ");
  Serial.println(trial);
  
  trial = adc.setConfig (0, Ad7124::RefInternal, Ad7124::Pga1, true);
  Serial.print("setConfig ");
  Serial.println(trial);
  
  trial = adc.setChannel (0, 0, Ad7124::AIN3Input, Ad7124::AIN0Input);
  Serial.print("setChannel ");
  Serial.println(trial);
  
  trial = adc.setAdcControl (Ad7124::ContinuousMode, Ad7124::FullPower, true);
  Serial.print("setAdcControl ");
  Serial.println(trial);

}
void loop() {
  value = adc.read (0);   // Ch 0 defined above in setChannel
  voltage = Ad7124Chip::toVoltage (value, 1, 2.5, true);  //value, gain, vref, bipolar boolean
  Serial.println(voltage, 3);
  value = adc.getRegister (AD7124_ID_REG);
  Serial.print("Dev ID ");
  Serial.println(value);

  delay(2000);
}
 
So looking at their headers I see:
Code:
/* Error codes */
#define AD7124_INVALID_VAL -1 /* Invalid argument */
#define AD7124_COMM_ERR    -2 /* Communication error on receive */
#define AD7124_TIMEOUT     -3 /* A timeout has occured */
#define AD7124_SPI_ERR     -4 /* A SPI has occured */

So what happens if you do something like:

Code:
  for (int retry_count = 0; retry_count < 5; retry_count++) {   
    trial = adc.begin(CSS);
    if (trial == 0) break;
    Serial.print("begin ");
    Serial.println(trial);
    delay(250);
  }
And similar for others...
 
I guess a 'Comm error on receive' is being indicated here. Kind of a vague term, IMHO.

I added the repeat loops you suggested, to all four function calls.

Results: immediately after sketch upload, the serial port begins showing ADC voltage levels, and Dev ID 4, which is expected.
After a power cycle, the "-2" is printed 5 times, for each of the functions, and then the - 2.5, Dev ID -2 starts scrolling again.
 
Next question is what do you actually have: i.e. which chip. Is it a raw chip and/or is part of some breakout board like setup. i.e. something like Adafruit or sparkfun sell?

Do you have a schematic or the like on how this is connected? including like connections to Teensy?
...

For example on the AD7124-8, there is I believe on Pin 27 SYNC, which if this pin is low sounds like device held in reset state...

Also other slight chance of helping:

The SPI normally starts up in MODE0 and I believe this one wants MODE3, sometimes it won't switch modes until something is transferred.

Code:
void setup()  {

  delay(1000);
  SPI.begin();

...
  pinMode(CSS,OUTPUT);
  digitalWrite(CSS,HIGH);

  SPI.beginTransaction (SPISettings (1000000, MSBFIRST, SPI_MODE3));
  SPI.transfer(0); // transfer something while CS not asserted
  SPI.endTransaction();

  delay(250);
  adc.begin(CSS);
 
The library returns negative numbers for any error, so I don't think one should be surprised about the values printed being negative - it just points to some kind of error, like Kurt says maybe SPI errors.

Some example code from the library:

Code:
 ret = startSingleConversion (ch);
  if (ret < 0) {

    return ret;
  }

  ret = waitEndOfConversion (timeout());
  if (ret < 0) {
    return ret;
  }

OP indicated the Teensy and A/D is on some kind of carrier board. Perhaps a power cycle doesn't reset all the devices. For example, maybe Vusb isn't cut on the Teensy, or maybe the A/D is being powered via an I/O pin when the power is off.
 
We're using raw chips from one of the common suppliers (e.g. Digikey or Mouser).

I tried accessing SPI before CSS was asserted, no help.

I clipped a portion of our schematic showing the Teensy-like section.
teensy1.jpg
The ADC in question uses SPI_ADC1_CS_L. The other ADC CS goes to a card that is not installed. You'll note that I de-asserted the remaining CS in the code posted above.

Here's the ADC schematic portion:
adc1.jpg
 
Sorry,

When it comes to completely custom boards, I am not experienced in seeing what is different versus a stock T3.2.
So I am probably not much good at debugging this. Except to suggest that you might want to instrument the library you are using.

If it returns -2 from a call, And that method calls multiple things that could return an error, than add prints within those functions to see where it fails.

But I still have no idea if this is a hardware issue or a software issue.

For example are there power hungry things on your board that can cause issues like sort of brownouts of part of them...
What happens if you cause the reset the teensy without unplugging, does it work then?
(Like use TyCommander to talk to the board) and then hit the reset button in it...

If I were wanting to debug on my own stuff, I would also use Logic Analyzer and look at several things including SPI and see if anything obvious pops up.

Sorry again not much help.
 
Kurt,
Thanks for your suggestions and assistance. I'll keep plugging away at trying to debug this puppy.
 
Maybe look at your power supply startup and stability?

Many years ago, in the days of Teensy 3.0 & 3.1, there was a big project using an Arduino Mega and 3 Teensy boards which suffered from power supply problems. Sometimes the Teensy boards wouldn't boot up, or experienced other strange problems. The old conversation is still somewhere on this forum. As I recall, after a long time trying to figure out the cause, it was a Traco DC-DC converter which caused so much trouble. Traco's datasheet said you only needed extra capacitance if the input voltage was on the high end of its range. But it turned out Teensy's current draw at startup, which is almost nothing until you reach about 1.5 volts and then suddenly becomes many milliamps, in combination with the Traco converters getting power from a "weak" source. In some extreme cases the DC-DC converter could become an oscillator! Adding capacitance at the DC-DC input made all the difference.

No idea if that's really what's wrong here. Just a blind guess based on a particularly painful story from many years ago. Unstable non-monotonic power supply startup has come up since then, but now we know it can be problematic.
 
Back
Top