Baremetal C Programming for Embedded Systems Class 1: C Concepts for Embedded Systems February 23, 2015 Jacob Beningo, CSDP
Jacob Beningo Newsletters P.O. Box 400 Embedded Bytes Linden, Michigan 48451 www.beningo.com Newsletters Embedded Bytes http://bit.ly/1BAHYXm Training MicroPython Bootloaders Low Power Design Real-time Software C/C++ Embedded : jacob@beningo.com : 810-844-1522 : Jacob_Beningo : Beningo Engineering : JacobBeningo : Embedded Basics Jacob Beningo Principal Consultant 2
Course Overview C Concepts for Embedded Systems Baremetal Scheduling Techniques Driver Design Techniques Design Patterns for Firmware Writing Portable Code
Session Overview Review of C Programming Understanding Scope Static and Volatile Pointer Review Pointers vs Arrays Enum vs Preprocessing Interrupts
Program Scope Global Program Scope Every variable is exposed Anyone or anything can purposely or accidentally access any other variable Poor structure Achieved by using single source file Achieved through heavy use of extern keyword Simple to implement Nightmare to debug
Controlling Program Scope Static is a storage class specifier that can be applied to any data type char, short, int, etc tells the compiler to make the variable or function limited in scope while allowing it to persist throughout the life of the program used to encapsulate or hide variables from the rest of the program to prevent inadvertent access
Using Volatile Definition of volatile “An object whose type is qualified with volatile may be modified by other processes or events. The volatile keyword instructs the compiler to reread the object’s value each time it is used, even if the program itself has not changed it since the previous access.” - C in a nutshell page 157 How can a variable change outside of the program? A second thread or processor could have modified the memory space The variable could be an access into hardware! The variable is modified by an interrupt service routine
Using Volatile Example hardware usage When accessing a hardware register the volatile keyword should be used! The reason? Because the compiler may try to optimize register code assuming it won’t change! uint16_t * Reg_Ptr = (uint16_t*)0x1000; while(*Reg_Ptr != 0); // Loop while register is not 0 uint16_t volatile * Reg_Ptr = (uint16_t volatile *)0x1000;
Reserved Words to Avoid auto break continue extern goto inline register restrict
A Review of Pointers Pointer Operators Examples * is used to dereference a pointer & is used to get the address of a variable Examples A NULL pointer int * NullPtr = 0; Variable pointer int * VarPtr = &Var1; Setting the value of Var1 *VarPtr = 0x22;
A Review of Pointers Examining the Memory Map int Var1 = 0x000E; int * PtrInt = &Var1;
A Review of Pointers Pointers and Arrays Passing an Array int Array[] = {14, 15, 16}; Var = Array[0]; // Access the value 14 Passing an Array Void Function(int *); Function(Array); Function(&Array[1]); Pointer Behavior int * IntPtr = array; Var = IntPtr[1]; // Access the value 14
A Review of Pointers Pointers and Structures struct Configtype Config; Configtype * ConfigPtr = &Config; Accessing a Pointer to a struct Config.size = 4; (*ConfigPtr).Size = 4 ConfigPtr->Size = 4 Summary *, ->, [] operators are used to dereference / get at the data stored by the & get address operator
Pointer Arrays An interesting way to map hardware Advantages Groups similar registers into a common array Breaks the system up into “channels” that can be accessed through an index in the array Simplifies initialization and access code Can use a configuration table to initialize the peripheral! Disadvantage Can appear more complicated than direct accessing a register Uses slightly more flash to store the pointers
Enum vs Preprocessing #define SYSTEM_STATE_1 1 typedef enum { SystemState1 = 1, SystemState2 = 2, SystemState3 = 3, SystemState4 = 4 }SystemStateType
Memory Allocation Statically allocated memory Dynamically allocated memory uint8_t Buffer[] = {1,2,3,4,5}; uint8_t * Buffer = malloc(5); for(int i = 1; i < 6; i++) { Buffer[i] = I; } free(Buffer);
Interrupts vs Polling Polling is easy Interrupts are “hard” Processor continually checks status bit to see if the device is ready (i.e. data has arrived, button has been pressed, etc) Generally inefficient (time is wasted to check the status) Usually checked far too often Not great solution for battery operated device Interrupts are “hard” Processor only interrupted when needed Very efficient Handled on the spot after a context switch Great solution for battery operated device
Additional Resources Download Course Material for Updated C Doxygen Templates (Feb 2015) Example drivers source code Microcontroller API Standard EDN Embedded Basics Articles Embedded Bytes Newsletter From www.beningo.com under - Blog and Articles > Software Techniques > CEC Baremetal C Programming
Jacob Beningo Newsletters P.O. Box 400 Embedded Bytes Linden, Michigan 48451 www.beningo.com Newsletters Embedded Bytes http://bit.ly/1BAHYXm Training MicroPython Bootloaders Low Power Design Real-time Software C/C++ Embedded : jacob@beningo.com : 810-844-1522 : Jacob_Beningo : Beningo Engineering : JacobBeningo : Embedded Basics Jacob Beningo Principal Consultant 19