3. 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
4. Design ToAvoid ‘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
7. 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.
8. 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
11. 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
12. 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)
13. $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.
14. 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.
15. 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
16. 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.)
17. 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_
18. 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);
}
20. 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
21. 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
23. 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)
Notes de l'éditeur
Welcome to the talk. Thanks Tech Week folks, etc Glad to have you here.
EMBEDDED DEVELOPMENT (AKA Things in Internet of Things)
SHITTY. SLOW. PAINFUL.
Stuck in the 1970’s