Chapter 5 JTAG Debugging
This chapter will introduce how to use TI's official CCS development tools and XDS100V2 emulator to connect to the JTAG interface of the Longquan BB board for software debugging.
5.1 Preparation
1. Prepare hardware: a Longquan BB board, a 5V power adapter, an XDS100V2 emulator (you can also use other models of emulators, such as JLINK, XDS100V3, XDS560, Hawk, etc., but only XDS100V2 has been tested so far, and this model is recommended), and a USB to UART cable. Please short the SD card startup jumper and connect all cables (the JTAG interface on the Longquan BB board is 20PIN, and the interface of the XDS100V2 is 14PIN. Please connect them one by one according to the schematic diagram, and the remaining 6PINs do not need to be connected).
2. Prepare software: CCS5.5 (you can also use a higher version, but the author has only tested version 5.5), AM335x Startware and BBB patch. It is recommended to install both the WINDOWS version and the LINUX version. The installer comes with the XDS100V2 driver, which does not need to be installed separately. If you need to debug u-boot, please prepare the LINUX development environment yourself.
After installing under WINDOWS, the sample code is as follows:
5.2 Debugging the BBB sample code in Startware.
Open CCS and switch the CCS Workspace to the following directory: D:\program\ti\am335x\build\armv7a\cgt_ccs\am335x\beaglebone.
Taking gpioLEDBlink as an example, the project properties are set as shown in the figure below.
Figure: Project property settings
Please note that the compiler version in the above figure has been changed to V5.1.1, the connection is the emulator, which has been changed to xds100v2, and the board has been changed to beaglebone_black (cortex A). If Cortex-M is selected here, it may be used to debug the PRU. Check and correct the include path, and check and correct the lib path. Note that this project requires four libraries: system, utils, drivers, platform (import and compile these libraries first).
After building, debug as CC debug session to start debugging, with the cursor positioned on the first line of main(). As shown in the figure below:
Press F6 to run in single step, and when it reaches the position shown in the figure below, the blue LED D4 will light up.
If you run further, this light will go out.
5.3 u-boot debugging.
u-boot debugging is more complicated. Generally speaking, you should install the Linux version of CCS for debugging. However, the cross-platform CCS also supports debugging u-boot in the LINUX host with the WINDOWS version of CCS. Both methods require the use of a LINUX host to compile u-boot. You may be able to use cygwin to compile under WINDOWS, but you need to modify the makefile, which is very troublesome, so this method is not recommended.
5.3.1 LINUX boot process of Longquan BBB
AM335x Linux boot mainly includes four boot steps: ROM, SPL, U-Boot and kernel:
1. ROM code
ROMcode is the code solidified inside the chip. When the power-on timing is correct and the conditions required for chip startup such as crystal oscillator are met, AM335x will start running from ROM code.
ROMcode will first read the configuration on the sys_boot pin to determine the memory where SPL is stored, or the peripheral that can obtain SPL.
For details, please refer to Chapter 26 Initialization in the AM335x technical reference manual.
ROMcode will read/obtain SPL from the corresponding place and run SPL.
2. SPL
SPL and U-Boot are two stages of bootloader. The reason for the two stages here is that the ROM code will not configure the minimum system such as DDR and clock, so the ROM code can only load the bootloader into the on-chip SRAM. The on-chip SRAM has a great impact on the cost, so it is usually very small. For example, there is only 64K on the AM335x, which is not enough to put the entire U-Boot, so U-Boot is divided into two parts, SPL and U-Boot. The
main responsibility of SPL is to initialize the minimum system such as DDR and clock to read U-Boot and load it into DDR. Specifically, SPL is loaded from ROM code to the starting position of the on-chip SRAM, which is 0x402F0400. SPL will further configure the chip, mainly including the following aspects to complete its main responsibilities:
Configure ARM core. Mainly includes the configuration of interrupt vector table, cache, MMU, etc.
Configure the clock system, mainly PLL, etc. This is the basis for configuring each functional module.
Configure UART, timer, etc. Mainly used to output necessary debugging information or provide some clock tools.
Configure I2C and PMIC. This is mainly to configure the power management chip.
Configure DDR.
Configure the memory or peripherals where U-Boot is located.
After completing the configuration, SPL will read U-Boot and run U-Boot.
3. U-Boot
The main task of U-Boot is to correctly load the Kernel. Similar to SPL, U-Boot also needs to load the image of the next stage, but U-Boot provides more peripheral support and more debugging tools. Therefore, U-Boot also needs to configure each module. For the above SPL configuration part, except for DDR, U-Boot will also reconfigure according to needs (the reset here is mainly because U-Boot is an open source project, which needs to be compatible with some special chips, so it needs to be reloaded). In addition, U-Boot will also configure the network port, SD card, etc. according to needs.
There is a big difference between the workflow of U-Boot and SPL, that is, it will reload itself once. This will be introduced in detail when introducing U-Boot debugging later.
After completing the configuration, U-Boot will read the kernel from the corresponding memory or peripherals, pass parameters to the kernel, and run the kernel.
4. Kernel
The running of the kernel means that Linux is running, indicating the end of the boot process.
1.2 Preparation of U-Boot/SPL debugging code
1.2.1 Download U-Boot/SPL code
The U-Boot/SPL code is in a package and is compiled separately through compiling macros. Currently, there are two main channels for TI U-Boot/SPL code release, as follows:
A. Release through Git open source:
git://arago-project.org/git/projects/U-Boot-am33x.git
You can get the latest code, including the latest bug fixes.
B. Release through TI's official website EZSDK:
http://software-dl.ti.com/dsps/dsps_public_sw/am_bu/sdk/AM335xSDK/latest/index_FDS.html
EZSDK is an officially released software package, which has been fully tested and has stable performance. U-Boot/SPL is in the board-support directory. You can choose EZSDK as the basic code for development. When there is a problem, you can go to GIT to find out whether the latest code has bug fixes.
5.3.2 U-Boot/SPL compilation
In order to facilitate debugging with CCS, two points should be noted in the compilation. First, debugging information should be added, that is, to add symbol and other information; second, the compiler's performance optimization compilation option should be removed. This is mainly because the execution order of the optimized code will be adjusted relative to the C code.
In view of these two points, in U-Boot/SPL, it is necessary to modify config.mk:
A. Add debug compilation options in CFLAG and AFLAG to add debugging information:
278ALL_AFLAGS = $(AFLAGS)$(AFLAGS_$(BCURDIR)/$(@F)) $(AFLAGS_$(BCURDIR))–g
279ALL_CFLAGS = $(CFLAGS)$(CFLAGS_$(BCURDIR)/$(@F)) $(CFLAGS_$(BCURDIR))–g
B. Remove the compilation options in CFLAG, -O2 (the default in U-Boot is -O2)
61HOSTCFLAGS =-Wall-Wstrict-prototypes -fomit-frame-pointer For
the compilation process, please refer to http://processors.wiki.ti.com/index.php/AM335x_U-Boot_User_Guide
5.3.3
After the executable file is compiled, an executable file will be generated, which is what we usually call an image. The image generated here is mainly used for the two stages of AM335x Linux startup, MLO (SPL) and U-Boot.
Here, the image generated by SPL is in am335x/U-Boot-am33x/am335x/spl.
A. am335/U-Boot-am33x/MLO is responsible for the first stage of AM335x startup.
B. U-Boot-spl is an image with debugging information, which can be used to import debugging information in CCS.
C. U-Boot-spl.bin contains debugging information and is the image required for debugging.
D. U-Boot-spl.map This file stores the memory map information of spl, which can find the address of each function entry.
The image generated by U-Boot is in U-Boot-am33x/am335x, as follows:
A. U-Boot.img is responsible for the second stage of AM335x startup
. B. U-Boot contains debugging information and is in ELF format. It is the image required for debugging.
C. U-Boot.map is the file that stores the memory map information of U-Boot, where the address of each function entry can be found.
5.3.4 Import CCS code.
In CCS, Menu File ->Import… Select Makefile to import, as shown below:
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image010.jpg
In ezsdk, the specific path of Makefile corresponding to U-Boot/SPL is as follows:
/home/sitara/ti-sdk-am335x-evm-05.05.00.00/board-support/U-Boot-2011.09-psp04.06.00.08, and mine is Z:\lsbbb\uboot, where Z is the drive letter mapped to Windows through network sharing by samba. This method is recommended because CCS needs to load all source codes in relative path after importing.
As mentioned earlier, the source codes of U-Boot and SPL are in the same folder, and are distinguished by different Makefiles managing different compilation macros. What is imported here is the Makefile corresponding to the U-Boot code, and the corresponding pre-compilation options of U-Boot will be imported accordingly, because it contains all the codes. As for SPL, it will also be brought in accordingly, but the macro definitions of the code seen in CCS are a little wrong, but this does not affect debugging.
5.3.5 CCS connects AM335x.
It is mainly divided into several parts, including emulator connection, target connection and Debug configuration:
1. Emulator connection
1. CCS configuration
CCS configuration mainly includes Target configuration and connection.
A. Target configuration
Target configuration includes two parts, one is the emulator (XDS100v2), and the other is SOC (AM335x). The specific operations are as follows:
i. View -> Target Configurations
ii. Right-click and select New TargetConfiguration.
iii. Create a new target called AM3352.
iv. Select Texas Instruments XDS100v2 USB Emulator for connection.
vi. Select AM3352 in Board or Device.
vii. Click Save to save.
viii. Click Test Connection to see if it can be connected normally.
After successfully configuring the target, you will see the following interface
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image012.jpg
2. Target connection
A. Right-click and select the configured target: AM3352.ccxml in Target Configurations, and select LaunchSelectedConfiguration in the right-click menu. After the connection is successful, you can get the following figure
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image014.jpg
At this time, the JTAG connection between PC and emulator and between emulator and SOC is successful, but ARMcore is not connected yet. As can be seen from the figure, there are multiple core configuration options. Since U-Boot/SPL, Linux runs on ARM coretex-A8 core, only ARM core is concerned here.
B. In the Debug window, right-click the CortxA8 core and select Connect Target. After the connection is successful, it will be as shown below:
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image016.jpg
At this point, the Cortex-A8 core of AM335x has been successfully connected.
3. Debug configuration
The debug configuration here is to set the behavior of the emulator after connecting to the core. You can get the following interface through the menu run-debugconfiguration:
In this page configuration, what needs to be adjusted during the debugging process is Auto Run Options, which can be set as needed. After the image is loaded, the core automatically runs to the specified symbol and is stopped by the JTAG interface.
5.3.6 SPL debugging
There are two ways to debug U-Boot/SPL, mainly involving how to load the image: one is to download the image to the on-chip RAM or DDR through JTAG, then import the symbol, reset the PC pointer to the entry of the image, and debug; the other is to burn the image to the SD card or other boot memory, start the board, stop the core's PC pointer through JTAG, import the symbol, reset the PC pointer to the entry of the image, and debug.
The following will explain how to operate these two methods in specific steps:
A. Download the SPL image to AM335x.
If AM335x is started from the SD card, the SPL image has been successfully read into the on-chip RAM by the ROM code, and there is no need to load the SPL image.
If you choose to download the SPL image through CCS, select the CortxA8 core with the left mouse button, then in the CCS menu, Tools -> Load Memory, select the compiled SPL image U-Boot-spl.bin, as shown in the figure below:
Select the loading address. Since the loaded U-Boot-spl.bin is RAW data, you need to specify the load address, which is the entry address of SPL. For AM335x, the entry address of SPL is 0x402F0400, and the corresponding macro definition is CONFIG_SPL_TEXT_BASE, which is defined in include/configs/am335x_evm.h. It can also be found through the compiled map file U-Boot-spl.map, which is the address corresponding to the __start symbol.
Set the internal type of the loaded image. Since all codes are running in ARM (32bit) mode. So Type-size should also be set to 32bit. The setting interface is as follows:
Finally, click Finish, and the SPL will be loaded into the on-chip RAM. If there is an error message in the console window, you need to reload the SPL image.
B. Load symbol.
In the previous step, only the RAW image was loaded, and the symbol with debugging information required for debugging has not been loaded.
You can load symbol information through Run -> Load -> Load Symbols. The interface is as follows:
Here, U-Boot-spl with symbol information is selected.
C. Set the Cortex-A8 core to ARM state.
After the ARMcore is started, it is in Thumb (16bit) mode by default. As mentioned earlier, it needs to be switched to ARM (32bit). The specific method is to View->Registers, expand the CPSR register, and set the T bit to 0. The interface is as follows:
D. Single-step debugging of SPL.
a. From the memory map compiled by SPL, it can be seen that SPL starts executing from 0x402f0400, so the value of register PC must be set to 0x402f0400 first. You can set the value of the PC pointer in View->Registers. The interface is as follows. Change the value in the red box to 0x402f0400.
b. Click the assembly single-step button in the tool bar on the Debug window (view->debug), as shown in the figure below, and start debugging.
At this time, in the disassembly window (view->disassembly), as shown in the figure below, you can see the assembly code, and you can't see the source code in the editing window. This is because the code that starts to execute is in /arch/arm/cpu/armv7/start.s. The disassembly is the same as the assembly, so the source code is not displayed.
At the same time, you can see that the PC pointer runs to 0x402f0458. Here, only one instruction is executed in a single step. Why is such a large block of addresses skipped? In the single step operation here, the instruction address space jumps to n instructions instead of one instruction. This is because the exception interrupt vector table is stored at 0x402f0400. The default startup entry jumps to the address corresponding to the reset symbol, that is, it jumps to 0x402f0458 at 0x402f0400. The specific code (arch/arm/cpu/armv7/start.S) is as follows:
_start: b reset
reset:
bl save_boot_params
Next, you can set breakpoints in the C code for debugging. There are two points worth noting:
i. If the performance optimization option of the cross compiler is turned on during compilation, the execution sequence of the code generated by the optimized compilation is different from the C source code. At this time, when setting breakpoints, the actual position will not be very accurate. Therefore, here you can decide whether to turn off the -O2 option as needed.
ii. In CCS, when the core is stopped, CCS will find the corresponding source code and symbol according to the source code path contained in the debugging information in the image. Since U-Boot/SPL is compiled in Linux, its path is the path under Linux, so the Linux version of CCS can directly find the corresponding source code, while the Windows version of CCS cannot find it directly and needs to find the source code manually. However, after finding the source code of a file, CCS will find other files according to the relative path. In addition to this, the configuration and use of CCS for Linux and Windows are the same.
5.3.7 Debugging of U-Boot
In general, the debugging process of U-Boot is similar to that of SPL. Here are the main differences:
A. From the startup process of AM335x, it can be seen that U-Boot runs in DDR, and DDR is initialized by SPL, which also initializes related underlying functions. Therefore, before loading U-Boot, load and run SPL first.
B. This version of UBOOT uses FDT (Flat Device Tree File). The meaning of the compiled file is as follows:
So we need to import the u-boot.bin file, which contains all the information of uboot and .dtb. This is different from the debugging of uboot without device tree.
C. There will be relocation operation during the execution of UBOOT code, which is implemented in relocate_code between board_init_f and board_init_f. In this version, relocaddr = 0x8FF57000. In order to debug the two parts of code before and after relocation. When LOADsymbols, use offset to distinguish.
1. Debug the UBOOT code before relocation
(1) Load U-Boot-spl.bin
(2) Stop immediately after running U-Boot-spl.bin, as shown below
(3) Load u-boot.bin, start address: CONFIG_SYS_TEXT_BASE 0x80800000 file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image034.gif
(4) Load symbols->
After u-boot is loaded, the interface is as follows:
You can see that the starting address is 0x80800000, and you can also see the corresponding source file vectors.s
(5) Set a breakpoint
to find the C function board_init_f before relocation, and set a breakpoint, as shown below;
click Run and you will see that it stops at the breakpoint, as shown below:
(6) Single-step debugging
At this point, you can single-step execute the corresponding code debugging.
Note: This way you can debug the code before relocate_code.
2. Debugging the UBOOT code after relocation
Refer to the debugging method before relocation. The debugging of the UBOOT code after relocation is different in step (4). It is the same as the previous steps (1), (2), and (3). It is reflected in the offset when loading symbols. The offset here is relocaddr = 0x8FF57000.
As shown in the figure below:
(4) Load symbols->
After u-boot is loaded, the interface is as follows:
Compared with the debugging steps before relocation, the corresponding source code or file cannot be seen at this time. My understanding is that this is because the symbol table is loaded to 0x8FF57000 at this time, so the corresponding code (symbols) cannot be seen at 0x80800000. But it doesn’t matter. Here we are just debugging the code after relocation.
(5) Set a breakpoint
in the board_init_r function
and click Run. You will see that the code stops at the breakpoint. As shown in the figure below:
At this time, you can debug the relevant code by single-step running.
The images in the article may not display properly. I wanted to insert or correct them one by one, but it was too much trouble, so I uploaded them as attachments in PDF format. Please bear with me!
bbb_jtag.pdf
(2.82 MB, downloads: 18)
|