IOT Firmware: Best Pratices

Post on 16-Jul-2015

607 views 2 download

Tags:

Transcript of IOT Firmware: Best Pratices

IOT FIRMWARE DESIGN:

BEST PRACTICES

(for embedded development that sucks less)

@farmckon

@BuLogics

EMBEDDED

DEVELOPMENT IS

PAINFULIt doesn’t have to be.

Common Problems:

• “Code, flash, bang-on-it” cycle

• Development environment setup sucks

• Debugging with little/no IO

• Complex bug scenario recreation

• “Hurry up and wait” on hardware spins

Design To Avoid ‘em:

• Program in C

• State Machines Everywhere

• Proper Modular Design

• Hardware Abstraction Layer,

• Hardware Abstraction Layer,

• Hardware Abstraction Layer!

• On-Device debugging is a last resort

Program Drivers/Firmware in C++?

Program Drivers/Firmware in C!

Just do it

• Platform portable

• Fast

• Clear behavior (mostly)

• Simple

State Machines Everywhere

Business Logic: State Machine

Hardware Abstraction: State Machine

Grocery List: State Machine

• Manages complexity.

• Testable.

• Automatically avoids most ‘'Once a year on a full moon”.

• Avoids accidental algrorithmic runtime complexity.

• Easier to share/outsource/reuse.

Modular Design

• Manages complexity

• Testable, unit and integration

• By side effect avoids “Once a year on a full moon”.

• Avoids accidental algorithmic runtime complexity.

• Allows desktop (a.k.a., much faster, better, stronger) debugging and testing by divorcing behavior from hardware.

AlarmBehavior.c, AlarmIO.c, AlertSend.c

vs.

Main.c, IO.c, Wireless.c

HARDWARE

ABSTRACTION LAYER

(HAL)

Separate hardware interface from behavior

Keep It Simple Stupid.

Do the minimum to create a clear abstraction.

(do not teach it to read lips)

Hardware Abstraction Layer (HAL)

A basic re-usable HAL design:

• HW_Init

• SW_Init

• Tick_1ms (10, 100)

• $OtherInterrupts

• ProcessData

• StateUpdate (Optional)

• SW_Deinit, HW_Deinit (Optional)

HW_Init, SW_Init

• HW_Init call to setup hardware (IO, memory, DMA)

• SW_Init to setup software (state machines, load NVM

values, etc)

• These happen on every awake, restore, or power on.

• Called by start-up or shutdown interrupts.

• (Optional mirror ‘HW_/SW_Deinit’ for sleep/shutdown).

• These do nothing but setup the landscape for the

program

Tick_?ms

• Maintenance function to tick clocks, watchdogs, timers

• Set time-based flags (timeouts, timers, error-flags)

• 1, 10, 100ms based on how “real time” your needs are

• Called by timer interrupt(s)

$OtherInterrupts

• All of your other interrupts in this category:

• DMA

• SPI

• FPU/GPU

• Radio

• Always: Clear or checks interrupt status, sets flags.

• Sometimes: Ticks state, sets timers, etc.

• Never: Processes data, does anything time-intensive.

ProcessData

• Checks flags. Does logic and intelligence. Shuffles

data/settings to modules.

• Called over and over again by main loop. Put time-

intensive things here.

• Checks flags, does business logic, and pulls/processes

data.

• For most projects StateUpdate behavior can be part of

this.

StateUpdate

• Updates state of HAL or driver

• Every HAL is a StateMachine

• With documentation

• And exceptions noted in cod

• Can be wrapped into ProcessData in most cases

SW_Deinit, HW_Deinit (Optional)

• Called on sleep/shutdown/timeout/fail

• First stop HAL software (SW_Deinit) then Hardware

• Set lines high

• Unregister interrupts

• Panic and/or cry

• In a lot of designs, this is avoidable.

• May never be called in a crash or a power-loss, so keep it

to “nice-to-have” things (sleep, pin safety, etc.)

Example Main.c

#include "spi.h"

#include "dma.h"

#include <interrupts.h>

// wake callback

int wakeFunction() I01_INT

{

int reason = IO1_INT_CAUSE & 0x0F;// Wake, POR,

SPI_HW_Init(reason);

DMA_HW_INIT(reason);

SPI_SW_INIT();

DMA_HW_INIT();

}

int main()

{

SPI_ProcessData();

DMA_ProcessData();

// Business Logic of how to handle, etc here.

If (DMA_running())

ThinkAboutDma();

else if (SPI_Complete())SpiToDmaCollection();

}

int Tick_10ms() TIMER_0_INT

{

tick++;

DMA_Tick_10ms();

if(tick %10)

SPI_Tick_100ms()

watchdogKick();

}

void watchdogTimeout() WD_DOWN_INT

{

DMA_Deinit();

// no SPI_Deinit. Too simple

}

// #endif _EXAMPLE_MAIN_

Example SPI.c#include "spi.h”

#include <interrupts.h>

Void SPI_HW_Init(WAKE_REASON r)

{

reason = r;

SET_INPUT(MISO);

SET_OUTPUT(MOSI,0);

SET_OUTPUT(SEL,0);

SET_OUTPUT(CLK,0);

w = CreateWatchdog();

Timer(&tick_10ms, 1);

}

void SPI_SW_Init()

{

queuedSz = 0; //bytes in quueed

memset(queued,0x5A, sizeof(queued)

clkLevel = 0;

byteJustCompleted = FALSE:

}

void SPI_Tick_10ms()

{

if (byteJustCompleted ) {

queueNextByte(); }

ColckBit() ..setsMOSI for next byte to send, reads MISO

PIN_SET(CLK, clkLevel)

clkLevel = (clkLevel == 1) ? 0 : 1 ; //toggle clk

// could do timeout checking here.

}

// We are master. No interrupts for us.

uint8_t SPI_QueueData( uint8_t data, uint8_t sz) {

//in reality, check size, buffer overflow, etc

memcpy( (&queued) + queueSz, data, sz)

queueSz += sz;

}

void SPI_ProcessData() {

tickWatchdog(w) ;

}

void SPI_SW_Deinit () { /*nothing to do here */ } ,

boolean SPI_Complete(){

return queueSz == 0;

}

void SPI_HW_Deinit ()

{

SET_OUTPUT(MISO,1);

SET_OUTPUT(MOSI,1);

SET_OUTPUT(SEL,1);

SET_OUTPUT(CLK,1);

}

ON DEVICE DEBUGGING

IS YOUR LAST RESORT

On device debugging is Last Resort

• If you are debugging on a device and it turns out it’s not a

hardware issue, you lost.

• Almost all testing should be on a desktop, using modern

desktop tools:

• Faster

• Better tools

• Less Flash/Test/WTF?/Tinker -> Flash/Test cycle

• Test -> WTF -> Test/ WTF cycle

• Using HAL and Modules = easy desktop debugging

• Using desktop debugging = easy HAL and modules

Bonus Best Pratices

20% Free Content, Yours For Only $10.99!!!

• Build and implement OTA/programming first(ish)

• Virtual Machines (for standard compilers at least)

• Have a canonical build server (even if just a senior

developer)

• Unit Test (almost) All The Things.

• Open Source (almost) All The Things.

• Decide on debugging streams at hardware design time

Questions? Comments?

Now Go Eat Cookies.

@farmckon

Bulogics.com

FarMcKon.net

Credits for Media

Pictures

• P1 - by Moyan Brenn on Flickr

• P2 – by Dannobytes on Flickr

• P4 - http://pixabay.com/en/lego-build-building-blocks-toys-708088/

• P5 - learnyousomeerlang.com (dog diagram)