In-Field Update
In-Field Update (IFU) updates the application and/or firmware on a deployed SITCore device — securely, atomically, and from any source. Updates can come from an SD card, a USB drive, a network download, a CAN bus, or anywhere else your application can pull bytes from.
The update is encrypted end-to-end. The new application/firmware is buffered in temporary storage (RAM or external flash) in its encrypted form, decrypted only inside the SITCore for verification, then atomically swapped into place.
NuGet packages: GHIElectronics.TinyCLR.Update, plus GHIElectronics.TinyCLR.Devices.Storage if buffering to external flash.
How it works
The high-level flow:
- Open an
InFieldUpdateinstance — pass a QSPI controller to buffer in external flash, or no argument to buffer in RAM. - Load the application key with
LoadApplicationKey(appKey). - Stream the application in chunks via
LoadApplicationChunk(...). IFU tracks position internally. - Stream the firmware the same way via
LoadFirmwareChunk(...). - Verify —
VerifyApplication()andVerifyFirmware()return the version number on success, or throw on a security check failure. FlashAndReset()— IFU atomically swaps in the new code and resets.
If anything goes wrong mid-load, call updater.ResetChunks() to clear both application and firmware counters and start over.
Don't lose power during FlashAndReset(). Depending on size, the swap can take several seconds. A power loss during this window leaves the device in an unbootable state that requires a manual recovery via the bootloader.
Memory requirements
IFU needs a temporary buffer the size of whatever you're updating:
- Firmware update — buffer must be at least the size of the new firmware.
- Application update — buffer must be at least the size of the internal deployment region, plus any extended external deployment.
Pick the buffer location based on what's available:
- External RAM (typical for SoMs with SDRAM) — fastest, simplest. Buffer in RAM with
new InFieldUpdate(). - External QSPI flash (for SoMs without SDRAM) — buffer in flash with
new InFieldUpdate(qspiController).
When IFU buffers to external flash, it overwrites the entire QSPI region except the first 2 MB and the extended-deployment area (see External Memory for the layout). The first 2 MB is preserved — so a Tiny File System installed there survives the update.
External-flash buffering uses block sizes that are powers of two starting at 1 KB (1K, 2K, 4K, 8K, …). 1 KB is recommended — firmware and .tca files are always multiples of 1 KB.
Example: updating from SD card
The example below reads the new application (your_app.tca) and firmware (ghi_firmware.ghi) from an SD card, verifies both, and applies them.
using GHIElectronics.TinyCLR.Devices.Gpio;
using GHIElectronics.TinyCLR.Devices.Storage;
using GHIElectronics.TinyCLR.Pins;
using GHIElectronics.TinyCLR.Update;
using System.Diagnostics;
using System.IO;
var qspiController = StorageController.FromName(SC20260.StorageController.QuadSpi);
var indicatorPin = GpioController.GetDefault().OpenPin(SC13048.GpioPin.PB5);
// 16-byte application key — replace with your real key.
var appKey = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
var updater = new InFieldUpdate(qspiController) {
ActivityPin = indicatorPin,
};
var dataChunk = new byte[1 * 1024]; // Must be a multiple of 1 KB.
// Buffer the new application.
using (var appStream = new FileStream(@"A:\your_app.tca", FileMode.Open)) {
var loaded = 0;
while (loaded < appStream.Length) {
var count = appStream.Read(dataChunk, 0, dataChunk.Length);
loaded += updater.LoadApplicationChunk(dataChunk, 0, count);
}
}
// Buffer the new firmware.
using (var fwStream = new FileStream(@"A:\ghi_firmware.ghi", FileMode.Open)) {
var loaded = 0;
while (loaded < fwStream.Length) {
var count = fwStream.Read(dataChunk, 0, dataChunk.Length);
loaded += updater.LoadFirmwareChunk(dataChunk, 0, count);
}
}
// Authenticate both.
updater.LoadApplicationKey(appKey);
Debug.WriteLine("Application version: " + updater.VerifyApplication());
Debug.WriteLine("Firmware version: " + updater.VerifyFirmware());
// Atomically swap and reset — system is locked until this completes.
updater.FlashAndReset();
Activity pin
Updates can take several seconds. Hook an LED (or any GPIO output) to track progress — useful for displaying an "Updating, do not power off" indicator on the front panel.
var indicatorLed = GpioController.GetDefault().OpenPin(SC20260.GpioPin.PB0);
updater.ActivityPin = indicatorLed;
Lightweight updates: ApplicationUpdate
If your device has no external memory (no SDRAM and no QSPI flash), the full InFieldUpdate class can't run — there's nowhere to buffer. But you can still update the application (not firmware) using ApplicationUpdate, which streams directly from a FileStream:
using GHIElectronics.TinyCLR.Update;
// Open a stream to an application file on SD card or USB memory.
using var appStream = new FileStream(@"A:\your_app.tca", FileMode.Open);
var updater = new ApplicationUpdate(appStream, appKey) {
ActivityPin = indicatorPin,
};
var version = updater.Verify();
updater.FlashAndReset();
ApplicationUpdate can't update firmware — only the application. If you need to update firmware on a device without external memory, you'll need to use TinyCLR Config over USB or serial.
Firmware and application version matching
The firmware and application versions need to line up. Each TinyCLR firmware release has matching libraries — building an application against firmware v2.4.1 libraries and trying to run it on a device with v2.3.0 firmware (or vice versa) is unsupported and will fail at load time.
When updating, plan to update both firmware and application together unless you've verified they're compatible.
API reference
| Namespace | Description |
|---|---|
| GHIElectronics.TinyCLR.Update | Firmware and application update classes |