olkal / HX711_ADC

Arduino library for the HX711 24-bit ADC for weight scales
MIT License
235 stars 124 forks source link

Can't read data when using external crystal #45

Closed dsafak closed 3 years ago

dsafak commented 4 years ago

I am trying to use a 20mhz external oscillator with hx711 and according to its datasheet it is in spec. When using 20mhz crystal, Reading data doesn't work and it only shows 0 and some high number when a force is applied.

I can read data with a quick test sketch I've made (didn't use the library) to check if all is working, so connections are right and oscillator is working.

olkal commented 4 years ago

Hi, I have just tested the current library version with a HX711 modified with 20mhz crystal, and I have no issues. Also, as using an external crystal only changes the HX711 internal sampling rate, it should make no difference with respect to data transfer/library functions.

So IMO there must be something else wrong. Did you try with any of the library example files?

dsafak commented 4 years ago

I have current library version and I connect the crystal directly across 13 and 14 pins according to datasheet. I agree that it shouldn't make any difference and none of the hx711 libraries worked but the sketches where I modified the reading method slightly.

I tried with the multiple loadcell example.

I also used 2 capacitors for connecting crystal but it wasn't required so it didn't matter.

I'll try with a single loadcell example and report back in couple minutes.

olkal commented 4 years ago

Okay. Did you disable the internal oscillator by soldering off pin 14 from from the pcb pad (originally connected VCC)? Here is a picture my HX711@20mhz:

58051875-9ee7bc80-7b53-11e9-922b-c91145bf967c

dsafak commented 4 years ago

Yes, I did. I think it is originally connected to GND? but regardless those are disconnected and there is a 20mhz xtal across them now. To clarfiy it more, I then removed the xtal and soldered 2 jumper wires so now I can switch between internal and external on a breadboard, If I did wiring wrong, I can make a change easily.

tried read_1x_loadcell example, connections are correct and I can retrieve data in my own sketch but not with this library. It is odd. Using library-wise I know I am not setti ng it wrong. Electronically, I just connect a crystal between 2 legs and could test it with a sketch so it is also fine.

hx711working.zip

attached sketch is working I had to modify the shift function to get it to work. Moved digitalWrite LOW below HIGH and then I have read the data. Otherwise it doesn't work for some reason.

