[ULP] undefined reference to

Hi all,

I would like to use ULP in PlatformIO (Arduino framework).
I’m coming from Arduino IDE, and there my code works :blush:

Now I get compile errors: “undefined reference to…”

Please see:

Linking .pio\build\ulp_test\firmware.elf
.pio\build\ulp_test\src\ULPADC.ino.cpp.o:(.literal._ZL16init_ulp_programv+0x0): undefined reference to `_binary_ulp_main_bin_end'
.pio\build\ulp_test\src\ULPADC.ino.cpp.o:(.literal._ZL16init_ulp_programv+0x4): undefined reference to `_binary_ulp_main_bin_start'
.pio\build\ulp_test\src\ULPADC.ino.cpp.o:(.literal._ZL16init_ulp_programv+0x14): undefined reference to `ulp_low_threshold'
.pio\build\ulp_test\src\ULPADC.ino.cpp.o:(.literal._ZL16init_ulp_programv+0x1c): undefined reference to `ulp_high_threshold'
.pio\build\ulp_test\src\ULPADC.ino.cpp.o:(.literal._Z5setupv+0x84): undefined reference to `ulp_ADC_reading'
.pio\build\ulp_test\src\ULPADC.ino.cpp.o:(.literal._Z5setupv+0x90): undefined reference to `ulp_entry'
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\ulp_test\firmware.elf] Error 1

My declarations are:

#include "esp32/ulp.h"
#include "../ulp/ulp_main.h"
#include "ulptool.h"
#include "esp_sleep.h"
#include "driver/rtc_io.h"
#include "driver/adc.h"

extern const uint8_t ulp_main_bin_start[] asm("_binary_ulp_main_bin_start");
extern const uint8_t ulp_main_bin_end[]   asm("_binary_ulp_main_bin_end");

ulp_main.h contains:

#include "Arduino.h"

#pragma once
extern uint32_t ulp_entry;
extern uint32_t ulp_sample_counter;
extern uint32_t ulp_low_threshold;
extern uint32_t ulp_high_threshold;
extern uint32_t ulp_ADC_reading;

Where are those “undefined reference” coming from? I searched and tried many things during the whole day, but nothing helped…

It has to do something with ULP right? Because all the other code works just fine. This morning I imported the ULP code-fragments from my “old” (in Arduino IDE) project, and then the problem popped up.

Who has an idea to fix this?

Thanks in advance! :sunglasses:

Best regards,

Stephan

Not possible in standard PlatformIO due to the ulp.py builder only being invoked for ESP-IDF projects.

You need to use GitHub - likeablob/ulptool-pio: A thin wrapper of ulptool for PlatformIO for this.

1 Like

Thank you for the reply maxgerhardt :grinning:

“Unfortunately” I am using exactly that already. [edit] please see the #include “ulptool.h” :innocent:
So while using ulptool I get this error.

I really don’t understand why this is…

Can you post the whole project?

No I’m sorry :neutral_face: It’s a very big project with a lot of code… (months and months of work every day)

But ulptool-pio/examples/ulp-counter at feat-pio-integration · likeablob/ulptool-pio · GitHub works?

1 Like

No, unfortunately not…

Same error(s):

.pio\build\test_detector\src\main.cpp.o:(.literal._Z5setupv+0x14): undefined reference to `_binary_ulp_main_bin_end'
.pio\build\test_detector\src\main.cpp.o:(.literal._Z5setupv+0x18): undefined reference to `_binary_ulp_main_bin_start'
.pio\build\test_detector\src\main.cpp.o:(.literal._Z5setupv+0x1c): undefined reference to `ulp_count'
.pio\build\test_detector\src\main.cpp.o:(.literal._Z5setupv+0x20): undefined reference to `ulp_entry'
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\test_detector\firmware.elf] Error 1

One other strange thing I see there (earlier in the terminal output) is:

warning: Ignoring missing SConscript 'C:\C:\Users\Stephan\Documents\PlatformIO\Projects\TestULP\.pio\libdeps\test_detector\ulptool-pio\post_extra_script_ulptool.py'

So 2x “C:\” that can’t be correct, right? :grimacing:

Yes, this is due to a wrong extra_scripts directive starting with /, aka the root of the filesystem.

But even then, and with using the PR from Amend for espressif32@~5.2.0 by xtrinch · Pull Request #3 · likeablob/ulptool-pio · GitHub, it’s not running correctly, giving a “commandline too long” error due to a mass of -I flags. I’ll fix it quickly.

1 Like

Thank you for your fast reply’s and help Maximilian! :slightly_smiling_face:

