Giter Site home page Giter Site logo

endail / hx711-pico-c Goto Github PK

View Code? Open in Web Editor NEW
29.0 5.0 6.0 3.73 MB

Implementation of single and multiple HX711 use via RP2040's state machine

Home Page: https://endail.github.io/hx711-pico-c/

License: MIT License

CMake 7.02% C 92.98%
raspberry-pi-pico rp2040 pioasm c hx711 load-cell loadcell state-machine pio raspberry-pi raspberry-pi-pico-rp2040 iot

hx711-pico-c's Introduction

hx711-pico-c

This is my implementation of reading from a HX711 via a Raspberry Pi Pico. It uses the RP2040's PIO feature to be as efficient as possible. It has two major functions: reading from a single HX711 and reading from multiple HX711s.

A MicroPython port is available here.

NOTE: if you are looking for a method to weigh objects (ie. by using the HX711 as a scale), see pico-scale.

resources/hx711_80sps_serialout.gif

The .gif above illustrates obtaining data from a single HX711 operating at 80 samples per second.

Clone Repository

git clone https://github.com/endail/hx711-pico-c

Run cmake to build the example program. The .uf2 file you upload to your Pico will be found under build/tests/.

Alternatively, include it as a submodule in your project and then #include "extern/hx711-pico-c/include/common.h".

git submodule add https://github.com/endail/hx711-pico-c extern/hx711-pico-c
git submodule update --init

Documentation

https://endail.github.io/hx711-pico-c

How to Use hx711_t

See here for a pinout to choose two GPIO pins on the Pico (RP2040). One GPIO pin to connect to the HX711's clock pin and a second GPIO pin to connect to the HX711's data pin. You can choose any two pins as the clock and data pins, as long as they are capable of digital output and input respectively.

#include "include/common.h"

// 1. Set configuration
hx711_config_t hxcfg;
hx711_get_default_config(&hxcfg);

hxcfg.clock_pin = 14; //GPIO pin connected to HX711 clock pin
hxcfg.data_pin = 15; //GPIO pin connected to HX711 data pin

//by default, the underlying PIO program will run on pio0
//if you need to change this, you can do:
//hxcfg.pio = pio1;

// 2. Initialise
hx711_init(&hx, &hxcfg);

// 3. Power up the hx711 and set gain on chip
hx711_power_up(&hx, hx711_gain_128);

// 4. This step is optional. Only do this if you want to
// change the gain AND save it to the HX711 chip
//
// hx711_set_gain(&hx, hx711_gain_64);
// hx711_power_down(&hx);
// hx711_wait_power_down();
// hx711_power_up(&hx, hx711_gain_64);

// 5. Wait for readings to settle
hx711_wait_settle(rate);

// 6. Read values
// You can now...

// wait (block) until a value is obtained
printf("blocking value: %li\n", hx711_get_value(&hx));

// or use a timeout
int32_t val;
const uint timeout = 250000; //microseconds
if(hx711_get_value_timeout(&hx, timeout, &val)) {
    // value was obtained within the timeout period
    printf("timeout value: %li\n", val);
}
else {
    printf("value was not obtained within the timeout period\n");
}

// or see if there's a value, but don't block if there isn't one ready
if(hx711_get_value_noblock(&hx, &val)) {
    printf("noblock value: %li\n", val);
}
else {
    printf("value was not present\n");
}

//6. Stop communication with HX711
hx711_close(&hx);

How to Use hx711_multi_t

See here for a pinout to choose at least two separate GPIO pins on the Pico (RP2040).

  • One GPIO pin to connect to every HX711's clock pin.
  • One or more contiguous GPIO pins to separately connect to each HX711's data pin.

For example, if you wanted to connect four HX711 chips, you could:

  • Connect GPIO pin 9 to each HX711's clock pin; and
  • Connect GPIO pins 12, 13, 14, and 15 to each separate HX711's data pin.

See the code example below for how you would set this up. You can choose any pins as the clock and data pins, as long as they are capable of digital output and input respectively.

You can connect up to 32 HX711s, although the Pico (RP2040) will limit you to the available pins.

Note: each chip should use the same sample rate. Using chips with different sample rates will lead to unpredictible results.

#include "../include/common.h"

