OSD335x EEPROM During Boot

Published On: June, 13, 2018 By: Erik Welsh | Updated: January 9, 2020 by Cathleen Wicks

OSD335x System in Package based on AM335xWhen creating a new embedded Linux design, getting a printed circuit board (PCB) to boot for the first time can have many unique challenges. These challenges can be hardware related: incorrect connections, improper voltages, bad component values, etc. or software related: incorrect device tree, improper drivers, bad configuration values etc. One common challenge: how to properly load and configure software drivers during boot.  It is important for the software running on the new design to recognize the unique set of peripherals and components used on the PCB so that the drivers can be properly loaded and configured. This can be accomplished in many different ways: pulling GPIO pins, programming hardware fuses, storing values in non-volatile memory, etc. This is an area where having non-volatile storage, like EEPROM, either inside a System-in-Package, as in the OSD335x-SM, or on the board can help. The Linux images from BeagleBoard.org used for the OSD335x Family of devices, identify designs by a unique code, a board ID, that is stored within an EEPROM attached to the I2C0 bus. This board ID is then used within U-Boot to properly configure the system.

This article will discuss: how the board ID is used in U-Boot (Section 3); how to modify U-Boot to ignore the board ID (Section 4); and how to program the board ID in an EEPROM either before boot (Section 6) or within U-Boot (Section 5). Your preferred method to program the board ID, depends on the hardware in your system. For example, if you can boot from a microSD card, then modifying U-Boot to program the board ID (either Section 4.2 or Section 5) might be your preferred method. Similarly, if you have an external I2C programmer, you would prefer the programming method outlined in Section 6.1. If you would like to program the EEPROM over USB from a host PC (Section 6.2), software has been provided in the associated zip file and can also be found in Sections 8 and 9.

Get updates to this application note and all of our documentation

"*" indicates required fields

Name*
Hidden
Hidden
Hidden
This field is for validation purposes and should be left unchanged.

Table of Contents

1.Introduction
2.Revision History
3.Understanding the Board ID
4.Modifying U-Boot to Ignore the Board ID
4.1Hard-Coding the Board ID
4.2Recognizing a “Blank” Board ID
5.Programming the Board ID Within U-Boot
6.Programming the Board ID Outside of U-Boot
6.1Using an External I2C Programmer
6.2Over USB From a Host PC
6.2.1Installing the Tools
6.2.2Compiling the Binary
6.2.3Programming the Device
7.References
8.Appendix A: hsi2cEeprom.c
9.Appendix B: hsi2cEeprom.lds

A PDF version of this App Note can be found here.

 

The code files associated with this App Note can be found here.

2      Revision History

 
Revision NumberRevision DateChangesAuthor
16/12/2018  Initial Release  E. Welsh
28/12/2019Added caveats for Windows compilation under section 6.2.2E. Basu
Notice
The information provided within this document is for informational use only. Octavo Systems provides no guarantees or warranty to the information contained.

3       Understanding the Board ID

A board ID can be used for many different functions:

  • Distinguishing between different hardware designs
  • Allowing inventory management and board tracking, such as differentiating between manufacturers
  • Identifying and tracking failures for yield analysis
  • Compatibility checking for software
  • Encoding board revisions for debug

During boot, it is especially important to distinguish between different hardware designs so that software drivers can be properly configured and loaded. As part of the Linux boot process for the OSD335x Family of devices, U-Boot uses the board ID to determine the printed circuit board (board) on which it is running. This makes U-Boot more flexible and allows a single U-Boot image to be used for many different development platforms. You can see that there are many functions defined in the U-Boot file “./board/ti/am335x/board.h” that are used to control what functions are performed during the boot process (you can find the files by viewing the U-Boot source code, see reference section on page 19). For example, the following function is used to determine if the board is the Beagleboard.org® PocketBeagle®:

This function uses a common board detect infrastructure defined in “./board/ti/common/board_detect.c” and “./board/ti/common/board_detect.h” to determine the board. The board detect infrastructure in turn relies on a specific data structure, a ti_am_eeprom struct. This structure is found at the beginning of an EEPROM on an I2C bus (I2C0 in the case of the AM335x devices):

In the definition above, the header field is a “magic number”, i.e. a constant, TI_EEPROM_HEADER_MAGIC, with a value of 0xEE3355AA. This structure can be generically referred to as a “board ID” even though it has many different pieces of information. If you read the contents of an EEPROM from the Octavo Systems development board OSD3358-SM-RED, you can see that it follows the above data structure format:

Unfortunately, the reliance on the board ID during U-Boot can cause problems when first booting a board after manufacturing. By default, all EEPROMs are initially unprogrammed (i.e. all bytes have a value of 0xFF) when placed on a board. Therefore, when U-Boot first comes up and reads the unprogrammed board ID, it will read a value that does not match any board causing the software to hang because U-Boot is unable to know how to configure any peripheral to continue the boot. Unfortunately, the software hang occurs before the U-Boot console is active which can be mistaken for hardware bring-up problems (i.e. power is applied to the board, but nothing happens).

To mitigate this issue, you can either modify U-Boot to ignore the board ID information within the EEPROM (i.e. hard code the board ID), or you can program the EEPROM to have the correct board ID information for the given system.

4       Modifying U-Boot to Ignore the Board ID

One way to overcome an unprogrammed EEPROM is to modify U-Boot itself so that either the board ID is ignored by U-Boot or that the value of an unprogrammed EEPROM is recognized as a “blank” board. While modifying U-Boot can be a good short-term solution to work around this condition, it is not necessarily a good long-term solution to have U-Boot either ignore the board ID or for the board to be recognized as “blank”. Doing this in a production software image can be problematic in the case that revisions of the system have components that must be handled differently during boot. It also limits the reusability of the production software image across multiple products. Therefore, it is recommended to only ignore the board ID during the prototyping phase of a design and to program the EEPROM with a valid board ID during production (See Section 5).

To modify U-Boot, you first must be familiar with the process needed to build U-Boot. You can find instructions on how to do this at https://eewiki.net/display/linuxonarm/BeagleBone+Black Once you are familiar with the process, there are two methods you can follow to update U-Boot to bypass the board ID checks.

4.1       Hard-Coding the Board ID

In this first method, you can manually modify U-Boot to hard code a function within “./board/ti/am335x/board.h” so that the board has a fixed identity (i.e. the board ID is “hard coded”). For example, to make U-Boot always identify the board as “BeagleBone® Black”, you will need to make the following modification:

By returning “1” (i.e. true), this function will make U-Boot believe that the board is BeagleBone® Black and follow the boot process for BeagleBone® Black. If this works for your system (i.e. you have similar components to the BeagleBone® Black for booting, like an eMMC on MMC1 and an SD card on MMC0), then you can use this to bypass the board ID check.

4.2    Recognizing a “Blank” Board ID

Another method to ignore the board ID, is to update U-Boot to recognize the unprogrammed EEPROM value as “blank”. To do this, a patch has been created that can help with this process. As part of the U-Boot build process there are two patches that must be downloaded and applied to the U-Boot code base:

In addition to these patches, another patch can be downloaded that will configure U-Boot to recognize the unprogrammed EEPROM value as a “blank” board and potentially program the EEPROM with a board ID. You can find this patch at:

https://github.com/RobertCNelson/Bootloader-Builder/raw/master/patches/v2018.03-rc1/0002-NFM-Production-eeprom-assume-device-is-BeagleBone-Bl.patch

Caveat
The version of U-Boot and the patches listed above may not have be the same in the future. The correct versions and names should be listed in the instructions to build U-Boot.

If you look at the patch, you can see how the files in U-Boot will be modified to ignore the board ID by recognizing the unprogrammed EEPROM as a “blank” (i.e. “A335BLNK”) board and then potentially program a board ID value into the EEPROM. If you look at lines 153 to 167 of the patch:

You can see that if the board is “blank” (i.e. “A335BLNK”), then the boot process will check to see if the file “/boot/.eeprom.txt” exists in the root file system of the boot image. If it does, then it will automatically run the eeprom_program command, defined in 0001-am335x_evm-uEnv.txt-bootz-n-fixes.patch, utilizing the variables set in the “/boot/.eeprom.txt” file. If you look at the eeprom_program command (lines 1607 to 1617 of 0001-am335x_evm-uEnv.txt-bootz-n-fixes.patch):

You can see that depending on the value of the variable board_eeprom_header, the appropriate board ID value will be programmed into the EEPROM. As of this writing, the acceptable values for board_eeprom_header are:

  • board_eeprom_header=bbb_blank
  • board_eeprom_header=bbbl_blank
  • board_eeprom_header=bbbw_blank
  • board_eeprom_header=os00_blank
  • board_eeprom_header=beaglelogic_blank

If you need to add in a custom board ID value to be programmed into the EEPROM, it is straight forward to extend the code from the patches (i.e. the eeprom_program command and the EEPROM_PROGRAMMING #define). In this way, you can use the updated U-Boot image to program all of your systems so that they can have a valid board ID.

5    Programming a Board ID Within U-Boot

If you used the “hard-coding method” or did not use the automated EEPROM programming functions of the “blank method” in Section 4, you can still program the board ID manually in U-Boot. Once you have been able to boot to the U-Boot console (i.e. you have bypassed the board ID check), it is straight forward to program values in the EEPROM corresponding to the board ID structure. From the U-Boot prompt, you only need to use the i2c command to program the EEPROM with the appropriate value. The commands below can be used to program the board ID for the OSD3358-SM-RED board.

 

Caveat
The version field of early revisions of the OSD3358-SM-RED had a value of “BBNR” (i.e. 42 42 4e 52)

Each of the values passed to the I2C write command (e.g. 42 or 4e) is a hexadecimal ASCII value (https://www.asciitable.com/). Once the name and version fields of the EEPROM data structure are written, you can check that the programming was successful using an I2C read command:

At this point, the board has been successfully programmed so that it can now boot a default Linux image from BeagleBoard.org®. However, if you would also like to add a serial number to the EEPROM, you may do so in the next twelve (12) bytes (above example has a serial number of: 000000000000).

6    Programming the Board ID Outside of U-Boot

If there is no removable media, like an microSD card, in a system, it can be difficult to modify and load U-Boot to program an EEPROM. However, it is possible to program the board ID directly without modifying U-Boot by either using an external I2C programmer or over USB from a host PC.

6.1    Using an External I2C Programmer

To program the board ID using an external I2C programmer, there are two requirements:

  1. The I2C0 pins must be accessible (i.e. the pins must be brought out to a header or test points) so that they can be connected to an external I2C programmer
  2. The AM335x within the OSD335x family of devices should be held in reset (i.e. WARMRSTN should be held low).

Making the I2C0 pins accessible is straight forward but must be added during the hardware design phase of your system. If the I2C0 pins are not accessible, it will make using an external I2C programmer difficult to impossible.

Also, the AM335x within the OSD335x family of devices should be held in reset when using an external I2C programmer. This will guarantee that there is only one master on the I2C0 bus and that there will be no conflicts with the AM335x trying to control the bus. This requires that a reset button or header exists that can hold the WARMRSTN pin low.

6.2    Over USB From a Host PC

To program the board ID over USB from host PC, you can use a custom bare-metal program that will write values to the EEPROM. This method requires:

  • AM335x StarterWare 02.00.01.01
  • GCC cross compiler
  • CCS UniFlash v3.4.1
  • Target system to boot from USB
  • Optional: UART-to-USB adapter and Terminal Emulator (such as Putty2)

For the target system to boot from USB, the boot mode must try to use the USB peripheral to download a boot image. For example, if the SYSBOOT[4:0] pins have a value of 11000b, i.e. the boot mode selected by the SD Boot button on the OSD3358-SM-RED, then the processor will try SPI0, MMC0, USB0, and UART0, in that order, to boot. This will allow programming over USB0.

6.2.1   Installing the Tools

To install StarterWare and the GCC cross compiler, please follow the instructions from Sections 3 (Installing StarterWare for AM335x) and 4 (Installing Linaro GCC Compiler) of the Bare Metal Applications on OSD335x using U-Boot application note which can be found here. The instructions provided below assume that both StarterWare and the GCC cross compiler tools were installed on a Linux system (Ubuntu 16.04 was used in the example). However, the instructions should be similar for a Windows system as long as the GCC compiler is used along with a POSIX-compatible environment tool like Cygwin which allows running linux commands on windows.

To install the CCS UniFlash first follow the Installation Instructions from:

http://processors.wiki.ti.com/index.php/CCS_UniFlash_v3.4.1_Release_Notes

The instructions provided below assume that CCS UniFlash tool was installed on a Windows system (Window 10 was used in the example). However, the instructions should be similar for a Linux system.

Once the UniFlash tool is installed, you will need to modify the configuration files so that the tool uses more appropriate IP addresses. By default, the configuration files use the 192.168.100 subnet. However, the USB RNDIS connection on the example system was configured to use the 192.168.0 subnet. Therefore, the following configuration files need to be modified:

File uniflash_3.4/third_party/sitara/opendhcp.ini:

  • Line 22:
    • Original version:
      • 168.100.1
    • New version:
      • 168.0.1
  • Lines 117 – 119:
    • Original version:
      • DHCPRange=192.168.100.2-192.168.100.254
      • NextServer=192.168.100.1
      • Router=192.168.100.1
    • New version:
      • DHCPRange=192.168.0.2-192.168.0.254
      • NextServer=192.168.0.1
      • Router=192.168.0.1

File uniflash_3.4/third_party/sitara/opentftp.ini:

  • Line 23:
    • Original version
      • 168.100.1
    • New version
      • 168.0.1

Depending on your USB RNDIS connection configuration, you should adjust the default subnet accordingly. If you do not wish to modify the configuration files, you can always manually modify the subnet values when running the tool.

6.2.2    Compiling the Binary

Next, you will need to modify the hsi2c_eeprom example in order to create a program that will program a custom value into the EEPROM to set the board ID. As part of the installation instruction for the GCC cross compiler, you should have set the LIB_PATH environment variable. This variable must be set for the makefiles for the GCC build to work correctly.

  1. Replace the c file with the one provided (see Appendix A: hsi2cEeprom.c)
    1. Change directories to: AM335X_StarterWare_02_00_01_01/examples/beaglebone/hsi2c_eeprom
    2. Replace the contents of c with the provided code. This code uses a polling I2C method to read values from and write values to the EEPROM.
  1. Modify the c file with your appropriate board ID value
    1. On approximately line 85, there are two #define variables that tell the program the number of bytes to write the EEPROM (NUM_BYTES_TO_WRITE) as well as the values to write to the EEPROM (EEPROM_VALUE_TO_WRITE).
    2. Currently, these values are set to the OSD3358-SM-RED board ID. These values should be updated to program your board ID.
  1. Replace the hsi2c_eeprom linker command file with the one provided(See Appendix B: hsi2cEeprom.lds):
    1. Change directories to: AM335X_StarterWare_02_00_01_01/build/armv7a/gcc/am335x/beaglebone/hsi2c_eeprom
    2. Replace the contents of the linker command file, lds, with the provided code. This will place the program within the internal AM335x memory so that it can be used directly as a Secondary Program Loader (SPL) without having to initialize DDR.
  1. Build the program
    1. In the same directory as the linker command file: AM335X_StarterWare_02_00_01_01/build/armv7a/gcc/am335x/beaglebone/hsi2c_eeprom
    2. Execute the following commands:
      1. make clean
      2. make
        Caveat
        Compiling the binary on Widows (using Cygwin)
        Generally, Starterware can build output files in 2 versions: “Debug” and “Release”. From the Windows command line (this example uses Cygwin), this version of Starterware will only build the “Debug” version of the output. Therefore, the compiler will look for any necessary library files under the “Debug” folder of the library. Unfortunately, the libraries for “drivers“, “system_config” and “platform” do not have a “Debug” folder for the default StarterWare installation for Windows. To overcome this issue:
        Go to the following directories, all under your install directory; make a “Debug” directory; and manually copy the library binaries from the “Release” directory into the “Debug” directory:

        • …AM335X_StarterWare_02_00_01_01binaryarmv7agccam335xbeagleboneplatform
        • …AM335X_StarterWare_02_00_01_01binaryarmv7agccam335xdrivers
        • …AM335X_StarterWare_02_00_01_01binaryarmv7agccam335xsystem_config

        Additionally, if you receive error messages like: “cannot find -lc” or “cannot find -lgcc”, make sure library path environment variable, LIB_PATH, is set properly. You can verify if “gcc” is working properly by running the command “gcc -v” on the command line.

  2. Collect the compiled binary to program into the device
    1. Change directories to: AM335X_StarterWare_02_00_01_01/binary/armv7a/gcc/am335x/beaglebone/hsi2c_eeprom/Debug
    2. Collect the following file to be used to program the device: bin

If you need to change the value programmed into the EEPROM for the board ID, you can update the hsi2cEeprom.c file from Step 2 and then recompile the executable using Step 4.

6.2.3      Programming the Device

Now that you have the executable program, hsi2cEeprom.bin, that will program the board ID into the EEPROM, you need to use the UniFlash tool to load and run the program.

  1. Update the UniFlash file to load into the device
    1. Open folder: C:AM335x_Flashtoolimages
    2. Copy bin to this directory
    3. Change the name of the file to u-boot-spl-restore.bin

  2. Setup the UniFlash tool
    1. Open the UniFlash tool
    2. Select “New Target Configuration”
    3. Select “Sitara Flash Connections” for “Conection”
    4. Select “Sitara Flash Devices” for “Board or Device”
    5. At this point, you should see the following settings in the tool (These can be adjusted if they are not correct for your setup).
  3. Optional: View program output
    1. Connection UART-to-USB adapter to the UART0 interface of the target system
    2. Start a terminal emulator program (such as Putty)This will allow you to see the output of the program on UART0 but is optional.This will allow you to see the output of the program on UART0 but is optional.
  4. Load and execute the program
    1. Connect a USB cable from the appropriate USB interface of the target system to the host system that is running CCS UniFlash.
    2. Boot the board in the appropriate boot mode
      1. Note: In Windows, you should hear a notification that the target system has connected to the host using USB RNDIS. You should also be able to see this connection in the “Network Connections” window. By looking at this connection, you can debug any IP address issues you may have with the UniFlash IP settings.
    3. Click the “Start Flashing” button in UniFlash
    4. After a few seconds (up to a minute), you should see the target system populate a line in the “Status View”. This will always show a “Progress %” of “0%” even though the program has been loaded and executed by the target system. You can view the download of the executable with a tool such as WireShark3.
    5. If you have the optional program output enabled, then you should see the following output on the UART0 interface (with the value that you set in the program instead of the default value pictured below).
    6. Close UniFlash since the target system has been successfully programmed.
Caveat
Please ensure that the EEPROM is not write protected when you try to write the board ID value into the EEPROM. For the OSD335x-SM, this means pulling the EEPROM_WP pin low.

 

7      References for OSD335x EEPROM During Boot

For more information on software and optional tools, please refer to the following links:

  1. U-Boot https://github.com/u-boot/u-boot
  2. Putty https://www.putty.org/
  3. WireShark https://www.wireshark.org/

8      Appendix A: hsi2cEeprom.c

The code files associated with this App Note can be found here.

9      Appendix B: hsi2cEeprom.lds

The code files associated with this App Note can be found here.

Please contact us on the forums for assistance https://octavosystems.com/forums/

*****