I’m very very new to PlatformIO. In fact: this is my first project ever in Pio! I worked on the project for several months (spread over almost 3 years now) in the Arduino IDE and with the help of a friend we loaded it into Pio. So I’m a newby in this :innocent: But except for this problem/topic is works really great and I like it VERY much :sunglasses:

But due to my “newby-ness” I don’t know exactly what you mean, but If i’m correct you mean that this C:\C:\ “thing” is not the cause of those “undefined reference”?

And is there anything else that I can try to fix the undefined reference problem?

Thanks again!

Stephan

Can you clone GitHub - maxgerhardt/ulptool-pio: A thin wrapper of ulptool for PlatformIO and open examples/ulp-counter in PlatformIO and build it?

1 Like

That works! :sunglasses:

That’s good progress already.

But… :smiling_face_with_tear: I can’t get this working with my own code…
If I copy the corresponding files (the files that you have changed, just like I did with your/the sample project) to my project, then an error shows up:

src/ulptool.h:48:12: error: 'TAG' was not declared in this scope

I think we are going in the right direction :slight_smile:

[edit]

Ahhhh, YES!! I think it works now :heart_eyes:

I placed

static const char* TAG = "MyModule";

at the top of the main *.ino file and now it compiles.

Thanks for the very good help and support Maximilian :+1:
Where/how can I buy you a cup of coffee or “ein leckeres Bier”? :sunglasses:

Best!

Stephan

Ahhh… I was happy too early :smiling_face_with_tear:

Now the code does compile, but after uploading the code (via OTA) it bricked my chip…

I always worked with:

platform = espressif32@~3.5.0

And now, due to the fantastic help in this topic I used:

platform = espressif32@5.3.0

But then the chip doesn’t boot anymore…

That section of platform.ini looks like this:

platform = espressif32@5.3.0 ; There is a newer version, 5.1.1, but it somehow doesn't boot. Might need to change SPIFFS or partition tables. //platform = espressif32@~3.5.0
board = esp32dev
framework = arduino
upload_speed = 921600 ; The upload baud rate
monitor_speed = 115200 ; The serial (monitor) baud rate
board_build.flash_mode = qio
board_build.partitions = min_spiffs.csv
board_build.filesystem = spiffs

Is there something wrong?

Thanks for helping me out :grinning:

Stephan

Did you try with dio too? Or without a custom partition table?

With Arduino core upgrades like this it can also be that previously existing / working code in the firmware is the problem. If you see that the chip doesn’t even reach setup() and can print an initial message via Serial, your chip may be crashing in the constructor of a custom C++ class.

I will try dio in a minute :slight_smile: Thanks!

Without a custom partition table I get:

Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
Error: The program size (1517561 bytes) is greater than maximum allowed (1310720 bytes)
RAM:   [==        ]  19.2% (used 62808 bytes from 327680 bytes)
*** [checkprogsize] Explicit exit, status 1
Flash: [==========]  115.8% (used 1517561 bytes from 1310720 bytes)

Yes, a friend just told me that I better can do a full erase when doing this (“playing” with partition tables and such) kind of things. Therefore I program via the serial interface in PlatformIO the last hour :slightly_smiling_face: (then it does a full erase, right?)

It’s easier to do a flash erase if you use the “Erase Flash” project task.

1 Like

Ok, I didn’t know of that function. But it looks (and works) good :slight_smile: The chip is erased!

But after I upload new code, only this is what I get:

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0030,len:1184
load:0x40078000,len:13104
load:0x40080400,len:3036
entry 0x400805e4
[     5][W][esp32-hal-timer.c:226] timerAttachInterrupt(): EDGE timer interru␃��␗R�.H�␗Ү␗.�K␗W␖V$��Y]�Z�␖$�␋␒��U␔��ɩHh␅         ␒R&�W+QW�Y.\&�KZX�K,\]�,'&MMW��Y](\]��equencyMhz(): PLL: 480 / 2 = 240 Mhz, APB: 80000000 Hz
Starting...

It doesn’t boot…

Do you call some setCPUFrequency() command maybe?

Can you confirm the simplest of blinky works?

No, I do nothing with setCPUFrequency() or so.

Yes, other (smaller/simpler) programs (like for example the examples/ulp-counter you told me about yesterday) work perfectly :grinning:

But there I only use:

platform = espressif32@5.3.0
board = esp32dev
framework = arduino
monitor_speed = 115200

Instead of:

