Things to Think About When Doing Low-Level Embedded Systems Development.

国立西洋美術館、あれそんなの関係ねぇ

Building a Mental Model

The ISA and ABI:

  • What registers does my ISA have, and how they are used by the compiler?
  • What is the calling convention? How much stack space is consumed by an ISR or a function call?
  • Can I at least quickly guess what any assembler mnemonic might mean?

The Stack:

  • What is the stack? Where is it? Who put it there? What register points to it?
  • How much stack memory do I have? Is it shared between interrupt context and task context?
  • What am I doing to avoid stack overflow? What am I storing on the stack?
  • What happens when I overflow the stack, how does my software recover?

Globals/Heap:

  • Where/how are globals initialized? What about function local statics?
  • Do I need to have a heap? What might need to be allocated/de-allocated at runtime?

Memory:

  • Where is the data stored? What is tightly coupled memory? What is cache? What’s the difference and what does my platform use?
  • What is memory alignment? What is the width of my platform’s bus?
  • Where is the code stored? Is random access to code penalty-free?

Interrupts/Critical Sections (The hardware):

  • How long does it take to enter/exit an ISR? What is tail chaining and does my platform benefit from it?
  • How do my critical sections work, do they block all interrupts, block a priority level, or a mask?
  • How long does a critical section take to enter and exit? What is my longest timed critical section?

Interrupts/Critical Sections (The software):

  • How am I prioritizing my interrupts? What is the most time-critical ISR?
  • Are there interrupts that are too time-critical to be blocked by a critical section?
  • What is interrupt nesting? What is the maximum nesting level of my interrupts? Do I have enough stack if they all nest?
  • Why should I not do too much work in a high-priority interrupt handler or critical section?
  • How do I delegate work from a high-priority interrupt to a lower-priority context?

Registers:

  • How do MMIO registers and system registers work? What’s the difference?
  • What are some gotcha’s with MMIOs, due to the fact they aren’t really memory?
  • Why should I use volatileto access MMIO?
  • Why should I be careful of the size of the memory bus used to access MMIO?
  • Why does reading a 64-bit timer register over a 32-bit bus occasionally have unexpected results?
  • Why might writing a set of 32-bit registers via a uint8_t* pointer lead to strange results?
  • What registers can I read-write-modify safely? Why do some registers have redundant views? (e.g. set register, clear register)
  • What are the modes, read-only, write-only, write-once, trigger-on-write, etc?

Execution privilege:

  • What are the different execution levels/privilege levels of my ISA? What permissions does each level have?
  • e.g Cortex-M ARMv6: Supervisor and task with just a different stack.
  • e.g Cortex-M ARMv7: Supervisor and task with different privileges.
  • e.g Cortex-R ARMv8 : (Hypervisor, Kernel, Task)
  • How do you transition between them? What level does the startup code exit to?
  • Does my RTOS use them? Do I need to call into a higher privilege to access some features?
  • Does my RTOS have different function calls depending on my context?

What About RTOSs? What about XYZ?

Conclusion

Application-Specific Questions

Low power/clock gating.

  • What is a clock, and why does the CPU need one? What does it mean to “gate” a clock?
  • What is and why is there a WFI/WFE instruction?
  • What power mode do I go into during WFI? What platform-dependent register controls the clocks? What clocks keep running?
  • Do I disable interrupts during clock gating control and WFI? What do you mean WFI is woken while interrupts are disabled? How can that even work?
  • If my CPU clock is disabled, do I wake up? (e.g. is there a special GPIO or comms port that can do asynchronous wake-up?)
  • How long does it take to exit a low power mode? Does an oscillator need to power up?
  • What blocks are powered off at any time? What happens if I write to a powered-off MMIO?
  • What happens to my timers (RTOS tick, real-time counter, etc) when I turn off clocks?

Analog Interfaces.

  • What is analog hardware? Why is it different from digital hardware?
  • Flash memory is an analog circuit!? Did I need to enable some high voltage line and wait a bit before I write to flash?
  • Pin IO is an analog circuit!? What is a pull-up, pull-down, drive strength, floating pins, (pseudo) open-drain/collector?
  • Does everything in analog-land get controlled by digital hardware or my firmware?
  • How does everything in analog-land synchronize to the same clock as digital-land?
  • Does the block have another power source? Reference voltage/current? How long do I wait after a block has been enabled until it can be used?
  • What is a setup time? What is a hold time?
  • What is the default state of a comparator? Does initialization trigger an edge and interrupt that I’m not expecting? What other corner cases can occur on the boundary?

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Phil Mulholland

Phil Mulholland

Experienced in Distributed Systems, Event-Driven Systems, Firmware for SoC/MCU, Systems Simulation, Network Monitoring and Analysis, Automated Testing and RTL.