NetBurner 3.5.7
PDF Version
SOMRT1061 Platform Reference

Introduction

This document provides the memory map and locations of reference materials for those who wish to add additional hardware to their NetBurner device.

Processor Information

The SOMRT1061 uses the NXP i.MX RT1061 microprocessor. The reference manual and datasheet provide in-depth information on the microprocessor, including register settings, bus configuration and timing information. It is located in the <nburn_install>\docs\NXP directory of your NetBurner installation.

Definitions

Definitions for the MIMXRT1061 can be found at arch/cortex-m7/cpu/MIMXRT10xx/include/MIMXRT1061.h

Datasheet and Pins

The datasheet for the SOMRT1061 module includes information on connectors, signal names, and operational parameters. It is located on the SOMRT1061 product page under Documents and Downloads.

An Excel spreadsheet of pin assignments is also available under the same Datasheet link.

Finally, NetBurner has created an interactive Pin Configurator tool which is available online as well as in your NNDK installation under <nburn_install>\docs\NetBurner\Platform\PinConfigurator

You may also find pinconstant.h to be a useful reference.

Development Board Schematic

The DEV-SOMRT1061 development board schematic is located in the <nburn_install>\docs\NetBurner\platform\Schematics directory. This schematic can be used for design ideas in your own hardware implementation for power, RS-232, RS-485, and SD Flash card implementation.

SOMRT1061 Platform General Information

The SOMRT1061 uses the NXP i.MX RT1061 microcontroller. The reference manual and datasheet provide in-depth information on the processor, including register settings, bus configuration and timing information. The reference manual is located in the <nburn_install>\docs\NXP directory of your NetBurner installation.

  • i.MX RT1061 running at 528MHz (ind temp)
  • 8MB SPI Flash (stores compressed application image)
  • 32MB PSRAM
  • 1MB onboard SRAM:
    • 128k ITCM single cycle instruction fetch memory,
    • 128K DTCM single cycle data fetch memory
    • 768k general purpose fast SRAM


The 8MB of Flash uses a Flash File System and is used for all storage purposes:

  • Sectors are 8k
  • The standard NetBurner configuration, certificate and user flash operate transparently through the file system.
  • First sector reserved for file partition table. Note: If you need direct flash access, please contact NetBurner support.
  • You can add a secondary Flash File System as demonstrated in the EFFS-STD examples. Multiple partitions are supported. Please refer to the documentation and examples, such as the EFFS-STD multiple partition (multi-part) example.
  • Application space varies by use case, but is typically 7.5MB for the compressed application. Items that can reduce the 8MB total space include: file system overhead, certificates, configuration data, secondary file system.


External Memory Bus

  • Chip selects configurable anywhere in the external bus range



SOMRT1061 EFFS-STD Flash File System

Overview

The SOMRT1061 uses an 8 MB SPI NOR flash (Winbond W25Q64JVXGIM) connected via the LPSPI3 peripheral. The flash is managed by EFFS-STD (Embedded Flash File System - Standard), which provides a structured file system with FAT-like directory and file operations.

Unlike older NetBurner platforms that use fixed compile-time memory regions (COMPCODEFLAGS) to partition flash between application firmware and file storage, the SOMRT1061 uses a dynamic partition table stored at sector 0 of the SPI flash. This partition table defines how the flash is divided, and all persistent data — including the application firmware image — is stored as files within the EFFS file system.

Key Source Files

File Purpose
arch/cortex-m7/cpu/MIMXRT10xx/include/effs_pt.h Partition table and EFFS config struct definitions
arch/cortex-m7/cpu/MIMXRT10xx/source/EffsStd.cpp Flash driver implementation and mount_std_fs()
arch/cortex-m7/cpu/MIMXRT10xx/source/nbpart.cpp Partition table operations and Hamming ECC
platform/SOMRT1061/source/hal_storage.cpp HAL storage layer (config, certs, app, user params)
platform/SOMRT1061/include/hal_platdefs.h Maximum storage size constants
nbrtos/include/file/fsf.h EFFS-STD API macros
nbrtos/include/file/fsm.h FS_SPACE struct definition

Flash Memory Layout

The 8 MB SPI flash has the following logical layout:

Address 0x00000000 +----------------------------------+
| Partition Table (512 bytes) | <- Hamming ECC protected
| - sectorLenExp, totalSectors |
| - Up to 8 PartitionEntry structs |
| - 16 Hamming checksums |
Address 0x00001000 +----------------------------------+
| EFFS Partition (default: all |
| remaining flash) |
| |
| Effs_Cfg (first sector) | <- Partition config
| FAT + Directory blocks (~64 KB) | <- EFFS metadata
| Data blocks | <- File storage
| A:/sys/files/config.xNN |
| A:/sys/files/certs.xNN |
| A:/sys/files/usrparam.xNN |
| A:/sys/files/app.xNN |
| (user application files) |
| |
Address 0x00800000 +----------------------------------+ <- 8 MB boundary
Filesystem Configuration.
Definition effs_pt.h:100
Definition effs_pt.h:59

By default, a single EFFS partition spans from sector 1 to the end of flash, and is marked as bootable. The partition table sector (sector 0) is reserved and not part of any partition.

Important**: On the SOMRT1061, the application firmware image is stored as a versioned file (A:/sys/files/app.xNN) inside the EFFS file system. There is no separate raw flash region for the application image as on older platforms.


Partition Table Architecture

The partition table is defined in effs_pt.h and occupies the first sector of SPI flash.

PartitionTable Structure

uint8_t bootExe[422]; // Reserved for boot executable
uint8_t tableLenExp; // Table length exponent (2^tableLenExp bytes)
uint8_t sectorLenExp; // Sector length exponent (e.g., 12 = 4096-byte sectors)
uint32_t totalSectors; // Total sectors in device (MSB encoding for large values)
PartitionEntry part[8]; // Up to 8 partition entries
uint8_t csums[16]; // Hamming code checksums (one per 31-byte block)
};
Definition effs_pt.h:81
PartitionEntry part[8]
Partition entries.
Definition effs_pt.h:88
uint32_t totalSectors
Total sectors available, see.
Definition effs_pt.h:87
uint8_t sectorLenExp
Sector Length, see Table Length.
Definition effs_pt.h:86
uint8_t bootExe[422]
If direct execution is ever supported...
Definition effs_pt.h:84
uint8_t tableLenExp
Table Length => 2**tableLenExp: 2**8 => 256 bytes.
Definition effs_pt.h:85
uint8_t csums[16]
Hamming code csum of 31 byte blocks comprising the Table.
Definition effs_pt.h:89

PartitionEntry Structure

uint32_t flags : 8; // PARTITION_FLAG_INUSE (0x01), PARTITION_FLAG_BOOT (0x80)
uint32_t sectorCount : 24; // Number of sectors (MSB encoding for large values)
uint32_t partitionType : 8; // PARTITION_TYPE_EFFS (0x25)
uint32_t firstSector : 24; // Starting sector (MSB encoding for large values)
};
uint32_t firstSector
Index of first sector for this partition.
Definition effs_pt.h:63
uint32_t flags
Any special flags for the partition.
Definition effs_pt.h:60
uint32_t partitionType
What type of filesystem is this partition.
Definition effs_pt.h:62
uint32_t sectorCount
How many sectors are in this partition.
Definition effs_pt.h:61

Partition types**: PARTITION_TYPE_EFFS (0x25) is the only type used by the NetBurner system. Other types (FAT12, FAT16, NTFS, Linux) are defined but reserved for future use.

MSB encoding**: When sectorCount or firstSector values exceed 2^23, the MSB is set and the value is encoded as (2^(exponent+4)) * mantissa, enabling representation of very large flash devices.

Error Protection

The partition table is protected by Hamming code checksums. Each 31-byte block of the table has an 8-bit checksum stored in the csums[] array. On read, validatePartitionTable() uses hamming_validateOrFix() to detect and correct single-bit errors. This protects against flash bit-rot and ensures the partition table remains valid over the device lifetime.

Partition Table Operations

All functions are in nbpart.cpp:

Function Purpose
getPartitionTable(pt) Read partition table from flash address 0 and validate
createPartitionTable(pt, sectorLenExp, totalSectors) Initialize an empty partition table
createPartitionEntry(pt, pte, startSector, sectorCount, type, bootable) Create a new partition entry
createPartition(pt, pte) Insert a partition entry (overlap-checked, sorted)
deletePartition(pt, partIdx) Remove a partition entry
writePartitionTable(pt) Compute checksums and write to flash
showPartitionTable(pt) Debug print of partition table contents

EFFS Configuration per Partition

Each EFFS partition stores its configuration in an Effs_Cfg struct at the first sector of the partition.

struct Effs_Cfg {
uint16_t maxblock; // Maximum number of usable blocks
uint8_t sSizeExp; // Sector size exponent (10 = 1024 bytes)
uint8_t blSizeExp; // Block size exponent (15 = 32768 bytes)
uint8_t dSizeExp; // Descriptor (FAT+directory) size exponent (15 = 32768 bytes)
uint8_t cacheSizeExp; // Write cache size exponent (10 = 1024 bytes)
uint8_t separatedir; // Separate directory from FAT (0 for NOR flash)
uint8_t csum; // Hamming code checksum
};
uint8_t dSizeExp
Max size of fat+directory+block index.
Definition effs_pt.h:106
uint8_t sSizeExp
Sector size wanted to use (less than block size.
Definition effs_pt.h:104
uint8_t csum
Hamming code csum of struct.
Definition effs_pt.h:109
uint8_t cacheSizeExp
Write cache size.
Definition effs_pt.h:107
uint8_t separatedir
If directory used separatelly from FAT (NAND)
Definition effs_pt.h:108
uint16_t maxblock
Maximum number of block can be used.
Definition effs_pt.h:103
uint8_t blSizeExp
Block size in bytes.
Definition effs_pt.h:105

Default configuration** (created by createDefaultFilesystem() in EffsStd.cpp):

Parameter Value Meaning
sSizeExp 10 1 KB sectors
blSizeExp 15 32 KB blocks (erase unit)
dSizeExp 15 32 KB for FAT + directory
cacheSizeExp 10 1 KB write cache
maxblock (calculated) partitionSize / 32KB

The maxblock value determines how many 32 KB blocks are available for file data storage within the partition. For the default single-partition configuration on 8 MB flash, this is approximately 244 blocks (after subtracting the partition table sector and EFFS metadata blocks).


File System Initialization

The EFFS file system is initialized automatically during the boot process, before UserMain() is called. Applications do not need to call any initialization functions.

Boot Sequence

HardwareInit() [hal_storage.cpp:92]
└─ ConfigFlash() Configure LPSPI3 pins and init SPIFlash
└─ mount_std_fs() [EffsStd.cpp:498]
├─ fs_init() Initialize EFFS library
├─ getPartitionTable(&AppFlash_pt) Read partition table (retry up to 5x)
│ └─ (if invalid) createDefaultPartitionTable() + writePartitionTable()
└─ For each EFFS partition with flags != 0:
├─ fs_getmem_flashdrive() Calculate RAM requirements
│ └─ (if 0) createDefaultFilesystem() and retry
├─ malloc(mem_size) Allocate RAM for FS metadata
├─ fs_mountdrive(drv, ...) Mount the partition as drive drv
│ └─ (if fails) fs_format(drv) Format and retry
└─ Create /sys/ and /sys/files/ directories (on boot partitions)
void init()
System initialization. Ideally called at the beginning of all applications, since the easiest Recover...

After mounting, hal_bootPt is set to the index of the first bootable partition, and fs_chdrive(hal_bootPt) sets it as the default drive.

Flash Driver Architecture

Each partition is backed by a set of four flash operation callbacks, registered in fs_phy_AF() (EffsStd.cpp:297):

  • ReadFlash(data, block, blockrel, datalen) — Read data from a flash block
  • WriteFlash(data, block, relsector, size, relpos) — Write data to flash (with bounds checking)
  • EraseFlash(block) — Erase a 32 KB block
  • VerifyFlash(data, block, relsector, size, relpos) — Verify written data matches

All operations translate logical block/sector addresses to physical flash addresses using:

physAddr = partitionStartAddr + (block * blockSize) + (relSector * sectorSize) + relPos

Bounds checking ensures no operation can read or write outside the partition's address range.

Since EFFS requires separate callback function pointers per drive, EffsStd.cpp generates 8 sets of wrapper functions (EraseFlash_0 through EraseFlash_7, etc.) that forward to a common implementation with the drive number as a parameter.


System File Storage (HAL Storage Layer)

The HAL storage layer (hal_storage.cpp) manages four categories of system data as versioned files in the A:/sys/files/ directory:

Storage Area File Pattern Max Size Purpose
HalStore_Config config.xNN 128 KB JSON system configuration
HalStore_Cert certs.xNN 2 MB SSL/TLS certificate store
HalStore_UserParams usrparam.xNN 16 KB Application user parameters
HalStore_App app.xNN 32 MB Firmware application image

Version Suffix

Each file has a .xNN suffix where NN is a two-digit hex sequence number (00-FF). When a new version is saved:

  1. HalStorage_FindLastVer() scans for the highest existing sequence number
  2. The new file is created with sequence number = last + 1 (wrapping at 0xFF)
  3. If insufficient free space, older versions are deleted starting from lastVer + 127 (opposite side of the circular sequence)

This versioning scheme provides safe atomic updates: if a write is interrupted (e.g., power loss), the previous version remains intact and will be loaded on the next boot.

Garbage Collection

Previous file versions are cleaned up by FlashErasePrevVersions(), which runs in the idle task (OSTaskIdle) approximately 2 seconds after boot. It keeps only the 2 most recent versions of each file type and deletes older ones.

HAL Storage API

Function Purpose
HalStorage_Save(area, pData, len, offset) Write a complete file (creates new version)
HalStorage_SavePartial(area, pData, len, offset) Write partial data at an offset
HalStorage_Read(area, pData, len, offset) Read from the latest version
HalStorage_Prepare(area, len, offset) Open file for writing (with space management)
HalStorage_Finalize(area) Close an open file handle
HalStorage_Erase(area, len, offset) Delete all versions of a file
HalStorage_GetAllocated(area) Get total usable space (free + used)
HalStorage_RemainingSpace(area) Get free space on the boot partition
HalStorage_GetMaxAllocation(area) Get per-area maximum size limit

File System Size and Statistics

Querying Free Space

Use fs_getfreespace() to get current space statistics for any mounted drive:

#include <file/fsf.h>
FS_SPACE fspace;
int rc = fs_getfreespace(driveNum, &fspace);
if (rc == FS_NOERR) {
iprintf("Total: %lu bytes\r\n", fspace.total);
iprintf("Free: %lu bytes\r\n", fspace.free);
iprintf("Used: %lu bytes\r\n", fspace.used);
iprintf("Bad: %lu bytes\r\n", fspace.bad);
}
#define fs_getfreespace(drivenum, space)
Provides information about the drive space usage.
Definition fsf.h:226

The FS_SPACE struct is defined in nbrtos/include/file/fsm.h:

typedef struct {
unsigned long total; // Total bytes available for file storage
unsigned long free; // Free bytes
unsigned long used; // Used bytes
unsigned long bad; // Bad sector bytes (unusable)
} FS_SPACE;

Storage Size Constants

Maximum storage sizes per area are defined in platform/SOMRT1061/include/hal_platdefs.h:

Constant Value Description
PLAT_STORAGE_MAX_CONFIG_SIZE 0x20000 (128 KB) Maximum config file size
PLAT_STORAGE_MAX_USERPARAMS_SIZE 0x4000 (16 KB) Maximum user params size
PLAT_STORAGE_MAX_CERTSTORE_SIZE 0x200000 (2 MB) Maximum certificate store size
PLAT_STORAGE_MAX_APP_SIZE 0x2000000 (32 MB) Maximum application image size
PLAT_STORAGE_MAX_FILESYS_SIZE 0x1F00000 (31 MB) Maximum file system size

Note: The MAX_APP_SIZE and MAX_FILESYS_SIZE values are logical maximums. The physical flash is 8 MB, so actual usable space is limited by the flash capacity minus partition table overhead and EFFS metadata (~64 KB).

Typical Space Budget (8 MB Flash, Default Single Partition)

Region Size
Partition table (sector 0) 4 KB
Effs_Cfg (partition sector 0) 4 KB
EFFS metadata (FAT + directory) ~64 KB
Usable file storage **~7.9 MB**

The usable storage is shared between all files: system files (config, certs, app image, user params) and any application-created files.


Application Coexistence with System Storage

Single Shared File System

Applications and the system share the same EFFS file system on the boot partition. There is no need to create a separate file system for application data.

Directory layout on the boot partition:**

A:/
├── sys/
│ └── files/
│ ├── config.x00 ← System config (managed by HAL)
│ ├── certs.x00 ← SSL certificates (managed by HAL)
│ ├── usrparam.x00 ← User params (managed by HAL)
│ └── app.x00 ← Firmware image (managed by HAL)
├── app/ ← Available for application use
├── usr/ ← Available for application use
└── (any user directories) ← Application can create freely

Rules for Application Code

  1. Do NOT write to A:/sys/files/ directly. This directory is managed exclusively by the HAL storage layer. Use the SaveUserParameters() / GetUserParameters() API for persistent application settings, or the HAL storage API for other areas.
  2. Use standard EFFS-STD API for application files. Applications can freely create directories and files anywhere outside of A:/sys/:

    // Create application directory
    fs_mkdir("mydata");
    fs_chdir("mydata");
    // Write a file
    FS_FILE *f = fs_open("sensor_log.dat", "w");
    if (f) {
    fs_write(buffer, 1, bufLen, f);
    }
    #define fs_write(buf, size, size_st, filehandle)
    Write data to the file at the current position.
    Definition fsf.h:370
    #define fs_mkdir(dirname)
    Makes a new directory.
    Definition fsf.h:246
    #define fs_close(filehandle)
    Closes an opened file.
    Definition fsf.h:358
    #define fs_open(filename, mode)
    Opens a file in the file system.
    Definition fsf.h:348
    #define fs_chdir(dirname)
    Change the directory.
    Definition fsf.h:259
  3. The file system is already mounted. On SOMRT1061, mount_std_fs() runs during HardwareInit(), before UserMain() is called. Applications do not need to call EffsStart() or any other initialization function.
  4. Thread safety. The EFFS-STD API is thread-safe. Each RTOS task is automatically tracked via FS_MULTI structures, and the fsm_* wrapper functions (which the fs_* macros resolve to) handle per-task locking internally. Multiple tasks can safely perform file operations concurrently.
  5. Check available space before large writes. Since all data shares the same partition, a large application file could consume space needed for firmware updates or config saves. Use fs_getfreespace() to check:

    FS_SPACE fspace;
    if (fs_getfreespace(fs_getdrive(), &fspace) == FS_NOERR) {
    if (fspace.free >= requiredBytes) {
    // Safe to write
    }
    }

Creating a Second Partition (Optional, NOT RECOMMENDED)

Applications can create additional EFFS partitions on the SPI flash, but this is not required for most use cases. The single default partition is sufficient for the vast majority of applications.

When to Consider a Second Partition

  • Data isolation: Prevent application data writes from interfering with system files (config, certs, firmware)
  • Separate formatting: Allow reformatting application data without affecting system data
  • Different block sizes: Optimize block size for different data access patterns

How to Create a Second Partition

The examples/PlatformSpecific/SOMRT1061/EFFS_MultiPart/ example demonstrates the full process:

  1. Backup all files from existing partitions into RAM using tree-walking (BuildFileTrees())
  2. Unmount all drives with fs_unmountdrive() and free allocated memory
  3. Modify the partition table: shrink partition 0's sectorCount and create a new PartitionEntry for the second partition
  4. Erase the entire flash with AppFlash.EraseChip()
  5. Write the new partition table with writePartitionTable()
  6. Create default filesystems on each partition with createDefaultFilesystem()
  7. Mount all partitions with fs_mountdrive() and format with fs_format()
  8. Restore files from the RAM backup to their respective partitions
// Example: Create a 1 MB second partition at the end of flash
void CreateSecondPartition(uint32_t fs_size)
{
uint32_t sectorCount = fs_size / (1ul << AppFlash_pt.sectorLenExp);
// Shrink partition 0
NewTable.part[0].sectorCount = NewTable.totalSectors - 1 - sectorCount;
// Create new partition entry at end of flash
createPartitionEntry(&NewTable, &pte,
NewTable.totalSectors - sectorCount, sectorCount,
PARTITION_TYPE_EFFS, false); // false = not bootable
createPartition(&NewTable, &pte);
// ... (erase, write table, mount, format, restore)
}

After creation, the second partition is accessed as a separate drive:

fs_chdrive(1); // Switch to partition 1 (B:)
fs_open("data.bin", "w"); // Create file on partition 1

Warning**: Creating a second partition requires erasing the entire flash chip. All existing data must be backed up to RAM first and restored afterward. This operation is destructive and should only be done during initial device provisioning or with careful data migration.


Comparison with Older Platforms

The SOMRT1061's partition-table approach is fundamentally different from the fixed-region approach used by older NetBurner platforms (MOD5441X, NANO54415, SB800EX, MODM7AE70, SBE70LC).

Feature SOMRT1061 MOD5441X / NANO54415 & SB800EX
Flash Type SPI NOR (8 MB) Parallel NOR (32 MB) / SPI NOR (8 MB)
Partitioning Dynamic partition table at sector 0 Fixed COMPCODEFLAGS compile-time regions
App Image Storage Stored as file in EFFS (A:/sys/files/app.xNN) Dedicated raw flash region
Config/Certs Versioned files in EFFS (*.xNN) Dedicated flash sectors or EFFS files
Block Size 32 KB (configurable per partition) 128 KB (MOD5441X), 4 KB (NANO54415 & SB800EX)
Sector Size 1 KB (configurable per partition) 1 KB
Max Partitions 8 1
Error Protection Hamming codes on partition table and Effs_Cfg None
FS Initialization Automatic in HardwareInit() (before UserMain()) Application must call EffsStart()
FS Source Files Built into platform library Copied from examples/_common/EFFS/STD/

Key Differences for Application Developers

  1. No EffsStart() call needed. On SOMRT1061, the file system is mounted before UserMain() runs. On older platforms, applications must explicitly call EffsStart("TaskName") to initialize and mount the file system.
  2. No EFFS source files in application. On older platforms, applications include source files from examples/_common/EFFS/STD/ (e.g., effsStdFlashDrv.cpp, fs_main.cpp, effs_std.cpp). On SOMRT1061, all flash driver and mounting code is part of the platform library.
  3. No COMPCODEFLAGS. Older platforms use COMPCODEFLAGS in the makefile to define the boundary between application code and file system regions. On SOMRT1061, this mechanism is not used — the partition table handles all flash region management.
  4. File system always available. On SOMRT1061, no special makefile flags or library includes are needed to use the file system. The PLAT_HAS_FILESYSTEM flag is always set.
  5. Application image is a file. On SOMRT1061, firmware updates write the application image as a file in the EFFS file system. On older platforms, the application image is written directly to a raw flash region. This means SOMRT1061 firmware updates use the same flash wear-leveling as regular file writes.

Boot Sequence

At power-up or reset, the application is decompressed from Flash memory to PSRAM, verified by checksum, and execution begins. If the checksum fails or the application crashes, the device will reboot to the Configuration Server to facilitate a recovery by downloading a new application.

If the application causes an issue in which continuous traps occur, or the state of the system is such the Configuration Server cannot run, a recovery hardware jumper procedure can be used to reset the device.

Note
It is always a good idea to have a serial port terminal connected to the boot/debug serial port to view status messages, or use the 'A' to abort the boot sequence command when prompted to abort application execution and boot to the Configuration Server.


UART Signals and Port Number Mapping

There can be a maximum of 7 serial port configured on the device. Note that each signal pin on the microprocessor can be configured for up to 5 different functions, so to achieve the maximum number of serial ports some peripheral functions will be unavailable.

Please refer to the Open All Serial Ports example for hardware and software port mapping: Open All UARTs. Port number mapping for software API calls is defined in SOMRT1061/include/serial_platdefs.h in the <nburn_install>\platform folder.

PCB Routing Guidelines

Routing signals for the SOMRT1061 can be broken down into a hierarchy of priorities and requirements. These are based around signal integrity of various flavors and application needs.

The following signals are considered 'routing critical', meaning that if you intend to use them, they must be routed to spec:

  • ENET.ERX*
  • ENET.ETX*
  • USB.OTG1_D*
  • USB.OTG2_D*

In the case of the ENET signals, they must be routed as "100 ohm differential" (and ideally a nominal 50 ohm single ended impedance) signals within the TX or RX pairs. The USB data signals must be routed as "90 ohm differential" (and ideally 45 ohm single ended). While the signals are differential, care should be taken to not route high power signals in a manner that would strongly couple to these signals and interfere with the them. Beyond this, avoid vias if possible for these, as they will introduce impedance discontinuities (i.e. reflect some power and introduce additional dispersion), and length match within the pairs as close as possible (ideally < 100mil). Obviously, the connected cables will introduce their own variability with the length matching, but the closer your routing, the better the noise immunity at install.

Next, are the 'performance critical' signals, where the feature would still work, but to differring levels of performance based on routing. These are:

  • SD_B0*, when used for SDIO (SD card)
  • AD_B1*, when used for analog inputs
  • EMC*, when using the databus

The SD_B0 and AD_B1 signals are routed on the bottom layer of the module, and thus will be directly over the top layer of your carrier PCB, with no additional copper between them. In the case of the SD_B0 signals, routing highspeed signals across the southwest corner of the module has potential to introduce issues when operating at high speeds with memory cards. If high speed signals must be routed under them without an isolating plane layer, they should be routed in an east/west direction relative to the module.

In the case of the AD_B1 signals, the concern is primarily regarding additional introduced noise into the analog measurements. While using the onboard ADC of a processor on a module is never going to yield the precision and accuracy of a dedicated, precision, ADC on a thermally and mechanically isolated portion of the PCB with it's own dedicated low noise power supply, it's still possible to have it perform better or worse depending on external coupling. Therefore, the AD_B1 signals that are used for analog sampling should be isolated as much as possible from high power sources of noise, and those signals affected by/carrying high power noise should not be routed under the Southwest portion of the module.

Finally, the EMC signals contain the External Databus, which if used, will be again sensitive to noise, and thus high power noise sources should be kept away from these when serving as a databus. Of additional note is that the signals involved with the databus have been length tuned for placement of timing sensitive devices towards the northwest of the module, such that the signals exiting nearer to pin 1 are longer on the SOM than those exiting further away. It should be noted that some of the databus signals are routed on the bottom layer of the module and previous comments about signal integrity apply.

Name   |  Length (mil)
EMC_13 |  1027.567
EMC_14 |  996.629
EMC_7  |  839.663
EMC_6  |  826.247
EMC_5  |  820.025
EMC_26 |  810.646
EMC_35 |  810.511
EMC_9  |  809.71
EMC_23 |  809.706
EMC_1  |  808.191
EMC_10 |  806.277
EMC_0  |  805.844
EMC_4  |  803.84
EMC_2  |  801.904
EMC_24 |  800.075
EMC_3  |  799.877
EMC_8  |  799.083
EMC_11 |  796.457
EMC_41 |  791.704
EMC_25 |  790.139
EMC_40 |  778.25
EMC_36 |  773.609
EMC_17 |  766.04
EMC_12 |  762.951
EMC_31 |  755.219
EMC_39 |  750.712
EMC_29 |  750.198
EMC_33 |  746.296
EMC_18 |  744.48
EMC_16 |  743.689
EMC_34 |  742.535
EMC_30 |  742.226
EMC_27 |  735.4
EMC_37 |  716.469
EMC_28 |  709.312
EMC_15 |  705.513
EMC_38 |  702.911
EMC_19 |  690.108
EMC_20 |  684.383
EMC_32 |  683.317

So, all that said, can you route signals directly underneath the SOMRT1061? Absolutely! But care should be taken when doing so. East/west is generally better than north/south, as most of the signals on the bottom layer of the SOMRT1061 are running in a north/south direction given the location of the processor. They are referenced to the ground plane present on the module, which does introduce some fun when looking at the return path and the ground pins, but basic GPIO isn't really a concern.