ESP32 Bare Metal Programming / Debugging with JTAG

nvitya
Posts: 3
Joined: Sat Nov 13, 2021 8:33 am

ESP32 Bare Metal Programming / Debugging with JTAG

Postby nvitya » Sat Nov 13, 2021 9:23 am

Hi,

I already have some experience with flashless Microctrontrollers like the ESP32. For example I know quite well the NXP IMXRT1051. I develop on the IMXRT so that I load the code image into the RAM and as the code starts writes itself to the QSPI flash for the permanent storage. I applied this technique on a STM32G473 too.

I know that using ESP32 without IDF is much more initial work, and I would never get the Wifi or the Bluetooth working, but for simpler tasks it would be fine.

I've spent the last two days figuring out if such a development method is possible on the ESP32 too. I made a very simple test application to test it (I'll attach it to this post). I can load it into the RAM to the address 0x40090000, data RAM is at 0x3FFF0000.
Unfortunately the openocd does not set the entry point, so I have to include the GDB command manually: "j _start"
Then it runs, I can pause and continue the execution, step instructions, check disassembly.
But breakpoints do not work. If I set a breakpoint, the execution does not stop there. This is crucial for me, and I would not invest more time to ESP32 development until this kind JTAG development works properly.

I tested Eclipse CDT on Ubuntu 20.04. I've also tried the Eclipse CDT on Windows 10.
The JTAG adapter is: interface/ftdi/dp_busblaster.cfg

Maybe I'm missing some setting.

If someone has a properly set up ESP32 development environment, please try this out. The code is so small that I can include it here:
main.cpp:

Code: Select all

volatile unsigned g_cnt = 0;
volatile unsigned g_cnt2 = 0;
volatile unsigned g_cnt3 = 0;

extern "C"
void _start(void)
{
	g_cnt = 1;
	g_cnt2 = 2;
	g_cnt3 = 3;

	while (1)
	{
		++g_cnt;
		++g_cnt2;
		++g_cnt3;
	}
}
I've made a linker script for that, it is found in the
esp32_bare_metal_test.zip
(1.19 KiB) Downloaded 379 times
.

I hope that this JTAG based development works fully and I just have only a wrong or missing setting somewhere.

br.
nvitya
Attachments
main.cpp
(217 Bytes) Downloaded 348 times

ESP_Sprite
Posts: 9749
Joined: Thu Nov 26, 2015 4:08 am

Re: ESP32 Bare Metal Programming / Debugging with JTAG

Postby ESP_Sprite » Sun Nov 14, 2021 1:46 am

I'm not familiar with OpenOCD configs anymore to know exactly what's going on, but on the hardware level at least, it's 100% possible to use breakpoints in your particular situation. It could be that the 'default' openocd config is tuned to be used on esp-idf and has a few things there that break compatibility with your scenario. (One of the things I'd try is switch between hard and soft breakpoints; possibly the one that is selected by default doesn't work.)

nvitya
Posts: 3
Joined: Sat Nov 13, 2021 8:33 am

Re: ESP32 Bare Metal Programming / Debugging with JTAG

Postby nvitya » Mon Nov 15, 2021 8:07 pm

Hi,

I've played again a bit with it.
I've removed almost everything from the openocd config. Just the JTAG setup and the "maskisr" setting remained. No esp_common.cfg included, just simple CPU, no RTOS flag.
Breakpoints still does not work, but instruction stepping does.
If I remove this too:
$_TARGETNAME_0 xtensa maskisr on
Then the instruction stepping does not work anymore.

I can not do more. I include with the esp32_ramtest.zip a correct linker script.
If someone could test it would be helpful.

br.
nvitya

openocd config:

Code: Select all

# The ESP32 only supports JTAG.
transport select jtag

# Source the ESP common configuration file
#source [find target/esp_common.cfg]

# Target specific registers
#set EFUSE_BLK0_RDATA1_REG 0x3ff5A004

if { [info exists CHIPNAME] } {
	set _CHIPNAME $CHIPNAME
} else {
	set _CHIPNAME esp32
}