// 1. Set configuration
hx711_multi_config_t hxmcfg;
hx711_multi_get_default_config(&hxmcfg);
hxmcfg.clock_pin = 9; //GPIO pin connected to each HX711 chip
hxmcfg.data_pin_base = 12; //first GPIO pin used to connect to HX711 data pin
hxmcfg.chips_len = 4; //how many HX711 chips connected

//by default, the underlying PIO programs will run on pio0
//if you need to change this, you can do:
//hxmcfg.pio = pio1;

// 2. Initialise
hx711_multi_t hxm;
hx711_multi_init(&hxm, &hxmcfg);

// 3. Power up the HX711 chips and set gain on each chip
hx711_multi_power_up(&hxm, hx711_gain_128);

// 4. This step is optional. Only do this if you want to
// change the gain AND save it to each HX711 chip
//
// hx711_multi_set_gain(&hxm, hx711_gain_64);
// hx711_multi_power_down(&hxm);
// hx711_wait_power_down();
// hx711_multi_power_up(&hxm, hx711_gain_64);

// 5. Wait for readings to settle
hx711_wait_settle(hx711_gain_128);

// 6. Read values
int32_t arr[hxmcfg.chips_len];

// 6a. wait (block) until values are ready
hx711_multi_get_values(&hxm, arr);

// then print the value from each chip
// the first value in the array is from the HX711
// connected to the first configured data pin and
// so on
for(uint i = 0; i < hxmcfg.chips_len; ++i) {
    printf("hx711_multi_t chip %i: %li\n", i, arr[i]);
}

// 6b. use a timeout
if(hx711_multi_get_values_timeout(&hxm, arr, 250000)) {
    // do something with arr
}

// 6c. or read values asynchronously
hx711_multi_async_start(&hxm);

// do other work while waiting for values...

// use hx711_multi_async_done(&hxm) to check
// if values are ready, then...

hx711_multi_async_get_values(&hxm, arr);

// do something with arr

// 7. Stop communication with all HX711 chips
hx711_multi_close(&hxm);

Notes

Where is Channel A and Channel B?

Channel A is selectable by setting the gain to 128 or 64. Channel B is selectable by setting the gain to 32.

The HX711 has no option for Channel A at a gain of 32, nor is there an option for Channel B at a gain of 128 or 64. Similarly, the HX711 is not capable of reading from Channel A and Channel B simultaneously. The gain must first be changed.

What is hx711_wait_settle?

After powering up, the HX711 requires a small "settling time" before it can produce "valid stable output data" (see: HX711 datasheet pg. 3). By calling hx711_wait_settle() and passing in the correct data rate, you can ensure your program is paused for the correct settling time. Alternatively, you can call hx711_get_settling_time() and pass in a hx711_rate_t which will return the number of milliseconds of settling time for the given data rate.

What is hx711_wait_power_down?

The HX711 requires the clock pin to be held high for at least 60us (60 microseconds) before it powers down. By calling hx711_wait_power_down() after hx711_power_down() you can ensure the chip is properly powered-down.

Save HX711 Gain to Chip

By setting the HX711 gain with hx711_set_gain and then powering down, the chip saves the gain for when it is powered back up. This is a feature built-in to the HX711.

Powering up with Unknown or Incorrect Gain

When calling hx711_power_up() or hx711_multi_power_up() it is assumed that the gain value passed to these functions indicates the previously saved gain value in the chip. If the previously saved gain is unknown, you can either:

  1. Power up with the gain you want then perform at least one read of the chip (eg. hx711_get_value(), hx711_multi_get_values(), etc...), and the subsequent reads will have the correct gain; or

  2. Power up with any gain and then call hx711_set_gain() or hx711_multi_set_gain() with the gain you want.

hx711_close/hx711_multi_close vs hx711_power_down/hx711_multi_power_down

In the example code above, the final statement closes communication with the HX711. This leaves the HX711 in a powered-up state. hx711_close and hx711_multi_close stops the internal state machines from reading data from the HX711. Whereas hx711_power_down and hx711_multi_power_down also begins the power down process on a HX711 chip by setting the clock pin high.

Synchronising Multiple Chips

When using multiple HX711 chips, it is possible they may be desynchronised if not powered up simultaneously. You can use hx711_multi_sync() which will power down and then power up all chips together.

PIO + DMA Interrupt Specifics

