The ConnectCore 8X 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 8X SBC Express and ConnectCore 8X SBC Pro, Digi uses U-Boot’s protected environment to store the board’s version and ID.

Variable Description Flags

$board_id

Carrier board ID

write-once

$board_version

Carrier board version

write-once

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 8X SBC Express or ConnectCore 8X SBC Pro and their different versions.

To program the board ID and board version you must set these variables in U-Boot:

setenv board_id <id>
setenv board_version <version>

Variables with write-once flag are protected after being set for the first time and will not be overwritten by setenv or env default commands (unless manually forced with -f option).

They will also keep their value after updating U-Boot.

Carrier board version and ID in U-Boot

Digi programs the board version and board ID of ConnectCore 8X 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-WMX8-EXPRESS

135

CC-WMX8-KIT

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

Board: ConnectCore 8X SBC Express, version 1, ID 129

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

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,ccimx8x");
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.