Flashing Over Serial Protocol#

The protocol is based on Protocol Buffers (protobuf) for message serialization. The protobuf definition is included at the end of this page.

All messages are wrapped in a FlashMessage envelope that carries a monotonically increasing message_id and a oneof payload containing the actual message. Messages are framed with a start-of-frame marker (0xA5), a length field, CRC32 integrity check, and an end-of-frame marker (0x5A).

Flash protocol message encoding diagramFlash protocol message encoding diagram

Activating Flashing Mode#

By default, the adapter forwards all UART transmissions to the target device and does not parse them. To trigger flashing mode in the adapter, toggle the DTR signal so that the time between adjacent falling edges meets the requirements in the TriggerSequence enum.

Protocol Timeout And Error States#

If communication between the host and the adapter is interrupted, the adapter returns to normal mode after the timeout specified in the TimingRequirements enum. After the adapter returns to normal mode, the adapter forwards received UART transfers to the target device again. Depending on when the communication is interrupted, the target device might still be running the flashloader. Send a reset sequence to the target device or restart the entire firmware upload process, depending on when the connection was interrupted.

If the adapter detects an error condition during communication, the adapter sends an error message and exits flashing mode. Possible reasons include dropped transmissions, CRC errors, or timeouts. Because the adapter and target device have limited storage and processing capabilities compared to current host machines, the protocol is timing sensitive. A host implementation should not send messages too quickly. Use a 1 ms delay between messages.

Typical Protocol Flows#

The protocol is intentionally flexible to support different usage scenarios. The first three message steps are always the same and represent a handshake between the host and the adapter. At any time, the host can send an AbortTransfer message to make the adapter exit flashing mode and return to normal mode.

Flashing Firmware#

The most common case is uploading new firmware to the target:

  1. The host triggers flash mode. This step is not part of the message protocol.

  2. The adapter sends a Hello message with device identification and capabilities.

  3. The host responds with HelloResponse, including flashloader configuration, firmware configuration, and chunk size.

  4. The host sends StartFlashloader. The adapter starts the flashloader and acknowledges the message when the flashloader is ready.

  5. (Optional) The host sends EraseRequest. The adapter erases the target flash region and responds.

  6. The host sends FirmwareData chunks. The adapter acknowledges each chunk.

  7. The host sends FirmwareComplete with the automatic reset option. The adapter verifies that all firmware chunks were received, resets the target, and exits flashing mode.

Erase Target Firmware Without Flashing A New Binary#

While the initial handshake messages are required, the messages for interacting with the target are optional. As a result, the protocol can erase a section of the target's flash without uploading firmware afterward. This flow is not supported for SiWx917 devices.

  1. The host triggers flash mode.

  2. The adapter sends a Hello message with device identification and capabilities.

  3. The host responds with HelloResponse, including flashloader configuration, firmware configuration, and chunk size.

  4. The host sends StartFlashloader. The adapter starts the flashloader and acknowledges the message when the flashloader is ready.

  5. The host sends EraseRequest. The adapter erases the target flash region and responds.

  6. The host sends ResetDevice. The adapter resets the target and exits flashing mode.

Notes For Implementing Host-Side Support#

  • Observe the timing requirements in the protocol file. When in doubt, slow down message sending. The adapter and target have limited resources to store and process incoming messages.

  • Send valid sequence numbers with each firmware chunk and check that the adapter acknowledged each chunk. The adapter does not check whether messages were received in sequence. The adapter acts on the last message received and then acknowledges the message.

Protocol File#

// Protocol for uploading firmware to Silicon Labs devices over serial
//
// Design constraints:
// - Maximum encoded message size: 300 bytes
// - Maximum byte array size: 256 bytes

// Changelog:
// - VERSION_1: Initial release

syntax = "proto3";

package flashing;

// ============================================================================
// Meta-specifications for protocol handling (not used in the actual messages)
// ============================================================================

