﻿ Embedded C | What is Embedded C | Difference between C and Embedded C Programming


Embedded C

Written By: 

Akshay Daga
Introduction to Embedded C
Embedded systems are programmed using different type of languages:
·           Machine Code
·           Low level language, i.e., assembly
Use of C in embedded systems is driven by following advantages
·      It is small and reasonably simpler to learn, understand, program and debug.
·      It is fairly efficient
Dynamic C and B# are some proprietary languages which are also being used in embedded applications.

Programming using Embedded C

Embedded C use most of the syntax and semantics of standard C, e.g., main() function, variable definition, datatype declaration, conditional statements (if, switch. case), loops (while, for), functions, arrays and strings, structures and union, bit operations, macros, etc. In addition, there are some specifics to embedded C which are mentioned below: 
1.      Low Level Codes
Embedded programming requires access to underlying hardware, i.e., timers, memory, ports, etc. In addition, it is often needed to handle interrupts, manage job queues, etc. As C offers pointers and bit manipulation features, they are extensively used for direct hardware access.
2.      In-line Assembly Code
For a particular embedded device, there may be instructions for which no equivalent C code is available. In such cases, inline assembly code, i.e., assembly code embedded within C programs is used; the syntax depends upon the compiler. An example for ‘gcc’ is shown here.
int a=10, b;
asm (“movl %1, %%eax;
movl %%eax, %0;”
:”=r”(b) /* output */
:”r”(a) /* input */
:”%eax” /* clobbered register */
Assembly code is written in C program itself.  Above code assigns ‘a’ to ‘b’. Writing inline assembly code is much easier than writing full fledged assembly code.
3.      Features like Heap, recursion
Embedded devices have no or limited heap area (where dynamic memory allocation takes place). Hence, embedded programs do not use standard C functions like malloc. Structures like linked lists/trees are implemented using static allocation only.
Similarly, recursion is not supported by most embedded devices because of its inefficiency in terms of space and time.
Such other costly features of standard C which consume space and execution time are either not available or not recommended
4.      I/O Registers
Microcontrollers typically have I/Os, ADCs, serial interfaces and other peripherals in-built into the chips. These are accessed as IO Registers, i.e., to perform any operation on these peripherals, bits in these registers are read/written.
Special function registers (SFRs) are accessed as shown below:
             SFR portb = 0x8B;
It is used to declare portB at location 0x8B.
Some embedded processors have separate IO space for such registers. Since there are no such concepts in C, compilers provide special mechanisms to access them
             unsigned char portB @portB 0x8B;
In this example, ‘@portB <address>’ declares portB at location 0x8B by the variable portB.
Such extensions are not a part of standard C, syntax and semantics differ in various embedded C compilers.
5.      Memory Pointers
Some CPU architectures allow us to access IO registers as memory addresses. This allows treating them just like any other memory pointers.
6.      Bit Access
Embedded controllers frequently need bit operations as individual bits of IO registers corresponds to the output pin of an I/O port. Standard C has quite powerful tools to do bitwise operations. However, care must be taken while using them in structures because C standard doesn’t define the bitfield allocation order and C compilers may allocate bitfields either from left to right or from right to left.
7.      Use of Variable data type
In C, datatypes can be simply declared, and compiler takes care of the storage allocation as well as that of code generation. But, datatypes usage should be carefully done to generate optimised code. For most 8-bit C compilers, ‘char’ is 8-bits, ‘short’ and ‘int’ are 16-bits, long is ’32-bits’.
Some embedded processors favour use of unsigned type. Use of ‘long’ and floating variable should be avoided unless it is very necessary. Using long data types increase code size and execution time. Use of floating point variables is not advised due to intrinsic imprecise nature of floating point operations, alongside speed and code penalty.
8.      Use of Const and Volatile
Volatile is quite useful for embedded programming. It means that the value can change without the program touching it.  Consequently, the compiler cannot make any assumptions about its value. The optimizer must reload the variable every time it is used instead of holding a copy in a register.
Const is useful where something is not going to change, for e.g., function declarations, etc.