Chapter 1-4 Making Embedded Systems Elecia White
Chapter 1:
An embedded system is a computerized system that is purpose-built for its application
Cross-compilers:
- runs on your desktop/laptop, creates code that does not run on that same machine, it creates an image that runs on your target embedded system
- GCC from GNU is common
Cross-debugger:
- sits on your computer and communicates with target processor using JTAG (regardless of whether or not it actually falls under JTAG)
- Also known as debug probe, hardware debugger, in-circuit emulator, programmers
An embedded system is designed to perform a specific task, cutting out resources that it doesn’t need to accomplish this goal.
Chapter 2: Creating a System Architecture
The goal is diagrams is to identify ways to architect the software to changing requirements and hardware: encapsulation, information hiding, having good interfaces between modules and so on Creating Interfaces:
- Definition of the module interface depends on specifics of the system
- Most modules will also need an initialization function
- Logging Interface example:
- Hides details of how logging is actually accomplished
- Should be able to handle different underlying implementations
- Logging methods should be subsystem specific
- Priority level that will let you debug the minutiae of the subsystem you are working on without losing critical information from other parts of the code
- Hides details of how logging is actually accomplished
Chapter 3: Getting your Hands on the Hardware
[[Prototype to Product_ A Practical Guide for Getting to — Alan M Cohen; ProQuest — 1 (early release), 2015 — O’Reilly Media, Incorporated — isbn13 9781449362294 — a6dc1cb9c8bae778bf914f9dccb2b1b5 — Anna’s Archive.pdf]]
When the schematic is done and the layout has started, focus on defining hardware tests while the boards are being created. Ask EE which parts are trickiest and prioritize development for those components.
Board Bring-Up:
- make each component individually testable
- once you receive the PCBA, start on the lowest-level pieces at the smallest granularity possible
- Make your tools independent of you being present to run them Software communicates with processor software using special interfaces known as registers
Resistors connected to power/processor are known as “pull-ups” since they pull the voltage up toward power.
Pull-Up Resistor:
- pulls voltage toward power
- High resistance
- so the processor can drive a pulled-up I/O line to be low
- Pull-up means that the signal on that line defined to be high when the processor isn’t driving it
Testing Hardware and Software
3 Tests:
- Power-On Self Test (POST)
- Runs each time you boot the system, even after code is released
- Unit
- Unit tests should be run before every software release but they might not be suitable to run at every boot
- These verify that hardware and software are working together as intended
- Test you created during bring-up
- Usually because a subsystem is not functioning as intended
Flash Test:
- Looking at Macronix MX25V8035
Nonvolatile Memory:
- memory that isn’t cleared when the power is turned off
- Flash memory, Read-Only Memory (ROM), and electrically erasable programmable read-only memory (EEPROM) RAM is most predominant form of volatile memory
EEPROM
- Electrically Erasable Programmable Read-Only Memory
- Usually most EEPROMs let you erase and write a byte at a time.
- generally smaller than flash memory
Flash Memory:
- Made up of sectors/pages
- These sectors must be erased all at one time
- The larger the flash the larger the sector.
- Once a sector is erased, the flash can be written one byte at a time.
- Nonvolatile
- Less power hungry compared to EEPROM
Chapter 4: Inputs, Outputs, Timers
Most processors have pins whose digital states can be read (input) or set (output) Common names: I/O pins, GPIO (General Purpose Input/Output), digital I/O (DIO), general I/O (GIO)
Hardware Abstraction Layer:
- HAL
- Provided by processor/compiler vendor
- Header file that hides memory map of chip so you can treat registers as global variables
“Keeping the I/O map in Excel is a pretty common way to make sure the hardware and software engineers agree on the pin definitions. with a little bit of creative scripting, you can generate your version-specific I/O map from a CSV file to ensure your pin identifiers match those on the schematic”
Using board-specific header file lets you avoid hardcoding the pin. If you have a header file, you just have to change the value there instead of going through the code to change everywhere it is referenced.
Keeping the board-specific information sequestered from the functionality of the system maintains loose coupling and flexibility of codebase
Many processor I/O pins have internal pull-up resistors. If the pin = output, pull-ups do nothing If the pin = input, then the pull-up gives consistent value (1) even when nothing is attached
Active low - if a button is actively pressed, the signal is low
ISR - Interrupt Service Routine (or interrupt code)
Debouncing:
- Technique used to eliminate spurious edges
Many buttons do not provide clean signal, looks more like the ‘bouncy digital button signal’ in the diagram below
- Switch bouncing can be caused by a mechanical or electrical effect Recommends looking for the rising edge of the signal, where the user releases the button. To avoid garbage, look for a relatively long period of consistent signal.
- Take multiple readings (samples) of pin at a periodic interval several times faster than you’d like to respond
- Once there have been several consecutive, consistent samples, alert the rest of the system that the button has changed Variables needed:
- Current raw reading of I/O line
- Counter to determine how long the raw reading has been consistent
- Debounced buttton value used by the rest of the code
Timer:
- Timer is a simple counter measuring time by accumulating a number of clock ticks
- The more deterministic the master clock is, the more precise the timer can be
- In order to set the frequency of the time, you need to determine the clock input PLL: Phase Lock Loop Denotes a way for processor to multiply slower clock (slow oscillator) to get fater clock (a processor clock)
Prescaler Register:
- Divides the clock so the counter increments at a slower rate
Setting up a timer is processor-specific, so consult the user manual
Chapter 5: Interrupts
- An interrupt request (IRQ) occurs in processor, triggered by external component, software, or fault
- Processor saves context, including where it was and the local variables
- Processor finds function associated with interrupt in vector table
- Callback function runs (aka interrupt service routine (ISR) or interrupt handler)
- Processor restores saved context, returning to point before interrupt occurred and program continues to run
-
Interrupts can be like high-priority tasks or exceptions
-
In the high-priority task case, once ISR is complete, processor restores original context and continues as though nothing happened.
-
In the exception case, they don’t return to normal execution. These errors usually imply something is seriously wrong.
-
If you didn’t set up an interrupt explicitly, check vendor startup code
-
Nonmaskable interrupts:
- Interrupts so important they cannot be disabled
- Must be handled immediately, even in critical sections of code
-
Interrupts do have different priorities.
- Some processors handle it by peripherals (so timer 1 has a higher priority than timer 2). Other processors allow you to configure the priority on a per-interrupt basis
-
Some processors can allow for nested interrupts. Unless nested interrupts solve a clear problem, customary to disable other interrupts while in ISR
Sidebar: Stacks (and Heaps) p 129
-
The stack
- the system call stack that lies behind every running program in a designated section of RAM
-
For each function called, the compiler creates a stack frame that contains local variables, parameters, and the address to return to once the function is finished. Stack frame for every function call.
-
The heap:
- where dynamically allocated memory comes from (usually implemented as heap data structure) ![[Pasted image 20261004090928.png]] Usually the heap grows up, whereas the stack grows down. The heap is NOT a Toys-R-us kid.
-
An IRQ happens
-
The processor saves context
-
Context includes program counter (points to the next instruction to execute), subset of processor register so interrupt code can use in execution without corrupting state of primary code path
-
Time between IRQ and ISR = processor’s interrupt latency
-
System latency = worst-case time from when interrupt event happens to the start of the ISR
- Includes processor’s interrupt latency and the maximum amount of time interrupts are ever disabled
-
Processor designers work to keep interrupt latency low, one effective way of doing this is by storing the minimum amount of context.
-
Calling many functions while in an interrupt is discouraged, each function call has some overhead. So function calls make it take longer. 10 cycles = interrupt overhead 10 cycles calling 5 short functions that collectively use 275 cycles for processing information
If the processor is 30MHz, then
-
-
ISR looks in IVT
-
The interrupt vector table is located in a specific area in your processor, set by the linker script.
- The IVT is composed of callback functions, one for each type of interrupt. The processor consults this table to look for the function associated with the interrupt.
-
Startup code will setup the vector table for you with placeholder interrupt handlers.
-
Each interrupt has an interrupt number, the interrupt is signaled using this number.
-
-
The callback function runs (aka interrupt service routine or ISR or interrupt handler)
- Keep ISRs short because longer ones increase system latency.
- Don’t call nonreentrant functions because global variables can be corrupted by interrupts
- Reentrant function: function that can be called multiple times while it is running.
- When an interrupt happens, the ISR will determine which peripheral activated the interrupt, which can be found in a cause/status register
-
The processor restores saved context, returning to the point before the interrupt occurred, and the program continues to run.
- Interrupts have a special assembly instruction (rti) to indicate they are returning from an interrupt Configuring Interrupts:
- Disable the interrupt
- Setting up interrupts requires registers that are memory mapped Processor has separate clear and set registers.
- Set bit in clear (ICER) register that disables the timer interrupt
- Known as “masking the interrupt”
- Once disabled, we can configure it to cause an IRQ when the timer has expired
“The more real-time the requirement to handle a change on the line, the more likely an interrupt is appropriate for a solution” but they make your system less deterministic
pub/sub model: schedular publishes the amount of time that has passed and several tasks subscribe to that information (at varying intervals)