bogde / HX711

An Arduino library to interface the Avia Semiconductor HX711 24-Bit Analog-to-Digital Converter (ADC) for Weight Scales.
MIT License
896 stars 538 forks source link

32-bit Teensy 3.X does not combine the 24-bit number correctly #84

Open TomekBrz opened 6 years ago

TomekBrz commented 6 years ago

Hello, I detailed some information on the sparkfun forums: https://forum.sparkfun.com/viewtopic.php?f=14&t=46875&p=196520#p196520

Basically, when I compile on a Teensy 3.5 I get nonsense values that seem to max out the ADC immediately. When I zero the offset and pull <1kg on the sensor (that should be good in the 20mV range to about 15kg) I max out the adc again in the other direction. I don't read 20mV on the A- and A+ pins as one would expect, if I was really maxing out the ADC.

I tried two HX711 boards from sparkfun.

The same code minus a pin change (from A4 and A5 to A0 and A1) works on an UNO.

I will do my best to try and understand more of this issue. It seems I could not find anyone using the HX711 on the Teensy 3.X platform, though there must have been some people who saw this (if I am correct in finding there to be an issue.)

I tried changing all the library calls for "long" to "int32_t" and "unsigned long" to uint32_t, as well as changing all the doubles to floats. It seems with other libraries this has been an issue before: (https://forum.pjrc.com/threads/27270-Float-versus-Double-on-Teensy-3-1)

But next I will try to understand how the bit combination works and if I can find a fix to what I believe is a real issue, and I will report back. But I'm not a 'real' programmer and it may take some time.

I hope by posting this issue, if other people see it and immediately know what could be wrong, I will save time in case I don't find the solution myself. I'm about 12 hours into trouble shooting this setup >.<, :).

TomekBrz commented 6 years ago

I modified the library to print the 3 byte values to serial so we can see how the teensy version combines them and what it is combined, as well as what the UNO version does. ^_^ I also have it return the value that is combined.

Unfortunately I don't see anything wrong with how the value has been combined. As best as I can tell, this suggests that something is going wrong with how teensy is constructing the 8-bit components of the system.

Attached is the CSV that I pulled from 2 configurations of the same load cell (different sparkfun HX711 boards), so 4 permutations of numbers. The UNO code consistently is giving me good numbers, the teensy code is not.

The serial prints that obtained the BIN values were added LoadCellDiagnostics2 - LoadCellDiagnostics2.txt after " // Replicate the most significant bit to pad out a 32-bit signed integer" in HX711.cpp

TomekBrz commented 6 years ago

I am fairly confident I've correctly narrowed down the issue to the "ShiftIn(blah) " function. I seem to get reasonable results when I 'hacked together' [meant in the non-positive sense] code from: https://github.com/ekwus/hx711/blob/master/src/hx711.cpp

`int32_t 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(); }

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

// pulse the clock pin 24 times to read the data
//from https://github.com/ekwus/hx711/blob/master/src/hx711.cpp
// pulse the clock pin 24 times to read the data
for (int16_t i = 0; i < 24; i++)
{
    digitalWrite(PD_SCK, HIGH);
    digitalWrite(PD_SCK, LOW);
    int32_t read = digitalRead(DOUT);
    data = data << 1;
    //std::cout << data << endl;
    if (read  == 1)
    {
        data++;
    }
}
/*data[2] = shiftIn(DOUT, PD_SCK, MSBFIRST);
data[1] = shiftIn(DOUT, PD_SCK, MSBFIRST);
data[0] = shiftIn(DOUT, PD_SCK, MSBFIRST);*/
// Replicate the most significant bit to pad out a 32-bit signed integer
if ( data & 0x800000 ) {
    filler = 0xFF000000;
} else {
    filler = 0x00000000;
}

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

value = data | filler;

// ... and add 1
return static_cast<long>(++value);

// Replicate the most significant bit to pad out a 32-bit signed integer
/*if (data[2] & 0x80) {
    filler = 0xFF;
} else {
    filler = 0x00;
}
Serial.print(F(",data2:,"));Serial.print(data[2],BIN);Serial.print(F(",data1:,"));Serial.print(data[1],BIN);Serial.print(F(",data0:,"));Serial.print(data[0],BIN);*/

/ // Construct a 32-bit signed integer value = ( static_cast(filler) << 24 | static_cast(data[2]) << 16 | static_cast(data[1]) << 8 | static_cast(data[0]) ); Serial.print(F(",BINVAL32:,")); int32_t DUMMYVAL = static_cast(value); Serial.print(DUMMYVAL,BIN);Serial.print(F(",BINVALDEC:,"));Serial.print(DUMMYVAL); return DUMMYVAL;/ }`

