ARM C Language & Assembler
Using C instead of Java (or Python, or your other favorite language)? C is the de facto standard for embedded systems because of: Precise control over what the processor is doing. Modest requirements for ROM and RAM, so much cheaper system. Predictable behavior, no OS (e.g. Garbage Collection) preemption. Why are we... ? Looking at assembly language? Helps our understanding of Processor’s organization. The compiler translates C into assembly language. To understand whether the compiler is doing a reasonable job, you need to understand what it has produced. Sometimes we may need to improve performance by writing assembly versions of functions.
Translation Process Translation: source code (files) → Object Files Object Files contain machine code and symbols (e.g. memory addresses, external variables and functions references)
Parser R eads in C code, Checks for syntax errors, Forms intermediate code (tree representation) High-Level Optimizer Modifies intermediate code (processor-independent) Code Generator Creates assembly code step-by-step from each node of the intermediate code Allocates variable uses to registers Low-Level Optimizer Modifies assembly code (parts are processor-specific) Assembler Creates object code (machine code) Translation performed in steps
Linking Process Linker/Loader Creates executable image from object file Output (executable) file contains machine code plus info where to load it in memory.
After Linking Hex File (programming file) is used to program the Flash Memory
Load & Store Architecture ALL Data operations performed on CPU Registers only
Load & Store Example in Assembly Task: Add 5 to the variable stored at SRAM address ADDR1 LD R0, #ADDR1 ; load variable’s address value to R0 LD R1, [R0] ; Load the variable value into R1 ADDS R1,R1, #5 ; add 5 to current value of R1 (“S” stands for update flags) STR R1,[R0] ; replace old value with new value in R1
C code Disassembly int counter = 0; /* Global variable */ int main() { counter = counter +5; return 0; } ; C-lib start-up code allocates the variable counter to RAM address ; 0x and initializes its value to zero. ; Then the main function is called using the BL _main (branch and link) _main: LDR.N R0, 0x ;.N stands for 16 bit instruction LDR R0, [R0] ; get the value of the counter variable ADDS R0, R0, #5 ; add 5 (immediate addressing) LDR.N R1, 0x STR R0,[R1] ; store the new value of the counter MOVS R0, #0 ; return value stored in R0 BX LR ; return from main (branch and exchange)
Using Pointers to Set SRAM Address int * p_counter = (int*) 0x ; int main(){ *p_counter = 0; /* contents at address 0x loaded with zero */ *p_counter = *pcounter +5; /* and subsequently incremented by 5 */ return 0; } Program Memory Dump of the main function: ROM Addr Machine Code 0xd8 : LDR.N R0, 0x xda: LDR R0, [R0] 0xdc: ADDS R0, R0, #5 0xde: LDR.N R1, 0x xe0: STR R0,[R1] 0xe2: MOVS R0, #0 0xe4: BX LR 0xe6: 0x DC32 counter
Pointer Arithmetic's int * pv = (int*) 0x ; int * uv = (int*) 0x A; int v = 0x ; int u = 0x ; *pv = v; *pv = *pv + 1; pv = pv + 1; What will be the byte values stored at byte addresses in range 0x to 0x D ? Answer:
Ampersand Operator & & operator acting on variable returns “address” of variable. Example: int u = 0x45; int* pu = &u; *pu = *pu +1; What will be the value of u ? Answer: 0x46
Using Pointers int counter = 0; int main() { int *p_int; p_int = &counter; while (*p_int < 21) { ++(*p_int); } p_int = (int *)0x ; *p_int = 0xDEADBEEF; return 0; } What will be the value of counter variable ? Answer: counter =21 What value will be stored at address 0x ? Answer: 0xDEADBEEF