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).
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:
The host triggers flash mode. This step is not part of the message protocol.
The adapter sends a
Hellomessage with device identification and capabilities.The host responds with
HelloResponse, including flashloader configuration, firmware configuration, and chunk size.The host sends
StartFlashloader. The adapter starts the flashloader and acknowledges the message when the flashloader is ready.(Optional) The host sends
EraseRequest. The adapter erases the target flash region and responds.The host sends
FirmwareDatachunks. The adapter acknowledges each chunk.The host sends
FirmwareCompletewith 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.
The host triggers flash mode.
The adapter sends a
Hellomessage with device identification and capabilities.The host responds with
HelloResponse, including flashloader configuration, firmware configuration, and chunk size.The host sends
StartFlashloader. The adapter starts the flashloader and acknowledges the message when the flashloader is ready.The host sends
EraseRequest. The adapter erases the target flash region and responds.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 }