Use HX711 data in ULP

hema20
Posts: 5
Joined: Sun Mar 22, 2020 2:18 pm

Use HX711 data in ULP

Postby hema20 » Tue Apr 14, 2020 4:28 pm

Hello together,

I need some help writing the ULP code to wake up from deep sleep when the weight of a loadcell exceeds a specific threshold. I know that the ULP registers can only store 16 Bit data and for now this resolution should be enough.
How do I define the GPIO Pins and access a measurement from HX711 in order to store the data in a register? Where I basically need help is to write the following process in assembly language:

Read current value -> Store 16 Bit value of 24 bit reading in R0 > Read next value

Once I know how to store data from HX711 in a ULP register the rest of the code should be an easy task.

Best regards

boarchuz
Posts: 606
Joined: Tue Aug 21, 2018 5:28 am

Re: Use HX711 data in ULP

Postby boarchuz » Tue Apr 14, 2020 7:06 pm

https://esp32.com/viewtopic.php?t=10116#p46617
I don't have a HX711 to test that program so I doubt it works right off the bat (and I can see now that the wake up logic is wrong) but it might be useful as a starting point.

hema20
Posts: 5
Joined: Sun Mar 22, 2020 2:18 pm

Re: Use HX711 data in ULP

Postby hema20 » Wed Apr 15, 2020 9:14 am

boarchuz wrote:
Tue Apr 14, 2020 7:06 pm
https://esp32.com/viewtopic.php?t=10116#p46617
I don't have a HX711 to test that program so I doubt it works right off the bat (and I can see now that the wake up logic is wrong) but it might be useful as a starting point.

This is definitely a good starting point and I already tried it out. Unfortunately it is not working right off, the CPU only wakes up from the timer. Once I am done I will definitely post a working version. At the moment debugging is not working in CLion for me, so finding the mistake is quite difficult. Could you just explain how to define a GPIO Pin (like the I_READ_PIN or I_WRITE_PIN) for the ULP because I didn't find anything in the documentation? That would help me a lot understanding the structure!

wevets
Posts: 112
Joined: Sat Mar 09, 2019 2:56 am

Re: Use HX711 data in ULP

Postby wevets » Sun Apr 19, 2020 6:53 am

Hi, I'm the guy who posted the question to which you were pointed above.
I've got HX711 code working along with code to test for threshold crossings.
1. If you want the HX711 to be read by both the ULP and the system, set up your GPIOs as RTC GPIOs, which can be controlled/read in both environments. A routine to read the HX711 in C is much simpler than assembly. I'll leave that to you, but the setting up of the GPIOs as RTC GPIOs while still on the main processor(s) is a neat trick I learned on this board. It makes life easy. Set the specific RTC GPIOs to use with #define statements. Here's some code:
  1. /* define clock and data pins, channel, and gain factor. HX711 Channel selection is made...
  2. ** by setting the appropriate gain: 128 or 64 for channel A, 32 for channel B.
  3. ** To set HX711 gain to default 128, do one throw-away read cycle at the end of each...
  4. ** read to set the gain for the next read, and never power down the HX711.  We power...
  5. ** down the HX711 when we can so the first read is at gain 128.  Power down the...
  6. ** the HX711 by setting SCLK high for > 60µS.
  7. ** Drive HX711 through ESP32 RTC_GPIO so it will work in ULP and SoC.
  8. ** See HX711 data sheet for details
  9. */
  10. void HX711_init(void)
  11. {
  12.     // Initialze RTC_GPIO pin for HX711 SCLK
  13.     gpio_reset_pin(GPIO_SCLK);
  14.     rtc_gpio_init(GPIO_SCLK);
  15.     rtc_gpio_set_direction(GPIO_SCLK, RTC_GPIO_MODE_OUTPUT_ONLY);
  16.     rtc_gpio_set_level(GPIO_SCLK, HIGH);       
  17.    
  18.     // Initialze RTC_GPIO pin for HX711 DOUT
  19.     gpio_reset_pin(GPIO_DOUT);
  20.     rtc_gpio_init(GPIO_DOUT);
  21.     rtc_gpio_set_direction(GPIO_DOUT, RTC_GPIO_MODE_INPUT_ONLY);
  22.  
  23.     gpio_set_level(GPIO_SCLK, HIGH);    // Leave HX711 in a power-down state
  24. }
