JTAG e OpenOCD

 O que é?

JTAG significa Joint Test Action Group, e o TAP ou Test Access Port definido por este grupo é uma das formas mais (se não a mais) comuns de programar e depurar dispositivos e computadores embarcados de todos os tipos. Para o profissional, os dispositivos JTAG são abundantes e geralmente não sobrecarregam muito o orçamento comercial. Mas para o aquarista, as coisas não são tão boas. Um Segger J-Link EDU pode ser adquirido por aproximadamente US$ 70 , mas o J-Link completo ainda custa aproximadamente US$ 400, o que é mais do que eu gostaria de pagar como hobby.

O que faz?

A porta JTAG TAP consiste em alguns sinais padrão que essencialmente fornecem controle completo sobre os sistemas da cadeia JTAG . A cadeia é exatamente o que parece: vários dispositivos que suportam encadeamento JTAG podem ser encadeados e acessados ​​a partir de uma única porta JTAG. Precisa daquele flash programado? JTAG pode fazer isso. Precisa depurar esse microcontrolador? JTAG também pode fazer isso. Quer fazer as duas coisas sem trocar de ferramentas? Sim, JTAG pode fazer isso. Veja este diagrama útil na Wikipedia para uma representação visual.

JTAG para o amador

Provavelmente, você tem um conversor USB -> serial algum lugar da sua estoque. Também é provável que seja baseado no popular FTDI FT232R ou em um chip semelhante ao FT232 que converte USB em RS232. Se você tiver a sorte de ter este equipamento essencial para hobby, você tem um adaptador USB-> JTAG esperando para ser usado!

Entre no OpenOCD

OpenOCD (Open On-chip Debugger) é um projeto fantástico que visa criar uma solução de TOC aberta e extensível para todos e, para nossa sorte, isso inclui o hobbyista! O projeto OpenOCD define interfaces entre as partes comuns do processo de TOC, como o quadro ou dispositivo de destino, o dispositivo de TOC usado, etc., e usando essas interfaces bem definidas é capaz de criar um sistema modular que pode suportar muitos alvos diferentes. e depuradores com apenas uma alteração na configuração. Esta é uma simplificação de como funciona, mas é suficiente para entender o que queremos fazer com isso.

Então, de volta ao FT232R. Este pequeno chip pode ser reconfigurado para usar os sinais RS232 como sinais JTAG bit-banged, e o OpenOCD pode controlá-lo. Melhor ainda, quando o agente OpenOCD estiver instalado e funcionando, poderemos usar o GDB para conectar e conduzir nossos esforços de depuração. Este modo de operação é detalhado no site de documentação (dica: procure por ft232r).

A ferramenta OpenOCD geralmente pode ser instalada com seu gerenciador de pacotes no Linux. Estou executando o Linux Mint, então instalei o openocd. Quando executei a ferramenta apontando para o arquivo de configuração do ft232r, ela reclamou que não era uma interface suportada... então acho que vamos construir a partir do código-fonte!

Construindo OpenOCD com as interfaces certas

Tudo o que precisamos fazer é construir o OpenOCD a partir do código-fonte com as interfaces corretas habilitadas e podemos fazê-lo funcionar. O que se segue é meu passo a passo para fazer isso. Estou fazendo isso em /tmp apenas para poder recriar as etapas que fiz anteriormente em meu diretório de aplicativos.

Pegue a fonte

Obtenha o código-fonte do espelho do GitHub aqui e coloque-o em um diretório de trabalho. Eu também leria o README para quaisquer dependências que você ainda não tivesse em sua máquina.

1
2
3
4
5
6
7
8
9
jacob@jacob-aspire-mint:/tmp$ git clone https://github.com/ntfreak/openocd.git
Cloning into 'openocd'...
remote: Enumerating objects: 74, done.
remote: Counting objects: 100% (74/74), done.
remote: Compressing objects: 100% (53/53), done.
remote: Total 62845 (delta 36), reused 50 (delta 21), pack-reused 62771
Receiving objects: 100% (62845/62845), 24.17 MiB | 24.90 MiB/s, done.
Resolving deltas: 100% (51571/51571), done.
jacob@jacob-aspire-mint:/tmp$

 

Execute o bootstrap

