Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spring cleaning with multiarch support #123

Merged
merged 37 commits into from
Feb 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
c04fee6
Ignore .idea directory
amotl Feb 16, 2019
6f89c03
Fix version guard pragma
amotl Feb 16, 2019
079c01d
Get rid of initialize-with-constructor variant
amotl Feb 16, 2019
86b3ea9
Improve example and documentation
amotl Feb 16, 2019
f8ad845
Added speed support for the esp32 chip
lemio Aug 17, 2017
5a1302a
Add shiftIn() speed support for Teensy
amotl Feb 16, 2019
bc0a684
Improve "yield" polyfill for ancient Arduino versions
amotl Feb 16, 2019
4439333
Add critical section to protect shared resource access on SMP machines
amotl Feb 16, 2019
ba7e811
Update README
amotl Feb 16, 2019
222b065
Prevent ints from corrupting the read sequence
dhmsjs Feb 20, 2017
fbaae9f
It's not appropriate to feed the ESP WDT using
amotl Feb 16, 2019
29a4f70
Add two examples for basic use and timeout operation
Feb 25, 2018
3953891
Adapt examples
amotl Feb 17, 2019
9d63b65
Improve multiarch support
amotl Feb 17, 2019
67342c3
Add "plaformio.ini" and build environment tooling for compiling the "…
amotl Feb 17, 2019
3b089dd
Update documentation
amotl Feb 17, 2019
4e3ef00
Add backlog notes
amotl Feb 17, 2019
319da9d
Bump library version
amotl Feb 17, 2019
c4e40c4
Forgot thinko in code
amotl Feb 17, 2019
ca03614
Add PlatformIO support for Bluepill
amotl Feb 17, 2019
70a285a
Bump version
amotl Feb 17, 2019
51a63c8
Document PlatformIO support for STM32
amotl Feb 17, 2019
fad56bf
Switch to ARDUINO_ARCH_ pragma constants, add bits for STM32
amotl Feb 17, 2019
e94d022
Update documentation
amotl Feb 17, 2019
b8e5511
Bump version
amotl Feb 17, 2019
53c4098
Minor cosmetics
amotl Feb 17, 2019
82d7531
Introduce custom architecture pragma constants to streamline conditio…
amotl Feb 17, 2019
421eae4
Bump version
amotl Feb 17, 2019
770a8ed
Fall back to regular Arduino "noInterrupts()" / "interrupts()"
amotl Feb 17, 2019
364f962
Update docs
amotl Feb 17, 2019
958e3ec
Bump version
amotl Feb 17, 2019
fad8a45
What's that?
amotl Feb 19, 2019
87727e0
Add more variants how to wait for HX711, see also #125
amotl Feb 19, 2019
a497b14
Minor documentation update
amotl Feb 19, 2019
3b48930
Reflect hardware support confirmed by @bogde, thanks!
amotl Feb 19, 2019
7d75502
Slightly correct testing state of HAL support
amotl Feb 19, 2019
83c9f51
Simplify pinout definitions by not trying
amotl Feb 20, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,10 @@
*.lai
*.la
*.a

# IDE metadata
/.idea

# PlatformIO virtualenv and pioenv
/.venv*
/.pioenvs
8 changes: 3 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@ cache:
directories:
- "~/.platformio"

env:
- PLATFORMIO_CI_SRC=examples/HX711Serial
- PLATFORMIO_CI_SRC=examples/HX711SerialBegin

install:
- pip install -U platformio

script:
- platformio ci --board=megaatmega2560 --lib="."
- platformio ci --board=megaatmega2560 --lib="." examples/HX711_full_example
- platformio ci --board=megaatmega2560 --lib="." examples/HX711_timeout_example
- platformio run
20 changes: 20 additions & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# HX711 library contributors

Listed in the order of appearance.

- Weihong Guan: First steps
- Bogdan Necula: Making it real
- Zachary J. Fields: Performance improvements on AVR. Simplify read logic.
- Rodrigo Wirth: Support to read the current `get_offset` and `get_scale`
- Ulrich Wolf: Move pin definition out of constructor
- Alexander Wilms: Improve documentation
- David Holland-Moritz: Improve interrupt safety on AVR
- Geert Roumen et al.: ESP32 support
- Thomas O Fredericks: Support for Teensy 3.2 and non-blocking readings
- Ahmad Elbadri: Improve ESP8266 stability
- Andreas Motl: Bookkeeping, multiarch support
- The Hiveeyes Developers: Spring-cleaning 2019
- Many bits and pieces by countless people from the community,
see also "doc/backlog.rst" in the repository.

Thanks a bunch!
177 changes: 156 additions & 21 deletions HX711.cpp
Original file line number Diff line number Diff line change
@@ -1,19 +1,66 @@
/**
*
* HX711 library for Arduino
* https://github.com/bogde/HX711
*
* MIT License
* (c) 2018 Bogdan Necula
*
**/
#include <Arduino.h>
#include <HX711.h>

