HULP - ULP Helper

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

HULP - ULP Helper

Postby boarchuz » Tue Dec 31, 2019 1:05 pm

https://github.com/boarchuz/HULP
HULP contains a bunch of useful macros and a few functions to more easily program the ULP coprocessor (using legacy macros).

ulp_var_t to easily share data between the SoC and ULP:

Code: Select all

RTC_DATA_ATTR ulp_var_t ulp_myvariable;

//ULP
I_GET(R0, R2, ulp_myvariable),
I_ADDI(R0, R0, 1),
I_PUT(R0, R2, ulp_myvariable),

//SoC
ulp_myvariable.put(1234);
if (ulp_myvariable.updated()) {
  uint16_t val = ulp_myvariable.get();
}
I2C bitbang driver supporting multiple slaves, 16 bit reads, error callbacks, etc. All in just 76 instructions. Single-line "include" to add to your ULP program:

Code: Select all

M_INCLUDE_I2CBB_MULTI(LBL_I2C_READ_ENTRY, LBL_I2C_WRITE_ENTRY, LBL_I2C_BUS_ERROR_HANDLER, LBL_I2C_NACK_ERROR_HANDLER, SCL_PIN, SDA_PIN),
Example here:
https://github.com/boarchuz/HULP/blob/r ... d/main.cpp

UART driver supporting TX, RX, and with a simple ulp_string_t to share char arrays between ULP and SoC.
Echo-style example here:
https://github.com/boarchuz/HULP/blob/r ... g/main.cpp

Timing functions and macros to convert transparently between milliseconds and RTC ticks. This allows for much easier timing of tasks, multi-tasking, etc.
To toggle an LED every 1650ms, for example:

Code: Select all

M_UPDATE_TICKS(),

M_IF_MS_ELAPSED(/*Label:*/ LBL_THIS_BLOCK, /*ms:*/ 1650, /*else goto:*/ LBL_HALT),
    M_GPIO_TOGGLE(PIN_LED),
    
M_LABEL(LBL_HALT),
    I_HALT(),
Example here: https://github.com/boarchuz/HULP/blob/r ... e/main.cpp

IO Macros:

Code: Select all

I_ANALOG_READ(R0, GPIO_NUM_36),
I_GPIO_PULLUP(GPIO_NUM_32, 1),
I_GPIO_READ(GPIO_NUM_32),
I_GPIO_OUTPUT_EN(GPIO_NUM_25),
I_GPIO_SET(GPIO_NUM_25, 1),
I_GPIO_SET(GPIO_NUM_25, 0),
Single APA RGB LED driver:

Code: Select all

M_APA1_SET(/*Label:*/ LBL_THIS_BLOCK, /*subroutine entry:*/ LBL_APA_ENTRY,  /*brightness:*/ 16, /*red:*/ 255, /*green:*/ 127, /*blue:*/ 63),

M_INCLUDE_APA1(LBL_APA_ENTRY, SCL_PIN, SDA_PIN),
Example: https://github.com/boarchuz/HULP/blob/r ... s/main.cpp

Other bits:

Code: Select all

hulp_configure_pin(GPIO_NUM_2, RTC_GPIO_MODE_INPUT_ONLY);
hulp_configure_i2c_pins(GPIO_NUM_4, GPIO_NUM_15);
hulp_configure_i2c_controller();
M_TOUCH_BEGIN(),
M_TOUCH_WAIT_DONE(),
I_TOUCH_GET_GPIO_VALUE(GPIO_NUM_x),

ESP_igrr
Posts: 2067
Joined: Tue Dec 01, 2015 8:37 am

Re: HULP - ULP Helper

Postby ESP_igrr » Thu Jan 02, 2020 1:48 pm

Very neat library @boarchuz — going to be very useful for lots of projects!

May I suggest dropping a CMakeLists.txt file into the root directory of the repository? This way the repository would be a valid esp-idf component, and could easily be included into other projects.

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

Re: HULP - ULP Helper

Postby boarchuz » Sun Mar 01, 2020 9:09 am

ESP_igrr wrote:
Thu Jan 02, 2020 1:48 pm
Very neat library @boarchuz — going to be very useful for lots of projects!

May I suggest dropping a CMakeLists.txt file into the root directory of the repository? This way the repository would be a valid esp-idf component, and could easily be included into other projects.
Thanks, Ivan! I've been using the VS Code extension since it came out so I've made the switch to CMake from PlatformIO now. I think I've got my head around it...
Incidentally, I only just realised that ST and LD functions wrap around in RTC memory. Is that safe/reliable to use?
eg. Store R1 at (RTC_SLOW_MEM + 100) ---> I_MOVI(R0, 65535), I_ST(R1, R0, 101)


I've made some updates, including making debugging significantly easier:

PRINTF+UART
There's now a 'printf' style subroutine that converts the value of R0 to its 5-digit ASCII representation. In combination with the UART TX subroutine, this allows the ULP to output runtime values independently of the SoC, even in deep sleep. There's an example of taking a touch sensor measurement and outputting the value over UART while the SoC is sleeping: https://github.com/boarchuz/HULP/blob/r ... h/main.cpp

Breakpoint Debugger
In addition, I've had a go at implementing a breakpoint-style SoC-assisted ULP debugger. It's a little unclear for now but it's potentially very useful and powerful. I'll make better examples/readme when I'm feeling motivated.

When the ULP reaches a breakpoint, it will halt and the HULP debugger will parse a lot of interesting information to hand off to a callback function, including:
  • General purpose register values (except one set aside as a scratch)
  • PC of the breakpoint
  • Line number of the breakpoint to easily locate it in the file
  • Label number of the breakpoint (if available)
And the ULP state may be altered:
  • Change general purpose register values (except scratch)
  • Change where the ULP will continue execution (by label number or PC)
  • Enable/disable breakpoints
When ready, the HULP debugger has a simple 'continue' call that will apply any changes made in the breakpoint and restart the ULP at the correct address.
Any number of M_DEBUG_SET_BP macros can be inserted anywhere a breakpoint is desired in the program. Each is only a few instructions for minimal overhead.

There is a basic debugger example that will use the default callback to simply dump breakpoint info and continue the ULP:
https://github.com/boarchuz/HULP/blob/r ... e/main.cpp
And a slightly more complex one that uses a callback to change values, alter pc, etc (it's not very clear, I know):
https://github.com/boarchuz/HULP/blob/r ... y/main.cpp
I still need to make an example with a 'proper' ISR that hands off the callback data to a FreeRTOS task.

Who is online

Users browsing this forum: No registered users and 24 guests