Difference between revisions of "JTAG"
m (→Debugging the Kernel with OpenOCD and GDB on APF28) |
|||
(70 intermediate revisions by 6 users not shown) | |||
Line 1: | Line 1: | ||
− | + | == Introduction == | |
− | + | ||
− | + | JTAG interface is useful in debugging some complicated issues with U-Boot, like [http://txlab.wordpress.com/2009/04/25/big-endian-for-imx27-found-the-problem/ this example here], during Linux kernel portage or for FPGA debugging with ChipScope. | |
− | First you need a decent JTAG connector. The | + | {{Note|However, most of the usual debugging functionalities are provided from within Armadeus BSP without the need for a JTAG interface. You won't also need JTAG to reflash an Armadeus board, even if you bricked U-Boot; serial connection should be enough (see [[Bootstrap]]). For debugging Linux applications directly on the APF you also can do without JTAG, see [[GDB]]}} |
+ | |||
+ | == Building a JTAG connector for APF27Dev board == | ||
+ | |||
+ | First you need a decent JTAG connector (the APF27Dev has a non standard JTAG port). | ||
+ | The following instructions will produce a 20-pin male JTAG connector with standard ARM pinout. | ||
List of material and part numbers at [http://www.conrad.ch Conrad]: | List of material and part numbers at [http://www.conrad.ch Conrad]: | ||
Line 11: | Line 15: | ||
* 2x10-pin IDC low profile header, 2.54mm pitch (Conrad: 743534) | * 2x10-pin IDC low profile header, 2.54mm pitch (Conrad: 743534) | ||
* 20-way flat cable, 1.27mm pitch (Conrad: 609463) | * 20-way flat cable, 1.27mm pitch (Conrad: 609463) | ||
+ | * 68 Ohm resistor | ||
Assembling it all together: | Assembling it all together: | ||
Line 26: | Line 31: | ||
! apf27dev J19 40-pin cable | ! apf27dev J19 40-pin cable | ||
|- | |- | ||
− | | | + | | 1 - VREF (+2.8v) |
− | | 39 | + | | J9 pin 2 OR J19 pin 39 with a 68 ohm resistor inline |
|- | |- | ||
| 2 - Vddh (+3.3v) | | 2 - Vddh (+3.3v) | ||
Line 41: | Line 46: | ||
| 35 | | 35 | ||
|- | |- | ||
− | | | + | | 7 - TMS |
| 36 | | 36 | ||
|- | |- | ||
− | | | + | | 9 - TCK |
| 37 | | 37 | ||
+ | |- | ||
+ | | 11 - RTCK | ||
+ | | (optional) J22 pin 2 (TCK_OWIRE) | ||
|- | |- | ||
| 13 –TDO | | 13 –TDO | ||
| 38 | | 38 | ||
|- | |- | ||
− | | 15 – | + | | 15 – nSRST |
− | | | + | | (optional) wired to apf27 R76 on cpu side: http://www.armadeus.com/_downloads/apf27/hardware/apf27_V1.2_top_assembly.pdf |
|} | |} | ||
− | == JTAG | + | == JTAG Probe == |
− | + | The examples below are tested with [http://www.amontec.com/jtagkey.shtml Amontec JTAGkey] adapter. It has a male 20-pin plug and a 20-way female-to-female cable which fits directly into the cable as described above. A cheaper solution would be to use the Amontec JTAGkey-Tiny and install a 20-pin female plug on the connector cable for APF27dev. | |
− | == | + | == Configure the board for JTAG == |
− | + | If the APF27 board is equipped with FPGA, the FPGA chip MUST be powered before using JTAG. Indeed, at system power-up, FPGA is low powered by cutting down the VCCAUX and VCCINT supplies until some data is loaded to FPGA. The simplest way to activate the FPGA chip is to enable the U-Boot ''firmware_autoload'' feature. Under U-Boot, set the environment variable ''firmware_autoload'' to 1 and save the environment variables to enable the FPGA on reset: | |
+ | |||
+ | {{Warning|Following instructions require that you wrote a firmware in dedicated FLASH partition '''BEFORE'''. Otherwise you may prevent your system from booting next time you boot !!}} | ||
+ | |||
+ | <pre class="apf"> | ||
+ | BIOS> setenv firmware_autoload 1 | ||
+ | BIOS> saveenv | ||
+ | Saving Environment to NAND... | ||
+ | Erasing Nand... | ||
+ | Erasing at 0xe0000 -- 100% complete. | ||
+ | Writing to Nand... done | ||
+ | BIOS> reset | ||
+ | ... | ||
+ | </pre> | ||
+ | |||
+ | == Install and configure OpenOCD to work with an Amontec JTAGkey== | ||
+ | |||
+ | Yet to be done. First it requires 2 libraries libusb and libftdi (libftd2xxx from ftdi). | ||
+ | Download and install the latest libftdi: http://www.intra2net.com/en/developer/libftdi/download.php | ||
+ | |||
+ | <pre class="host"> | ||
+ | >./configure | ||
+ | >make | ||
+ | >sudo make install | ||
+ | </pre> | ||
+ | |||
+ | then openocd up to the release 0.3.1 : http://developer.berlios.de/projects/openocd | ||
+ | {{Note|The new version 0.4.0 of openocd does not support the configuration file provided hereafter. help is welcome to fix this issue}} | ||
+ | |||
+ | <pre class="host"> | ||
+ | > ./bootstrap | ||
+ | ... | ||
+ | >./configure --enable-ft2232_libftdi | ||
+ | ... | ||
+ | >make | ||
+ | ... | ||
+ | >sudo make install | ||
+ | ... | ||
+ | </pre> | ||
+ | |||
+ | Basic tests show that cable works as expected. You can use the following configuration file with jtagkey and openocd. | ||
+ | |||
+ | {{Note| If you own a board without fpga, please remove the lines declaring the fpga in ftag chain : | ||
+ | jtag newtap xc3s200a.fpga fpga... | ||
+ | .... -expected-id 0x2218093 | ||
+ | }} | ||
<source lang="text"> | <source lang="text"> | ||
Line 69: | Line 122: | ||
gdb_memory_map enable | gdb_memory_map enable | ||
gdb_flash_program enable | gdb_flash_program enable | ||
− | + | gdb_breakpoint_override hard | |
interface ft2232 | interface ft2232 | ||
Line 75: | Line 128: | ||
ft2232_layout jtagkey | ft2232_layout jtagkey | ||
ft2232_vid_pid 0x0403 0xcff8 | ft2232_vid_pid 0x0403 0xcff8 | ||
− | jtag_khz | + | jtag_khz 6000 |
− | + | # The APF27 board has a IMX27 chip and one fpga spartan3 200k | |
− | + | #source [find board/apf27.cfg] | |
+ | #source [find target/imx27.cfg] | ||
+ | reset_config trst_and_srst | ||
set _CHIPNAME imx27 | set _CHIPNAME imx27 | ||
Line 104: | Line 159: | ||
arm7_9 dcc_downloads enable | arm7_9 dcc_downloads enable | ||
+ | #endof target/imx27.cfg | ||
+ | jtag newtap xc3s200a.fpga fpga \ | ||
+ | -irlen 6 \ | ||
+ | -irmask 0x3f \ | ||
+ | -ircapture 0x35 \ | ||
+ | -expected-id 0x2218093 | ||
− | # | + | #NOTE: for spartan3A 400k write : -ircapture 0x9 |
− | # | + | |
− | #- | + | $_TARGETNAME configure -event reset-init { apf27_init } |
− | # | + | |
− | #- | + | proc apf27_init { } { |
+ | # This setup puts RAM at 0xA0000000 | ||
+ | |||
+ | # reset the board correctly | ||
+ | #reset run | ||
+ | #reset halt | ||
+ | |||
+ | # reset keeping fpga alive | ||
+ | soft_reset_halt | ||
+ | halt | ||
+ | |||
+ | |||
+ | mww 0x10000000 0x20040304 | ||
+ | mww 0x10020000 0x00000000 | ||
+ | mww 0x10000004 0xDFFBFCFB | ||
+ | mww 0x10020004 0xFFFFFFFF | ||
+ | |||
+ | sleep 100 | ||
+ | |||
+ | # ======================================== | ||
+ | # Configure DDR on CSD0 -- initial reset | ||
+ | # ======================================== | ||
+ | mww 0x10027818 0x0000080F | ||
+ | mww 0xD8001010 0x0000000C | ||
+ | |||
+ | # ======================================== | ||
+ | # Configure DDR on CSD0 -- wait 5000 cycle | ||
+ | # ======================================== | ||
+ | mww 0x10027828 0x55555555 | ||
+ | mww 0x10027830 0x55555555 | ||
+ | mww 0x10027834 0x55555555 | ||
+ | mww 0x10027838 0x00005005 | ||
+ | mww 0x1002783C 0x15555555 | ||
+ | |||
+ | mww 0xD8001004 0x00695728 | ||
+ | |||
+ | mww 0xD8001000 0x92100000 | ||
+ | mww 0xA0000F00 0x0 | ||
+ | |||
+ | mww 0xD8001000 0xA2100000 | ||
+ | mww 0xA0000F00 0x0 | ||
+ | mww 0xA0000F00 0x0 | ||
+ | mww 0xA0000F00 0x0 | ||
+ | mww 0xA0000F00 0x0 | ||
+ | |||
+ | mww 0xD8001000 0xA2100000 | ||
+ | mww 0xA0000F00 0x0 | ||
+ | mww 0xA0000F00 0x0 | ||
+ | mww 0xA0000F00 0x0 | ||
+ | mww 0xA0000F00 0x0 | ||
+ | |||
+ | mww 0xD8001000 0xB2100000 | ||
+ | mwb 0xA0000033 0xDA | ||
+ | mwb 0xA2000000 0x00 | ||
+ | |||
+ | mww 0xD8001000 0x82126080 | ||
+ | } | ||
− | |||
</source> | </source> | ||
− | + | launch openocd with administrator right and with this config file and test the connection from a telnet terminal to send commands reset, soft_reset_halt, halt. | |
+ | Without the nSRST line wired to the board it is still possible to reset the apf27 with the reset button. ;-) | ||
− | " | + | <pre class="host"> |
+ | > openocd | ||
+ | |||
+ | 6000 kHz | ||
+ | dcc downloads are enabled | ||
+ | Info : JTAG tap: imx27.bs tap/device found: 0x1b900f0f (Manufacturer: 0x787, Part: 0xb900, Version: 0x1) | ||
+ | Info : JTAG Tap/device matched | ||
+ | Info : JTAG tap: imx27.cpu tap/device found: 0x07926121 (Manufacturer: 0x090, Part: 0x7926, Version: 0x0) | ||
+ | Info : JTAG Tap/device matched | ||
+ | Info : JTAG tap: xc3s400a.fpga.fpga tap/device found: 0x02220093 (Manufacturer: 0x049, Part: 0x2220, Version: 0x0) | ||
+ | Info : JTAG Tap/device matched | ||
+ | Warn : no tcl port specified, using default port 6666 | ||
+ | ... | ||
+ | </pre> | ||
+ | |||
+ | and from another terminal: | ||
+ | <pre class="host"> | ||
+ | > telnet 127.0.0.1 4444 | ||
+ | |||
+ | Trying 127.0.0.1... | ||
+ | Connected to 127.0.0.1. | ||
+ | Escape character is '^]'. | ||
+ | Open On-Chip Debugger | ||
+ | > reset | ||
+ | JTAG tap: imx27.bs tap/device found: 0x1b900f0f (Manufacturer: 0x787, Part: 0xb900, Version: 0x1) | ||
+ | JTAG Tap/device matched | ||
+ | JTAG tap: imx27.cpu tap/device found: 0x07926121 (Manufacturer: 0x090, Part: 0x7926, Version: 0x0) | ||
+ | JTAG Tap/device matched | ||
+ | JTAG tap: xc3s400a.fpga.fpga tap/device found: 0x02220093 (Manufacturer: 0x049, Part: 0x2220, Version: 0x0) | ||
+ | JTAG Tap/device matched | ||
+ | |||
+ | > soft_reset_halt | ||
+ | requesting target halt and executing a soft reset | ||
+ | target state: halted | ||
+ | target halted in ARM state due to debug-request, current mode: Supervisor | ||
+ | cpsr: 0x000000d3 pc: 0x00000000 | ||
+ | MMU: disabled, D-Cache: disabled, I-Cache: disabled | ||
> halt | > halt | ||
− | + | target state: halted | |
+ | target halted in ARM state due to debug-request, current mode: Supervisor | ||
+ | cpsr: 0x200000d3 pc: 0xaff20bb8 | ||
+ | MMU: disabled, D-Cache: disabled, I-Cache: enabled | ||
+ | |||
+ | > reset init | ||
+ | JTAG tap: imx27.bs tap/device found: 0x1b900f0f (Manufacturer: 0x787, Part: 0xb900, Version: 0x1) | ||
+ | JTAG Tap/device matched | ||
+ | JTAG tap: imx27.cpu tap/device found: 0x07926121 (Manufacturer: 0x090, Part: 0x7926, Version: 0x0) | ||
+ | ... | ||
+ | </pre> | ||
+ | |||
+ | == Working with BDI2000 == | ||
+ | |||
+ | Firstly, check if your BDI2000 is rev C (see on the back of the probe, near the serial number). If your probe is A or B, it does not support target supply voltage less than 3.0 V. In this case, there might be a solution putting a serial resistor, see above [[#Building a JTAG connector for apf27Dev board|Building a JTAG connector for APF27Dev board]]. | ||
+ | |||
+ | In addition, you can follow these drawings : | ||
+ | [[Image:Schema brochage bdi2000 apf27dev 1.png|thumb|none|300px|BDI2000 to APF27-Dev, board side]] | ||
+ | |||
+ | [[Image:Schema brochage bdi2000 apf27dev 2.png|thumb|none|300px|BDI2000 to APF27-Dev, BDI side]] | ||
+ | |||
+ | The BDI2000 probe comes with a firmware (bdiGDB) that make one able to connect directly GDB (GNU debugger) to the BDI2000 via ethernet. In the following example, we use a precompiled GDB from CodeSourcery. But any GDB configured for an ARM target might work. | ||
+ | |||
+ | You can use the following configuration file with BDI2000. It has been built like OpenOCD configuration file. | ||
+ | |||
+ | <pre> | ||
+ | ; bdiGDB configuration for ARMadeus APF27 board | ||
+ | ; --------------------------------------------- | ||
+ | ; Jonathan ILIAS-PILLET | ||
+ | ; | ||
+ | ; Many settings translated from OpenOCD's one, thanks to SSinyagin and Jorasse | ||
+ | [INIT] | ||
+ | |||
+ | ; to be done : memory map | ||
+ | |||
+ | ;This setup puts RAM at 0xA0000000 | ||
+ | |||
+ | ; reset the board correctly | ||
+ | |||
+ | wm32 0x10000000 0x20040304 | ||
+ | wm32 0x10020000 0x00000000 | ||
+ | wm32 0x10000004 0xDFFBFCFB | ||
+ | wm32 0x10020004 0xFFFFFFFF | ||
+ | |||
+ | delay 100 | ||
+ | |||
+ | ; ======================================== | ||
+ | ; Configure DDR on CSD0 -- initial reset | ||
+ | ; ======================================== | ||
+ | wm32 0x10027818 0x0000080F | ||
+ | wm32 0xD8001010 0x0000000C | ||
+ | |||
+ | ; ======================================== | ||
+ | ; Configure DDR on CSD0 -- wait 5000 cycle | ||
+ | ; ======================================== | ||
+ | wm32 0x10027828 0x55555555 | ||
+ | wm32 0x10027830 0x55555555 | ||
+ | wm32 0x10027834 0x55555555 | ||
+ | wm32 0x10027838 0x00005005 | ||
+ | wm32 0x1002783C 0x15555555 | ||
+ | |||
+ | wm32 0xD8001004 0x00695728 | ||
+ | |||
+ | wm32 0xD8001000 0x92100000 | ||
+ | wm32 0xA0000F00 0x0 | ||
+ | |||
+ | wm32 0xD8001000 0xA2100000 | ||
+ | wm32 0xA0000F00 0x0 | ||
+ | wm32 0xA0000F00 0x0 | ||
+ | wm32 0xA0000F00 0x0 | ||
+ | wm32 0xA0000F00 0x0 | ||
+ | |||
+ | wm32 0xD8001000 0xB2100000 | ||
+ | wm8 0xA0000033 0xDA | ||
+ | wm8 0xA2000000 0x00 | ||
+ | |||
+ | wm32 0xD8001000 0x82126080 | ||
+ | |||
+ | |||
+ | [TARGET] | ||
+ | CPUTYPE ARM926E ; processor core | ||
+ | CLOCK 1 ; JTAG clock 1 = 16 MHz, 6 = 200KHz (last setting used only for testing) | ||
+ | WAKEUP 200 ; millisecond to wait after a reset to let target start | ||
+ | SCANPRED 1 6 ; JTAG chain starts with FGPA (spartan3), it has a 6 bits Instruction Register | ||
+ | SCANSUCC 1 4 ; i.MX27 JTAG Controller, not used but present in the JTAG chain | ||
+ | TRST OPENDRAIN ; pullup provided by iMX27 (§7.4 JTAG Controller Pin List) | ||
+ | RESET NONE | ||
+ | ENDIAN LITTLE ; memory model is little endian | ||
+ | ;VECTOR CATCH 0x1f ; not used now | ||
+ | BREAKMODE HARD ; hardware breakpoints | ||
+ | ;BREAKMODE SOFT 0xDFFFDFFF ;SOFT or HARD, ARM / Thumb break code | ||
+ | BDIMODE AGENT | ||
+ | |||
+ | [HOST] | ||
+ | DEBUGPORT 2001 ; TCP port to connect GDB to | ||
+ | FORMAT ELF ; format of image files | ||
+ | LOAD MANUAL ; load code manually after reset | ||
+ | PROMPT APF27> | ||
+ | |||
+ | [FLASH] | ||
+ | ; to be done | ||
+ | |||
+ | [REGS] | ||
+ | FILE reg926e.def | ||
+ | </pre> | ||
+ | |||
+ | You can also use the optionnal register file below : | ||
+ | <pre> | ||
+ | ;Register definition for ARM926E | ||
+ | ;=============================== | ||
+ | ; | ||
+ | ; name: user defined name of the register | ||
+ | ; type: the type of the register | ||
+ | ; GPR general purpose register | ||
+ | ; CP15 CP15 register | ||
+ | ; MM memory mapped register | ||
+ | ; DMMx direct memory mapped register with offset | ||
+ | ; x = 1..4 | ||
+ | ; the base is defined in the configuration file | ||
+ | ; e.g. DMM1 0x02200000 | ||
+ | ; addr: the number, adddress or offset of the register | ||
+ | ; size the size of the register (8,16 or 32) | ||
+ | ; | ||
+ | ;name type addr size | ||
+ | ;------------------------------------------- | ||
+ | ; | ||
+ | ; | ||
+ | ; CP15 Registers | ||
+ | ; | ||
+ | ; Register Numbers for 926E: | ||
+ | ; +-------+-------+-------+-------+ | ||
+ | ; | | | | | | | | | | | | | | | | | | ||
+ | ; +-+-----+-+-----+-------+-------+ | ||
+ | ; |-|opc_1|-|opc_2| CRm | nbr | | ||
+ | ; +-+-----+-+-----+-------+-------+ | ||
+ | ; | ||
+ | ; | ||
+ | id CP15 0x0000 32 ;ID code | ||
+ | cache CP15 0x0100 32 ;Cache type | ||
+ | tcm CP15 0x0200 32 ;TCM status | ||
+ | control CP15 0x0001 32 ;Control | ||
+ | ttb CP15 0x0002 32 ;Translation table base | ||
+ | dac CP15 0x0003 32 ;Domain access control | ||
+ | dfsr CP15 0x0005 32 ;Data fault status | ||
+ | ifsr CP15 0x0105 32 ;Inst fault status | ||
+ | far CP15 0x0006 32 ;Fault address | ||
+ | ; | ||
+ | fcsr CP15 0x000d 32 ;Fast context switch PID | ||
+ | context CP15 0x010d 32 ;Context ID | ||
+ | ; | ||
+ | </pre> | ||
+ | |||
+ | Now, we want to connect GDB to the BDI probe. Here are the IP addresses choosen for the example : | ||
+ | * 192.168.5.1 is the host, where GDB runs | ||
+ | * 192.168.5.2 is the BDI2000's address | ||
+ | |||
+ | GDB command and its output should looks like this : | ||
+ | (gdb) target remote 192.168.5.2:2001 | ||
+ | Remote debugging using 192.168.5.2:2001 | ||
+ | 0xaff20cb4 in ?? () | ||
+ | |||
+ | == Using OpenOCD == | ||
+ | |||
+ | Now we can use OpenOCD / JTAG to boot a new U-Boot image: | ||
+ | |||
+ | * Reset the target manually | ||
+ | |||
+ | * Run OpenOCD | ||
+ | <pre class="host"> | ||
+ | openocd -f openocd.cfg | ||
+ | </pre> | ||
+ | |||
+ | * Start a telnet session from another terminal | ||
+ | <pre class="host"> | ||
+ | telnet localhost 4444 | ||
+ | </pre> | ||
+ | |||
+ | * Halt the CPU and configure the DDRAM controler | ||
+ | <pre class="host"> | ||
+ | > soft_reset_halt | ||
+ | ... | ||
+ | > reset init | ||
+ | ... | ||
+ | </pre> | ||
+ | |||
+ | * Load the U-Boot image to RAM | ||
+ | <pre class="host"> | ||
+ | > load_image /home/{mydir}/armadeus/buildroot/project_build_armv5te/apf27/u-boot-1.3.4/u-boot-nand.bin 0xA0000000 | ||
+ | ... | ||
+ | </pre> | ||
+ | |||
+ | |||
+ | * Assert a breakpoint | ||
+ | <pre class="host"> | ||
+ | > bp 0xa0000010 4 hw | ||
+ | breakpoint added at address 0xa0000010 | ||
+ | </pre> | ||
+ | |||
+ | * Run U-Boot up to the breakpoint | ||
+ | <pre class="host"> | ||
+ | > resume 0xa0000000 | ||
+ | target state: halted | ||
+ | target halted in ARM state due to breakpoint, current mode: Supervisor | ||
+ | cpsr: 0x600000d3 pc: 0xa0000010 | ||
+ | MMU: disabled, D-Cache: disabled, I-Cache: disabled | ||
+ | </pre> | ||
+ | |||
+ | OpenOCD is operational... | ||
+ | |||
+ | == Debugging U-Boot with OpenOCD and GDB on APF27 == | ||
+ | |||
+ | The booting procedure of apf27 is as follows: | ||
+ | # the NAND_SPL loader reads the u-boot image from NAND flash to 0xA0000000 (nand_spl/board/armadeus/apf27/start.S) | ||
+ | # The SPL loader gives control to the U-boot startup (cpu/arm926ejs/start.S) | ||
+ | # The startup code gives control to the board-specific initialization code (lowlevel_init in board/armadeus/apf27/lowlevel_init.S) | ||
+ | # The startup code relocates the image to its base address (TEXT_BASE=0xAFF00000) | ||
+ | # The startup code gives control to start_armboot() in lib_arm/board.c | ||
+ | # U-boot reads the environment and does its booting job. | ||
+ | |||
+ | If you plan to debug a new U-boot image with JTAG, you have to prevent it from resetting FPGA (GPIO port F). By default, the startup code resets the FPGA ports to their initial state, and that disconnects our JTAG adapter, because FPGA chip is part of the chain. | ||
+ | |||
+ | Comment out the following lines in the patched U-boot code in buildroot/project_build_armv5te/apf27/u-boot-1.3.4: | ||
+ | |||
+ | <pre> | ||
+ | ### cpu/arm926ejs/start.S lines 185-186 | ||
+ | /* bl coloured_LED_init | ||
+ | bl red_LED_on */ | ||
+ | |||
+ | ### board/armadeus/apf27/lowlevel_init.S lines 113-126 | ||
+ | /* PORTF */ | ||
+ | /* writel( DR(PORTF), CFG_DR_F_VAL) | ||
+ | writel( OCR1(PORTF), CFG_OCR1_F_VAL) | ||
+ | writel( OCR2(PORTF), CFG_OCR2_F_VAL) | ||
+ | writel( ICONFA1(PORTF), CFG_ICFA1_F_VAL) | ||
+ | writel( ICONFA2(PORTF), CFG_ICFA2_F_VAL) | ||
+ | writel( ICONFB1(PORTF), CFG_ICFB1_F_VAL) | ||
+ | writel( ICONFB2(PORTF), CFG_ICFB2_F_VAL) | ||
+ | writel( ICR1(PORTF), CFG_ICR1_F_VAL) | ||
+ | writel( ICR2(PORTF), CFG_ICR2_F_VAL) | ||
+ | writel( IMR(PORTF), CFG_IMR_F_VAL) | ||
+ | writel( DDIR(PORTF), CFG_DDIR_F_VAL) | ||
+ | writel( GPR(PORTF), CFG_GPR_F_VAL) | ||
+ | writel( PUEN(PORTF), CFG_PUEN_F_VAL) | ||
+ | writel( GIUS(PORTF), CFG_GIUS_F_VAL) */ | ||
+ | </pre> | ||
+ | |||
+ | Compile the new U-boot image. This example disables optimization and stores the build commands into a logfile. From Armadeus BSP root folder, | ||
+ | <pre class="host"> | ||
+ | make u-boot-clean && (make OPTFLAGS=-O0 | tee loglog) && cp -v buildroot/binaries/apf27/apf27-u-boot.bin /tftpboot/ | ||
+ | </pre> | ||
+ | |||
+ | Reset the board and press any key to get U-Boot prompt in the serial console. | ||
+ | |||
+ | Launch OpenOCD (we assume the JTAG adapter is already connected). It should report finding of 3 devices: | ||
+ | <pre class="host"> | ||
+ | openocd -f apf27-openocd.cfg | ||
+ | </pre> | ||
+ | |||
+ | Figure out which address to use for the first breakpoint. The build process has created the file ''u-boot.map'' which lists all the addresses of all global symbols. In this example, the address of start_armboot() is 0xaff01630: | ||
+ | <pre class="host"> | ||
+ | [root@lab0 u-boot-1.3.4]# grep start_armboot u-boot.map | ||
+ | lib_arm/libarm.a(board.o) cpu/arm926ejs/start.o (start_armboot) | ||
+ | 0x00000000aff01630 start_armboot | ||
+ | </pre> | ||
+ | |||
+ | Telnet to the OpenOCD console and install the breakpoint at the address of interest. It is important to issue "halt" and "resume": | ||
+ | <pre class="host"> | ||
+ | [root@lab0 armadeus]# telnet localhost 4444 | ||
+ | Trying 127.0.0.1... | ||
+ | Connected to localhost. | ||
+ | Escape character is '^]'. | ||
+ | Open On-Chip Debugger | ||
+ | > halt | ||
+ | target state: halted | ||
+ | target halted in ARM state due to debug-request, current mode: Supervisor | ||
+ | cpsr: 0x000000d3 pc: 0xaff20c4c | ||
+ | MMU: disabled, D-Cache: disabled, I-Cache: enabled | ||
+ | |||
+ | > bp 0xaff01630 4 hw | ||
+ | breakpoint added at address 0xaff01630 | ||
+ | |||
+ | > resume | ||
+ | </pre> | ||
+ | |||
+ | Now the original u-boot image continues to function. Load our test image into the memory and launch it: | ||
+ | <pre class="host"> | ||
+ | BIOS> setenv ipaddr 192.168.1.5; setenv serverip 192.168.1.40; run download_uboot; go ${loadaddr} | ||
+ | FEC ETHERNET: Link is up - 100/Full | ||
+ | TFTP from server 192.168.0.2; our IP address is 192.168.0.10 | ||
+ | Filename 'apf27-u-boot.bin'. | ||
+ | Load address: 0xa0000000 | ||
+ | Loading: ########################### | ||
+ | done | ||
+ | Bytes transferred = 392232 (5fc28 hex) | ||
+ | ## Starting application at 0xA0000000 ... | ||
+ | </pre> | ||
+ | |||
+ | Here our breakpoint should fire, and the following should be seen in OpenOCD telnet session: | ||
+ | <pre class="host"> | ||
+ | target state: halted | ||
+ | target halted in ARM state due to breakpoint, current mode: Supervisor | ||
+ | cpsr: 0x200000d3 pc: 0xaff01630 | ||
+ | MMU: disabled, D-Cache: disabled, I-Cache: enabled | ||
+ | </pre> | ||
+ | |||
+ | Remove the breakpoint. Note that there is a very limited number of hardware breakpoints (3?) and you can't set up too many of them. | ||
+ | <pre class="host"> | ||
+ | rbp 0xaff01630 | ||
+ | </pre> | ||
+ | |||
+ | Now we can launch GDB or its graphical interface DDD and connect it to our paused bootloader: | ||
+ | <pre class="host"> | ||
+ | ddd --debugger buildroot/build_armv5te/staging_dir/usr/bin/arm-linux-gdb | ||
+ | </pre> | ||
+ | |||
+ | In GDB command window, load the symbol table and connect to OpenOCD: | ||
+ | <pre class="host"> | ||
+ | (gdb) add-symbol-file u-boot 0xaff00000 | ||
+ | add symbol table from file "u-boot" at | ||
+ | .text_addr = 0xaff00000 | ||
+ | (gdb) target remote localhost:3333 | ||
+ | start_armboot () at board.c:304 | ||
+ | /home/armadeus-be/buildroot/project_build_armv5te/apf27/u-boot-1.3.4/lib_arm/board.c:304:8383:beg:0xaff01630 | ||
+ | </pre> | ||
+ | |||
+ | The DDD code display window should show the start_armboot() entry point. Now you can follow with the debugging as usual. | ||
+ | |||
+ | Hint: in order to get back to start_armboot(), you don't have to reset the board. Disconnect GDB from OpenOCD, then in OpenOCD telnet window, set the program counter back to the start address of start_armboot(), and then re-attach GDB. | ||
+ | |||
+ | == Debugging the Kernel with OpenOCD and GDB on APF28/APF6 == | ||
+ | {{Note|Openocd version 0.8.0 (default Debian version (apt-get install openocd)) and Linux Kernel 3.16 are used here.}} | ||
+ | |||
+ | The [[APF28Dev]]/[[APF6Dev]] has a standard JTAG connector so just connect your JTAG probe on it. | ||
+ | [[Image:apf6dev_jtag_connector.jpg]] | ||
+ | |||
+ | Compile the kernel with debug symbols. To do so: | ||
+ | <pre class="host"> | ||
+ | $ make linux-menuconfig | ||
+ | </pre> | ||
+ | <pre class="config"> | ||
+ | Kernel hacking --> | ||
+ | Compile-time checks and compiler options --> | ||
+ | [*] Compile the kernel with debug info. | ||
+ | </pre> | ||
+ | |||
+ | Now create a new file ''apf28-openocd.cfg'' with the following content: | ||
+ | |||
+ | <pre> | ||
+ | source [find interface/ftdi/jtagkey.cfg] | ||
+ | source [find target/imx28.cfg] | ||
+ | source [find mem_helper.tcl] | ||
+ | |||
+ | gdb_memory_map enable | ||
+ | gdb_flash_program enable | ||
+ | |||
+ | adapter_khz 100 | ||
+ | reset_config trst_and_srst separate trst_push_pull srst_open_drain | ||
+ | </pre> | ||
+ | |||
+ | Of course you have to adapt the first line depending on the JTAG probe you are using. Have a look in /usr/share/openocd/scripts/interface/ on your computer, a config file for you probe may already exists. | ||
+ | |||
+ | Power the board. | ||
+ | |||
+ | On a terminal on your host computer, start openocd: | ||
+ | <pre> | ||
+ | # openocd -d2 -f apf28-openocfd.cfg | ||
+ | Open On-Chip Debugger 0.9.0-dev-00161-g9c47dc9 (2014-10-02-16:23) | ||
+ | Licensed under GNU GPL v2 | ||
+ | For bug reports, read | ||
+ | http://openocd.sourceforge.net/doc/doxygen/bugs.html | ||
+ | debug_level: 2 | ||
+ | trst_and_srst separate srst_gates_jtag trst_push_pull srst_open_drain connect_deassert_srst | ||
+ | adapter_nsrst_delay: 100 | ||
+ | Error: session's transport is not selected. | ||
+ | Info : session transport was not selected, defaulting to JTAG | ||
+ | jtag_ntrst_delay: 100 | ||
+ | dcc downloads are enabled | ||
+ | adapter speed: 100 kHz | ||
+ | trst_and_srst separate srst_gates_jtag trst_push_pull srst_open_drain connect_deassert_srst | ||
+ | Info : clock speed 100 kHz | ||
+ | Info : JTAG tap: imx28.cpu tap/device found: 0x079264f3 (mfg: 0x279, part: 0x7926, ver: 0x0) | ||
+ | Info : Embedded ICE version 6 | ||
+ | Info : imx28.cpu: hardware has 2 breakpoint/watchpoint units | ||
+ | </pre> | ||
+ | |||
+ | On another termnial on your host computer, launch gdb: | ||
+ | |||
+ | <pre> | ||
+ | ~/development/armadeus-git-apf28 $ ./buildroot/output/host/usr/bin/arm-linux-gdb buildroot/output/build/linux-3.16/vmlinux | ||
+ | GNU gdb (GDB) 7.5.1 | ||
+ | Copyright (C) 2012 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-unknown-linux-gnu --target=arm-buildroot-linux-uclibcgnueabi". | ||
+ | For bug reporting instructions, please see: | ||
+ | <http://www.gnu.org/software/gdb/bugs/>... | ||
+ | Reading symbols from /home/sszy/development/armadeus-git-apf28/buildroot/output/build/linux-3.16/vmlinux...done. | ||
+ | (gdb) | ||
+ | </pre> | ||
+ | |||
+ | Connect gdb to openocd: | ||
+ | |||
+ | <pre> | ||
+ | (gdb) target remote :3333 | ||
+ | Remote debugging using :3333 | ||
+ | __vectors_start () at arch/arm/kernel/entry-armv.S:1138 | ||
+ | 1138 W(b) vector_rst | ||
+ | </pre> | ||
+ | |||
+ | Now let's add a breakpoint every time we read the wakealarm of the RTC present on the APF28. "rtc_read_alarm" is the function called everytime you read the file /sys/class/rtc/rtc0/wakealarm. First whe have to put the board in halt mode and the add the breakpoint: | ||
+ | <pre> | ||
+ | (gdb) monitor halt | ||
+ | target state: halted | ||
+ | target halted in ARM state due to debug-request, current mode: Supervisor | ||
+ | cpsr: 0x600000d3 pc: 0xc0013024 | ||
+ | MMU: enabled, D-Cache: enabled, I-Cache: disabled | ||
+ | (gdb) break rtc_read_alarm | ||
+ | Breakpoint 1 at 0xc02f9990: file drivers/rtc/interface.c, line 317. | ||
+ | (gdb) c | ||
+ | Continuing. | ||
+ | </pre> | ||
+ | |||
+ | In another terminal, connect on your board via the debug interface. Log in and show the alarm date of the RTC: | ||
+ | <pre> | ||
+ | Welcome to Armadeus development platform ! | ||
+ | apf28 login: root | ||
+ | # cat /sys/class/rtc/rtc0/wakealarm | ||
+ | |||
+ | </pre> | ||
+ | |||
+ | In gdb you should see: | ||
+ | |||
+ | <pre> | ||
+ | Breakpoint 1, rtc_read_alarm (rtc=0xc752b400, alarm=0xc6ee7ea8) at drivers/rtc/interface.c:317 | ||
+ | 317 { | ||
+ | </pre> | ||
+ | |||
+ | To make a move of one step: | ||
+ | |||
+ | <pre> | ||
+ | (gdb) step | ||
+ | 320 err = mutex_lock_interruptible(&rtc->ops_lock); | ||
+ | </pre> | ||
+ | |||
+ | You can see more lines of codes: | ||
+ | |||
+ | <pre> | ||
+ | (gdb) list | ||
+ | 315 | ||
+ | 316 int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) | ||
+ | 317 { | ||
+ | 318 int err; | ||
+ | 319 | ||
+ | 320 err = mutex_lock_interruptible(&rtc->ops_lock); | ||
+ | 321 if (err) | ||
+ | 322 return err; | ||
+ | 323 if (rtc->ops == NULL) | ||
+ | 324 err = -ENODEV; | ||
+ | </pre> | ||
+ | |||
+ | To resume: | ||
+ | |||
+ | <pre> | ||
+ | (gdb) continue | ||
+ | Continuing. | ||
+ | |||
+ | </pre> | ||
+ | |||
+ | Here, you can stop the kernel any time by hitting ctrl + C | ||
+ | |||
+ | <pre> | ||
+ | Continuing. | ||
+ | ^C | ||
+ | Program received signal SIGINT, Interrupt. | ||
+ | cpu_arm926_do_idle () at arch/arm/mm/proc-arm926.S:112 | ||
+ | 112 mcr p15, 0, r1, c1, c0, 0 @ Restore ICache enable | ||
+ | (gdb) | ||
+ | </pre> | ||
+ | |||
+ | To resume and still have the gdb prompt: | ||
+ | |||
+ | <pre> | ||
+ | (gdb) monitor resume | ||
+ | (gdb) | ||
+ | </pre> | ||
+ | |||
+ | == Troubleshooting == | ||
+ | |||
+ | * TRST does not stop the CPU | ||
+ | **Most probably the FPGA chip went offline during the U-Boot initialization and didn't come online. | ||
+ | |||
+ | * FPGA chip is not visible when OpenOCD detects the TAPs. | ||
+ | **FPGA chip is in low power mode at startup. Load some data in the FPGA to enable it in JTAG chain. | ||
+ | |||
+ | * In [[Bootstrap]] mode FPGA and CPU are not accessible. | ||
+ | **Yes, be sure to remove the bootstrap jumper to be able to use JTAG. There could be a small hardware modification to fix it but this change would disable the low power features. | ||
+ | |||
+ | == Links == | ||
+ | |||
+ | * http://www.amontec.com/ | ||
+ | * http://www.abatron.ch/products/debugger-support/gnu-support.html | ||
+ | * http://www.intra2net.com/opensource/ftdi/ | ||
+ | * http://openocd.berlios.de/web/ | ||
+ | * http://www.gnu.org/software/gdb/ | ||
+ | * http://www.gnu.org/software/ddd/ | ||
+ | * http://www.denx.de/wiki/view/DULG/DebuggingUBoot |
Latest revision as of 17:23, 3 June 2016
Contents
- 1 Introduction
- 2 Building a JTAG connector for APF27Dev board
- 3 JTAG Probe
- 4 Configure the board for JTAG
- 5 Install and configure OpenOCD to work with an Amontec JTAGkey
- 6 Working with BDI2000
- 7 Using OpenOCD
- 8 Debugging U-Boot with OpenOCD and GDB on APF27
- 9 Debugging the Kernel with OpenOCD and GDB on APF28/APF6
- 10 Troubleshooting
- 11 Links
Introduction
JTAG interface is useful in debugging some complicated issues with U-Boot, like this example here, during Linux kernel portage or for FPGA debugging with ChipScope.
Note: However, most of the usual debugging functionalities are provided from within Armadeus BSP without the need for a JTAG interface. You won't also need JTAG to reflash an Armadeus board, even if you bricked U-Boot; serial connection should be enough (see Bootstrap). For debugging Linux applications directly on the APF you also can do without JTAG, see GDB |
Building a JTAG connector for APF27Dev board
First you need a decent JTAG connector (the APF27Dev has a non standard JTAG port). The following instructions will produce a 20-pin male JTAG connector with standard ARM pinout.
List of material and part numbers at Conrad:
- 2x20-pin header, 2.54mm pitch (Conrad: 741973)
- ATA/IDE cable (Conrad: 971742)
- 2x10-pin IDC low profile header, 2.54mm pitch (Conrad: 743534)
- 20-way flat cable, 1.27mm pitch (Conrad: 609463)
- 68 Ohm resistor
Assembling it all together:
- Solder the 40-pin header onto the J19 connector on the apf27dev board
- Cut off a ~10cm piece from the ATA cable with the 40pin plug at the end.
- Cut off ~10cm from 20-way flat cable
- Carefully attach the 20-pin header to the flat cable. The thing is easy to break and it requires some forcing. Better buy a spare piece in advance.
- Use a knife and a cutting pad and dissect the cable endings, ~3cm long. Dissect the whole width of the 20-way cable and only pins 40 to 31 on the 40-way ATA cable.
- Strip the cable endings
- Solder the two cables together, as specified below:
ARM JTAG 20-pin cable | apf27dev J19 40-pin cable |
---|---|
1 - VREF (+2.8v) | J9 pin 2 OR J19 pin 39 with a 68 ohm resistor inline |
2 - Vddh (+3.3v) | 39 |
3 - nTRST | 33 |
4, 6, 8, 10, 12, 14, 16, 18, 20 - Vss (ground) | 31, 34, 40 |
5 - TDI | 35 |
7 - TMS | 36 |
9 - TCK | 37 |
11 - RTCK | (optional) J22 pin 2 (TCK_OWIRE) |
13 –TDO | 38 |
15 – nSRST | (optional) wired to apf27 R76 on cpu side: http://www.armadeus.com/_downloads/apf27/hardware/apf27_V1.2_top_assembly.pdf |
JTAG Probe
The examples below are tested with Amontec JTAGkey adapter. It has a male 20-pin plug and a 20-way female-to-female cable which fits directly into the cable as described above. A cheaper solution would be to use the Amontec JTAGkey-Tiny and install a 20-pin female plug on the connector cable for APF27dev.
Configure the board for JTAG
If the APF27 board is equipped with FPGA, the FPGA chip MUST be powered before using JTAG. Indeed, at system power-up, FPGA is low powered by cutting down the VCCAUX and VCCINT supplies until some data is loaded to FPGA. The simplest way to activate the FPGA chip is to enable the U-Boot firmware_autoload feature. Under U-Boot, set the environment variable firmware_autoload to 1 and save the environment variables to enable the FPGA on reset:
Warning: Following instructions require that you wrote a firmware in dedicated FLASH partition BEFORE. Otherwise you may prevent your system from booting next time you boot !! |
BIOS> setenv firmware_autoload 1 BIOS> saveenv Saving Environment to NAND... Erasing Nand... Erasing at 0xe0000 -- 100% complete. Writing to Nand... done BIOS> reset ...
Install and configure OpenOCD to work with an Amontec JTAGkey
Yet to be done. First it requires 2 libraries libusb and libftdi (libftd2xxx from ftdi). Download and install the latest libftdi: http://www.intra2net.com/en/developer/libftdi/download.php
>./configure >make >sudo make install
then openocd up to the release 0.3.1 : http://developer.berlios.de/projects/openocd
Note: The new version 0.4.0 of openocd does not support the configuration file provided hereafter. help is welcome to fix this issue |
> ./bootstrap ... >./configure --enable-ft2232_libftdi ... >make ... >sudo make install ...
Basic tests show that cable works as expected. You can use the following configuration file with jtagkey and openocd.
Note: If you own a board without fpga, please remove the lines declaring the fpga in ftag chain :
jtag newtap xc3s200a.fpga fpga... .... -expected-id 0x2218093 |
telnet_port 4444
gdb_port 3333
# GDB can also flash my flash!
gdb_memory_map enable
gdb_flash_program enable
gdb_breakpoint_override hard
interface ft2232
ft2232_device_desc "Amontec JTAGkey"
ft2232_layout jtagkey
ft2232_vid_pid 0x0403 0xcff8
jtag_khz 6000
# The APF27 board has a IMX27 chip and one fpga spartan3 200k
#source [find board/apf27.cfg]
#source [find target/imx27.cfg]
reset_config trst_and_srst
set _CHIPNAME imx27
set _ENDIAN little
# The bs tap
set _BSTAPID 0x1b900f0f
jtag newtap $_CHIPNAME bs \
-irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_BSTAPID
# The CPU tap
set _CPUTAPID 0x07926121
jtag newtap $_CHIPNAME cpu \
-irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID
set _TARGETNAME [format "%s.cpu" $_CHIPNAME]
target create $_TARGETNAME arm926ejs \
-endian $_ENDIAN -chain-position $_TARGETNAME -variant arm926ejs
$_TARGETNAME configure \
-work-area-virt 0xffff4c00 -work-area-phys 0xffff4c00 \
-work-area-size 0x8000 -work-area-backup 1
arm7_9 dcc_downloads enable
#endof target/imx27.cfg
jtag newtap xc3s200a.fpga fpga \
-irlen 6 \
-irmask 0x3f \
-ircapture 0x35 \
-expected-id 0x2218093
#NOTE: for spartan3A 400k write : -ircapture 0x9
$_TARGETNAME configure -event reset-init { apf27_init }
proc apf27_init { } {
# This setup puts RAM at 0xA0000000
# reset the board correctly
#reset run
#reset halt
# reset keeping fpga alive
soft_reset_halt
halt
mww 0x10000000 0x20040304
mww 0x10020000 0x00000000
mww 0x10000004 0xDFFBFCFB
mww 0x10020004 0xFFFFFFFF
sleep 100
# ========================================
# Configure DDR on CSD0 -- initial reset
# ========================================
mww 0x10027818 0x0000080F
mww 0xD8001010 0x0000000C
# ========================================
# Configure DDR on CSD0 -- wait 5000 cycle
# ========================================
mww 0x10027828 0x55555555
mww 0x10027830 0x55555555
mww 0x10027834 0x55555555
mww 0x10027838 0x00005005
mww 0x1002783C 0x15555555
mww 0xD8001004 0x00695728
mww 0xD8001000 0x92100000
mww 0xA0000F00 0x0
mww 0xD8001000 0xA2100000
mww 0xA0000F00 0x0
mww 0xA0000F00 0x0
mww 0xA0000F00 0x0
mww 0xA0000F00 0x0
mww 0xD8001000 0xA2100000
mww 0xA0000F00 0x0
mww 0xA0000F00 0x0
mww 0xA0000F00 0x0
mww 0xA0000F00 0x0
mww 0xD8001000 0xB2100000
mwb 0xA0000033 0xDA
mwb 0xA2000000 0x00
mww 0xD8001000 0x82126080
}
launch openocd with administrator right and with this config file and test the connection from a telnet terminal to send commands reset, soft_reset_halt, halt. Without the nSRST line wired to the board it is still possible to reset the apf27 with the reset button. ;-)
> openocd 6000 kHz dcc downloads are enabled Info : JTAG tap: imx27.bs tap/device found: 0x1b900f0f (Manufacturer: 0x787, Part: 0xb900, Version: 0x1) Info : JTAG Tap/device matched Info : JTAG tap: imx27.cpu tap/device found: 0x07926121 (Manufacturer: 0x090, Part: 0x7926, Version: 0x0) Info : JTAG Tap/device matched Info : JTAG tap: xc3s400a.fpga.fpga tap/device found: 0x02220093 (Manufacturer: 0x049, Part: 0x2220, Version: 0x0) Info : JTAG Tap/device matched Warn : no tcl port specified, using default port 6666 ...
and from another terminal:
> telnet 127.0.0.1 4444 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. Open On-Chip Debugger > reset JTAG tap: imx27.bs tap/device found: 0x1b900f0f (Manufacturer: 0x787, Part: 0xb900, Version: 0x1) JTAG Tap/device matched JTAG tap: imx27.cpu tap/device found: 0x07926121 (Manufacturer: 0x090, Part: 0x7926, Version: 0x0) JTAG Tap/device matched JTAG tap: xc3s400a.fpga.fpga tap/device found: 0x02220093 (Manufacturer: 0x049, Part: 0x2220, Version: 0x0) JTAG Tap/device matched > soft_reset_halt requesting target halt and executing a soft reset target state: halted target halted in ARM state due to debug-request, current mode: Supervisor cpsr: 0x000000d3 pc: 0x00000000 MMU: disabled, D-Cache: disabled, I-Cache: disabled > halt target state: halted target halted in ARM state due to debug-request, current mode: Supervisor cpsr: 0x200000d3 pc: 0xaff20bb8 MMU: disabled, D-Cache: disabled, I-Cache: enabled > reset init JTAG tap: imx27.bs tap/device found: 0x1b900f0f (Manufacturer: 0x787, Part: 0xb900, Version: 0x1) JTAG Tap/device matched JTAG tap: imx27.cpu tap/device found: 0x07926121 (Manufacturer: 0x090, Part: 0x7926, Version: 0x0) ...
Working with BDI2000
Firstly, check if your BDI2000 is rev C (see on the back of the probe, near the serial number). If your probe is A or B, it does not support target supply voltage less than 3.0 V. In this case, there might be a solution putting a serial resistor, see above Building a JTAG connector for APF27Dev board.
In addition, you can follow these drawings :
The BDI2000 probe comes with a firmware (bdiGDB) that make one able to connect directly GDB (GNU debugger) to the BDI2000 via ethernet. In the following example, we use a precompiled GDB from CodeSourcery. But any GDB configured for an ARM target might work.
You can use the following configuration file with BDI2000. It has been built like OpenOCD configuration file.
; bdiGDB configuration for ARMadeus APF27 board ; --------------------------------------------- ; Jonathan ILIAS-PILLET ; ; Many settings translated from OpenOCD's one, thanks to SSinyagin and Jorasse [INIT] ; to be done : memory map ;This setup puts RAM at 0xA0000000 ; reset the board correctly wm32 0x10000000 0x20040304 wm32 0x10020000 0x00000000 wm32 0x10000004 0xDFFBFCFB wm32 0x10020004 0xFFFFFFFF delay 100 ; ======================================== ; Configure DDR on CSD0 -- initial reset ; ======================================== wm32 0x10027818 0x0000080F wm32 0xD8001010 0x0000000C ; ======================================== ; Configure DDR on CSD0 -- wait 5000 cycle ; ======================================== wm32 0x10027828 0x55555555 wm32 0x10027830 0x55555555 wm32 0x10027834 0x55555555 wm32 0x10027838 0x00005005 wm32 0x1002783C 0x15555555 wm32 0xD8001004 0x00695728 wm32 0xD8001000 0x92100000 wm32 0xA0000F00 0x0 wm32 0xD8001000 0xA2100000 wm32 0xA0000F00 0x0 wm32 0xA0000F00 0x0 wm32 0xA0000F00 0x0 wm32 0xA0000F00 0x0 wm32 0xD8001000 0xB2100000 wm8 0xA0000033 0xDA wm8 0xA2000000 0x00 wm32 0xD8001000 0x82126080 [TARGET] CPUTYPE ARM926E ; processor core CLOCK 1 ; JTAG clock 1 = 16 MHz, 6 = 200KHz (last setting used only for testing) WAKEUP 200 ; millisecond to wait after a reset to let target start SCANPRED 1 6 ; JTAG chain starts with FGPA (spartan3), it has a 6 bits Instruction Register SCANSUCC 1 4 ; i.MX27 JTAG Controller, not used but present in the JTAG chain TRST OPENDRAIN ; pullup provided by iMX27 (§7.4 JTAG Controller Pin List) RESET NONE ENDIAN LITTLE ; memory model is little endian ;VECTOR CATCH 0x1f ; not used now BREAKMODE HARD ; hardware breakpoints ;BREAKMODE SOFT 0xDFFFDFFF ;SOFT or HARD, ARM / Thumb break code BDIMODE AGENT [HOST] DEBUGPORT 2001 ; TCP port to connect GDB to FORMAT ELF ; format of image files LOAD MANUAL ; load code manually after reset PROMPT APF27> [FLASH] ; to be done [REGS] FILE reg926e.def
You can also use the optionnal register file below :
;Register definition for ARM926E ;=============================== ; ; name: user defined name of the register ; type: the type of the register ; GPR general purpose register ; CP15 CP15 register ; MM memory mapped register ; DMMx direct memory mapped register with offset ; x = 1..4 ; the base is defined in the configuration file ; e.g. DMM1 0x02200000 ; addr: the number, adddress or offset of the register ; size the size of the register (8,16 or 32) ; ;name type addr size ;------------------------------------------- ; ; ; CP15 Registers ; ; Register Numbers for 926E: ; +-------+-------+-------+-------+ ; | | | | | | | | | | | | | | | | | ; +-+-----+-+-----+-------+-------+ ; |-|opc_1|-|opc_2| CRm | nbr | ; +-+-----+-+-----+-------+-------+ ; ; id CP15 0x0000 32 ;ID code cache CP15 0x0100 32 ;Cache type tcm CP15 0x0200 32 ;TCM status control CP15 0x0001 32 ;Control ttb CP15 0x0002 32 ;Translation table base dac CP15 0x0003 32 ;Domain access control dfsr CP15 0x0005 32 ;Data fault status ifsr CP15 0x0105 32 ;Inst fault status far CP15 0x0006 32 ;Fault address ; fcsr CP15 0x000d 32 ;Fast context switch PID context CP15 0x010d 32 ;Context ID ;
Now, we want to connect GDB to the BDI probe. Here are the IP addresses choosen for the example :
- 192.168.5.1 is the host, where GDB runs
- 192.168.5.2 is the BDI2000's address
GDB command and its output should looks like this :
(gdb) target remote 192.168.5.2:2001 Remote debugging using 192.168.5.2:2001 0xaff20cb4 in ?? ()
Using OpenOCD
Now we can use OpenOCD / JTAG to boot a new U-Boot image:
- Reset the target manually
- Run OpenOCD
openocd -f openocd.cfg
- Start a telnet session from another terminal
telnet localhost 4444
- Halt the CPU and configure the DDRAM controler
> soft_reset_halt ... > reset init ...
- Load the U-Boot image to RAM
> load_image /home/{mydir}/armadeus/buildroot/project_build_armv5te/apf27/u-boot-1.3.4/u-boot-nand.bin 0xA0000000 ...
- Assert a breakpoint
> bp 0xa0000010 4 hw breakpoint added at address 0xa0000010
- Run U-Boot up to the breakpoint
> resume 0xa0000000 target state: halted target halted in ARM state due to breakpoint, current mode: Supervisor cpsr: 0x600000d3 pc: 0xa0000010 MMU: disabled, D-Cache: disabled, I-Cache: disabled
OpenOCD is operational...
Debugging U-Boot with OpenOCD and GDB on APF27
The booting procedure of apf27 is as follows:
- the NAND_SPL loader reads the u-boot image from NAND flash to 0xA0000000 (nand_spl/board/armadeus/apf27/start.S)
- The SPL loader gives control to the U-boot startup (cpu/arm926ejs/start.S)
- The startup code gives control to the board-specific initialization code (lowlevel_init in board/armadeus/apf27/lowlevel_init.S)
- The startup code relocates the image to its base address (TEXT_BASE=0xAFF00000)
- The startup code gives control to start_armboot() in lib_arm/board.c
- U-boot reads the environment and does its booting job.
If you plan to debug a new U-boot image with JTAG, you have to prevent it from resetting FPGA (GPIO port F). By default, the startup code resets the FPGA ports to their initial state, and that disconnects our JTAG adapter, because FPGA chip is part of the chain.
Comment out the following lines in the patched U-boot code in buildroot/project_build_armv5te/apf27/u-boot-1.3.4:
### cpu/arm926ejs/start.S lines 185-186 /* bl coloured_LED_init bl red_LED_on */ ### board/armadeus/apf27/lowlevel_init.S lines 113-126 /* PORTF */ /* writel( DR(PORTF), CFG_DR_F_VAL) writel( OCR1(PORTF), CFG_OCR1_F_VAL) writel( OCR2(PORTF), CFG_OCR2_F_VAL) writel( ICONFA1(PORTF), CFG_ICFA1_F_VAL) writel( ICONFA2(PORTF), CFG_ICFA2_F_VAL) writel( ICONFB1(PORTF), CFG_ICFB1_F_VAL) writel( ICONFB2(PORTF), CFG_ICFB2_F_VAL) writel( ICR1(PORTF), CFG_ICR1_F_VAL) writel( ICR2(PORTF), CFG_ICR2_F_VAL) writel( IMR(PORTF), CFG_IMR_F_VAL) writel( DDIR(PORTF), CFG_DDIR_F_VAL) writel( GPR(PORTF), CFG_GPR_F_VAL) writel( PUEN(PORTF), CFG_PUEN_F_VAL) writel( GIUS(PORTF), CFG_GIUS_F_VAL) */
Compile the new U-boot image. This example disables optimization and stores the build commands into a logfile. From Armadeus BSP root folder,
make u-boot-clean && (make OPTFLAGS=-O0 | tee loglog) && cp -v buildroot/binaries/apf27/apf27-u-boot.bin /tftpboot/
Reset the board and press any key to get U-Boot prompt in the serial console.
Launch OpenOCD (we assume the JTAG adapter is already connected). It should report finding of 3 devices:
openocd -f apf27-openocd.cfg
Figure out which address to use for the first breakpoint. The build process has created the file u-boot.map which lists all the addresses of all global symbols. In this example, the address of start_armboot() is 0xaff01630:
[root@lab0 u-boot-1.3.4]# grep start_armboot u-boot.map lib_arm/libarm.a(board.o) cpu/arm926ejs/start.o (start_armboot) 0x00000000aff01630 start_armboot
Telnet to the OpenOCD console and install the breakpoint at the address of interest. It is important to issue "halt" and "resume":
[root@lab0 armadeus]# telnet localhost 4444 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Open On-Chip Debugger > halt target state: halted target halted in ARM state due to debug-request, current mode: Supervisor cpsr: 0x000000d3 pc: 0xaff20c4c MMU: disabled, D-Cache: disabled, I-Cache: enabled > bp 0xaff01630 4 hw breakpoint added at address 0xaff01630 > resume
Now the original u-boot image continues to function. Load our test image into the memory and launch it:
BIOS> setenv ipaddr 192.168.1.5; setenv serverip 192.168.1.40; run download_uboot; go ${loadaddr} FEC ETHERNET: Link is up - 100/Full TFTP from server 192.168.0.2; our IP address is 192.168.0.10 Filename 'apf27-u-boot.bin'. Load address: 0xa0000000 Loading: ########################### done Bytes transferred = 392232 (5fc28 hex) ## Starting application at 0xA0000000 ...
Here our breakpoint should fire, and the following should be seen in OpenOCD telnet session:
target state: halted target halted in ARM state due to breakpoint, current mode: Supervisor cpsr: 0x200000d3 pc: 0xaff01630 MMU: disabled, D-Cache: disabled, I-Cache: enabled
Remove the breakpoint. Note that there is a very limited number of hardware breakpoints (3?) and you can't set up too many of them.
rbp 0xaff01630
Now we can launch GDB or its graphical interface DDD and connect it to our paused bootloader:
ddd --debugger buildroot/build_armv5te/staging_dir/usr/bin/arm-linux-gdb
In GDB command window, load the symbol table and connect to OpenOCD:
(gdb) add-symbol-file u-boot 0xaff00000 add symbol table from file "u-boot" at .text_addr = 0xaff00000 (gdb) target remote localhost:3333 start_armboot () at board.c:304 /home/armadeus-be/buildroot/project_build_armv5te/apf27/u-boot-1.3.4/lib_arm/board.c:304:8383:beg:0xaff01630
The DDD code display window should show the start_armboot() entry point. Now you can follow with the debugging as usual.
Hint: in order to get back to start_armboot(), you don't have to reset the board. Disconnect GDB from OpenOCD, then in OpenOCD telnet window, set the program counter back to the start address of start_armboot(), and then re-attach GDB.
Debugging the Kernel with OpenOCD and GDB on APF28/APF6
Note: Openocd version 0.8.0 (default Debian version (apt-get install openocd)) and Linux Kernel 3.16 are used here. |
The APF28Dev/APF6Dev has a standard JTAG connector so just connect your JTAG probe on it.
File:Apf6dev jtag connector.jpg
Compile the kernel with debug symbols. To do so:
$ make linux-menuconfig
Kernel hacking --> Compile-time checks and compiler options --> [*] Compile the kernel with debug info.
Now create a new file apf28-openocd.cfg with the following content:
source [find interface/ftdi/jtagkey.cfg] source [find target/imx28.cfg] source [find mem_helper.tcl] gdb_memory_map enable gdb_flash_program enable adapter_khz 100 reset_config trst_and_srst separate trst_push_pull srst_open_drain
Of course you have to adapt the first line depending on the JTAG probe you are using. Have a look in /usr/share/openocd/scripts/interface/ on your computer, a config file for you probe may already exists.
Power the board.
On a terminal on your host computer, start openocd:
# openocd -d2 -f apf28-openocfd.cfg Open On-Chip Debugger 0.9.0-dev-00161-g9c47dc9 (2014-10-02-16:23) Licensed under GNU GPL v2 For bug reports, read http://openocd.sourceforge.net/doc/doxygen/bugs.html debug_level: 2 trst_and_srst separate srst_gates_jtag trst_push_pull srst_open_drain connect_deassert_srst adapter_nsrst_delay: 100 Error: session's transport is not selected. Info : session transport was not selected, defaulting to JTAG jtag_ntrst_delay: 100 dcc downloads are enabled adapter speed: 100 kHz trst_and_srst separate srst_gates_jtag trst_push_pull srst_open_drain connect_deassert_srst Info : clock speed 100 kHz Info : JTAG tap: imx28.cpu tap/device found: 0x079264f3 (mfg: 0x279, part: 0x7926, ver: 0x0) Info : Embedded ICE version 6 Info : imx28.cpu: hardware has 2 breakpoint/watchpoint units
On another termnial on your host computer, launch gdb:
~/development/armadeus-git-apf28 $ ./buildroot/output/host/usr/bin/arm-linux-gdb buildroot/output/build/linux-3.16/vmlinux GNU gdb (GDB) 7.5.1 Copyright (C) 2012 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-unknown-linux-gnu --target=arm-buildroot-linux-uclibcgnueabi". For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>... Reading symbols from /home/sszy/development/armadeus-git-apf28/buildroot/output/build/linux-3.16/vmlinux...done. (gdb)
Connect gdb to openocd:
(gdb) target remote :3333 Remote debugging using :3333 __vectors_start () at arch/arm/kernel/entry-armv.S:1138 1138 W(b) vector_rst
Now let's add a breakpoint every time we read the wakealarm of the RTC present on the APF28. "rtc_read_alarm" is the function called everytime you read the file /sys/class/rtc/rtc0/wakealarm. First whe have to put the board in halt mode and the add the breakpoint:
(gdb) monitor halt target state: halted target halted in ARM state due to debug-request, current mode: Supervisor cpsr: 0x600000d3 pc: 0xc0013024 MMU: enabled, D-Cache: enabled, I-Cache: disabled (gdb) break rtc_read_alarm Breakpoint 1 at 0xc02f9990: file drivers/rtc/interface.c, line 317. (gdb) c Continuing.
In another terminal, connect on your board via the debug interface. Log in and show the alarm date of the RTC:
Welcome to Armadeus development platform ! apf28 login: root # cat /sys/class/rtc/rtc0/wakealarm
In gdb you should see:
Breakpoint 1, rtc_read_alarm (rtc=0xc752b400, alarm=0xc6ee7ea8) at drivers/rtc/interface.c:317 317 {
To make a move of one step:
(gdb) step 320 err = mutex_lock_interruptible(&rtc->ops_lock);
You can see more lines of codes:
(gdb) list 315 316 int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) 317 { 318 int err; 319 320 err = mutex_lock_interruptible(&rtc->ops_lock); 321 if (err) 322 return err; 323 if (rtc->ops == NULL) 324 err = -ENODEV;
To resume:
(gdb) continue Continuing.
Here, you can stop the kernel any time by hitting ctrl + C
Continuing. ^C Program received signal SIGINT, Interrupt. cpu_arm926_do_idle () at arch/arm/mm/proc-arm926.S:112 112 mcr p15, 0, r1, c1, c0, 0 @ Restore ICache enable (gdb)
To resume and still have the gdb prompt:
(gdb) monitor resume (gdb)
Troubleshooting
- TRST does not stop the CPU
- Most probably the FPGA chip went offline during the U-Boot initialization and didn't come online.
- FPGA chip is not visible when OpenOCD detects the TAPs.
- FPGA chip is in low power mode at startup. Load some data in the FPGA to enable it in JTAG chain.
- In Bootstrap mode FPGA and CPU are not accessible.
- Yes, be sure to remove the bootstrap jumper to be able to use JTAG. There could be a small hardware modification to fix it but this change would disable the low power features.