Developers Club geek daily blog

1 year ago
It is given: there is a device, with ARM926E-JS (Cypress FX3) onboard. The device is on other continent. The device is connected (JTAG+USB+COM) to Linux to a computer. On a computer there is SSH access (more than nothing, only SSH port).

Problem: The device needs to be debugged and written under it a code. And to do it, it is desirable, conveniently.

Solution with use of OpenOCD, GDB and Qt Creator, and also the description of a way to it, under a cat.

Solutions can be much. Fast and simple: start of a linking of GDB+OpenOCD on a remote computer through ssh session. There is not a lot of convenience since a code it is more convenient to govern locally, and for debugging it is necessary to fill in constantly a code on the server by means of scp or rsync.

After short reflections, the idea comes: and we can start commands far off on the server using SSH:
ssh user@host some-command some-arguments

Hm … And besides GDB can start OpenOCD in the mode of the pipeline (pipe) and communicate with it. It is so possible to make so that OpenOCD, and deleted, on ssh was started not just, and the received sheaf was already used for debugging.

Unfortunately such option was impractical: connection constantly fell off on a timeout.

The following idea was: to somehow lift VPN and to use it for connection to any ports on the server then to start far off OpenOCD.

But how to lift VPN if there are no ports, except SSH? All right, we know that SSH can forward ports. We start far off OpenOCD, we forward port … Yes, it is slightly better, than start in the pipeline mode. But that it is sensitive. It does not suit for work in any way.

Almost decided to give up this business and to use the very first, simple, reliable, but inconvenient solution, but here gathered a sheaf in Google: SSH VPN. To tell that I was surprised — not to tell anything. Not to look for, it is enough these two links:

After settings, by the remote machine the tap8 interface with the address 192.168.100.1 and locally appeared: the tap7 interface with the address 192.168.100.2 (addresses will be useful further).

I try to start … About a miracle! The solution was the worker! The code is loaded, everything works, break points are put. Problem one: slowly. And if I can reconcile to waiting of updating of a status (stektreysa, local variables, etc.), then loading of 300 kb of elf'a takes more than 6 minutes. Locally quicker. Considerably.

Anyway, here couple of scripts which implement this scheme (the SSH settings I do not bring):
  1. openocd-remote — just a cover for start of remote OpenOCD through ssh. I will note that an arrangement
    files and directories by the local machine and deleted I made identical. In opposite a case
    would add preprocessing of parameters by means of sed to the same script to make replacements. Plus,
    OpenOCD at me is built from Git and is copied in ~/bin/openocd-git/{bin,share} (corresponding directories).
    Configs for FX3 (about them further) lie in ~/bin/openocd-git/ . In ~/bin/ it is made simlink for performed
    openocd file.
    #!/bin/sh
    ssh user@host -T killall -9 openocd
    exec ssh -TC user@host bin/openocd $@
    
  2. gdb-remote — is connected to remote OpenOCD, loads a code:
    #!/bin/sh
    
    gdbcfg=fx3_gdb.ini
    elf=some-code.elf
    
    cat > $gdbcfg << EOF
    set prompt (arm-gdb)
    set remotetimeout 30
    target remote 192.168.100.1:3333
    monitor halt
    monitor soft_reset_halt
    monitor adapter_khz 1000
    set endian little
    load
    EOF
    
    arm-none-eabi-gdb -x $gdbcfg $elf
    

Thoughts about acceleration of start went approximately in such bed: simple copying of elf of the file on a remote server borrows seconds 10, plus or minus. And here would be abruptly, to load an image on the server and at to load into the device already from it …

Shtudirovany documentation on OpenOCD and here it: OpenOCD can load a code into the device, and GDB will simply be connected and will give command for start of a firmware. Magic command: load_image.

The first experiments were unfavourable: loading takes place VERY unstably. The code is loaded, loaded quickly: 1 minute against 6 with a tail). But the firmware starts, is not present. At the same time, if in the same GDB session to make load, everything is perfectly started.

Began to look for distinctions. The last line of loading interested through load:
Start address 0x40035948, load size 298456

It cast to zalogirovat after loading of a code through load and through load_image (through OpenOCD) and before start (continue) register contents $pc. And … difference is found: later load $pc it is set in this "Start address" whereas later load_image in $pc there is something at the time of what was there began loading. After installation pc in the correct value loading became stable. There was a question: magic numbers are not a buzzing. But here the fact that it is possible to specify the character in GDB helped and its address will be taken. In case of FX3 this character: CyU3PFirmwareEntry (by the way, on local applications it will be, most likely _start) and command of installation $pc turned into such:
set $pc = CyU3PFirmwareEntry
Besides, GDB has an opportunity to call commands of a cover therefore we can easily and easy at start upload elf the file on a remote server and give command to the started OpenOCD to load it (any command for OpenOCD can be given from GDB having preceded it by the word monitor).

Final script for start of GDB:
#!/bin/sh

gdbcfg=fx3_gdb.ini
elf=some-code.elf

# Генерим конфиг для GDB
cat > $gdbcfg << EOF
set prompt (arm-gdb)
set remotetimeout 30
target remote 192.168.100.1:3333
shell scp $elf user@192.168.100.1:
monitor halt
monitor soft_reset_halt
monitor sleep 1000
monitor load_image %elf 0x00 elf
set $pc = CyU3PFirmwareEntry
EOF