This is my remixed version of the other code, this time compatible with Teensy by not relying on the 'ShiftIn' function.

But I am a total newb..I would be super grateful to learn what is going on. I also do not have the equipment on me to totally confirm that the code is now running correctly, nor [clearly] have I cleaned up the code to eliminate all the old stuff or my serial prints I used earlier for diagnostics.

jpk73 commented 6 years ago

Hi! I am very interested in this too. I used the sparkfun HX711 board succsessfully on the DUE and am planning to run all my future projects on Teensies. Hope you find a solution!

TomekBrz commented 6 years ago

UPDATE: @jpk73 Whenever you do get around to swapping in a teensy (<3 teensies), I would still try the original code on the teensy 3.X to replicate the issues I was having, just to get a confirmation from another person.

That said, I tested everything again today. Original HX711 library code does not work compiled at 120Mhz or 24Mhz on the Teensy.

Code that I got from the pjrc thread (https://forum.pjrc.com/threads/47002-Conflict-with-Teensy-3-X-and-HX711-Libary-I-think-related-to-ShiftIn-function) from "Frank B" adds a delaymicros(1) between pin changes and that fixes things for me.

The theory being the teensy is running too fast, is one that I'm still a little unsure about, given that jpk73 says the original code works on the Due. Although the Due is slower than a teensy 3.5 compiled at default 120Mhz, I doubt it is slower than a teensy compiled at 24Mhz (i tried slowing down the teensy speed per Paul's suggestion.)

The only changes my code has thanks to Frank B: // 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);*/ data[2] = my_shiftIn_msbFirst(DOUT,PD_SCK); data[1] = my_shiftIn_msbFirst(DOUT,PD_SCK); data[0] = my_shiftIn_msbFirst(DOUT,PD_SCK);

And

[uint8_t HX711::my_shiftIn_msbFirst(uint8_t dataPin, uint8_t clockPin){ uint8_t mask, value=0; for (mask=0x80; mask; mask >>= 1) { digitalWrite(clockPin, HIGH); delayMicroseconds(1); if (digitalRead(dataPin)) value |= mask; digitalWrite(clockPin, LOW); delayMicroseconds(1); } return value; }

As well as the required protofunctions in the .cpp and .h . If you have any trouble making the same modifications jpk73 (should you need them) let me know, since this isn't a thorough explanation here.

What complicated this is that partway through all the debugging I damaged my board and killed an HX711 due to disconnected the Vdd a bunch (and killed the corresponding analog pins on the teensy that I was hooked up to.) So I basically had one night at midnight in which I was thinking "all right! It's fixed! Woooohh!" then the next morning I was thinking "wait shit, am I losing it? It's not working anymore."

The fix was real, I replicated that the original code doesn't work still for me, and I think I've done things thoroughly (i hope) such that I'm not wasting anyone's time :). I don't know if/what the HX711 library code should be updated, but I will at least I hope by updating the issue tracker someone will find the fix that worked for me.

jpk73 commented 6 years ago

Many thanks, that sounds good to me! As soon as I manage to test my HX711 with a Teensy I will report. It can take some time though as I am on tour at the moment. The speed issue seems resonable to me, and if delayMS's cure the problem I will be fine. Let's see if Paul includes the delays in the core. Again thanks! JPK

igorjansen commented 6 years ago

Actually I had the same issue on ESP8266 @80MHz - the sign bit (i.e. the first being transferred) was wrong most of the time (zero instead of one=negative). It was sufficient to put a digitalWrite(PD_SCK, HIGH); before the shiftIn block in HX711.cpp, which solved the issue. Now the section of HX711.cpp looks like this:

     digitalWrite(PD_SCK, HIGH);
     data[2] = shiftIn(DOUT, PD_SCK, MSBFIRST);
data[1] = shiftIn(DOUT, PD_SCK, MSBFIRST);
data[0] = shiftIn(DOUT, PD_SCK, MSBFIRST);

On ESP8266 I also solved an issue with the yield by defining the yield function in the beginning of HX711.cpp as delay(0);

lewsut commented 6 years ago

I've had exactly this issue with Teensy 3.x and igorjansen's changes solve it for me.

jesutor commented 6 years ago

@igorjansen genius, thanks!!! I get to solve my problem with esp32.

amotl commented 5 years ago

Hi there,

we recently had the opportunity to contribute #123, the routine for reading the HX711 now looks like https://github.com/bogde/HX711/blob/master/src/HX711.cpp#L36-L62 and should account for different aspects mentioned here.

When revisiting this, it would be cool to add the Teensy 3.x to the list of verified hardware [1], so we are humbly asking if someone of you who still owns an appropriate device could give this a try?

Thanks already!

Cheers, Andreas.

[1] https://github.com/bogde/HX711#hardware-support