Lecture 5 - Embedded C Programming

![[CPE 316 Embedded C Programming fall 2023.pptx]]

Really the presentation above has a lot of information, but here's some highlights:

The Preprocessor

Embedded C really focuses on using #define since any computations done at compile time is saved computations during runtime. Make sure to use include guards:

	#ifndef MY_HEADER_FILE_H
	#define MY_HEADER_FILE_H

	// code body

	#endif

Data Types

Make sure to realize that generic types like int, long, ... are variable size (based on the target architecture). If you use int32_t or similar, however, then the bits are actually of that size (really, C is going to simulate what the behavior of that datatype in terms of other int and so on).

So instead of using:

unsigned int my_32b_int = 55; // behavior depends on target architecture 

Use:

uint32_t my_32b_integer = 55; // behavior is simulated to target artitecture

The only exception is usually char is used as is, since it's the only generic type where it's always defined as uint8_t.

Loops

Embedded Programming is a bare-metal program, and as a result should never stop. There may be RTOS (real-time operating systems), but for the most part we will always need to just have an infinite loop, for simplicity sake.

static

This keyword implies that the value is placed on the heap, or in some static memory space:

The issue is that that piece of memory is needed to exist for the entire life of the program, which sometimes we may not have.

const

const doesn't actually mean that the variable is constant. It just means that the value is read-only. Recall from Lecture 3 - GPIO Review, LCD Screen that the BSRR register could, in theory, reset or set a register that itself could be constant. In embedded C this is sort of the same process.

volatile

Is defined as:

volatile

Easily exploded

Ok not really. It really means that the variable can change unexpectedly. It's telling the compiler "hands-off", allowing it to use memory that potentially other programs are using.

Note that some variables can be both const and volatile, and a pointer can be volatile if the pointer is modified in the ISR.

ISRs

LUTs (Look-Up Tables)

If we can compute things at compile time, we should do that. But for certain functions like sin(x) we should do the same thing. Hence, LUTs.

You get better performance overall, but it might take up a huge chunk of memory!!! Further, every, single, thing that you have to save in ROM:

uint16_t sin_table[100] = {/* put values here */};