enum TimingRequirements {
    // timings in milliseconds
    _ = 0;
    DEFAULT_COMMUNICATION_TIMEOUT = 5000;
    ACK_TIMEOUT = 1000;
}

// The flashing mode is triggered by falling edges of DTR with defined timing intervals in between.
enum TriggerSequence {
    __ = 0;
    Milliseconds_between_1st_and_2nd_edge = 55;
    Milliseconds_between_2nd_and_3rd_edge = 120;
    Milliseconds_between_3rd_and_4th_edge = 35;
}

enum FramingConstants {
    ___ = 0;
    START_OF_FRAME = 0xA5;
    END_OF_FRAME = 0x5A;
}

// ============================================================================
// Enums
// ============================================================================

enum ProtocolVersion {
    VERSION_UNKOWN = 0;
    VERSION_1 = 1;
}

enum Status {
    STATUS_OK = 0;
    STATUS_ERROR_UNKNOWN = 1;
    STATUS_ERROR_INVALID_SEQUENCE = 2;
    STATUS_ERROR_CRC_MISMATCH = 3;
    STATUS_ERROR_TIMEOUT = 4;
    STATUS_ERROR_FLASH_FAILED = 5;
    STATUS_ERROR_ERASE_FAILED = 6;
    STATUS_ERROR_VERIFICATION_FAILED = 7;
    STATUS_ERROR_INVALID_ADDRESS = 8;
    STATUS_ERROR_INVALID_SIZE = 9;
    STATUS_ERROR_FLASHLOADER_NOT_READY = 10;
    STATUS_ERROR_FLASHLOADER_START_FAILED = 11;
    STATUS_ERROR_OUT_OF_MEMORY = 12;
    STATUS_ERROR_BUSY = 13;
    STATUS_ERROR_RESET_FAILED = 14;
    STATUS_ERROR_WRITE_FAILED = 15;

    // Adapter-internal errors
    STATUS_ERROR_STATE_MISMATCH = 101;
}

enum DeviceFamily {
    DEVICE_FAMILY_UNKNOWN = 0;
    DEVICE_FAMILY_SIWX917 = 1;
    DEVICE_FAMILY_EFR32_SERIES2 = 2;
    DEVICE_FAMILY_EFR32_SERIES3 = 3;
}

enum AckType {
    ACK_TYPE_UNKNOWN = 0;
    ACK_TYPE_HELLO = 1;
    ACK_TYPE_FLASHLOADER_DATA = 2;
    ACK_TYPE_START_FLASHLOADER = 3;
    ACK_TYPE_ERASE = 4;
    ACK_TYPE_FIRMWARE_DATA = 5;
    ACK_TYPE_FIRMWARE_COMPLETE = 6;
    ACK_TYPE_RESET = 7;
}

// ============================================================================
// Top-level message wrapper
// ============================================================================

// Main message envelope - all communication uses this wrapper
message FlashMessage {
    // Monotonically increasing message ID for request/response correlation
    uint32 message_id = 1;

    // Payload - only one field will be set
    oneof payload {
        // Adapter -> Host messages
        Hello hello = 10;
        Ack ack = 11;
        ErrorResponse error = 12;

        // Host -> Adapter messages
        HelloResponse hello_response = 20;
        FlashloaderData flashloader_data = 21;
        StartFlashloader start_flashloader = 22;
        EraseRequest erase_request = 23;
        FirmwareData firmware_data = 24;
        FirmwareComplete firmware_complete = 25;
        ResetDevice reset_device = 26;
        AbortTransfer abort_transfer = 27;
    }
}

// ============================================================================
// Adapter -> Host messages
// ============================================================================

// Information about a detected board
message BoardInfo {
    // Board ID (e.g., BRD4001A -> 0x4001)
    uint32 board_id = 1;

    // Encoded variant + revision, encoded as 0xvvMMmmRR:
    // - v: variant (offset from 'A' - value of 1 means 'B' etc.)
    // - M: major revision (offset from 'A')
    // - m: minor revision
    // - R: reserved for future use, set to zero
    // example: 0x01000700 would decode as variant B, rev A07
    uint32 variant_revision = 2;

    // Board serial number
    uint32 serial_number = 3;
}