When using hx711_multi_t, two interrupts are claimed: one for a PIO interrupt and one for a DMA interrupt. By default, PIO[N]_IRQ_0 and DMA_IRQ_0 are used, where [N] is the PIO index being used (ie. configuring hx711_multi_t with pio0 means the resulting interrupt is PIO0_IRQ_0 and pio1 results in PIO1_IRQ_0). If you need to change the IRQ index for either PIO or DMA, you can do this when configuring.

hx711_multi_config_t hxmcfg;
hx711_multi_get_default_config(&hxmcfg);
hxmcfg.pio = pio1;
hxmcfg.pio_irq_index = 0; //PIO1_IRQ_0 is claimed
hxmcfg.dma_irq_index = 1; //DMA_IRQ_1 is claimed

Mutex?

Mutex functionality is included and enabled by default to protect the HX711 conversion process. If you are sure you do not need it, define the preprocessor flag HX711_NO_MUTEX then recompile.

Custom PIO Programs

#include include/common.h includes the PIO programs I have created for both hx711_t and hx711_multi_t. Calling hx711_get_default_config() and hx711_multi_get_default_config() will include those PIO programs in the configurations. If you want to change or use your own PIO programs, set the relevant hx711_*_config_t defaults, and do the following:

hx711_config_t hxcfg;
hxcfg.pio_init = my_hx_pio_init_func; // function to setup the PIO
hxcfg.reader_prog = my_pio_program; // pio_program_t*
hxcfg.reader_prog_init = my_pio_program_init_func; // function to setup the PIO program

hxcfg.pio_init and hxcfg.pio_prog_init take a pointer to the hx711_t as the only parameter.

hx711_multi_config_t hxmcfg;
hxmcfg.pio_init = my_hxm_pio_init_func; // function to setup the PIO
hxmcfg.awaiter_prog = my_pio_awaiter_program; // pio_program_t*
hxmcfg.awaiter_prog_init = my_hxm_awaiter_init_func; // function to setup the awaiter PIO program
hxmcfg.reader_prog = my_pio_reader_progam; // pio_program_t*
hxmcfg.reader_prog_init = my_pio_reader_program_init; // function to setup the reader PIO progam

hxmcfg.pio_init, hxmcfg.awaiter_prog_init, and hxmcfg.reader_prog_init take a pointer to the hx711_multi_t as the only parameter.

Overview of Functionality

hx711_t

The single chip hx711_t functions with a single RP2040 State Machine (SM) in one PIO. This includes setting and changing the HX711's gain. The SM is configured to be free-running which constantly obtains values from the HX711. Values are buffered in the SM's RX FIFO which enables application code to retrieve the most up-to-date value possible. Reading from the RX FIFO simultaneously clears it, so applications are simply able to busy-wait on the RX_FIFO being filled for the next value.

hx711_multi_t

The multi chip hx711_multi_t functions with two RP2040 State Machines (SM) in one PIO. This includes setting and changing all HX711s gains. The first SM is the "awaiter". It is free-running. It constantly reads the pin state of each RP2040 GPIO pin configured as a data input pin. If and when every pin is low - indicating that every chip has data ready - a PIO interrupt is set.

The second SM is the "reader". It is also free-running. The reader waits for the data ready PIO interrupt from the awaiter and then begins the HX711 conversion period of reading in bits. The conversion period is synchronised with application code by setting and clearing an interrupt to denote when a conversion period is in progress.

The reader clocks in the state of each data input pin as a bitmask and then pushes it back out of the SM into the RX FIFO. There are 24 pushes; one for each HX711 bit. Due to the size of the RX FIFO only being 32 bits, a SM is not capable of buffering all HX711 input bits when there are multiple chips. Hence why there is a push for each HX711 bit.

On the receiving end of the SM is a DMA channel which automatically reads in each bitmask of HX711 bits into an array. These bitmasks are then transformed into HX711 values for each chip and returned to application code.