#ifndef ESP8266
#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
// TEENSYDUINO has a port of Dean Camera's ATOMIC_BLOCK macros for AVR to ARM Cortex M3.
#define HAS_ATOMIC_BLOCK (defined(ARDUINO_ARCH_AVR) || defined(TEENSYDUINO))

// Whether we are running on either the ESP8266 or the ESP32.
#define ARCH_ESPRESSIF (defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32))

// Whether we are actually running on FreeRTOS.
#define IS_FREE_RTOS defined(ARDUINO_ARCH_ESP32)

// Define macro designating whether we're running on a reasonable
// fast CPU and so should slow down sampling from GPIO.
#define FAST_CPU \
( \
ARCH_ESPRESSIF || \
defined(ARDUINO_ARCH_SAM) || defined(ARDUINO_ARCH_SAMD) || \
defined(ARDUINO_ARCH_STM32) || defined(TEENSYDUINO) \
)

#if HAS_ATOMIC_BLOCK
// Acquire AVR-specific ATOMIC_BLOCK(ATOMIC_RESTORESTATE) macro.
#include <util/atomic.h>
#endif

HX711::HX711(byte dout, byte pd_sck, byte gain) {
#ifndef ESP8266
begin(dout, pd_sck, gain);
#endif
#if FAST_CPU
// Make shiftIn() be aware of clockspeed for
// faster CPUs like ESP32, Teensy 3.x and friends.
// See also:
// - https://github.com/bogde/HX711/issues/75
// - https://github.com/arduino/Arduino/issues/6561
// - https://community.hiveeyes.org/t/using-bogdans-canonical-hx711-library-on-the-esp32/539
uint8_t shiftInSlow(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) {
uint8_t value = 0;
uint8_t i;

for(i = 0; i < 8; ++i) {
digitalWrite(clockPin, HIGH);
delayMicroseconds(1);
if(bitOrder == LSBFIRST)
value |= digitalRead(dataPin) << i;
else
value |= digitalRead(dataPin) << (7 - i);
digitalWrite(clockPin, LOW);
delayMicroseconds(1);
}
return value;
}
#define SHIFTIN_WITH_SPEED_SUPPORT(data,clock,order) shiftInSlow(data,clock,order)
#else
#define SHIFTIN_WITH_SPEED_SUPPORT(data,clock,order) shiftIn(data,clock,order)
#endif


HX711::HX711() {
}
Expand Down Expand Up @@ -53,27 +100,74 @@ void HX711::set_gain(byte gain) {
}

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

// Wait for the chip to become ready.
wait_ready();

// Define structures for reading data into.
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);
// Protect the read sequence from system interrupts. If an interrupt occurs during
// the time the PD_SCK signal is high it will stretch the length of the clock pulse.
// If the total pulse time exceeds 60 uSec this will cause the HX711 to enter
// power down mode during the middle of the read sequence. While the device will
// wake up when PD_SCK goes low again, the reset starts a new conversion cycle which
// forces DOUT high until that cycle is completed.
//
// The result is that all subsequent bits read by shiftIn() will read back as 1,
// corrupting the value returned by read(). The ATOMIC_BLOCK macro disables
// interrupts during the sequence and then restores the interrupt mask to its previous
// state after the sequence completes, insuring that the entire read-and-gain-set
// sequence is not interrupted. The macro has a few minor advantages over bracketing
// the sequence between `noInterrupts()` and `interrupts()` calls.
#if HAS_ATOMIC_BLOCK
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {

#elif IS_FREE_RTOS
// Begin of critical section.
// Critical sections are used as a valid protection method
// against simultaneous access in vanilla FreeRTOS.
// Disable the scheduler and call portDISABLE_INTERRUPTS. This prevents
// context switches and servicing of ISRs during a critical section.
portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL(&mux);

#else
// Disable interrupts.
noInterrupts();
#endif

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

// set the channel and the gain factor for the next reading using the clock pin
// 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);
#if ARCH_ESPRESSIF
delayMicroseconds(1);
#endif
digitalWrite(PD_SCK, LOW);
#if ARCH_ESPRESSIF
delayMicroseconds(1);
#endif
}

#if IS_FREE_RTOS
// End of critical section.
portEXIT_CRITICAL(&mux);

#elif HAS_ATOMIC_BLOCK
}

#else
// Enable interrupts again.
interrupts();
#endif