if { [info exists CPUTAPID] } {
	set _CPUTAPID $CPUTAPID
} else {
	set _CPUTAPID 0x120034e5
}

if { [info exists ESP32_ONLYCPU] } {
	set _ONLYCPU $ESP32_ONLYCPU
} else {
	set _ONLYCPU 3
}

if { [info exists ESP32_FLASH_VOLTAGE] } {
	set _FLASH_VOLTAGE $ESP32_FLASH_VOLTAGE
} else {
	set _FLASH_VOLTAGE 3.3
}

set _CPU0NAME cpu0
#set _CPU1NAME cpu1
set _TARGETNAME_0 $_CHIPNAME.$_CPU0NAME
#set _TARGETNAME_1 $_CHIPNAME.$_CPU1NAME

jtag newtap $_CHIPNAME $_CPU0NAME -irlen 5 -expected-id $_CPUTAPID
if { $_ONLYCPU != 1 } {
	jtag newtap $_CHIPNAME $_CPU1NAME -irlen 5 -expected-id $_CPUTAPID
} else {
#	jtag newtap $_CHIPNAME $_CPU1NAME -irlen 5 -disable -expected-id $_CPUTAPID
}

# PRO-CPU
target create $_TARGETNAME_0 $_CHIPNAME -endian little -chain-position $_TARGETNAME_0 -coreid 0

#configure_esp_workarea $_TARGETNAME_0 0x40090000 0x3400 0x3FFC0000 0x10000
#configure_esp_flash_bank $_TARGETNAME_0 $_CHIPNAME $_FLASH_SIZE

#$_TARGETNAME_0 esp32 flashbootstrap $_FLASH_VOLTAGE
$_TARGETNAME_0 xtensa maskisr on
#$_TARGETNAME_0 xtensa smpbreak BreakIn BreakOut

#$_TARGETNAME_0 configure -event gdb-attach {
#	$_TARGETNAME_0 xtensa smpbreak BreakIn BreakOut
#	# necessary to auto-probe flash bank when GDB is connected
#	halt
#}

#gdb_breakpoint_override hard

set hardware-breakpoint-limit 2
Attachments
esp32_ramtest.zip
(1.92 KiB) Downloaded 187 times

ESP_Sprite
Posts: 9749
Joined: Thu Nov 26, 2015 4:08 am

Re: ESP32 Bare Metal Programming / Debugging with JTAG

Postby ESP_Sprite » Tue Nov 16, 2021 10:18 am

Okay, I dug through the Xtensa docs I have here (sorry, can't share, something with a NDA) and I think the issue may be that your ps.intlevel is too high (probably 15). You want to lower that to less than 6 before break instructions start to work. The panic handler assembly does something like this:

Code: Select all

    movi    a0, PS_INTLEVEL(XCHAL_DEBUGLEVEL - 2) | PS_UM | PS_WOE                                        
    wsr     a0, P
perhaps that helps you out if you dump it somewhere at the beginning of your program?

nvitya
Posts: 3
Joined: Sat Nov 13, 2021 8:33 am

Re: ESP32 Bare Metal Programming / Debugging with JTAG

Postby nvitya » Tue Nov 16, 2021 8:39 pm

Thank You!

That was it. I've included these at the beginning:
asm("movi a0, (3 | 0x00040000 | 0x00000020)"); // = PS_INTLEVEL(3) | PS_UM | PS_WOE
asm("wsr a0, PS");

And now the breakpoints work like expected.

Searching for PS_INTLEVEL in the ESP-IDF source tree showed me a bunch of ASM parts that could be also useful for me.

Thank you for your excellent support.

ESP_Sprite
Posts: 9749
Joined: Thu Nov 26, 2015 4:08 am

Re: ESP32 Bare Metal Programming / Debugging with JTAG

Postby ESP_Sprite » Wed Nov 17, 2021 4:11 am

You're welcome, glad it worked for you!

Who is online

Users browsing this forum: Dennie and 89 guests