Additional Notes

  • channel_config_set_ring in conjunction with a static array buffer to constantly read in values from the SM lead to misaligned write addresses. As the HX711 uses 3 bytes to represent a value and the ring buffer requires a "naturally aligned buffer", it would take another byte to "reset" the ring back to the initial address. An application could not simply read the buffer and obtain valid value.

  • Two DMA channels in a ping-pong configuration to activate each other were tried as a method to keep the application-side reading in values. But there did not appear to be a straightforward method to constantly reset the write address back to the address of an array buffer. There also seemed to be an inherent race condition in having DMA write to a buffer when an application could read from it at any moment without a method to protect access to it which DMA would abide by.

  • A major disdvantage of the HX711 conversion period process is the time it takes to both wait for it to begin and complete. A processor could be doing other work. This is where DMA is particularly advantageous because the processor can do other work even while waiting for a value to be clocked-in.

  • Reading in the state of all configured data input pins as a bitmask has the advantage of being simultaneous on all HX711 chips. If each bit of each HX711 were to be clocked in round robin style, it would be much slower and run the risk of holding the clock pin for longer than the power down period. The second issue would lead to one or more chips powering down and becoming desynchronised from each other.

hx711-pico-c's People

Contributors

endail avatar github-actions[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

hx711-pico-c's Issues

request description of data and clock pins specifying both GP# and pad#

Current main.c, calibration.c and test.c have
// SET THESE TO THE GPIO PINS CONNECTED TO THE
// HX711's CLOCK AND DATA PINS
const uint clkPin = 14;
const uint datPin = 15;
request
const uint clkPin = 14; /* GP14 pad 19 /
const uint datPin = 15; /
GP15 pad 20 */

This might help someone else to avoid making the same mistake I did: connecting to pads 14 and 15.

You can make something foolproof
but you can't make it damn foolproof
because some damn fool will still find a way...

Don't disable pin input in close

gpio_set_input_enabled(

It seems intuitive for this to complement the gpio_init/gpio_set_dir calls within the hx711_init function. But the HX711 init function merely ensures the data pin can be used as an input. It should not be seen as a method for toggling the data pin's input state back and forth.

Increase frequency to 10MHz

image

Experiment with delaying and reading at the absolute minimum rates possible. Currently resolution is at 1us.

>2 bits in RX FIFO leaves residual data when retrieving gain

out x, 2 ; Get 2 bits from the OSR into x. This is enough

An out instruction moves n bits out of the OSR, but does not reset the output shift count to 0. The result is that if >2 bits of data are put into the SM, an out which only moves 2 bits will leave the rest in there. The following iteration of the main SM loop means that an incorrect gain value will be set.

The out should be replaced with either:

  1. a mov which shifts the entire contents and resets the output shift counter to 0 (RP2040 datasheet, pg. 326);

  2. a out which shifts out 32 bits; or

  3. a out which shifts out 2 bits and then a out null, 32 to discard any remaining bits.

The advantage of 1 and 2 is that it can be done in one instruction. The disadvantage is that an erroneous gain value will make the SM pulse the clock pin an invalid number of times.

The advantage of 3 is that it restricts the number of clock pulses to a maximum of 4 (which is still incorrect; valid range is 0-2). The disadvantage is that it takes two instructions.

I think an out which shifts the entire 32 bits (or whatever the contents of the FIFO is) out is the best solution. C can make sure the value being pushed into the FIFO is valid. I don't think the SM should be used for validation.

32-bit signed conversion

I get incorrect values for negative numbers. The following function for the conversion from 24-bit to 32-bit works correctly for me.

static inline int32_t hx711_get_twos_comp(const uint32_t raw) {

    int32_t val = raw;
    if (val & 0x800000) {
      val -= 0x1000000;
    }
    assert(val >= HX711_MIN_VALUE && val <= HX711_MAX_VALUE);

    return val;
}

Move PIO init function out of .pio file

% c-sdk {
// MIT License
//
// Copyright (c) 2022 Daniel Robertson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include "hardware/clocks.h"
#include "hardware/pio.h"
#include "../include/hx711.h"
void hx711_noblock_program_init(hx711_t* const hx) {
assert(hx != NULL);
assert(hx->_pio != NULL);
pio_sm_config cfg = hx711_noblock_program_get_default_config(hx->_offset);
//set state machine to 10MHz clock speed
const float div = (float)(clock_get_hz(clk_sys)) / 10000000;
sm_config_set_clkdiv(
&cfg,
div);
//clock pin setup
pio_sm_set_out_pins(
hx->_pio,
hx->_state_mach,
hx->clock_pin,
1);
pio_sm_set_set_pins(
hx->_pio,
hx->_state_mach,
hx->clock_pin,
1);
pio_gpio_init(
hx->_pio,
hx->clock_pin);
pio_sm_set_consecutive_pindirs(
hx->_pio,
hx->_state_mach,
hx->clock_pin,
1,
true);
sm_config_set_set_pins(
&cfg,
hx->clock_pin,
1);
sm_config_set_out_pins(
&cfg,
hx->clock_pin,
1);
sm_config_set_sideset_pins(
&cfg,
hx->clock_pin);
//data pin setup
pio_sm_set_in_pins(
hx->_pio,
hx->_state_mach,
hx->data_pin);
pio_sm_set_consecutive_pindirs(
hx->_pio,
hx->_state_mach,
hx->data_pin,
1,
false);
pio_gpio_init(
hx->_pio,
hx->data_pin);
sm_config_set_in_pins(
&cfg,
hx->data_pin);
/**
* Why enable autopush?
*
* "The state machine keeps an eye on the total amount of data shifted into the ISR, and on the in which reaches or
* breaches a total shift count of 32 (or whatever number you have configured), the ISR contents, along with the new data
* from the in. goes straight to the RX FIFO. The ISR is cleared to zero in the same operation."
* - Raspberry Pi Pico C/C++ SDK pg. 45
*
* When manually pushing using noblock, the FIFO contents are NOT changed.
*
* "The PIO assembler sets the Block bit by default. If the Block bit is not set, the PUSH does not stall on a full RX FIFO, instead
* continuing immediately to the next instruction. The FIFO state and contents are unchanged when this happens. The ISR
* is still cleared to all-zeroes, and the FDEBUG_RXSTALL flag is set (the same as a blocking PUSH or autopush to a full RX FIFO)
* to indicate data was lost."
* - Raspberry Pi Pico C/C++ SDK pg. 64
*
* Manually pushing is not ideal. Application code should be able to look at the FIFO and assume
* that the value inside is the most up-to-date data available. Autopushing does this.
*/
sm_config_set_in_shift(
&cfg,
false, //false = shift in left
true, //true = autopush enabled
HX711_READ_BITS); //autopush on 24 bits
//store a copy of the configuration for resetting the sm
hx->_default_config = cfg;
}
%}

#include "../include/hx711.h" is not playing nice with the CMake build system when this repo needs to be included in another (re: #30).

It seems that after calling pico_generate_pio_header in CMakeLists.txt, the c-sdk portion of the pio file is merely dropped in-place in the resulting generated header file. That header file then sits in the CMake build directory (eg. extern/hx711-pico-c/hx711_noblock.pio.h) with the relative #include to a non-existent hx711.h header file.

Solution: move the init function to a new source file, hx711_noblock.c.

Sparkfun HX711

Will the SparkFun Load Cell Amplifier - HX711 work with the library? According to what I've read, the pico can only give 3.3V and not 5V to the HX711 board, making it impossible to attach a standard HX711 board to it.
For which HX711 board is the library meant for?
P.S. My wiring appears to be correct because I can use the Sparkfun HX711 and Load Cells on an Arduino, but I want to run it with a Pico.

The output I get after uploading the main to the pico looks like the following:
---- Opened the serial port COM17 ----
blocking value: 4167482
timeout value: -1
noblock value: -1
Closed communication with single HX711 chip
hx711_multi_t chip 0: -1
hx711_multi_t chip 0: -1
hx711_multi_t chip 0: -1
Closed communication with multiple HX711 chips

Unused parameter in release build causes compile-time error

/**
* @brief Asserts that the hx has been properly initialised. Only calls assert().
*
* @param hx pointer to hx711_t
*/
static inline void hx711__assert_hx_initd(hx711_t* const hx) {
assert(hx != NULL);
assert(hx->_pio != NULL);
assert(pio_sm_is_claimed(hx->_pio, hx->_state_mach));
assert(mutex_is_initialized(&hx->_mut));
}

assert is removed in release causing hx pointer to go unused. Perhaps a macro instead?

State machine should accept an initial, configurable gain

set x, DEFAULT_GAIN ; Set an initial default gain (this is 0-based).

Currently the state machine begins with a predefined default gain of 128. This is fine if when the HX711 chip has powered up it too is configured for a gain of 128. But it is possible for a different gain to be saved to the chip for when it restarts.

This may require filling the TX FIFO with a gain value prior to starting the state machine, but also a nonblocking pull in the PIO program to set a default.

Assert *len == 0

++(*len);

This function should not assume *len == 0. It should however either assign a value of 0 before reading any values, or use a local len var then assign to *len before returning. Preferably the latter.

hx711_get_value_timeout suggestions

The hx711_get_value_timeout() function takes a pointer to the timeout value as an argument. I think it would be more convenient to pass by value, so you could write

bool ok = hx711_get_value_timeout(&hx, 2500, &val);

I think it might also be good to change the loop to

do {

} while (!timeReached(endTime));

This would allow calling the function with a timeout of zero and still get a value back if one is available. Alternatively, a function

bool hx711_get_value_noblock(hx711_t* const hx, int32_t* const val);

would be good and avoid the overhead of computing the timeout.

BTW, your library is great, I really appreciate you making it available on github.

Move clk/dat pin assignment out of init func?

const uint clk,
const uint dat,

Perhaps set them directly on the struct? But this gives the impression that if the pins are changed in the same way, that change would be reflected in the underlying code (gpio init, etc...) which is wrong.

Maybe prefixing the clock/data_pin vars with an underscore gives a better indication that they're C++-esque "private" and shouldn't be accessed/changed.

Restarting SM clears clock divider

Clock is set in state machine init function:

//set state machine to 1MHz clock speed
const float div = (float)(clock_get_hz(clk_sys)) / 1000000;
sm_config_set_clkdiv(
&cfg,
div);

But powering up from hx711_set_power restarts the SM, which also clears the clock setting.

pio_sm_restart(hx->_pio, hx->_state_mach);

pio_sm_restart

Restart a state machine with a known state.

This method clears the ISR, shift counters, clock divider counter pin write flags, delay counter, latched EXEC instruction, and IRQ wait condition.

https://raspberrypi.github.io/pico-sdk-doxygen/group__hardware__pio.html#ga7b89b93dd0553c77538c70baf6a7e4f0

Multiple hx711s wastes PIO/SM resources

Each time a hx711_t is init'd, a copy of the PIO program is inserted into one of the RP2040's PIOs. It should instead:

  • check if the program already exists in PIO memory
  • if not, add it
  • then set up an individual state machine with the program counter pointing to the program

Many SMs to one PIO.

[novice question] Not getting values using hx711_get_value; how should I debug my setup?

I am not getting value using hx711_get_value or any of its variants. This method blocks and waits endlessly. I am using this amplifier for the first time. So it could be an issue with my setup. I want to know how do I make sure that I have connect the right pins.

I am on Linux host and using CLI to copy files and checking using minicom. I am printing statements and reading via USB.

Allocating before obtaining

(*arr)[(*len) - 1] = hx711_get_value(sc->_hx);

This is backward. The value should be obtained first, then a realloc, then assignment.

Another check for timeout after obtaining the blocking call should be used as well.

Reading into ISR is stalling the SM

Initially the PIO program runs for a few iterations but eventually stalls on something. I suspect it is the ISR. The input values are never read by application code because it doesn't need to. But it probably means the ISR is filling up and not being cleared. So eventually it blocks and stalls the SM. When it stalls, the IRQs don't fire which also blocks the application code. This would explain why it runs x amount of times but then stalls.

If the above is correct, a push noblock should do the trick to clear the ISR without any other modifications to application code. Just make sure it's after the copy to the y register.

Possible side-set optimisation when setting gain

The nature of the HX711 is that it requires at least one clock pulse each time a read takes place to set the gain. It may be possible to side-set the clock pin for at least one clock pulse on the pull, out, or mov instructions to avoid looping.

pull noblock ; Pull in any data if it's available, but don't
; wait if there isn't any. If no data is there,
; preload from x (this is what noblock does).
out x, 2 ; Get 2 bits from the OSR into x. This is enough
; to hold the max expected value (2). x will also
; persist after the wrap loop.
mov y, x ; Copy x into y. y will hold the number of clock
; pulses minus 1 to be used as the following loop
; counter.
; gainloop will always execute at least once; the
; HX711 expects at least one clock pulse when
; setting the gain, so this works well.
gainloop:
set pins, 1 ; Set clock pin high.
jmp y-- gainloop side 0 ; Set clock pin low and keep pulsing clock pin

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.