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.

Evolution of carrier 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. 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.

Programming Board ID and Board version

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:

OTP bits
Bits 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.

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.

Programming the OTP bits is an irreversible operation.

The U-Boot command board_version allows you to read and program the carrier board version:

{pu}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 U-Boot command board_id allows you to read and program the carrier board ID:

{pu}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
The carrier board version and/or ID number must be given in DECIMAL.

Carrier board version and ID in U-Boot

Digi programs the board version and board ID 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-SBP-WMX-JN58

136

CC-SBP-WMX-JN7A

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

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

On stand-alone SOMs, Digi does not program these parameters and the U-Boot banner displays "Undefined board version" and "Undefined board ID" warning messages.

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 board_id and board_version variables in scripts to perform different actions.

Boot script

Find an example on Digi Embedded Yocto U-Boot boot script in meta-digi layer.

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 non-volatile media.

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:

{pt}cat /proc/device-tree/digi,carrierboard,version
{pt}cat /proc/device-tree/digi,carrierboard,id

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