hx711-pico-c
hx711.c
Go to the documentation of this file.
1 // MIT License
2 //
3 // Copyright (c) 2023 Daniel Robertson
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in all
13 // copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 // SOFTWARE.
22 
23 #include <assert.h>
24 #include <stdint.h>
25 #include "hardware/gpio.h"
26 #include "hardware/pio.h"
27 #include "hardware/timer.h"
28 #include "pico/platform.h"
29 #include "pico/mutex.h"
30 #include "pico/time.h"
31 #include "../include/hx711.h"
32 #include "../include/util.h"
33 
34 const unsigned short HX711_SETTLING_TIMES[] = {
35  400,
36  50
37 };
38 
39 const unsigned char HX711_SAMPLE_RATES[] = {
40  10,
41  80
42 };
43 
44 const unsigned char HX711_CLOCK_PULSES[] = {
45  25,
46  26,
47  27
48 };
49 
51  hx711_t* const hx,
52  const hx711_config_t* const config) {
53 
54  assert(!hx711__is_initd(hx));
55 
56  assert(hx != NULL);
57  assert(config != NULL);
58 
59  assert(config->pio != NULL);
60  assert(config->pio_init != NULL);
61 
62  assert(config->reader_prog != NULL);
63  assert(config->reader_prog_init != NULL);
64 
65  check_gpio_param(config->clock_pin);
66  check_gpio_param(config->data_pin);
67  assert(config->clock_pin != config->data_pin);
68 
69 #ifndef HX711_NO_MUTEX
70  mutex_init(&hx->_mut);
71 #endif
72 
74 
75  hx->_clock_pin = config->clock_pin;
76  hx->_data_pin = config->data_pin;
77  hx->_pio = config->pio;
78  hx->_reader_prog = config->reader_prog;
79 
81 
95  gpio_set_input_enabled(
96  hx->_data_pin,
97  true);
98 
107  //either statement below will panic if it fails
108  hx->_reader_offset = pio_add_program(
109  hx->_pio,
110  hx->_reader_prog);
111 
112  hx->_reader_sm = (uint)pio_claim_unused_sm(
113  hx->_pio,
114  true);
115 
116  config->pio_init(hx);
117  config->reader_prog_init(hx);
118 
119  );
120 
121 }
122 
123 void hx711_close(hx711_t* const hx) {
124 
125  //state machines do not have to be running in order
126  //to close
127  assert(hx711__is_initd(hx));
128 
129  HX711_MUTEX_BLOCK(hx->_mut,
130 
131  pio_sm_set_enabled(
132  hx->_pio,
133  hx->_reader_sm,
134  false);
135 
136  pio_sm_unclaim(
137  hx->_pio,
138  hx->_reader_sm);
139 
140  pio_remove_program(
141  hx->_pio,
142  hx->_reader_prog,
143  hx->_reader_offset);
144 
145  );
146 
147 }
148 
149 void hx711_set_gain(hx711_t* const hx, const hx711_gain_t gain) {
150 
152  assert(hx711_is_gain_valid(gain));
153 
154  const uint32_t pioGain = hx711_gain_to_pio_gain(gain);
155 
156  assert(hx711_is_pio_gain_valid(pioGain));
157 
158  HX711_MUTEX_BLOCK(hx->_mut,
159 
168  pio_sm_drain_tx_fifo(
169  hx->_pio,
170  hx->_reader_sm);
171 
172  pio_sm_put(
173  hx->_pio,
174  hx->_reader_sm,
175  pioGain);
176 
204  //1. clear the RX FIFO with the non-blocking read
205  pio_sm_get(
206  hx->_pio,
207  hx->_reader_sm);
208 
209  //2. wait until the value from the currently-set gain
210  //can be safely read and discarded
211  pio_sm_get_blocking(
212  hx->_pio,
213  hx->_reader_sm);
214 
227  );
228 
229 }
230 
231 int32_t hx711_get_twos_comp(const uint32_t raw) {
232  return
233  (int32_t)(-(raw & +HX711_MIN_VALUE)) +
234  (int32_t)(raw & HX711_MAX_VALUE);
235 }
236 
237 bool hx711_is_min_saturated(const int32_t val) {
238  assert(hx711_is_value_valid(val));
239  return val == HX711_MIN_VALUE;
240 }
241 
242 bool hx711_is_max_saturated(const int32_t val) {
243  assert(hx711_is_value_valid(val));
244  return val == HX711_MAX_VALUE;
245 }
246 
247 unsigned short hx711_get_settling_time(const hx711_rate_t rate) {
248  assert(hx711_is_rate_valid(rate));
249  assert((int)rate <= count_of(HX711_SETTLING_TIMES) - 1);
250  return HX711_SETTLING_TIMES[(int)rate];
251 }
252 
253 unsigned char hx711_get_rate_sps(const hx711_rate_t rate) {
254  assert(hx711_is_rate_valid(rate));
255  assert((int)rate <= count_of(HX711_SAMPLE_RATES) - 1);
256  return HX711_SAMPLE_RATES[(int)rate];
257 }
258 
259 unsigned char hx711_get_clock_pulses(const hx711_gain_t gain) {
260  assert(hx711_is_gain_valid(gain));
261  assert((int)gain <= count_of(HX711_CLOCK_PULSES) - 1);
262  return HX711_CLOCK_PULSES[(int)gain];
263 }
264 
265 int32_t hx711_get_value(hx711_t* const hx) {
266 
268 
269  uint32_t rawVal;
270 
271  HX711_MUTEX_BLOCK(hx->_mut,
272 
282  rawVal = pio_sm_get_blocking(
283  hx->_pio,
284  hx->_reader_sm);
285 
286  );
287 
288  return hx711_get_twos_comp(rawVal);
289 
290 }
291 
293  hx711_t* const hx,
294  int32_t* const val,
295  const uint timeout) {
296 
298  assert(val != NULL);
299 
300  bool success = false;
301  const absolute_time_t endTime = make_timeout_time_us(timeout);
302  uint32_t tempVal;
303 
304  assert(!is_nil_time(endTime));
305 
306  HX711_MUTEX_BLOCK(hx->_mut,
307  while(!time_reached(endTime)) {
308  if((success = hx711__try_get_value(hx->_pio, hx->_reader_sm, &tempVal))) {
309  break;
310  }
311  }
312  );
313 
314  if(success) {
315  *val = hx711_get_twos_comp(tempVal);
316  }
317 
318  return success;
319 
320 }
321 
323  hx711_t* const hx,
324  int32_t* const val) {
325 
327  assert(val != NULL);
328 
329  bool success;
330  uint32_t tempVal;
331 
332  HX711_MUTEX_BLOCK(hx->_mut,
333  success = hx711__try_get_value(
334  hx->_pio,
335  hx->_reader_sm,
336  &tempVal);
337  );
338 
339  if(success) {
340  *val = hx711_get_twos_comp(tempVal);
341  }
342 
343  return success;
344 
345 }
346 
347 bool hx711__is_initd(hx711_t* const hx) {
348  return hx != NULL &&
349  hx->_pio != NULL &&
350 #ifndef HX711_NO_MUTEX
351  mutex_is_initialized(&hx->_mut) &&
352 #endif
353  pio_sm_is_claimed(hx->_pio, hx->_reader_sm);
354 }
355 
357  return hx711__is_initd(hx) &&
359 }
360 
361 bool hx711_is_value_valid(const int32_t v) {
362  return util_int32_t_in_range(
363  v,
366 }
367 
368 bool hx711_is_pio_gain_valid(const uint32_t g) {
369  return util_uint32_t_in_range(
370  g,
373 }
374 
376  return util_int_in_range(
377  (int)r,
379  hx711_rate_80);
380 }
381 
383  return util_int_in_range(
384  (int)g,
386  hx711_gain_64);
387 }
388 
390  hx711_t* const hx,
391  const hx711_gain_t gain) {
392 
393  //the struct should be init'd, but the state machines
394  //should not be running
395  assert(hx711__is_initd(hx));
396  assert(!hx711__is_state_machine_enabled(hx));
397 
398  assert(hx711_is_gain_valid(gain));
399 
400  const uint32_t gainVal = hx711_gain_to_pio_gain(gain);
401 
402  assert(hx711_is_pio_gain_valid(gainVal));
403 
404  HX711_MUTEX_BLOCK(hx->_mut,
405 
421  gpio_put(
422  hx->_clock_pin,
423  false);
424 
425  //2. reset the state machine using the default config
426  //obtained when init'ing.
427  pio_sm_init(
428  hx->_pio,
429  hx->_reader_sm,
430  hx->_reader_offset,
432 
433  //make sure TX FIFO is empty before putting the
434  //gain in.
435  pio_sm_drain_tx_fifo(
436  hx->_pio,
437  hx->_reader_sm);
438 
439  //3. Push the initial gain into the TX FIFO
440  pio_sm_put(
441  hx->_pio,
442  hx->_reader_sm,
443  gainVal);
444 
445  //4. start the state machine
446  pio_sm_set_enabled(
447  hx->_pio,
448  hx->_reader_sm,
449  true);
450 
451  );
452 
453 }
454 
455 void hx711_power_down(hx711_t* const hx) {
456 
457  //don't have to have SMs running; just check for init
458  assert(hx711__is_initd(hx));
459 
460  HX711_MUTEX_BLOCK(hx->_mut,
461 
462  //1. stop the state machine
463  pio_sm_set_enabled(
464  hx->_pio,
465  hx->_reader_sm,
466  false);
467 
479  gpio_put(
480  hx->_clock_pin,
481  true);
482 
483  );
484 
485 }
486 
487 void hx711_wait_settle(const hx711_rate_t rate) {
488  sleep_ms(hx711_get_settling_time(rate));
489 }
490 
492  sleep_us(HX711_POWER_DOWN_TIMEOUT);
493 }
494 
495 uint32_t hx711_gain_to_pio_gain(const hx711_gain_t gain) {
496 
505  assert(hx711_is_gain_valid(gain));
506 
507  const uint32_t clockPulses =
509 
510  assert(hx711_is_pio_gain_valid(clockPulses));
511 
512  return clockPulses;
513 
514 }
515 
517  PIO const pio,
518  const uint sm,
519  uint32_t* const val) {
520 
521  assert(pio != NULL);
522  check_sm_param(sm);
523  assert(util_pio_sm_is_enabled(pio, sm));
524  assert(val != NULL);
525 
526  static const uint byteThreshold = HX711_READ_BITS / 8;
527 
528  return util_pio_sm_try_get(
529  pio,
530  sm,
531  val,
532  byteThreshold);
533 
534 }
void hx711_set_gain(hx711_t *const hx, const hx711_gain_t gain)
Sets the HX711 gain.
Definition: hx711.c:149
bool hx711_is_max_saturated(const int32_t val)
Returns true if the HX711 is saturated at its maximum level.
Definition: hx711.c:242
bool hx711_get_value_noblock(hx711_t *const hx, int32_t *const val)
Obtains a value from the HX711. Returns immediately if no value is available.
Definition: hx711.c:322
const unsigned short HX711_SETTLING_TIMES[]
Definition: hx711.c:34
void hx711_init(hx711_t *const hx, const hx711_config_t *const config)
Definition: hx711.c:50
int32_t hx711_get_value(hx711_t *const hx)
Obtains a value from the HX711. Blocks until a value is available.
Definition: hx711.c:265
bool hx711__is_initd(hx711_t *const hx)
Check whether the hx struct has been initalised.
Definition: hx711.c:347
void hx711_close(hx711_t *const hx)
Stop communication with the HX711.
Definition: hx711.c:123
unsigned short hx711_get_settling_time(const hx711_rate_t rate)
Returns the number of milliseconds to wait according to the given HX711 sample rate to allow readings...
Definition: hx711.c:247
bool hx711_is_min_saturated(const int32_t val)
Returns true if the HX711 is saturated at its minimum level.
Definition: hx711.c:237
bool hx711__try_get_value(PIO const pio, const uint sm, uint32_t *const val)
Attempts to obtain a value from the PIO RX FIFO if one is available.
Definition: hx711.c:516
bool hx711_is_rate_valid(const hx711_rate_t r)
Check whether the given rate is within the range of the predefined rates.
Definition: hx711.c:375
bool hx711_is_gain_valid(const hx711_gain_t g)
Check whether the given gain is within the range of the predefined gains.
Definition: hx711.c:382
unsigned char hx711_get_rate_sps(const hx711_rate_t rate)
Returns the numeric sample rate of the given rate.
Definition: hx711.c:253
const unsigned char HX711_SAMPLE_RATES[]
Definition: hx711.c:39
void hx711_wait_settle(const hx711_rate_t rate)
Convenience function for sleeping for the appropriate amount of time according to the given sample ra...
Definition: hx711.c:487
bool hx711_is_value_valid(const int32_t v)
Check whether the given value is valid for a HX711 implementation.
Definition: hx711.c:361
void hx711_power_down(hx711_t *const hx)
Definition: hx711.c:455
int32_t hx711_get_twos_comp(const uint32_t raw)
Convert a raw value from the HX711 to a 32-bit signed int.
Definition: hx711.c:231
void hx711_wait_power_down()
Convenience function for sleeping for the appropriate amount of time to allow the HX711 to power down...
Definition: hx711.c:491
bool hx711_is_pio_gain_valid(const uint32_t g)
Check whether a given value is permitted to be transmitted to a PIO State Machine to set a HX711's ga...
Definition: hx711.c:368
const unsigned char HX711_CLOCK_PULSES[]
Definition: hx711.c:44
bool hx711_get_value_timeout(hx711_t *const hx, int32_t *const val, const uint timeout)
Obtains a value from the HX711. Blocks until a value is available or the timeout is reached.
Definition: hx711.c:292
uint32_t hx711_gain_to_pio_gain(const hx711_gain_t gain)
Convert a hx711_gain_t to a numeric value appropriate for a PIO State Machine.
Definition: hx711.c:495
bool hx711__is_state_machine_enabled(hx711_t *const hx)
Check whether the hx struct's state machines are running.
Definition: hx711.c:356
void hx711_power_up(hx711_t *const hx, const hx711_gain_t gain)
Definition: hx711.c:389
unsigned char hx711_get_clock_pulses(const hx711_gain_t gain)
Returns the clock pulse count for a given gain value.
Definition: hx711.c:259
#define HX711_MUTEX_BLOCK(mut,...)
Definition: hx711.h:36
#define HX711_MIN_VALUE
Definition: hx711.h:52
#define HX711_PIO_MAX_GAIN
Definition: hx711.h:56
#define HX711_PIO_MIN_GAIN
Definition: hx711.h:55
#define HX711_READ_BITS
Definition: hx711.h:49
hx711_rate_t
Definition: hx711.h:62
@ hx711_rate_10
Definition: hx711.h:63
@ hx711_rate_80
Definition: hx711.h:64
hx711_gain_t
Definition: hx711.h:67
@ hx711_gain_64
Definition: hx711.h:70
@ hx711_gain_128
Definition: hx711.h:68
#define HX711_POWER_DOWN_TIMEOUT
Definition: hx711.h:50
#define HX711_MAX_VALUE
Definition: hx711.h:53
uint clock_pin
Definition: hx711.h:95
hx711_pio_init_t pio_init
Definition: hx711.h:99
const pio_program_t * reader_prog
Definition: hx711.h:101
hx711_program_init_t reader_prog_init
Definition: hx711.h:102
uint data_pin
Definition: hx711.h:96
Definition: hx711.h:73
const pio_program_t * _reader_prog
Definition: hx711.h:79
uint _data_pin
Definition: hx711.h:76
PIO _pio
Definition: hx711.h:78
uint _reader_sm
Definition: hx711.h:81
pio_sm_config _reader_prog_default_config
Definition: hx711.h:80
uint _clock_pin
Definition: hx711.h:75
mutex_t _mut
Definition: hx711.h:85
uint _reader_offset
Definition: hx711.h:82
void util_gpio_set_output(const uint gpio)
Initialises and sets GPIO pin to output.
Definition: util.c:185
bool util_pio_sm_is_enabled(PIO const pio, const uint sm)
Check whether a given state machine is enabled.
Definition: util.c:366
bool util_pio_sm_try_get(PIO const pio, const uint sm, uint32_t *const word, const uint threshold)
Attempts to get a word from the state machine's RX FIFO if more than threshold words are in the buffe...
Definition: util.c:484