// Replicate the most significant bit to pad out a 32-bit signed integer
if (data[2] & 0x80) {
filler = 0xFF;
Expand All @@ -90,11 +184,52 @@ long HX711::read() {
return static_cast<long>(value);
}

void HX711::wait_ready(unsigned long delay_ms) {
// Wait for the chip to become ready.
// This is a blocking implementation and will
// halt the sketch until a load cell is connected.
while (!is_ready()) {
// Probably will do no harm on AVR but will feed the Watchdog Timer (WDT) on ESP.
// https://github.com/bogde/HX711/issues/73
delay(delay_ms);
}
}

bool HX711::wait_ready_retry(int retries, unsigned long delay_ms) {
// Wait for the chip to become ready by
// retrying for a specified amount of attempts.
// https://github.com/bogde/HX711/issues/76
int count = 0;
while (count < retries) {
if (is_ready()) {
return true;
}
delay(delay_ms);
count++;
}
return false;
}

bool HX711::wait_ready_timeout(unsigned long timeout, unsigned long delay_ms) {
// Wait for the chip to become ready until timeout.
// https://github.com/bogde/HX711/pull/96
unsigned long millisStarted = millis();
while (millis() - millisStarted < timeout) {
if (is_ready()) {
return true;
}
delay(delay_ms);
}
return false;
}

long HX711::read_average(byte times) {
long sum = 0;
for (byte i = 0; i < times; i++) {
sum += read();
yield();
// Probably will do no harm on AVR but will feed the Watchdog Timer (WDT) on ESP.
// https://github.com/bogde/HX711/issues/73
delay(0);
}
return sum / times;
}
Expand Down
26 changes: 20 additions & 6 deletions HX711.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
/**
*
* HX711 library for Arduino
* https://github.com/bogde/HX711
*
* MIT License
* (c) 2018 Bogdan Necula
*
**/
#ifndef HX711_h
#define HX711_h

Expand All @@ -17,23 +26,28 @@ class HX711
float SCALE = 1; // used to return weight in grams, kg, ounces, whatever

public:
// define clock and data pin, channel, and gain factor
// channel selection is made by passing the appropriate gain: 128 or 64 for channel A, 32 for channel B
// gain: 128 or 64 for channel A; channel B works with 32 gain factor only
HX711(byte dout, byte pd_sck, byte gain = 128);

HX711();

virtual ~HX711();

// Allows to set the pins and gain later than in the constructor
// Initialize library with data output pin, clock input pin and gain factor.
// Channel selection is made by passing the appropriate gain:
// - With a gain factor of 64 or 128, channel A is selected
// - With a gain factor of 32, channel B is selected
// The library default is "128" (Channel A).
void begin(byte dout, byte pd_sck, byte gain = 128);

// check if HX711 is ready
// Check if HX711 is ready
// from the datasheet: When output data is not ready for retrieval, digital output pin DOUT is high. Serial clock
// input PD_SCK should be low. When DOUT goes to low, it indicates data is ready for retrieval.
bool is_ready();

// Wait for the HX711 to become ready
void wait_ready(unsigned long delay_ms = 0);
bool wait_ready_retry(int retries = 3, unsigned long delay_ms = 0);
bool wait_ready_timeout(unsigned long timeout = 1000, unsigned long delay_ms = 0);

// set the gain factor; takes effect only after a call to read()
// channel A can be set for a 128 or 64 gain; channel B has a fixed 32 gain
// depending on the parameter, the channel is also set to either A or B
Expand Down
62 changes: 62 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# ============
# Main targets
# ============


# -------------
# Configuration
# -------------

$(eval venvpath := .venv2)
$(eval pip := $(venvpath)/bin/pip)
$(eval python := $(venvpath)/bin/python)
$(eval platformio := $(venvpath)/bin/platformio)

# Setup Python virtualenv
setup-virtualenv:
@test -e $(python) || `command -v virtualenv` --python=python2 --no-site-packages $(venvpath)


# ----------
# PlatformIO
# ----------

install-platformio: setup-virtualenv
@$(pip) install platformio --quiet

build-all: install-platformio
@$(platformio) run

build-env: install-platformio
@$(platformio) run --environment $(environment)


# Note: This are legacy build targets, the new ones are defined through `platformio.ini`.

ci-all: install-platformio
# atmelavr
$(platformio) ci --board=megaatmega2560 --lib="." examples/HX711_basic_example
$(platformio) ci --board=megaatmega2560 --lib="." examples/HX711_timeout_example
$(platformio) ci --board=megaatmega2560 --lib="." examples/HX711_full_example

# atmelavr
$(MAKE) ci-basic board=feather328p

# espressif8266
$(MAKE) ci-basic board=huzzah

# espressif32
$(MAKE) ci-basic board=lopy4

# atmelsam
$(MAKE) ci-basic board=adafruit_feather_m0
$(MAKE) ci-basic board=adafruit_feather_m4

# bluepill
$(MAKE) ci-basic board=bluepill_f103c8

ci-basic:
$(platformio) ci --board=$(board) --lib="." examples/HX711_basic_example --verbose

clean:
platformio run -t clean
Loading