[sfwa]

Configuring TI C6657 SPI boot

One of the more painful parts of the FCS development has been getting the TI C6657 DSP to boot from a NOR flash device connected via SPI. Although it’s conceptually quite simple, there’s a lot of confusing and frequently just incorrect documentation out there on how to do it.

The EVMs for the C6657 and C6678 devices use a two-stage boot process, with the FPGA configuring the DSP’s bootmode pins to start an intermediate bootloader (IBL) from an I2C flash device at address 0x51. The IBL does some initialization and then determines which second-stage bootloader to run based on the DIP switches on the board.

In our design, we have both I2C and SPI flash devices, but the 256Kbit I2C device wouldn’t be able to store our whole application. Since we don’t need the flexibility of the EVM, which also supports Ethernet boot, PCI-E boot, and all kinds of other things, we decided to boot directly from the 256Mbit NOR flash connected via SPI.

There are three main tasks involved in this process: configuring the DSP bootmode pins to run the SPI code in the device’s internal ROM bootloader (RBL), creating a firmware image that can be read by the RBL, and writing that image to the flash.

The first task, configuring the bootmode pins, is a couple of documentation revisions away from being really straightforward:

The second task is what caused most of the pain. For some reason there isn’t actually a tool that will take you directly from a CCS .out file (ELF or COFF) to something that can be written to a flash device. Instead, the process goes something like this. (You may see some variations on the TI forums; I haven’t tested those but know that this one works.)

  1. Run the hex6x tool supplied with the C66x compiler/assembler/linker to convert the ELF/COFF application to a boot table image in ASCII format. The hex6x tool takes a .rmd file with a structure like the following:
    fcs.out
    --ascii
    --boot
    -e=_c_int00
    
    ROMS
    {
        SPI: org = 0x00000400, length = 0x00100000, memwidth = 32, romwidth = 32
    }
    
    Here, fcs.out is the output file name; --ascii means ASCII hex output; --boot means generate a boot table; -e=_c_int00 means the entry point is _c_int00 (which is automatically generated by the C66x compiler). The ROMS block identifies the output file structure, with one file generated per entry. The org, length, memwidth and romwidth parameters generally don’t need changing, although if your binary is > 1MiB you’ll want to increase the value of length. The output file is specified on the command line, and in our case it’s fcs.btbl.
  2. Since our program runs in little-endian mode, but the RBL always runs in big-endian mode, we need to convert the boot table such that all sections are 32-bit-aligned, using bconvert64x -le INFILE OUTFILE. This tool is available in the MCSDK distribution, but we have our own version here; it compiles on any platform with a standard C compiler.
  3. The SPI and I2C boot processes in the RBL are very similar, and involve reading individual segments of the boot table with their own checksums and lengths. Thus, there’s a tool called b2i2c which converts the boot table to a series of 128-byte chunks containing a 16-bit length, a 16-bit checksum, and 124 bytes of boot table data. Again, this is available in the MCSDK, but their version is limited to 128KiB binaries. This can be changed by updating the value of SIZE on line 161; ours is set to 2MiB. Usage is just b2i2c INFILE OUTFILE.
  4. The file now needs to be converted to “CCS” format, which is a \n-separated list of 32-bit words in hexadecimal format (e.g. 0x12345678), with a header indicating the length of the file: 1651 1 10000 1 LENGTH, where LENGTH is the number of words. This is done using b2ccs, which also has a SIZE definition which might need to be changed for large files.
  5. Here’s the tricky bit: the file is now a bootable image, but the SPI bootloader requires a configuration block to be prepended to the application’s binary image. The configuration block includes SPI mode settings (which override those set via the bootmode pins after the first block is read), PLL settings, and location information. The tool that writes this block and appends the boot table file is called romparse, but unfortunately it’s extremely buggy—it just crashed for me, but even when it works it writes the wrong output address, so you need to hand-edit the resulting files, and it doesn’t do PLL configuration correctly so all your SPI timing will be wrong. Instead of that, I used a tool called bootbuild, developed by one of the members of the TI forums. Our version is available here; it’s essentially the same approach but generates output files more consistent with what romparse theoretically should. The tool takes a configuration file; ours is below.
    section {
        boot_mode = 50
        param_index = 0
        options = 1
        core_freq_mhz = 1000
        exe_file = "fcs.ccs"
        next_dev_addr_ext = 0x0
        sw_pll_prediv = 0
        sw_pll_mult = 19
        sw_pll_postdiv = 1
        sw_pll_flags = 1
        addr_width = 24
        n_pins = 4
        csel = 2
        mode = 2
        c2t_delay = 0
        bus_freq_mhz = 10
        bus_freq_khz = 0
    }
    
    These options are the same as those we’re setting via the bootmode pins; the only change to SPI device configuration is the clock frequency (bus_freq_mhz), which we increase to 10MHz after the PLLs are configured. Output from this tool is written to i2crom.ccs.
  6. Having added the boot configuration block to the boot table (romparse and our version of bootbuild also set the boot table itself to start at address 0x400 in flash, but that’s not strictly required), we now just need to convert the “CCS” format file to binary. Run ccs2bin -swap INFILE OUTFILE, then write the resulting binary to the flash device however you see fit.

We have a makefile which automates most of the process above (just build the .btbl file in CCS and run make fcs.debug.bin), but depending on how frequently we run it, we may write a script to do everything in one go. The actual manipulation of data formats is trivial, but spreading it out over half a dozen different undocumented tools makes things seem much more complex.

The third task, writing a firmware image to the flash, can be done however you like. We run these lines through the CPLD, so we could program it directly from the CPU (running Linux), but for development we used the norwriter application in the DSP MCSDK: mcsdk_2_01_01_04/tools/writer/nor/evmc6657 for those following along at home. The process here is to compile and write the application to DSP SRAM via a JTAG adapter, then open the CCS debugger’s memory view and copy the file from your filesystem into the DDR3 address space, then hit “run” and wait until it outputs a success message on the built-in console. The instructions in that tool’s README.txt are both correct and easy to follow.

github.com/sfwa twitter.com/sfwa_uav youtube.com/user/sfwavideo