dsafak commented 4 years ago
uint8_t HX711_ADC::conversion24bit()  //read 24 bit data, store in dataset and start the next conversion
{
    ...
    { //read 24 bit data + set gain and start next conversion
        if(SCK_DELAY) delayMicroseconds(1); // could be required for faster mcu's, set value in config.h
        digitalWrite(sckPin, 1);
                if(SCK_DELAY) delayMicroseconds(1); // could be required for faster mcu's, set value in config.h
        digitalWrite(sckPin, 0);
        if (i < (24)) 
        {
            dout = digitalRead(doutPin);
            data = data << 1;
            if (dout) 
            {
                data++;
            }
        ...
}

Editing this part of conversion24bit function and all starts working, I have a little more noise then 80sps, not sure if this is expected or not, but it starts functioning.

Config is set to 1 samples and no delays.

olkal commented 4 years ago

It could very well be that your change: SCK 1 > SCK 0 > read DOUT is more correct then the library's SCK 1 > read DOUT > SCK 0. If so it's an easy fix if that's what needed. Strange thing is that I don't know of anyone else that have had the same issue. Can I ask what kind of MCU are you using, is it particulary slow or fast?

BTW; yes you're right, pin 14 to GND enables the internal clock.

dsafak commented 4 years ago

I am using atmel32u4 on an Arduino Leonardo so nothing special, somehow this change makes it work and the other doesn't I am trying to figure out why because according to datasheet it should work either way.

and more suprisingly none of the available hx711 libraries seem to work in my case.

I also tried it with just an empty sketch and with a sketch which is really heavy (where I actually need to use the library) and it didn't work in both without this change.

olkal commented 4 years ago

I have never tried the library with the 32u4. I don't fully understand what is happening other than that it seems to be timing related, but I will move the digitalWrite LOW anyway if it can improve library compability. Studying the data sheet, it is also done like this in the driver example on page 8. however, I need to do some testing first to check that the change works okay with other MCU's.

dsafak commented 4 years ago

Sadly, I don't have anything else around right now to test with exact hx711 and crystal setup, but I also believe it is a timing issue. Thank you for paying attention to my issue, hope it just works fine on all MCUs so the change can be moved to master.

olkal commented 4 years ago

I did some testing with Uno, Due and ESP8266, all good. Changes implemented in new release 1.2.2.

dsafak commented 4 years ago

I have investigated this further and this is a timing issue (I added microsecond delays by 1 each time and encountered exact same issue at some point not really far from 0 microseconds).

There was one more issue with 20mhz crystal. With internal crystal at 80SPS, load cell at rest (no weight) reads 90K (offset is 0 so it just reads) When using 20mhz crystal it was dropping to 68K at rest, so this got me wondering why?

I thought it is because of Arduino's digitalWrite() function speed and maybe I am losing some data (I am still not sure), so I loaded the test sketch I've shared 7 messages above and switched digitalWrites with FastGPIO library. Nothing have changed about what is being read still around same 90K and 68K. BUT, With digitalWrite() At 80SPS with internal oscillator the noise is around 400 units. At 144SPS with external oscillator noise is around 1600 units. with FastGPIO At 80SPS with internal oscillator the noise is around 400 units. At 144SPS with external oscillator noise is around 400 units.

This can be done just by writing into registers directly to set High and Low, I just wanted to use a library to save myself some time.

I thought this issue is kind of okay to also include this information. I guess writing into registers for setting pins high and low is not an option for a library targeting many devices. But these are my findings.

olkal commented 4 years ago

Lots of strange things here... Direct port manipulation for faster writing is difficult with a library, yes. I did some testing today with a 32u4 together with 20mhz HX711, and it seems to work fine here, also with the previous library version. Could there be something wrong with your HX711 module? Do you have another one to test with?

dsafak commented 4 years ago

How does it work for you with previous version but doesn't work for me is strange.

When I put a counter for a second and read load cell data and then read counter after a second, I get 145 with 20mhz, and 84 with internal oscillator. Serial plotter also moves faster and slower when I change oscillator. I don't know why with 20mhz it reads about 30K less at rest. about 65K vs 90K. Also I can't really point a finger at why there is more noise with digitalWrite vs Port manipulation. Port manipulation brings noise back to exactly internal oscillator levels.

But it is functioning as expected when there is a force applied on it, so I can't point fingers at anything.

I tried with 2 different Arduino, one is a normal clone, the other one is a little special and has better quality. They are both running 32u4 @ 16mhz. 2 Different HX711s, cheap regular ones thought. A new sketch just with bare minimum to read load cell. tried digital pins 2-3, 3-4, 8-9 4-5 different 20mhz crystals but all bought at the same time from same store. At this point I wonder what if they are not 20 but 20.1mhz 20.2mhz? Maybe messes up with timing? or my Cheap hx711s have to do something with this? but they are the only ones available here. I can't think of anything else.

so it's not the 32u4, not the Arduino board, not hx711(same IC cheap or expensive board anyway, right?)

doesn't work with old version of library, works with new version. At this point I really hope your 32u4s were running faster than 16mhz at that was why old one worked for oyu.

One more question did you observe a drop in the read value switcihng between 80 and 144SPS as I have? and more noise with 144SPS with digitalWrite?

About direct port manipulation, I am writing more methods into library to enable direct port manipulation right now, I have some issues and trying to fix them.

dsafak commented 4 years ago

One more think, what capacitors are you using? Maybe that is why we are seeing different results.

olkal commented 4 years ago

On the crystal? I think it's 22pF

dsafak commented 4 years ago

Thanks, I'll try but what do you think, I think I have tried enough different hardware. I tried with 33pF and without any, nothing was different.

it is either crystal, capacitor or cheap hx711 (shouldn't be this one).

Are you sure it is working on old version with 32u4 @ 16mhz? This is really strange.

olkal commented 4 years ago

Yes, it's working fine with my 32u4 16mhz mini (china manufactured) also with old version library with the digitalWrite(sckPin, 0) in original position. Tested with 20mhz + internal osc, high rate and low rate. I don't see any noticable difference in noise changing from 20mhz to internal osc.

I do see an offset in the output value comparing internal and external osc. but not much, its aprox. 2.5gr on a 1000gr load cell, so 0.25%.

The Arduino 32u4 modules use a "real" crystal, not ceramic oscilator, so MCU frequency should be accurate within 50ppm and same as yours.

dsafak commented 4 years ago

I didn't know the last bit about 32u4. The noise offset looks to be right in line with my experience. Noise is so important for my project so I was talking about raw reading noise, so it is normal for you to not see any noticible noise but there was in raw data about 200-500 vs 800-1600. (Filter is also disabled because latency is also important, so no filter either just raw data)

so all looks inline with what I see here, so it must be my crystals I suppose, but lets assume they are a little over 20mhz, I still don't think it should cause such issue, maybe it does mess up with timings. They all say "20mhz" on them thought, maybe I should measure them for real, the measurementI do on arduino isn't that accurate but still lays right on 145sps (should be 144 with exact 20mhz but again not accurate)... well...

About library and pulsing with port manipulation. at first I was converting every method and naming them "xxxWPM" then I realized it isn't really required.

I implemented a real simple method into the library, void pulseUsingPortManipulation(byte aDDRB, byte aDDRC, byte aDDRD); So you do everything as before, but if you call this method like, loadcell.pulseUsingPortManipulation(B00000000, B10000000, B00000000); This will set a flag and inside conversion24bit() method, Port manipulation will be used to pulse pin13 (for arduino leonardo). I didn't touch the digitalRead as it wasn't necessary.

I don't plan to map ports to pin numbers arduino, it even changes between arduino type to arduino type, so when this method is used, correct register should be put into parameters for the correct pin, this is kinda low level and a special case anyway.

At least this is the plan. Works with single loadcell, all good, no issues. Gonna test it with multiple loadcells.

olkal commented 4 years ago

I added some lines in the library .cpp file to roughly measure digital write time:

{ //read 24 bit data + set gain and start next conversion
        long t; //add
        t = micros(); //add
        if(SCK_DELAY) delayMicroseconds(1); // could be required for faster mcu's, set value in config.h
        digitalWrite(sckPin, 1);
        if(SCK_DELAY) delayMicroseconds(1); // could be required for faster mcu's, set value in config.h
        digitalWrite(sckPin, 0);
        if (i == 0) Serial.println(micros() - t); //add
        if (i < (24)) ....

The result was 16us, sometimes 20us. That is for 2x digital write + some time to read the micros() value so I suppose each digital write is about 6-7us. Could you try the same?

olkal commented 4 years ago

I just measured with oscilloscope using my 32u4 and library latest version: the SCK high time is 6.6us, well within the required range of 0.2-50us in the H711 data sheet.

dsafak commented 4 years ago

I don't have access to an oscilloscope right now but I did the changes and measured with my Arduino. I got 12-16 in serial monitor -> Works. Old library 16-20 -> Doesn't work.

My knowledge about how things work as of right now ends here, so I wonder if increasing xtal to 20mhz reduces the time windows?

olkal commented 3 years ago

Closed due to no activity