Here's a ULP assembly snippet that reads both the low 16 and high 8 bits from the HX711. I defined 2 macros, SCLK_high and SCLK_low that manipulate the system clock lines of the HX711. DOUT is the data out line from the HX711.
Here are the macros:
  1. // Some macros
  2. .macro DOUT_read
  3.     READ_RTC_REG(RTC_GPIO_IN_REG, RTC_GPIO_IN_NEXT_S + DOUT, 1)
  4. .endm
  5.  
  6. /* These two marco for set bus high and set low when GPIO_L is called, enable W1TS. */
  7. .macro SCLK_high
  8.     WRITE_RTC_REG(RTC_GPIO_OUT_REG, RTC_GPIO_OUT_DATA_S + SCLK, 1, 1)
  9. .endm
  10.  
  11. .macro SCLK_low
  12.     WRITE_RTC_REG(RTC_GPIO_OUT_REG, RTC_GPIO_OUT_DATA_S + SCLK, 1, 0)
  13. .endm
And here's the code segment to read the HX711, both the low 16 bits into a location accessible by both the ULP and the system, and the high 8 bits, similarly accessible. There are just enough registers in the ULP to make register allocation not too painful.
  1. ReadHX711:
  2.     move    r1, 0           // Initialzation HX711 read storage to 0
  3.     move    r3, HX711HiWord
  4.     st      r1, r3, 0       // Offset points to HX711HiWord
  5.     st      r1, r3, 4       // Offset points to HX711LoWord
  6.     move    r2, 2           // count of passes through bit clocking code
  7.     stage_rst
  8.     stage_inc   8           // Setup to read hi 8 bits HX711 output
  9. ReadCycleBegin:
  10.     SCLK_low
  11. CheckReady:
  12.     DOUT_read
  13.     jumpr   CheckReady, 1,  ge  // Ready when DOUT goes low
  14. RdBit:
  15.     SCLK_high
  16.     SCLK_low
  17.     DOUT_read
  18.     lsh     r1, r1, 1
  19.     jumpr   GotAZeroBit, 1, lt
  20.     add     r1, r1, 1       // If last read was a 1, OR it with accumulator
  21. GotAZeroBit:
  22.     stage_dec   1
  23.     jumps   RdBit,  0,  gt  // if bit count down not 0, go read another bit
  24.     st      r1, r3, 0       //  store accumulated read, 8 or 16 bits
  25.     sub     r2, r2, 1       //  Have we read two words?
  26.     jump    ReadDone,   eq
  27.    
  28.     stage_inc   16          // else setup to read 16 bits of low HX711 output
  29.     move    r3, HX711LoWord // point r3 for the low word read
  30.     move    r1, 0           // init r1 for low word read (Is this needed? Be safe)
  31.     jump    RdBit
  32.  
  33. ReadDone:                   // must cycle SCLK one more time to set gain to
  34.     SCLK_high               // 128 on next HX711 read, then leave SCLK hi for
  35.     SCLK_low                // for > 60 uS to power down HX711, ~10 clocks
I'll leave the rest to you. With some "jiggery-pokery" you can do the threshold arithmetic in the ULP too, but without an XOR instruction, its not as easy as it should be.

Can you tell me what kind of a project you're working on? Tell me by PM if you can.

wevets

Threepwood
Posts: 1
Joined: Sat Mar 11, 2023 6:26 pm

Re: Use HX711 data in ULP

Postby Threepwood » Sat Mar 11, 2023 6:45 pm

Hi wevets

For new project I also would like to start the main cpu
whenever a weight threshold is reached as sensed by the HX711 in ULP mode.

Unfortunately, I am rather new to esp32 coding (and especially to the ULP part)
While your code is already very helpful, I am still having issues to put together the crucial pieces ...

As far as I understand we need a main.c file that inits the RTC_GPIOS and then the loads the assembly code
to the ULP coprocessor before falling asleep.
I am however a bit lost what your macros exactly do and how to use the assembly code that reads the data from the H711
I suppose the part that wakes up the main CPU is not part of the post - where would that go?

Would you be so kind and provide me with a simple sample script
that combines the pieces you already showed here?

I would greatly appreciate you help here!

Thanks a lot!

Threepwood

Who is online

Users browsing this forum: No registered users and 58 guests