platform = espressif32@5.3.0 ; There is a newer version, 5.1.1, but it somehow doesn't boot. Might need to change SPIFFS or partition tables. //platform = espressif32@~3.5.0
board = esp32dev
framework = arduino
upload_speed = 921600 ; The upload baud rate
monitor_speed = 115200 ; The serial (monitor) baud rate
board_upload.flash_size = 16MB
board_upload.maximum_size = 16777216
board_build.flash_mode = dio ; qio
board_build.partitions = large_spiffs_16MB.csv ; min_spiffs.csv
board_build.filesystem = spiffs
custom_device_type = 0 ; Override this for every new environment

So I have the idea that it has to do something with those partitions, don’t you think?

Very weird… I can only recommend to partially comment out the creation of custom C++ objects and code in setup() and loop() until you get a stable bootup again, then comment it back in one-by-one to see where it breaks.

1 Like

Okay, with the help of a friend I got it working now :grinning:

No Idea WHY exactly this is, but here is the corresponding platform.ini code:

platform = espressif32@~3.5.0 ; There is a newer version, 5.1.1, but it somehow doesn't boot. Might need to change SPIFFS or partition tables. //platform = espressif32@~3.5.0
board = esp32dev
framework = arduino
upload_speed = 921600 ; The upload baud rate
monitor_speed = 115200 ; The serial (monitor) baud rate
board_build.flash_mode = qio
board_build.partitions = min_spiffs.csv
board_build.filesystem = spiffs
lib_deps = 
	https://github.com/powelllens/ulptool-pio
extra_scripts =
    pre:$PROJECT_LIBDEPS_DIR/$PIOENV/ulptool-pio/pre_extra_script_ulptool.py
    post:$PROJECT_LIBDEPS_DIR/$PIOENV/ulptool-pio/post_extra_script_ulptool.py

With this, the code compiles and works! :sunglasses:

BUT: now comes the thing that also didn’t work when I was still programming in the Arduino-IDE :innocent:

I use the code below to put the ESP32 in sleep and wake on 2 things:

  1. if a button is pushed
  2. if the ADC measures a value that is below ulp_low_threshold (in my case 2000)
if (EnableSleep){
  esp_sleep_wakeup_cause_t wakeReason = esp_sleep_get_wakeup_cause();    // 0 = BOOT, 3 = Wake by Push Button, 6 = Wake by ADC
  if (wakeReason != ESP_SLEEP_WAKEUP_ULP){
    Serial.println(String(wakeReason));
  } else {
    ulp_ADC_reading &= UINT16_MAX;
    Serial.println("ulp_ADC_reading: " + String(ulp_ADC_reading)); 
    Serial.println(String(wakeReason));
  }


  if (wakeReason == 0 || wakeReason == 6){
    init_ulp_program(wakeReason);
  }

  start_ulp_program();
  
  ESP_ERROR_CHECK(esp_sleep_enable_ulp_wakeup());

  esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ALL_LOW);  //wake with pushbutton (BUTTON_PIN_BITMASK is 0x4000)

  Serial.println("Going into sleep...");
  esp_deep_sleep_start();

}






static void init_ulp_program(int wakeReason)
{
  esp_err_t err = ulp_load_binary(0, ulp_main_bin_start,
                                  (ulp_main_bin_end - ulp_main_bin_start) / sizeof(uint32_t));
  ESP_ERROR_CHECK(err);

  ulp_low_threshold = 2000; 
  ulp_high_threshold = 4096; 

  digitalWrite(POWER, HIGH); //pcb power
  digitalWrite(26, HIGH);    //tcrt led power

  gpio_hold_en(GPIO_NUM_13); //pcb power
  gpio_hold_en(GPIO_NUM_26); //tcrt power
  gpio_deep_sleep_hold_en(); 

  //if (wakeReason == 0 || wakeReason == 6){
    adc1_config_channel_atten(ADC1_CHANNEL_4, ADC_ATTEN_DB_11);
    adc1_config_width(ADC_WIDTH_BIT_12);
    adc1_ulp_enable();
  //}

}

static void start_ulp_program()
{
  esp_err_t err = ulp_run((&ulp_entry - RTC_SLOW_MEM) / sizeof(uint32_t));
  ESP_ERROR_CHECK(err);
}

Both work. So I can wake the processor with ADC and with the pushbutton. BUT: if it wakes with the pushbutton, then the ADC doesn’t work anymore. So if it’s going back to sleep, I can’t wake it with ADC, but only with the button…

I tried sooooo many things/settings/code changes/whatever: I can’t get the ADC working anymore after pushing the button. This also didn’t work in the Arduino IDE. I even have paid people on Fivver (or Upwork, didn’t remind it anymore) for this, but they also couldn’t get this working :smiling_face_with_tear:

It there a chance that you know the solution? :grinning:

Thanks / best regards,

Stephan