Need Help with Teensy 3.6. Serial COM port disappears after uploading code

Status
Not open for further replies.

pynpyn

Member
Hi everyone,

I'm using a Teensy 3.6 with a project involving load cell. I hooked up Teensy with HX711 load cell amplifier from Sparkfun.

Here is the webpage: https://learn.sparkfun.com/tutorials/load-cell-amplifier-hx711-breakout-hookup-guide

My hardware setup is (the default setup suggested in the hookup guide):

Teensy HX711
3.3V-----------------VCC
GND-----------------GND
Pin 2-----------------CLK
Pin 3-----------------DAT

My code is:
Code:
#include "HX711.h"

#define DOUT  3
#define CLK  2

HX711 scale(DOUT, CLK);

float calibration_factor = -58970; 

void setup() {
  
  Serial.begin(9600);
  Serial.println("HX711 calibration sketch");
  Serial.println("Remove all weight from scale");
  Serial.println("After readings begin, place known weight on scale");
  Serial.println("Press + or a to increase calibration factor");
  Serial.println("Press - or z to decrease calibration factor");

  scale.set_scale();
  scale.tare(); //Reset the scale to 0

  long zero_factor = scale.read_average(); //Get a baseline reading
  Serial.print("Zero factor: "); //This can be used to remove the need to tare the scale. Useful in permanent scale projects.
  Serial.println(zero_factor);
}

void loop() {

  scale.set_scale(calibration_factor); //Adjust to this calibration factor

  Serial.print("Reading: ");
  Serial.print(scale.get_units(), 3);
  Serial.print(" lbs"); //Change this to kg and re-adjust the calibration factor if you follow SI units like a sane person
  Serial.print(" calibration_factor: ");
  Serial.print(calibration_factor);
  Serial.println();

  if(Serial.available())
  {
    char temp = Serial.read();
    if(temp == '+' || temp == 'a')
      calibration_factor += 100;
    else if(temp == '-' || temp == 'z')
      calibration_factor -= 10;
  }
}

My trouble is that everytime I upload this code into Teensy 3.6, the serial COM disappears. I have no problem when I use this Teensy for other projects. It seems this code or hardware setup confuses the Teensy. I have to follow the troubleshooting guide (disconnect Teensy, hold the reset button without plugging in the cable, connect Teensy and release the button) to get my Teensy be recognized again. At the first time, I thought the main core was dead and fortunately I found this procedure to reboot. I tried using different pins but didn't help. After every failed attempt, I have to reboot Teensy to get it work again.

I have used this HX711 and my load cell with arduino Nano and Teensy 3.2 (exactly same setup and code), and there is no problem. I don't understand why the serial port disappears after I upload this code. I attached two pictures showing before and after uploading.

Please help or provide insights! Thank you!

Before uploading.jpgAfter uploading.jpg
 
Seems like something is trashing the USB/Serial code on init.

Before the scale.set_scale() I'd put a : while(!Serial.available()) {delay(100);}

That will stop in setup() before anything happens to show those initial prints - until the SerMon opens and something is sent in - though it may be dead by then from the : HX711 scale(DOUT, CLK);

Try a compile as DEBUG or "FAST with LTO". Those may re-order the code before setup() to change the behavior enough to suggest someone giving that a look.
 
When HX711 is instantiated, the begin() function calls set_gain() which in turn calls read().
read() sets the clock pin LOW and then waits until it sees that the DOUT pin (3) has gone LOW. If it never goes low, the code hangs right there in the instantiation and that will probably kill the serial port.
You should check the connections very carefully to make sure that the wiring is correct. If in doubt, post a photo which clearly shows the connections.
One thing you can check, if you have a multimeter, is to look at the two pins. They should initially be high, but when you upload the code both of them should go low.

Pete
 
Seems like something is trashing the USB/Serial code on init.

Before the scale.set_scale() I'd put a : while(!Serial.available()) {delay(100);}

That will stop in setup() before anything happens to show those initial prints - until the SerMon opens and something is sent in - though it may be dead by then from the : HX711 scale(DOUT, CLK);

Try a compile as DEBUG or "FAST with LTO". Those may re-order the code before setup() to change the behavior enough to suggest someone giving that a look.


I tried adding the line and compile using "FAST with LTO". However, the serial was still killed before I could even open the serial monitor.
 
When HX711 is instantiated, the begin() function calls set_gain() which in turn calls read().
read() sets the clock pin LOW and then waits until it sees that the DOUT pin (3) has gone LOW. If it never goes low, the code hangs right there in the instantiation and that will probably kill the serial port.
You should check the connections very carefully to make sure that the wiring is correct. If in doubt, post a photo which clearly shows the connections.
One thing you can check, if you have a multimeter, is to look at the two pins. They should initially be high, but when you upload the code both of them should go low.

Pete

Thanks for elaborating the mechanism behind HX711 code!

Since it's a relatively straightforward setup, I'm pretty the wiring is correct. Here attached some pictures on my hardware setup. I hope they are clear enough.
Teensy HX711
3.3V-----------------VCC
GND-----------------GND
Pin 2-----------------CLK
Pin 3-----------------DAT