Este pequeno trecho de código verifica essencialmente se seu ambiente de construção está são e se você tem todas as ferramentas necessárias para construir o OpenOCD. A saída está abaixo, você não deve sair sem erros.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
jacob@jacob-aspire-mint:/tmp/openocd$ ./bootstrap
+ aclocal
+ libtoolize --automake --copy
+ autoconf
+ autoheader
+ automake --gnu --add-missing --copy
configure.ac:26: installing './compile'
configure.ac:37: installing './config.guess'
configure.ac:37: installing './config.sub'
configure.ac:16: installing './install-sh'
configure.ac:16: installing './missing'
Makefile.am:46: warning: wildcard $(srcdir: non-POSIX variable name
Makefile.am:46: (probably a GNU make extension)
Makefile.am: installing './INSTALL'
Makefile.am: installing './depcomp'
Makefile.am:23: installing './mdate-sh'
Makefile.am:23: installing './texinfo.tex'
Setting up submodules
Submodule 'jimtcl' (http://repo.or.cz/r/jimtcl.git) registered for path 'jimtcl'
Submodule 'src/jtag/drivers/libjaylink' (http://repo.or.cz/r/libjaylink.git) registered for path 'src/jtag/drivers/libjaylink'
Submodule 'tools/git2cl' (http://repo.or.cz/r/git2cl.git) registered for path 'tools/git2cl'
Cloning into '/tmp/openocd/jimtcl'...
warning: redirecting to https://repo.or.cz/r/jimtcl.git/
Cloning into '/tmp/openocd/src/jtag/drivers/libjaylink'...
warning: redirecting to https://repo.or.cz/r/libjaylink.git/
Cloning into '/tmp/openocd/tools/git2cl'...
warning: redirecting to https://repo.or.cz/r/git2cl.git/
Submodule path 'jimtcl': checked out 'a9bf5975fd0f89974d689a2d9ebd0873c8d64787'
Submodule path 'src/jtag/drivers/libjaylink': checked out 'f73ad5e667ae8b26a52b847c603fdadaabf302a6'
Submodule path 'tools/git2cl': checked out '8373c9f74993e218a08819cbcdbab3f3564bbeba'
Generating build system...
libtoolize: putting auxiliary files in AC_CONFIG_AUX_DIR, 'build-aux'.
libtoolize: copying file 'build-aux/config.guess'
libtoolize: copying file 'build-aux/config.sub'
libtoolize: copying file 'build-aux/install-sh'
libtoolize: copying file 'build-aux/ltmain.sh'
libtoolize: putting macros in AC_CONFIG_MACRO_DIRS, 'm4'.
libtoolize: copying file 'm4/libtool.m4'
libtoolize: copying file 'm4/ltoptions.m4'
libtoolize: copying file 'm4/ltsugar.m4'
libtoolize: copying file 'm4/ltversion.m4'
libtoolize: copying file 'm4/lt~obsolete.m4'
configure.ac:42: installing 'build-aux/ar-lib'
configure.ac:37: installing 'build-aux/compile'
configure.ac:30: installing 'build-aux/missing'
Makefile.am: installing './INSTALL'
libjaylink/Makefile.am: installing 'build-aux/depcomp'
Bootstrap complete. Quick build instructions:
./configure ....
jacob@jacob-aspire-mint:/tmp/openocd$

 

Execute o script de configuração

É aqui que determinamos que queremos que o FTDI FT232R seja suportado. Fazemos isso adicionando um sinalizador à linha de configuração. A saída é interrompida no meio porque é bastante longa, mas a parte importante está no final.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
jacob@jacob-aspire-mint:/tmp/openocd$ ./configure --enable-ft232r
checking for makeinfo... no
configure: WARNING: Info documentation will not be built.
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... gawk
 
[ ... snip ... ]
 
libjaylink configuration summary:
 - Package version ................ 0.2.0-git-f73ad5e
 - Library version ................ 0:0:0
 - Installation prefix ............ /usr/local
 - Building on .................... x86_64-pc-linux-gnu
 - Building for ................... x86_64-pc-linux-gnu
 
Enabled transports:
 - USB ............................ yes
 - TCP ............................ yes
 
 
 
OpenOCD configuration summary
--------------------------------------------------
MPSSE mode of FTDI based devices        yes (auto)
ST-Link Programmer                      yes (auto)
TI ICDI JTAG Programmer                 yes (auto)
Keil ULINK JTAG Programmer              yes (auto)
Altera USB-Blaster II Compatible        yes (auto)
Bitbang mode of FT232R based devices    yes
Versaloon-Link JTAG Programmer          yes (auto)
TI XDS110 Debug Probe                   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
Cypress KitProg Programmer              no
Altera USB-Blaster Compatible           no
ASIX Presto Adapter                     no
OpenJTAG Adapter                        no
SEGGER J-Link Programmer                yes (auto)

 

Compile

Finalmente, nós podemos compilar. Novamente, estou reduzindo o tamanho da saída, mas você deve acabar com um binário executável em src/ chamado openocd. Esta etapa final não demora muito (na minha máquina apenas cerca de 45s).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
jacob@jacob-aspire-mint:/tmp/openocd$ make
Makefile:4634: warning: overriding recipe for target 'check-recursive'
Makefile:4045: warning: ignoring old recipe for target 'check-recursive'
cat src/helper/startup.tcl src/jtag/startup.tcl src/target/startup.tcl src/server/startup.tcl src/flash/startup.tcl | ./src/helper/bin2char.sh > src/startup_tcl.inc || { rm -f src/startup_tcl.inc; false; }
cp src/jtag/drivers/minidriver_imp.h src/jtag/minidriver_imp.h
make  all-recursive
make[1]: Entering directory '/tmp/openocd'
Makefile:4634: warning: overriding recipe for target 'check-recursive'
Makefile:4045: warning: ignoring old recipe for target 'check-recursive'
Making all in jimtcl
make[2]: Entering directory '/tmp/openocd/jimtcl'
 
 
[ ... snip ... ]
 
libtool: link: ranlib src/.libs/libopenocd.a
libtool: link: rm -fr src/.libs/libopenocd.lax src/.libs/libopenocd.lax
libtool: link: ( cd "src/.libs" && rm -f "libopenocd.la" && ln -s "../libopenocd.la" "libopenocd.la" )
depbase=`echo src/main.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;\
gcc -DHAVE_CONFIG_H -I.   -I./src -I./src -I./src/helper -DPKGDATADIR=\"/usr/local/share/openocd\" -DBINDIR=\"/usr/local/bin\" -I./jimtcl -I./jimtcl  -Wall -Wstrict-prototypes -Wformat-security -Wshadow -Wextra -Wno-unused-parameter -Wbad-function-cast -Wcast-align -Wredundant-decls -Werror -g -O2 -MT src/main.o -MD -MP -MF $depbase.Tpo -c -o src/main.o src/main.c &&\
mv -f $depbase.Tpo $depbase.Po
/bin/bash ./libtool  --tag=CC   --mode=link gcc -Wall -Wstrict-prototypes -Wformat-security -Wshadow -Wextra -Wno-unused-parameter -Wbad-function-cast -Wcast-align -Wredundant-decls -Werror -g -O2   -o src/openocd src/main.o src/libopenocd.la  ./jimtcl/libjim.a  -ldl
libtool: link: gcc -Wall -Wstrict-prototypes -Wformat-security -Wshadow -Wextra -Wno-unused-parameter -Wbad-function-cast -Wcast-align -Wredundant-decls -Werror -g -O2 -o src/openocd src/main.o  src/.libs/libopenocd.a -lusb-1.0 -lm ./jimtcl/libjim.a -ldl
make[2]: Leaving directory '/tmp/openocd'
make[1]: Leaving directory '/tmp/openocd'

Testando OpenOCD

Agora que temos um binário, precisamos testá-lo e ver se funciona. Meu alvo para hoje é um Raspberry Pi 3 B. Primeiro precisamos reunir algumas informações sobre nosso alvo , ou seja, o Raspberry Pi 3. Precisamos saber quais pinos no cabeçalho GPIO correspondem a quais sinais JTAG.

Primeiro, vamos pegar a referência de pinagem do BCM2835. ( Nota lateral: usamos a referência BCM2835 porque não há referência BCM2837 e parece que as pinagens são praticamente as mesmas. ) Isso nos dirá o que cada pino GPIO faz. Alguns dos GPIOs são designados apenas para uma função singular, enquanto muitos outros GPIOs são multifuncionais e sua função é programável por software. Essas funções alternativas são designadas ALT no material de referência. Usei a referência no e-Linux porque acho a tabela fácil de ler. Pesquisando a tabela, encontramos os sinais JTAG nos quais estamos interessados ​​(TRST, TCK, TMS, TDI, TDO) atribuídos na faixa de GPIOs 22-27 para a função ALT4. Em seguida, queremos abrir o esquema do nosso Raspberry Pi 3 B e ver o que cada um deles mapeia no cabeçalho GPIO. Criei a tabela abaixo para manter as coisas em ordem.

Sinal JTAGBCM283xGPIO#Pino Raspberry Pi 3B J8 #
TRSTGPIO22P15
TCKGPIO25P22
EMTGPIO27P13
TDIGPIO26P37
TDOGPIO24P18
GNDmuitosP6

Depois de descobrirmos isso, precisamos preparar o Pi para uso JTAG. Esta é a parte mais simples de toda a configuração. No cartão SD do Pi, adicione a seguinte linha ao config.txt.

1
enable_jtag_gpio=1

Finalmente, estamos prontos para conectar nosso depurador JTAG. Procurando na documentação a configuração do OpenOCD FT232R, encontramos a tabela a seguir que nos mostra quais sinais RS232 correspondem a quais sinais JTAG. Precisamos (desligado, é claro!) Conectar nosso módulo / cabo FT232R e Pi de acordo, e não se esqueça do fio terra!

1
2
3
4
5
6
- RXD(5) - TDI
- TXD(1) - TCK
- RTS(3) - TDO
- CTS(11) - TMS
- DTR(2) - TRST
- DCD(10) - SRST

Depois que tudo estiver conectado, precisamos definir nossa configuração para a ferramenta OpenOCD. A configuração padrão do ft232r.cfg é suficiente para a interface, mas eu queria adicionar um item e para nos depurar, precisamos dizer ao OpenOCD como se conectar ao Pi e seus quatro núcleos. Baseei minha configuração rpi3b.cfg na configuração de um colega colaborador do GitHub , mas fiz algumas modificações.

ft232r.cfg

1
2
3
adapter driver ft232r
adapter speed 3000
ft232r_restore_serial 0x15

Modifiquei o ft232r.cfg para aumentar a velocidade do adaptador para 3M (3000 kHz) e para restaurar a configuração da porta quando o OpenOCD for concluído, para que o adaptador possa ser usado como um dispositivo serial novamente.

rpi3b.cfg

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
transport select jtag
 
adapter speed 3000
 
reset_config trst_and_srst
 
jtag_ntrst_delay 500
 
if { [info exists CHIPNAME] } {
  set _CHIPNAME $CHIPNAME
} else {
  set _CHIPNAME rpi3
}
 
if { [info exists DAP_TAPID] } {
   set _DAP_TAPID $DAP_TAPID
} else {
   set _DAP_TAPID 0x4ba00477
}
 
jtag newtap $_CHIPNAME tap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -enable
dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap
 
set _TARGETNAME $_CHIPNAME.a53
set _CTINAME $_CHIPNAME.cti
 
set DBGBASE {0x80010000 0x80012000 0x80014000 0x80016000}
set CTIBASE {0x80018000 0x80019000 0x8001a000 0x8001b000}
set _cores 4
 
for { set _core 0 } { $_core < $_cores } { incr _core } {
 
    cti create $_CTINAME.$_core -dap $_CHIPNAME.dap -ap-num 0 \
        -ctibase [lindex $CTIBASE $_core]
 
    target create $_TARGETNAME.$_core aarch64 \
        -dap $_CHIPNAME.dap -coreid $_core \
        -dbgbase [lindex $DBGBASE $_core] -cti $_CTINAME.$_core
 
    $_TARGETNAME.$_core configure -event reset-assert-post "aarch64 dbginit"
}

Juntando tudo

Agora temos todas as peças que precisamos para depurar usando nosso adaptador JTAG. Vamos começar!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
jacob@jacob-aspire-mint:/opt/apps/openocd$ sudo ./src/openocd -f ./ft232r.cfg -f ./rpi3b.cfg
Open On-Chip Debugger 0.10.0+dev-01047-g09ac9ab1 (2020-02-04-09:11)
Licensed under GNU GPL v2
For bug reports, read
Info : only one transport option; autoselect 'jtag'
FT232R restore serial: 0x0015 (enabled)
 
Warn : Transport "jtag" was already selected
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : clock speed 3000 kHz
Info : JTAG tap: rpi3.tap tap/device found: 0x4ba00477 (mfg: 0x23b (ARM Ltd.), part: 0xba00, ver: 0x4)
Info : rpi3.a53.0: hardware has 6 breakpoints, 4 watchpoints
Info : rpi3.a53.1: hardware has 6 breakpoints, 4 watchpoints
Info : rpi3.a53.2: hardware has 6 breakpoints, 4 watchpoints
Info : rpi3.a53.3: hardware has 6 breakpoints, 4 watchpoints
Info : Listening on port 3333 for gdb connections
Info : Listening on port 3334 for gdb connections
Info : Listening on port 3335 for gdb connections
Info : Listening on port 3336 for gdb connections

Agora estamos cozinhando! Você pode conectar o GDB a cada núcleo, depurar dessa forma ou usar a interface OpenOCD, veja abaixo:

Interface OpenOCD

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
acob@jacob-aspire-mint:/tmp/openocd$ telnet localhost 4444
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
> halt
rpi3.a53.3 cluster 0 core 3 multi core
target halted in AArch64 state due to debug-request, current mode: EL3H
cpsr: 0x000003cd pc: 0x20001c
MMU: disabled, D-Cache: disabled, I-Cache: disabled
> targets
    TargetName         Type       Endian TapName            State      
--  ------------------ ---------- ------ ------------------ ------------
 0  rpi3.a53.0         aarch64    little rpi3.tap           running
 1  rpi3.a53.1         aarch64    little rpi3.tap           running
 2  rpi3.a53.2         aarch64    little rpi3.tap           running
 3* rpi3.a53.3         aarch64    little rpi3.tap           halted
 
> reg
===== Aarch64 registers
(0) x0 (/64): 0x0000000000000003 (dirty)
(1) x1 (/64): 0x00000000C1000000
(2) x2 (/64)
(3) x3 (/64)
(4) x4 (/64)
(5) x5 (/64)
(6) x6 (/64)
(7) x7 (/64)
(8) x8 (/64)
 
[ ... snip ... ]

Interface GDB

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
jacob@jacob-aspire-mint:/tmp/openocd$ aarch64-none-elf-gdb
GNU gdb (GNU Toolchain for the A-profile Architecture 9.2-2019.12 (arm-9.10)) 8.3.0.20190709-git
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "--host=x86_64-pc-linux-gnu --target=aarch64-none-elf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://bugs.linaro.org/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.
 
For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) target remote :3333
Remote debugging using :3333
warning: No executable has been specified and target does not support
determining executable automatically.  Try using the "file" command.
0x0000000000200028 in ?? ()
(gdb) si
0x000000000020002c in ?? ()
(gdb) si
0x0000000000200074 in ?? ()
(gdb) si
0x0000000000200078 in ?? ()
(gdb)

Empacotando

Agora temos uma solução JTAG que pode depurar muitos tipos de processadores e microcontroladores com a configuração correta. Torna-se ainda mais útil se o seu módulo FT232R suportar a seleção da tensão do nível lógico como o meu. Veja abaixo alguns prós e contras dessa abordagem.

Prós

Esta é uma maneira rápida e suja de obter um adaptador JTAG sem nenhum custo se você já tiver esses chips FTDI disponíveis. É rápido e totalmente configurável (confira as páginas de configuração do OpenOCD para ver tudo o que ele pode fazer) e é um ótimo depurador.

Contras

Como estamos avançando um pouco para o sucesso aqui, é um pouco lento. Não é inutilizável, mas é mais lento que uma interface nativa. Se você ainda não tem um desses chips à sua disposição, eu optaria por um dos FT232H ou melhor ainda, o FT2232H, ambos com motor MPSSE que melhora muito a emulação.

Comments

Popular posts from this blog

Neoprogrammer (CH341A)

BIOS E ESQUEMA ELÉTRICO ITAUTEC ST 4272

TUTORIAL: Testando Placas de Vídeo NVIDIA com MATS / MODS