The summary.
AVOID DYNAMIC ALLOCATION AFTER INITIALISATION
Fragmentation over long uptimes and unpredictable timing are why. Allocate statically at known sizes.
INTERRUPT HANDLERS MUST BE SHORT AND NON-BLOCKING
Record what happened and signal the main loop. Long handlers delay other interrupts and cause missed events.
Mark hardware registers and interrupt-shared variables volatile, or the compiler optimises the reads away.
NEVER SHIP A DEVICE WITH NO UPDATE MECHANISM
Vulnerabilities are found, and unpatchable devices stay exploitable permanently.
Use two system partitions with automatic rollback, and require the new image to prove it works rather than merely start.
VERIFY A SIGNATURE BEFORE APPLYING ANY UPDATE
Otherwise anyone able to deliver an image controls the device.
ASSUME PHYSICAL ACCESS AND FIRMWARE EXTRACTION
Which rules out shared secrets across devices. Provision unique per-device keys, and disable debug interfaces before shipping — they are routinely left enabled.
ADD A SERIAL OUTPUT CHANNEL EARLY
It is the most useful diagnostic available and difficult to add later. And test long uptime — counter overflow appears only after extended running.
CHECK PART AVAILABILITY AND LIFETIME BEFORE SELECTING
Supply disruption has halted production lines for months.