These instructions are only for Ubuntu in stand-alone (or VM) machine; not (yet) for WSL/Ubuntu on Windows.
To debug in VSCode, I am using the C/C++ for VSCode Extension along with an Olimex ARM-USB-OCD-H JTAG debugger. There are 2 main parts: installing (covered here) and debug setup (covered in part 2). I also show the wiring connections here.
If you already have the toolchain installed and want to simply debug, see step 2!
I've also added a step 3 using ESP WIP OpenOCD.
I started with the esp-idf instructions http://esp-idf.readthedocs.io/en/latest/get-started/linux-setup.html with release 2.1 from https://github.com/espressif/esp-idf. Once the toolchain is installed, there's also a special version of OpenOCD here: https://github.com/espressif/openocd-esp32
Nothing new here not presented in espressif instructions; so in brief... basically for the esp-idf:
# see https://github.com/espressif/esp-idf.git sudo apt-get install git wget make libncurses-dev flex bison gperf python python-serial # download the toolchain, in this case the 64-bit linux version 1.22.0-61-gab8375a-5.2.0 mkdir -p ~/Downloads cd ~/Downloads/ wget https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-61-gab8375a-5.2.0.tar.gz # put the download into the ~/esp/xtensa-esp32-elf/ directory mkdir -p ~/esp cd ~/esp tar -xzf ~/Downloads/xtensa-esp32-elf-linux64-1.22.0-61-gab8375a-5.2.0.tar.gz # get the esp-idf from github, don't forget the --recursive !! mkdir -p ~/esp cd ~/esp git clone --recursive https://github.com/espressif/esp-idf.git export PATH=$PATH:$HOME/esp/xtensa-esp32-elf/bin if installing on WSL (Ubuntu on Windows), I needed to also install:
sudo apt-get install libtool sudo apt-get install autotools-dev sudo apt-get install automake # needed for aclocal sudo apt-get install pkg-config # needed to solve error: configure.ac:12: error: possibly undefined macro: AC_MSG_WARN sudo apt-get install libusb-1.0 # otherwise No package 'libusb-1.0' found then for the openocd-32; make sure you do not have a regular distro version of openocd installed, if you do:
sudo apt-get remove openocd Here too, just restating the instructions from https://github.com/espressif/openocd-esp32:
mkdir -p ~/workspace cd ~/workspace git clone --recursive https://github.com/espressif/openocd-esp32.git sudo apt-get install make libtool pkg-config autoconf automake texinfo sudo apt-get install libusb-1.0 cd openocd-esp32 ./bootstrap ./configure the default configure should show this when done:
libjaylink configuration summary: - Package version ................ 0.1.0 - Library version ................ 0:0:0 - Installation prefix ............ /usr/local - Building on .................... x86_64-pc-linux-gnu - Building for ................... x86_64-pc-linux-gnu OpenOCD configuration summary -------------------------------------------------- MPSSE mode of FTDI based devices yes (auto) Segger J-Link JTAG Programmer yes (auto) ST-Link JTAG Programmer yes (auto) TI ICDI JTAG Programmer yes (auto) Keil ULINK JTAG Programmer yes (auto) Altera USB-Blaster II Compatible yes (auto) Versaloon-Link JTAG Programmer yes (auto) OSBDM (JTAG only) Programmer yes (auto) eStick/opendous JTAG Programmer yes (auto) Andes JTAG Programmer yes (auto) USBProg JTAG Programmer no Raisonance RLink JTAG Programmer no Olimex ARM-JTAG-EW Programmer no CMSIS-DAP Compliant Debugger no if installing in WSL, the only difference I saw:
- Building on .................... x86_64-unknown-linux-gnu - Building for ................... x86_64-unknown-linux-gnu continue with:
make sudo make install openocd The make takes a rather long time. I did observe a couple of errors/warnings on WSL (didn't notice on linux). Seems to be only related to docs. Note the "makeinfo missing": Making install in doc make[1]: Entering directory `/home/gojimmypi/workspace/openocd-esp32/doc' restore=: && backupdir=".am$$" && \ am__cwd=`pwd` && CDPATH="${ZSH_VERSION+.}:" && cd . && \ rm -rf $backupdir && mkdir $backupdir && \ if (echo makeinfo missing; true --version) >/dev/null 2>&1; then \ for f in openocd.info openocd.info-[0-9] openocd.info-[0-9][0-9] openocd.i[0-9] openocd.i[0-9][0-9]; do \ if test -f $f; then mv $f $backupdir; restore=mv; else :; fi; \ done; \ else :; fi && \ cd "$am__cwd"; \ if echo makeinfo missing; true -I . \ -o openocd.info openocd.texi; \ then \ rc=0; \ CDPATH="${ZSH_VERSION+.}:" && cd .; \ else \ rc=$?; \ CDPATH="${ZSH_VERSION+.}:" && cd . && \ $restore $backupdir/* `echo "./openocd.info" | sed 's|[^/]*$||'`; \ fi; \ rm -rf $backupdir; exit $rc makeinfo missing make[2]: Entering directory `/home/gojimmypi/workspace/openocd-esp32/doc' make[2]: Nothing to be done for `install-exec-am'. restore=: && backupdir=".am$$" && \ am__cwd=`pwd` && CDPATH="${ZSH_VERSION+.}:" && cd . && \ rm -rf $backupdir && mkdir $backupdir && \ if (echo makeinfo missing; true --version) >/dev/null 2>&1; then \ for f in openocd.info openocd.info-[0-9] openocd.info-[0-9][0-9] openocd.i[0-9] openocd.i[0-9][0-9]; do \ if test -f $f; then mv $f $backupdir; restore=mv; else :; fi; \ done; \ else :; fi && \ cd "$am__cwd"; \ if echo makeinfo missing; true -I . \ -o openocd.info openocd.texi; \ then \ rc=0; \ CDPATH="${ZSH_VERSION+.}:" && cd .; \ else \ rc=$?; \ CDPATH="${ZSH_VERSION+.}:" && cd . && \ $restore $backupdir/* `echo "./openocd.info" | sed 's|[^/]*$||'`; \ fi; \ rm -rf $backupdir; exit $rc makeinfo missing /bin/mkdir -p '/usr/local/share/info' install-info --info-dir='/usr/local/share/info' '/usr/local/share/info/openocd.info' This is not dpkg install-info anymore, but GNU install-info See the man page for ginstall-info for command line arguments install-info: No such file or directory for /usr/local/share/info/openocd.info /bin/mkdir -p '/usr/local/share/man/man1' As we did not previously have apt-get install openocd, we should now see version 0.10 when running it. Open On-Chip Debugger 0.10.0-dev-g372bb59 (2017-05-25-16:24) copy the hello_world app:
export IDF_PATH=~/esp/esp-idf cd ~/esp cp -r $IDF_PATH/examples/get-started/hello_world . cd ~/esp/hello_world make menuconfig if you have a hard time with the config window on WSL, try resizing the [Bash on Ubuntu] Windows size (typically smaller). Hit arrows up & down to screen refresh. If you see the problem you'll understand. If not - then there's no problem! :)
next, edit
~/workspace/openocd-esp32/tcl/interface/ftdi/olimex-arm-usb-ocd-h.cfg to add the
adapter_khz 1000 line (I saved mine to a file called olimex-arm-usb-ocd-h-1MHz.cfg): cd ~/workspace/openocd-esp32/tcl/interface/ftdi/ cp olimex-arm-usb-ocd-h.cfg olimex-arm-usb-ocd-h-1MHz.cfg nano olimex-arm-usb-ocd-h-1MHz.cfg # # Olimex ARM-USB-OCD-H # # http://www.olimex.com/dev/arm-usb-ocd-h.html # interface ftdi ftdi_device_desc "Olimex OpenOCD JTAG ARM-USB-OCD-H" ftdi_vid_pid 0x15ba 0x002b ftdi_layout_init 0x0908 0x0b1b ftdi_layout_signal nSRST -oe 0x0200 ftdi_layout_signal nTRST -data 0x0100 ftdi_layout_signal LED -data 0x0800 adapter_khz 1000 I also slightly modified my esp32.cfg file (thanks @ba0sh1 http://ba0sh1.com/) cd ~/workspace/openocd-esp32/tcl/target/ cp esp32.cfg ESP32-RTOS-none.cfg just one change needed to set ESP32_RTOS none, but the whole file shown for reference.As a reminder, don't try to uncomment a setting and leave a comment at the end of the same line. I saved mine to: ~/workspace/openocd-esp32/tcl/target/ESP32-RTOS-none.cfg
#With no variables set, openocd will configure JTAG for the two cores of the ESP32 and #will not automatic RTOS detection. This can be be adjusted: #set ESP32_ONLYCPU 1 # Only configure the PRO CPU #set ESP32_ONLYCPU 2 # Only configure the APP CPU # Disable RTOS support set ESP32_RTOS none #set ESP32_RTOS freertos # Force RTOS to be FreeRTOS 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_RTOS] } { set _RTOS "$ESP32_RTOS" } else { set _RTOS "auto" } if { [info exists ESP32_ONLYCPU] } { set _ONLYCPU $ESP32_ONLYCPU } else { set _ONLYCPU 3 } proc esp_core_halt { tgt } { #We need to disable the watchdogs here. #TIMG1 WDT $tgt mww 0x3FF5F064 0x50D83AA1 $tgt mww 0x3FF5F048 0x0 #TIMG2 WDT $tgt mww 0x3FF60064 0x50D83AA1 $tgt mww 0x3FF60048 0x0 #RTC WDT #ToDo: Figure out how to kill the RTC WDT } proc configure_esp32_core { TGT } { $TGT configure -event halted [list esp_core_halt $TGT] } #Change the name of the CPU taps depending on if it's enabled or not. This way, the user #gets immediate feedback in the openocd logs. if { $_ONLYCPU == "1" } { set _CPU0NAME cpu0 set _CPU1NAME ignored } elseif { $_ONLYCPU == "2" } { set _CPU0NAME ignored set _CPU1NAME cpu1 } else { set _CPU0NAME cpu0 set _CPU1NAME cpu1 } #Do add both taps, even if one of the CPUs is disabled. jtag newtap $_CHIPNAME $_CPU0NAME -irlen 5 -expected-id $_CPUTAPID jtag newtap $_CHIPNAME $_CPU1NAME -irlen 5 -expected-id $_CPUTAPID set _TARGETNAME1 $_CHIPNAME.cpu1 set _TARGETNAME2 $_CHIPNAME.cpu0 if { $_ONLYCPU != 2 } { if { $_RTOS == "none" } { target create $_TARGETNAME2 esp108 -endian little -chain-position $_TARGETNAME2 } else { target create $_TARGETNAME2 esp108 -endian little -chain-position $_TARGETNAME2 -rtos $_RTOS } configure_esp32_core $_TARGETNAME2 } if { $_ONLYCPU != 1 } { if { $_RTOS == "none" } { target create $_TARGETNAME1 esp108 -endian little -chain-position $_TARGETNAME1 } else { target create $_TARGETNAME1 esp108 -endian little -chain-position $_TARGETNAME1 -rtos $_RTOS } if { $_ONLYCPU != 3 } { configure_esp32_core $_TARGETNAME1 } } #Force hw breakpoints. Once we have a memory map, we can also allow software bps. gdb_breakpoint_override hard Tips and Suggestions:
Note that when moving between Windows and Linux... if you use VSCode to create bash script files from Windows, there's a little issue with the LF vs CRLF settings. (note the little LF in the status bar at the bottom of the screen). You really only want to save files with LF on Linux, not CRLF like on Windows. If you ignore this, you'll may see an err like Not able to execute a .sh file: /bin/bash^M: bad interpreter. The CRLF's are to blame. The linux dosa2unix utility might also be helpful.
Is it working?
See my gist or use this set of commands:export PATH=$PATH:$HOME/esp/xtensa-esp32-elf/bin export IDF_PATH=~/esp/esp-idf cd ~/workspace/openocd-esp32/tcl sudo openocd -f interface/ftdi/olimex-arm-usb-ocd-h-1MHz.cfg -c "transport select jtag" -f target/ESP32-RTOS-none.cfg Continued in step 2...
Resources and Inspiration:
- esp-idf - Standard Setup of Toolchain for Windows
- esp-idf - Getting Started
- The GDB/MI Interface
- https://github.com/FHFS/esp-idf-VSCode-template
- https://www.allaboutcircuits.com/technical-articles/getting-started-with-openocd-using-ft2232h-adapter-for-swd-debugging/
- OpenOCD FreeRTOS source
- https://stackoverflow.com/questions/2420813/using-gdb-to-single-step-assembly-code-outside-specified-executable-causes-error
- sparkfun forum - OpenOCD with Olimex ARM-USB-OCD-H
- https://github.com/espressif/openocd-esp32
- http://openocd.org/doc/html/Server-Configuration.html
- olimex forum - Olimex ARM-USB-OCD-H with OpenOCD - libusb_open() failed with LIBUSB_ERROR_NOT_S
- [TW#12206] VSCode works really well. Worth adding setup instructions in to the docs? #303
- allaboutcircuits - Getting Started with OPENOCD Using FT2232H Adapter for SWD Debugging
- Benjamin's robotics - Debugging the STM32F4 using openocd, gdb and Eclipse
- custom board script example (JLINK SWD)
Interesting but not really related:
(this is still a work in progress, sorry for spelling / formatting / content)
Continued in step 2....
Do you know why we have to add/uncomment "set ESP32_RTOS none" in esp32.cfg, even if we are using FreeRTOS? I can see that if it's not done then there's no thread with Id="1" listed in the VS Code debug console, and we get "Failed to find thread 1 for break event", but why is this?
ReplyDeleteThank you for the great post. Microsoft recently released WSL2 which is based on VM. Have you tried if the USB debugger can be recognized in WSL/Ubuntu? I'm very interested to know.
ReplyDeleteGlad you found the post helpful. :) I've not yet had a chance to try out WSL2
Delete