// Sent by Adapter upon entering flash mode
message Hello {
    // Protocol version for compatibility checking
    uint32 protocol_version = 1;

    // Current firmware info
    // Encoded in the format 0xrrMMmmPP where:
    // - r: Reserved for future use (set to zero)
    // - M: Major
    // - m: Minor
    // - P: Patch
    uint32 current_fw_version = 2;

    // Detected boards (usually one in case of a devkit or two in case of a WPK)
    repeated BoardInfo boards = 3;

    // Capabilities
    uint32 max_chunk_size = 10;     // Maximum chunk size Adapter can handle
}

// Generic acknowledgment for chunked transfers and commands
message Ack {
    Status status = 1;

    // For chunked transfers: the sequence number being acknowledged
    uint32 sequence_number = 2;

    // Identifies which message type this ack is for
    AckType ack_type = 4;
}

// Error response with details
message ErrorResponse {
    Status status = 1;
    uint32 error_code = 2;         // Additional error code
    string error_message = 3;      // Human-readable error (max 64 chars via options)
    uint32 failed_sequence = 4;    // If applicable, the sequence that failed
}

// ============================================================================
// Host -> Adapter messages
// ============================================================================

// Response to Hello, configures the flashing session
message HelloResponse {
    Status status = 1;

    DeviceFamily target_device = 2;

    // Flashloader configuration
    uint32 flashloader_address = 3;    // RAM address for flashloader
    uint32 flashloader_size = 4;       // Total size of flashloader binary
    uint32 flashloader_crc = 5;        // CRC32 of complete flashloader binary

    // Firmware configuration
    uint32 firmware_address = 6;       // Flash address for firmware
    uint32 firmware_size = 7;          // Total size of firmware binary
    uint32 firmware_crc = 8;           // CRC32 of complete firmware binary

    // Transfer configuration
    uint32 chunk_size = 11;            // Agreed chunk size for this session
}

// Chunk of flashloader binary
message FlashloaderData {
    uint32 sequence_number = 1;        // 0-indexed chunk number
    uint32 offset = 2;                 // Byte offset within flashloader
    bytes data = 3;                    // Chunk data (max 256 bytes via options)
    bool is_last = 4;                  // True if this is the last chunk
}

// Command to start the flashloader (after upload or using bundled flashloader)
message StartFlashloader {
    DeviceFamily device = 1;           // Device family determines the memory address
    uint32 timeout_ms = 2;             // Timeout for flashloader initialization
}

// Request to erase a flash region (requires flashloader)
message EraseRequest {
    uint32 start_address = 1;          // Start address (page-aligned)
    uint32 size = 2;                   // Size to erase in bytes
}

// Upload a chunk of firmware binary (requires flashloader)
message FirmwareData {
    uint32 sequence_number = 1;        // 0-indexed chunk number
    uint32 address = 2;                // Target flash address for this chunk
    bytes data = 3;                    // Chunk data (max 512 bytes via options)
    bool is_last = 4;                  // True if this is the last chunk
}

// Notification that firmware transfer is complete
message FirmwareComplete {
    uint32 total_size = 1;             // Total firmware size transferred
    uint32 total_chunks = 2;           // Total number of chunks sent
    bool verify_firmware = 3;          // Request verification before reset
    bool auto_reset = 4;               // Automatically reset after verification
}

// Command to reset the device
message ResetDevice {
    uint32 delay_ms = 1;               // Delay before reset (0 = immediate)
}

// Abort an ongoing transfer
// This will also cause the Adapter to exit the flashing mode
// Resuming is not supported. Instead the entire protocol flow has to be restarted
message AbortTransfer {
    uint32 reason = 1;                 // Abort reason code
}