Currently, I don't have a multimeter next to me. Is there any other way to check the issue? Is this issue specifically associated with Teensy 3.6? Will I need to use any pullup resistors?
IMG_0565.jpgIMG_0566.jpgIMG_0567.jpg
 
Last edited:
It may be dead on device instantiation before setup. el_supremo may have the answer - but there isn't a .begin() shown - unless that is implied in the instantiation.

This should compile and if it gets to setup - turn on the LED at least - perhaps more. If nothing then it is not making it that far. To prove no life I'd start with this and confirm no LED. Any change with debug build?

Code:
void setup() {
  pinMode( LED_BUILTIN, OUTPUT );
  digitalWriteFast( LED_BUILTIN, 1 );
  delay( 400 );
  Serial.begin(9600);
  while (!Serial && millis() < 2000) ; // wait for Arduino Serial Monitor
  digitalWriteFast( LED_BUILTIN, 0 );
  while (!Serial && millis() < 6000) ; // wait for Arduino Serial Monitor
  digitalWriteFast( LED_BUILTIN, 1 );
  Serial.println("HX711 calibration sketch");
  delay( 400 );
  while(!Serial.available()) {delay(100);}

  Serial.println("Remove all weight from scale");
  Serial.println("After readings begin, place known weight on scale");
  Serial.println("Press + or a to increase calibration factor");
  Serial.println("Press - or z to decrease calibration factor");
// ...
 
It may be dead on device instantiation before setup. el_supremo may have the answer - but there isn't a .begin() shown - unless that is implied in the instantiation.

This should compile and if it gets to setup - turn on the LED at least - perhaps more. If nothing then it is not making it that far. To prove no life I'd start with this and confirm no LED. Any change with debug build?

Code:
void setup() {
  pinMode( LED_BUILTIN, OUTPUT );
  digitalWriteFast( LED_BUILTIN, 1 );
  delay( 400 );
  Serial.begin(9600);
  while (!Serial && millis() < 2000) ; // wait for Arduino Serial Monitor
  digitalWriteFast( LED_BUILTIN, 0 );
  while (!Serial && millis() < 6000) ; // wait for Arduino Serial Monitor
  digitalWriteFast( LED_BUILTIN, 1 );
  Serial.println("HX711 calibration sketch");
  delay( 400 );
  while(!Serial.available()) {delay(100);}

  Serial.println("Remove all weight from scale");
  Serial.println("After readings begin, place known weight on scale");
  Serial.println("Press + or a to increase calibration factor");
  Serial.println("Press - or z to decrease calibration factor");
// ...

Thanks for the help. However, my problem is that I cannot even open the serial monitor. Once I upload the code (the moment of "Done uploading"), the serial COM port disappeard/gone/died. If I try to open serial monitor, I got message "No serial port, please select with Tools > Port".

Therefore, I couldn't tell if there is any difference with the code you provided since I couldn't get to the setup stage. Tried with "debug" and "Fast with LTO", serial port still disappeared once the uploading was done. I doubt the code change in setup block will do anything because the issue seemed to kick in prior to the setup stage.

I'm very confused. This Teensy 3.6 works perfectly for my other sketches. I just did another experiment. I was suspicious about both the hardware setup and the code. Therefore, I disconnected all wiring from Teensy except the USB cable between it and the computer, and uploaded the code. Again, Teensy's serial port disappeared after the uploading, so now I seriously think there might be something incompatible with Teensy 3.6 in HX711 code (cpp file). What do you guys think?
 
Last edited:
The LED should appear if there is any entry to setup() - if not that then it is a pre-setup issue in the library code.

Had the LED come on - the delays and other stuff shown would give a few seconds before subsequent calls if they are the problem - but with no LED it is trashed before that.
 
There was no LED at all. So it's probably something wrong in the library code? Maybe the library is specifically incompatible with Teensy 3.6 since I can get Teensy 3.2 works with it.
 
Below is the HX711 library (cpp file). I'm suspicious about several places that may cause trouble with a Teensy 3.6:

1. Arduino.h

2. #if ARDUINO_VERSION <= 106
// "yield" is not implemented as noop in older Arduino Core releases, so let's define it.
// See also: https://stackoverflow.com/questions...f-the-arduino-yieldfunction/34498165#34498165
void yield(void) {};
#endif

3. long HX711::read() {
// wait for the chip to become ready
while (!is_ready()) {
// Will do nothing on Arduino but prevent resets of ESP8266 (Watchdog Issue)
yield();
}

However, I'm not sure how to test/fix the library. Please let me know if anyone has any comment/suggestion.

Code:
#include <Arduino.h>
#include <HX711.h>

#if ARDUINO_VERSION <= 106
    // "yield" is not implemented as noop in older Arduino Core releases, so let's define it.
    // See also: https://stackoverflow.com/questions/34497758/what-is-the-secret-of-the-arduino-yieldfunction/34498165#34498165
    void yield(void) {};
#endif

HX711::HX711(byte dout, byte pd_sck, byte gain) {
	begin(dout, pd_sck, gain);
}

HX711::HX711() {
}

HX711::~HX711() {
}

void HX711::begin(byte dout, byte pd_sck, byte gain) {
	PD_SCK = pd_sck;
	DOUT = dout;

	pinMode(PD_SCK, OUTPUT);
	pinMode(DOUT, INPUT);

	set_gain(gain);
}

bool HX711::is_ready() {
	return digitalRead(DOUT) == LOW;
}

void HX711::set_gain(byte gain) {
	switch (gain) {
		case 128:		// channel A, gain factor 128
			GAIN = 1;
			break;
		case 64:		// channel A, gain factor 64
			GAIN = 3;
			break;
		case 32:		// channel B, gain factor 32
			GAIN = 2;
			break;
	}

	digitalWrite(PD_SCK, LOW);
	read();
}

long HX711::read() {
	// wait for the chip to become ready
	while (!is_ready()) {
		// Will do nothing on Arduino but prevent resets of ESP8266 (Watchdog Issue)
		yield();
	}

	unsigned long value = 0;
	uint8_t data[3] = { 0 };
	uint8_t filler = 0x00;

	// pulse the clock pin 24 times to read the data
	data[2] = shiftIn(DOUT, PD_SCK, MSBFIRST);
	data[1] = shiftIn(DOUT, PD_SCK, MSBFIRST);
	data[0] = shiftIn(DOUT, PD_SCK, MSBFIRST);

	// set the channel and the gain factor for the next reading using the clock pin
	for (unsigned int i = 0; i < GAIN; i++) {
		digitalWrite(PD_SCK, HIGH);
		digitalWrite(PD_SCK, LOW);
	}

	// Replicate the most significant bit to pad out a 32-bit signed integer
	if (data[2] & 0x80) {
		filler = 0xFF;
	} else {
		filler = 0x00;
	}

	// Construct a 32-bit signed integer
	value = ( static_cast<unsigned long>(filler) << 24
			| static_cast<unsigned long>(data[2]) << 16
			| static_cast<unsigned long>(data[1]) << 8
			| static_cast<unsigned long>(data[0]) );

	return static_cast<long>(value);
}

long HX711::read_average(byte times) {
	long sum = 0;
	for (byte i = 0; i < times; i++) {
		sum += read();
		yield();
	}
	return sum / times;
}

double HX711::get_value(byte times) {
	return read_average(times) - OFFSET;
}

float HX711::get_units(byte times) {
	return get_value(times) / SCALE;
}

void HX711::tare(byte times) {
	double sum = read_average(times);
	set_offset(sum);
}

void HX711::set_scale(float scale) {
	SCALE = scale;
}

float HX711::get_scale() {
	return SCALE;
}

void HX711::set_offset(long offset) {
	OFFSET = offset;
}

long HX711::get_offset() {
	return OFFSET;
}

void HX711::power_down() {
	digitalWrite(PD_SCK, LOW);
	digitalWrite(PD_SCK, HIGH);
}

void HX711::power_up() {
	digitalWrite(PD_SCK, LOW);
}
 
Yikes, yeah if not LED then the USB was just a clue it was dead - that indicates really dead. Can you run that code on the T_3.2 just to see what it was meant to show and that it works without issue?

The toolchain in compile/link might be at fault - if properly connected and working like it did on the T_3.2. But - if like other times that was an issue IIRC - that fault is really in the code doing stuff during init/create from the : HX711 scale(DOUT, CLK);

That is just noting that has shown up - test the hardware back on the T_3.2 to be sure - other wise it may be something T_3.6 specific if not the above build issue.
 
I found the problem!

It's actually the function "void yield(void) {}" defined in this HX711 library. After I commented out all lines containing it, now Teensy compiles/uploads and runs normally. Although I don't quite understand what yield() do in arduino/teensy programming environment. Any idea?

Many thanks to defragster and Pete for helping me narrow down the problem and give suggestions in testing! Very appreciated!

Yinan
 
Usually doing that with yield() is a fun thing to do and harmless - when done within the sketch.INO. It just bypasses time wasted emulating Arduino serialEvent() processing.

That should okay as you've corrected it - Paul calls yield() early in setup via delay().

Putting the native PJRC yield() code in by removing that private is either hiding the true problem - or the way it is done in that code is confusing the build somehow.

Would be interesting to see if doing the same declaration in the main INO file has the same effect.

Without your change the compiler should complain if defined twice - if not then it is confused linking with the library version.
Code:
void yield(void) {}
 
Last edited:
Just to let you know that commenting the yield() function at the beginning of the .cpp file also helped in my case. The difference to the problem of pynpyn was in my case that it locked out also my Teensy 3.2.
 
Yes, slightly older, I was using version 1.39. Now, with 1.40 the yield() function in HX711 library does not lock the Teensy 3.2 anymore.
 
Status
Not open for further replies.
Back
Top