iot firmware: best pratices

23
IOT FIRMWARE DESIGN: BEST PRACTICES (for embedded development that sucks less) @farmckon @BuLogics

Upload: farmckon

Post on 16-Jul-2015

605 views

Category:

Engineering


2 download

TRANSCRIPT

Page 1: IOT Firmware:  Best Pratices

IOT FIRMWARE DESIGN:

BEST PRACTICES

(for embedded development that sucks less)

@farmckon

@BuLogics

Page 2: IOT Firmware:  Best Pratices

EMBEDDED

DEVELOPMENT IS

PAINFULIt doesn’t have to be.

Page 3: IOT Firmware:  Best Pratices

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

Page 4: IOT Firmware:  Best Pratices

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

Page 5: IOT Firmware:  Best Pratices

Program Drivers/Firmware in C++?

Page 6: IOT Firmware:  Best Pratices

Program Drivers/Firmware in C!

Just do it

• Platform portable

• Fast

• Clear behavior (mostly)

• Simple

Page 7: IOT Firmware:  Best Pratices

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.

Page 8: IOT Firmware:  Best Pratices

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

Page 9: IOT Firmware:  Best Pratices

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)

Page 10: IOT Firmware:  Best Pratices

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)

Page 11: IOT Firmware:  Best Pratices

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

Page 12: IOT Firmware:  Best Pratices

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)

Page 13: IOT Firmware:  Best Pratices

$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.

Page 14: IOT Firmware:  Best Pratices

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.

Page 15: IOT Firmware:  Best Pratices

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

Page 16: IOT Firmware:  Best Pratices

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.)

Page 17: IOT Firmware:  Best Pratices

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_

Page 18: IOT Firmware:  Best Pratices

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);

}

Page 19: IOT Firmware:  Best Pratices

ON DEVICE DEBUGGING

IS YOUR LAST RESORT

Page 20: IOT Firmware:  Best Pratices

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

Page 21: IOT Firmware:  Best Pratices

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

Page 22: IOT Firmware:  Best Pratices

Questions? Comments?

Now Go Eat Cookies.

@farmckon

Bulogics.com

FarMcKon.net

Page 23: IOT Firmware:  Best Pratices

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)