Show Contents

# Carrier board version and ID

The ConnectCore 6UL is a surface mount device (SMD) module that must be assembled on user-designed carrier boards. Users often redesign carrier boards and may also offer multiple configuration options of those boards, thus reaching a wider market.

For example, your company designs a carrier board that goes to market as version 1. Later, you redesign the carrier board to add a new user button and some LEDs, and introduce a new power regulator. This becomes version 2. Your company decides to sell two different variants of version 2 in order to reach different markets. Carrier board ID=1 is fully populated. Carrier board ID=2 is the same board but with fewer components, as it does not assemble Ethernet, USB, or audio chip. Then you redesign the carrier board again to improve the layout and fix some issues with an external controller, moving some buttons and changing some GPIO lines in the process. This becomes version 3. Your company still creates two variants (ID=1, ID=2) of the board.

While certain changes to the design of the carrier board (different carrier board version) do not affect the software—for example, moving a button or a connector, some carrier board redesigns do require changes to the software—for example, enabling a GPIO that powers a new chip on the board.

Similarly, different variants of the same carrier board and version (different carrier board ID) may require changes to the software—for example, not enabling Ethernet PHY if you don't assemble one.

For these reasons, it is convenient to store both the carrier board version and carrier board ID in non-volatile media such as the OTP (One Time Programmable) bits. You can then add conditional code in the bootloader (or in the operating system) to make the same software run on different versions and variants of the carrier board.

## Location in OTP bits

For the ConnectCore 6UL SBC Express and ConnectCore 6UL SBC Pro, Digi uses Bank 4 Word 6 (GP1)—general-purpose OTP word available to OEM/customers—to store the carrier board's version and ID as follows:

Word | OCOTP_GP1
--- | ---
Bits | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
Field |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | board ID | board version

Field | Description
--- | ---
11..4 board ID | Carrier board ID number starting at 1. A zero is considered an undefined ID. IDs 128 through 255 are reserved by Digi. Users can use this field to program conditional software for different IDs of the same carrier board.
3..0 board version | Carrier board version. A zero is considered an undefined version. Users can use this field to program conditional software for different versions of the carrier board.

## Carrier board version and ID in U-Boot

### Banner

Digi programs the board version and board ID on the OTP bits of ConnectCore 6UL SOMs when assembled in Digi carrier boards:

- The board version depends on the version of the PCB.
- The board ID is assigned to each Digi product based on the SOM:

Board ID | Smart part number | Wireless | Bluetooth
--- | --- | --- | ---
129 | CC-WMX6UL-START | ✓ | ✓
135 | CC-WMX6UL-SBC | ✓ | ✓

The board version and the board ID appear in the U-Boot banner:

    Board: ConnectCore 6UL SBC, version 3, ID 135

On stand-alone SOMs, Digi does not program these fields on the OTP bits and the U-Boot banner displays warning messages:

    Board: ConnectCore 6UL SBC
       WARNING: Undefined board version!
       WARNING: Undefined board ID!

### Environment variables

U-Boot reads the carrier board version and ID from the OTP bits during startup and generates the environment variables board_id and board_version accordingly. You can use these variables in scripts to perform different actions.

#### Boot script

The boot script for Digi Embedded Yocto and Android uses the board_id variable to determine the board it is running on and select the appropriate device tree file (among several in the kernel partition) to use when booting the system. The following boot script excerpt uses board_id:

