Esp32 variable on stack shows up as <unavailable> within Task-function

I am playing around with RTOS tasks and queues, and have started the JTAG debugger. Certain variables are shown as <unavailable> within the watch-area. so I investigated the phenomena more closely with a small blink program. It looks like inside the simple C function all variables are shown, even the ones on the stack. That looks completely different in the task function. Variables that end up on the stack are listed as in the watch area.

The C-function: icnt:0 and num:2 are shown as expected.

The Task function: the variable on stack shows up as num_blink:<unavailable>

My dev environment looks like this, I would say from pio point of view, it is quite up to date:

OS                Win10 (21H2, build 19044.2130)
VS-Code           1.72.2
PlatformIO IDE    2.5.4
IO core           6.1.5a4   
PIO home          3.4.3     
platform esp32    5.2.0 

ESP32 board    = ESP32 NodeMCU (38pins)
JTAG interface = FT2232HL USB

platformio.ini, debug environment
My first thought was that the build_flags und build_unflags should do the trick.

;----------------------------------------------------------------------
; debug environment
;----------------------------------------------------------------------
[env:esp32dev_dbg]
build_type = debug
platform = espressif32
board = esp32dev
framework = arduino

;##### Serial Port Settings #####
monitor_filters = esp32_exception_decoder, time
monitor_speed = 115200
monitor_port = COM4

;##### Upload-Port-Settings #####
upload_speed = 921600
upload_port = COM4

;##### In-Circuit-Debug-Settings #####
debug_tool = esp-prog
debug_init_break = tbreak setup
debug_speed = 8000

;build_flags =
;  -DCORE_DEBUG_LEVEL=5
build_unflags = -Os
build_flags = -O1 -g3 -ggdb

the main.cpp file:
a simple C function and a similar task function as LED blinker.

#include <Arduino.h>

#define IR_LED    16  // led indicates received message

xQueueHandle LedQueue;
TaskHandle_t LedTask_h;

void LedBlink(int num, uint32_t pause){
  int icnt=0;
  for (icnt=0;icnt<num;icnt++) {
    digitalWrite(IR_LED, LOW);
    delay(pause);
    digitalWrite(IR_LED, HIGH);
    delay(pause);
  }
}

void LedTask(void *parameter){
  uint8_t num_blink=0;
  uint8_t icnt=0;
  while(1){
    if(pdTRUE==xQueueReceive(LedQueue,&num_blink,portMAX_DELAY)) { 
      printf("received num_blink=%d\n",num_blink);
      for(icnt=0;icnt<num_blink;icnt++){
        digitalWrite(IR_LED,LOW);
        delay(50);
        digitalWrite(IR_LED,HIGH);
        delay(50);
      }
    } 
  }
}

void setup() {
  Serial.begin(115200);
  LedQueue = xQueueCreate(50, sizeof(uint8_t));
  printf("LedQueue created\n");
  xTaskCreate(LedTask,"LedTask",2048,NULL,1,&LedTask_h);
  printf("LedTask created\n");
  pinMode(IR_LED,OUTPUT); 
  LedBlink(2,50);  // double blink at start
}

uint8_t blinky=0;

void loop() {
  blinky = (++blinky>5)? 1 : blinky;
  xQueueSend(LedQueue,&blinky,0);
  delay(2000);
}

I wonder what the cause is. Maybe there exists a special gcc switch or another setting of the debugger or the IDE ?

Any Ideas?

Add

debug_build_flags = -O0 -ggdb3 -g3

(docs) to the platformio.ini.

Thank you,
but well it does not change anything. I changed the flags, cleaned, rebuild and started the debugger.

The compiler flags:
before:

build_unflags = -Os
build_flags = -O1 -ggdb3 -g3

test 1:

build_unflags = -Os
build_flags = -O0 -ggdb3 -g3

test 2:

;build_unflags = -Os
build_flags = -O0 -ggdb3 -g3

I’ m sorry but somehow the picture upload currently does not work.
OK, once the debugger started a popup tells this, and as before the variable within the watch-area is<unavailable>

-var-create: unable to create variable object   
(from var-create watch_3b0b2eef88f0ef62401368661138dcca} @ "num_blink")

But none of these change debug_build_flags? Those are the critical flags used during debugging. The default is -Ogwhich allows optimization.

I’d recommend to remove any build_* options and just have the debug_build_flags option I referenced.

Ohhh, yes my fault. OK once again, clean rebuild and run debugger:

test3:

;build_unflags = -Os
debug_build_flags = -O0 -ggdb3 -g3

But still no difference for the watch-area. A difference I found compared to test1 and test2 is that the build runs twice, inside the terminal and afterwards in debug-console



Checking size .pio\build\esp32dev_dbg\firmware.elf
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM:   [=         ]   5.0% (used 16456 bytes from 327680 bytes)
Flash: [==        ]  19.6% (used 256869 bytes from 1310720 bytes)
========================= [SUCCESS] Took 27.01 seconds =========================

Environment    Status    Duration
-------------  --------  ------------
esp32dev_dbg   SUCCESS   00:00:27.005
========================= 1 succeeded in 00:00:27.005 =========================
undefinedC:\Users\Besitzer\.platformio\packages\toolchain-xtensa-esp32\bin\xtensa-esp32-elf-gdb.exe: warning: Couldn't determine a path for the index cache directory.

Reading symbols from d:\anderl\esp32_projects\esp_dbg_test\.pio\build\esp32dev_dbg\firmware.elf...
PlatformIO Unified Debugger -> https://bit.ly/pio-debug
PlatformIO: debug_tool = esp-prog
PlatformIO: Initializing remote target...
Open On-Chip Debugger  v0.11.0-esp32-20220706 (2022-07-06-15:48)
Licensed under GNU GPL v2
For bug reports, read
	http://openocd.org/doc/doxygen/bugs.html
adapter speed: 20000 kHz

WARNING: boards/esp-wroom-32.cfg is deprecated, and may be removed in a future release.
adapter speed: 12000 kHz

Info : tcl server disabled
Info : telnet server disabled
Info : ftdi: if you experience problems at higher adapter clocks, try the command "ftdi tdo_sample_edge falling"
Info : clock speed 12000 kHz

I made some further tests. Not all variables living at the task’s stack are unavailable. As it looks the debug_build_flags are OK. It has something to do with how gdb evaluates the access to the pointer and cast that happens in the xQueueReceive() function call (line 25)

icnt , my_var are available but ptr and num_blink are not.

The lower-right popup shows this.

Can’t take address of “num_blink” which isn’t an lvalue. (from data-evaluate-expression &num_blink)

Ok, if just one single instance of the task is running only and reentrance does not occur, the variable num_blink could be declared static, which leaves the variable visible again. (that can be done at least for debugging purposes)

Maximilian, thanks again for your hints