In the ideal world, everything should “just work”. In reality, porting to new boards is far from that. This page should help give direction in such situations.
First thing to do is check the Hardware Design Checklist for the Blackfin® Processors.
Here we'll explain how things go from power on to command line. The very early startup sequence may differ slightly depending on whether you're booting an LDR, booting in bypass mode (parallel flash), or simply executing a binary via the U-Boot
Generally speaking, the files in question (in order) are:
One thing to keep in mind is that the Blackfin can make PC-relative function calls. That means you can make function calls at any time without having yet relocated into the final place in memory. The Blackfin startup process takes advantage of this feature many times.
Some common conventions used by U-Boot:
However, due to the way the Blackfin processor boots (LDRs), the notion of first executing in flash for a while, then relocating, then executing in ram does not really apply to the Blackfin port. All code is relocated from flash to external memory either by the on-chip Boot ROM or by the initial start function (in bypass mode).
Since the LDR format has the ability to execute small pieces of code (init blocks), as well as load chunks of code into specific memory addresses, the startup sequence process is streamlined nicely. For a general overview of the LDR process, please see Booting Overview.
Here we will start at the ELF entry point of U-Boot which is cpu/blackfin/start.S:_start(). When booting in bypass mode (parallel flash), or using the U-Boot
go command, this is the first thing executed.
All of these options are placed into your board configuration file. They require a CONFIG_ prefix to be added (it has been omitted here for readability).
When an unhandled exception or interrupt occurs, the state of the processor will be dumped to the console as well as the hardware trace buffer. You can use this information to easily locate the code that triggered the exception.
For more in-depth information for how to use the hardware trace effectively as well as some examples, see the Debugging Applications document.
This option adds little overhead in terms of code size (1 kB) and adds no runtime overhead as it is only executed when an unhandled exception occurs -- which should never happen in at runtime.
The normal dump output will only include undecoded addresses. You need to translate them by hand to the actual symbols by comparing them to the objdump output of the U-Boot ELF. This can get tedious very quickly while doing development, so this option will embed the symbol table in the U-Boot binary. When a dump occurs, the addresses will be translated automatically so the output will include both the address and the associated symbol.
This option adds quite a bit of overhead in terms of code size (11 kB) but adds no runtime overhead as it is only executed by the dump code mentioned above.
This will turn on serial output as early as possible (almost at power on) so that status messages will be constantly written to the UART console. Additional status messages will also be enabled at significant steps in the booting process.
The actual early implementation details can be found in the cpu/blackfin/serial.h and cpu/blackfin/serial.c files.
This option adds little overhead in terms of code size (2 kB) but adds runtime overhead and output that is really only suitable for debugging.
If you have code that may be accessing initialized data (or NULL pointers), then you can catch them. This will cover the start of memory (first 1kB) with two CPLB's. That way, any memory access to that region (data or instruction) will cause an exception. Any unhandled exceptions will cause a processor dump (see the DEBUG_DUMP options).
Keep in mind that any valid accesses will also be flagged, so this should only be enabled during development. You will be unable to use standard U-Boot commands such as memory display, copy, fill, etc… on the protected memory region.
This option adds little overhead (~70 bytes), but prevents the start of memory from being used.
This option is pretty straight forward. Upon a crash that would automatically reset the board, the board will instead hang and constantly execute the emuexcpt instruction. If a JTAG ICE is hooked up, it will automatically be triggered.
While not strictly a debug option, it can be quite useful while debugging remotely. This will enable the on-chip Blackfin hardware watchdog right after power on, and then common pieces of U-Boot will routinely poke it. If some piece of code gets hung up, the watchdog will reset the processor.
If you're booting an LDR image, you should use a “largish” timeout value here as the processor will not be able to poke the watchdog until the LDR has finished completely loading. When booting over the UART or slow SPI devices, it can take a few seconds before U-Boot can take over. The default timeout is set to 20 seconds.
Once U-Boot has started executing (before initialization/relocation), the watchdog will be programmed with a 5 second timeout. If your initialization process can take a while, increase this timeout as needed.
The most common problem people hit is external memory setup. Either the hardware is not solid and so cannot run at all or at the max theoretical frequency, or the timings are wrong for the specified SCLK and memory part.
This is often observed when enabling early serial debug and then only seeing a string of letters that end in
Rather than figure out the timings yourself, read the sdram page (and in particular, read the spreadsheet at the bottom).
If things still aren't working, slow down the timings from whatever the memory datasheet says. Once you have a known working configuration, you can try speeding things back up until they fail, and then reviewing the hardware signals to fix any problems there.
It might also be helpful to connect a JTAG device and examine external memory to make sure the contents match exactly the u-boot binary that should be there. Failing memory devices/timings will show random bit errors.
Sometimes it is useful to load U-Boot directly up into external memory and bypass the flash programming process. Here are a few notes to show you how with GDB and a JTAG connection. By themselves, these commands will not work. You have to connect to a remote jtag target first, so see the gdbproxy if you need more information.
First, since GDB will load things directly into external memory, we need to make sure external memory has been set up properly first. Normally this is handled by the Boot ROM calling our initcode, but since we are bypassing the Boot ROM, we need to load it by hand.
Start with a simple piece of code like so (call it
#include <asm/blackfin.h> .global __start __start: sp.l = LO(L1_SRAM_SCRATCH_END - 20); sp.h = HI(L1_SRAM_SCRATCH_END - 20); call _initcode; 1: emuexcpt; jump 1b; .size __start, .-__start
Then just link it against the initcode to produce a standalone ELF like so (make sure to replace the -mcpu argument with the appropriate value for your board):
$ bfin-elf-gcc -nostartfiles init.S arch/blackfin/cpu/initcode.o -o init.elf -Iinclude -D__ASSEMBLY__ -mcpu=bf547
Now, armed with these two ELF's (
u-boot), we can get things running with GDB.
The important commands we run are:
set remotetimeout 300- do not time out when working with slow JTAG devices
load init.elf- load the initcode into on-chip memory …
continue- … and execute it -- the
emuexcptinstruction we used earlier will automatically signal the JTAG when it is done
symbol-file u-boot- you may need this when call memset fails …
load u-boot- load u-boot into the right place …
call memset(&_bss_vma, 0, &_bss_len)- clear the BSS since GDB will not do it for us …
continue- … and start executing U-Boot
Here is a sample run. Note that the addresses and sizes may be significantly different from your setup -- that is perfectly normal!
If you're using this procedure repeatedly, enter this sequence in .gdbinit (working directory)
$ bfin-elf-gdb ./u-boot (gdb) set remotetimeout 300 ... connect to your jtag device ... (gdb) load init.elf Loading section .text, size 0x32c lma 0xffa00000 Start address 0xffa0031c, load size 812 Transfer rate: 1676 bits/sec, 812 bytes/write. (gdb) c Continuing. Program received signal SIGTRAP, Trace/breakpoint trap. 0xffa00328 in ?? () (gdb) load u-boot Loading section .text, size 0xa778 lma 0xfeb00000 Loading section .rodata, size 0x31e4 lma 0xfeb0a778 Loading section .data, size 0x2300 lma 0xfeb0d95c Loading section .u_boot_cmd, size 0x280 lma 0xfeb0fc5c Loading section .text_l1, size 0x40 lma 0xfeb0fedc Start address 0xfeb00000, load size 65308 Transfer rate: 7829 bits/sec, 9329 bytes/write. (gdb) call memset(&_bss_vma, 0, &_bss_len) (note for BF609 board you may skip this) warning: Unable to restore previously selected frame. $6 = 0xfeb0ff1c Current language: auto; currently asm (gdb) c Continuing.