(You can find the original at https://github.com/digi-embedded/meta-digi/blob/morty/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey-2015.04/ccimx6ulsbc/boot.txt.)

    if test -n "${board_id}"; then
            setenv fdt_file zImage-imx6ul-ccimx6ulsbc-id${board_id}.dtb
    else
            #
            # Set device tree filename depending on the hardware variant
            #
            if test "${module_variant}" = "0x02" || test "${module_variant}" = "0x04"; then
                    setenv fdt_file zImage-imx6ul-ccimx6ulsbc-wb.dtb
            elif test "${module_variant}" = "0x03"; then
                    setenv fdt_file zImage-imx6ul-ccimx6ulsbc.dtb
            else
                    echo "------ Using default fdt_file: $fdt_file"
            fi
    fi

The boot script does the following:

- If the variable board_id exists, selects as device tree a file that contains that ID in its name.
- If board_id isn't defined, selects as device tree the one that matches the module variant programmed in the OTP bits of the SOM (in variable module_variant), assuming the SOM is running on the standard Digi development kit carrier board.
- If module_variant is also not defined, selects as device tree the one specified in the environment variable fdt_file.

## Programming in U-Boot

Programming the carrier board version and/or ID is optional. However, Digi's BSP in U-Boot and the Linux kernel may contain conditional code for the ConnectCore 6UL SBC Express or ConnectCore 6UL SBC Pro and their different versions.

CAUTION! Programming the OTP bits is an irreversible operation.

The command board_version enables you to read and program the carrier board version:

    => help board_version
    board_version - Carrier board version on fuse sub-system

    Usage:
    board_version read - read carrier board version from shadow registers
    board_version sense - sense carrier board version from fuses
    board_version prog [-y] <version> - program carrier board version (PERMANENT)
    board_version override <version> - override carrier board version

    NOTE: <version> parameter is in DECIMAL

The command board_id enables you to read and program the carrier board ID:

    => help board_id
    board_id - Carrier board ID on fuse sub-system

    Usage:
    board_id read - read carrier board ID from shadow registers
    board_id sense - sense carrier board ID from fuses
    board_id prog [-y] <id> - program carrier board ID (PERMANENT)
    board_id override <id> - override carrier board ID

    NOTE: <id> parameter is in DECIMAL

Note The carrier board version and/or ID number must be given in DECIMAL.

## Conditional programming based on carrier board version and/or ID

### U-Boot

Digi's U-Boot contains platform functions get_carrierboard_version()and get_carrierboard_id() which read the carrier board version and ID from the OTP bits.

You can use these values to program conditional code in U-Boot, like in this example:

    static void my_function(void)
    {
        unsigned int board_id = get_carrierboard_id();
        unsigned int board_version = get_carrierboard_version();

        if (board_id == 1) {
            if (board_version == 1) {
                /* do this */
            } else if (board_version > 1) {
                /* do that */
            }
        } else if (board_id == 2}
            /* more differences */
        }
    }

### Linux kernel

The carrier board version and ID are populated by U-Boot inside the device tree before the kernel boots. You can program conditional code by reading the board version and ID from the device tree properties, as in this example:

    struct device_node *np = of_find_compatible_node(NULL, NULL,
                             "digi,ccimx6ul");
    const char *board_version_str, *board_id_str;
    int board_version;
    int board_id;

    if (!np)
        return -EPERM;
    if (of_property_read_string(np, "digi,carrierboard,version",
                    &board_version_str);
    board_version = atoi(board_version_str);
    if (of_property_read_string(np, "digi,carrierboard,id",
                    &board_id_str);
    board_id= atoi(board_id_str);

    /* Conditional code based on carrier board version and ID */
    switch(board_id) {
    case 1:
    case 2:
        /* code for carrier boards with ID 1 and 2 */
        switch(board_version) {
        case 0:
            /* code for undefined board version */
            break;
        case 1:
            /* code for carrier board version 1 */
            break;
        }
        break;
    default:
        /* code for the rest of board IDs */
        break;
    }

From user space, you can read the carrier board version and ID from the device tree, which is exposed via the procfs:

    cat /proc/device-tree/digi,carrierboard,version
    cat /proc/device-tree/digi,carrierboard,id

You can use the value of these properties to program conditional code in scripts or applications.

© 2018 Digi International Inc. All rights reserved.
Carrier board version and ID updated on 22 January 2018 02:43:37 PM