arm-none-eabi-gdb -x $gdbcfg $elf

The script for start of OpenOCD remains same.

That now it is necessary for us to begin remote debugging:
  1. To Zapusit openocd-remote script. It is possible to restart it on requirements.
  2. To Ostroit a code and to start gdb a script above.
  3. ...
  4. PROFIT
Whether and PROFIT? On me, so not. I write a code to Qt Creator and there is a wish to do in one click all this of it. And it becomes in one click. There is enough:
  1. To open dialog of settings
  2. To select Bare Metal and to add new GDB Server Provider with the OpenOCD type with the following parameters:
    • Name: on your discretion, let there will be FX3 Remote
    • Startup mode: Startup in TCP/IP
    • Host: 192.168.100.1
    • Port: 3333
    • Executable file: a way to openocd-remote, I have it / home/alexd/bin/openocd-remote
    • Root scripts directory: /home/alexd/bin/openocd-git/share/openocd/scripts — at you can differ,
      you remember the main thing that the smart adjuster checks these directories for availability for this reason I
      did an identical tree on the local computer and on remote.
    • Configuration file: /home/alexd/bin/openocd-git/share/openocd/scripts/interface/ftdi/olimex-arm-usb-ocd-h.cfg — at
      me Olimex ARM-USB-OCD-H debugger is used, you can have another. I do not consider setup of a debugger.
    • Additional argumets: - f ~/bin/openocd-git/fx3-common.cfg - f ~/bin/openocd-git/fx3-threadx.cfg — these scripts
      I will publish below.
    • Init commands — the most interesting:
      monitor echo "Upload image..."
      shell scp %{DebuggedExecutable:NativeFilePath} user@192.168.100.1:
      monitor halt
      monitor soft_reset_halt
      monitor sleep 1000
      monitor echo "Load image..."
      monitor load_image %{DebuggedExecutable:FileName} 0x00 elf
      set $pc = CyU3PFirmwareEntry
      monitor echo "Run image..."
      
      As you can see, completely repeats a code from a script, only with macrosubstitutions not to rewrite for each target.
    • Reset commands: monitor reset halt (we leave by default).
  3. Then we go to Devices, we do Add-> Bare Metal Device-> we Name (let there will be FX3 Device Remote) and we assign our GDB Server provider (FX3 Remote)
  4. Then we go to Build &Runs and in the used set (Kits) for Cypress (or ARM or what at you there) we select:
    • Device type: Bare Metal Device
    • Device: FX3 Device Remote
Here I had to create for a set — for local and for remote development. But that … It is possible to worry.

Everything then in settings of the project we add a new set, we configure it, on the Run tab we add a konfiruration in the name of which is "(via GDB Server or hardware debugger)" and we begin debugging with simple clicking of F5.

Useful materials


Scripts of fx3-common.cfg, fx3-threadx.cfg, fx3-boot.cfg (for debugging of a butloder or when there is no ThreadX) respectively:
fx3-common.cfg
######################################
# Target: CYPRESS FX3 ARM926-ejs
# Common part
######################################
if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
set _CHIPNAME fx3
}

if { [info exists ENDIAN] } {
set _ENDIAN $ENDIAN
} else {
set _ENDIAN little
}

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

#delays on reset lines
adapter_nsrst_delay 200
jtag_ntrst_delay 200

adapter_khz 1000

#reset_config trst_only
#reset_config trst_only combined
#reset_config trst_and_srst combined
#reset_config trst_and_srst srst_pulls_trst
# From the Cypress SDK
reset_config trst_and_srst srst_pulls_trst
# My own well worked
#reset_config trst_only

jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID
jtag_rclk 3


fx3-threadx.cfg
######################################
# Target: CYPRESS FX3 ARM926-ejs
######################################

#source [find fx3-common.inc]

######################
# Target configuration
######################
set _TARGETNAME $_CHIPNAME.cpu 
target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME -rtos ThreadX
adapter_khz 1000


fx3-boot.cfg
######################################
# Target: CYPRESS FX3 ARM926-ejs
######################################

#source [find fx3-common.inc]

######################
# Target configuration
######################
set _TARGETNAME $_CHIPNAME.cpu 
target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME 
adapter_khz 1000



The project type in Qt Creator for ARM, FX3 and others can be Generic, but I wrote CMake of the rule for FX3: github.com/h4tr3d/fx3-cmake also I use CMake Project manager that allows to have easily several configurations in different directories, shadow assembly and an occasion not to be confused in assembly parameters on difficult projects.

OpenOCD commands: openocd.org/doc/html/General-Commands.html

For calculation of Entry Point automatically, it is possible to collect GDB with support a python and to use recommendations:

This article is a translation of the original post at habrahabr.ru/post/274179/
If you have any questions regarding the material covered in the article above, please, contact the original author of the post.
If you have any complaints about this article or you want this article to be deleted, please, drop an email here: sysmagazine.com@gmail.com.

We believe that the knowledge, which is available at the most popular Russian IT blog habrahabr.ru, should be accessed by everyone, even though it is poorly translated.
Shared knowledge makes the world better.
Best wishes.

comments powered by Disqus