Skip to content

Instantly share code, notes, and snippets.

@LegalizeAdulthood
Last active December 14, 2017 18:54
Show Gist options
  • Save LegalizeAdulthood/79609d91ce59bd4b4203a4dcf483e1c1 to your computer and use it in GitHub Desktop.
Save LegalizeAdulthood/79609d91ce59bd4b4203a4dcf483e1c1 to your computer and use it in GitHub Desktop.
Embedded Development with Kvasir

Refresher of Embedded Development

  • Characteristics of an embedded environment
    • Bare metal interaction with hardware
    • No operating system
    • No virtual memory
    • No C/C++ runtime
      • No RTTI
      • No exceptions
      • Custom start up code
    • Peripheral access for I/O
    • More important to be on-time than fast
  • Memory-mapped I/O
    • Physical address space
    • Read-only, write-only and read/write registers
    • Register fields
    • Value written is not value read
    • Funny clear behavior
    • Bit-banding
  • Direct memory access (DMA) transfers
  • Interrupt routines
    • Tricky race conditions
  • Debugging
    • Platform emulator
    • In-circuit emulator (ICE)
    • Debug port (JTAG, etc.)
    • Serial port

Gameboy Advance

  • Design Goals
    • Scott Meyers: Make interfaces easy to use correctly and hard to use incorrectly.
    • Bjarne Stroustrup: Make simple things simple.
  • Requirements
    • Zero cost
    • Intuitive interface
    • Static checking for unexpected register behavior
    • Atomic actions and thread safe support
    • Well packaged meta programming
    • C++11 support
    • Header only and easily configurable
    • Few macros
    • Static analysis tool friendly
      • No indirect calls
      • No recursion
  • Template expression library
  • Meta programming tools
  • Uses compile-time programming to optimize interaction with hardware
  • Model of special function register (SFR)
    • SFR access types:
      • Readable
      • Writable
      • Clear on read (e.g. interrupt status bits)
      • Poppable (e.g. FIFO queues)
      • Set to clear
    • SFR address characteristics:
      • Location in memory
      • Write ignored if zero mask
      • Write ignored if one mask
      • Data type
    • Bit locations
    • Field locations
    • Reading values
    • Setting values
    • Atomic operations
  • Advantages of a better interface
  • Better than hand-coded C?
  • Kvasir::StartUp
    • Inject start up code into the application
    • Facilitate merged initialization
    • Encourages modularized start up
    • Initialization conflicts can be detected
    • Hook up ISRs
    • Configure the system clock
    • Provide hooks for power users to inject other init steps
  • Macro architecture
    • Generic code calls chip specific code via traits specialization
    • Start up code is injected via macro

Example 1: What does this do?

using Kvasir::Io;
constexpr auto statusLed = makePinLocation(port0, pin13);
apply(makeOpenDrain(statusLed),
    makeOutput(statusLed),
    set(statusLed));
if (something) {
    apply(toggle(statusLed));
}

Example 2: Is this a race condition?

// main thread
apply(atomic(set(Can::txPacketSent)));

// interrupt service routine
apply(atomic(set(Can::rxPacketReceived)));

What about this?

// main thread
apply(atomic(set(Can::txPacketSend)));

// interrupt service routine
apply(set(Can::rxPacketReceived));

Local Temporaries Encouraged

Reading into a temporary and testing pieces of it is more efficient than repeatedly reading the register.

auto res = apply(read(thing1, thing2));
if (get<0>(res)) {
    // ...
}
if (get<1>(res)) {
    // ...
}

Reorder Access

On ARM, LDR and STR instructions can have a hard-coded offset. (LDM and STM still have untapped potential.)

LDR  rn, [pc, #offset to literal pool]
unsigned volatile &reg1 = *reinterpret_cast<unsigned *>(0x40013004);
unsigned volatile &reg2 = *reinterpret_cast<unsigned *>(0x40024000);
unsigned volatile &reg3 = *reinterpret_cast<unsigned *>(0x40013008);

reg1 += 4;
reg2 += 5;
reg3 += 6;

Reorder the access to reg1 and reg3 so that their adjacency in memory can be exploited.

Merge Access

When modifying multiple bit fields in the same register, merge their modifications into a single modification.

auto i = reg;
i &= ~0x10;
i |= 0x100;
reg = i;

i = reg;
i &= ~0x03;
i |= 0x08;
reg = i;

becomes

auto i = reg;
i &= ~0x13;
i |= 0x108;
reg = i;

This is a work in progress. The idea is to revisit the tonc library and layer on top of Kvasir.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment