Embedded system 1: Basics of Embedded C Programming
Embedded system consists of both Hardware and Software
The main Hardware module is Processor, the processor is the heart of the embedded system and it can be anything like a microprossor, microcontroller, DSP, CPLD and FPGA
All this device have one thing in common, They are programmable we can write a program (which is the SW part of embedded system) to define how the device actually works.
Embedded Software or Programm allow Hardware to monitor external events (Input) and control external devices (outputs) accordingly. During this process, the program for embedded system may have to directly manipulate the internal architecture of the Embedded Hardware such as LEDs, Serial Communications, Interrupt Handling, and I/O Ports
Embedded Systems programming is different from developing applications on a desktop computers:
Factors for Selecting the Programming Language
Language use for embedded systems programming
Assemby Language programming
Assembly language maps mnemonic words with the binary machine codes that the processor uses to code the instructions. Assembly language seems to be an obvious choice for programming embedded devices. However, use of assembly language is restricted to developing efficient codes in terms of size and speed. Developing small codes are not much of a problem, but large programs/projects become increasingly difficult to manage in assembly language. Finding good assembly programmers has also become difficult nowadays. Hence high level languages are preferred for embedded systems programming.
Assembly is also used but mainly to implement those portions of the code where very high timing accuracy, code size efficiency, etc., are prime requirements. As assembly language programs are specific to a processor, assembly language didn’t offer portability across systems. To overcome this disadvantage, several high-level languages such as C were developed.
C programming & Embedded C Programming
The C Programming Language, developed by Dennis Ritchie in the late 60’s and early 70’s, is the most popular and widely used programming language. The C Programming Language provided low-level memory access using an uncomplicated compiler (a software that converts programs to machine code) and achieved efficient mapping to machine instructions. The C Programming Language became so popular that it is used in a wide range of applications ranging from Embedded Systems to Super Computers.
Embedded C Programming Language, which is widely used in the development of Embedded Systems, is an extension of C Program Language. The Embedded C Programming Language uses the same syntax and semantics of the C Programming Language like main function, declaration of data types, defining variables, loops, functions, statements, etc.
The extension in Embedded C from standard C Programming Language includes I/O Hardware Addressing, fixed point arithmetic operations, accessing address spaces, etc.
Use of C in Embedded systems is driven by following advantages
Compared to assembly language, C Code written is more reliable and scalable, more portable between different platforms (with some changes). Moreover, programs developed in C are much easier to understand, maintain and debug.
Compared to other high level languages, C offers more flexibility because C is relatively small, structured language; it supports low-level bit-wise data manipulation.
Objected oriented language, C++ is not apt for developing efficient programs in resource constrained environments like embedded devices. Virtual functions & exception handling of C++ are some specific features that are not efficient in terms of space and speed in embedded systems. Sometimes C++ is used only with very few features, very much as C.
Java is another language used for embedded systems programming. It primarily finds usage in high-end mobile phones as it offers portability across systems and is also useful for browsing applications. Java programs require Java Virtual Machine (JVM), which consume lot of resources. Hence it is not used for smaller embedded devices.
Difference between C and Embedded C
C is used for desktop computers, while embedded C is for microcontroller-based applications. Accordingly, C has the luxury to use resources of a desktop PC like memory, OS, etc. While programming on desktop systems, we need not bother about memory. However, embedded C has to use the limited resources (RAM, ROM, I/O, OS) on an embedded processor. Thus, program code must fit into the available program memory. If code exceeds the limit, the system is likely to crash.
Compilers for C (ANSI C) typically generate OS-dependent executables. Embedded C requires compilers to create files to be downloaded to the microcontrollers/microprocessors where it needs to run. Embedded compilers give access to all resources which is not provided in compilers for desktop computer applications.
Embedded systems often have the real-time constraints, which is usually not there with desktop computer applications.
Embedded systems often do not have a console, which is available in case of desktop applications.
So, what basically is different while programming with embedded C is the mindset; for embedded applications, we need to optimally use the resources, make the program code efficient, and satisfy real-time constraints, if any. All this is done using the basic constructs, syntaxes, and function libraries of ‘C’.
Embedded C compiler working
Source code file, it contains the source program to be compiled. The source code is usually developed in C.
Embedded C compiler generates a series of output files during compilation.
Preprocessor works on .c file and generates .i file. This file contains source text as expanded by the preprocessor like all macros are expanded and all comments are deleted.
Compiler works on .i file and generates .src files.
.src: these are assembly source files.
Assembler converts assembly file to .obj file.
.obj file contains the relocatable object code. These files are used to link with other .obj, library (.Lib) files by linker to generate an absolute
object file. OH converter object code to hex converter generates
.hex file this is a binary file used to program the processor.
Variables in Embedded C
A variable is an addressable storage location to information to be used by the program. Each variable must be declared to indicate size and type of information to be stored, plus name to be used to reference the information.
Automatic variables stocké dans registers
Static variables stocké dans RAM
Automatic variables
void delay()
{
int i, j; // automatic variables – visible only within delay()
for (i = 0; i < 100; i++) // outer loop
{
for (j = 0; j < 20000; j++) // inner loop
{
// do nothing
}
}
}
Variables i and j must be initialized each time the procedure is entered since values are not retained when the procedure is exited.
Static variables
Retained for use throughout the program in RAM locations that are not reallocated during program execution.
Declare either within or outside of a function:
void math_op()
{
int i; // automatic variable – allocated space on stack when function entered
static int j; // static variable – allocated a fixed RAM location to maintain the value
if (count == 0)
{
j = 0; // initialize static variable j first time math_op() entered
}
i = count; // initialize automatic variable each time math_op() entered
j = j + i; // change static variable j – value kept for next function call
}
// return & de-allocate space used by automatic variable i.
C control structures
Control order in which instructions are executed:
Conditional execution
Iterative execution
Repeated execution of a set of statements:
Function in Embedded C
C function
A function is a group of statements that together perform a task. A function declaration tells the compiler about a function's name, return type, and parameters.
A function definition provides the actual body of the function.
Functions partition large programs into a set of smaller tasks:
#include <reg51.h>
int math_func(int k, int n); // Function Declaration
void main()
{
int a, b, c;
a = 10;
b = 20;
c = math_func(a, b); // Function call
}
int math_func(int k, int n) // Function definition
{
int j; // local variable
j = n + k - 5; // function body
return (j); // return the result
}
Constant/ literal in Embedded C
Constant in C programming language, as the name suggests are the data that doesn't change. Constants are also known as literals.
Integer constants
123 /* decimal constant */
0x9b /* hexadecimal constant */
0456 /* octal constant */
/* For decimal literals: no prefix is used. */
/* Prefix used for hexadecimal: 0x / 0X */
/* Prefix used for octal: 0 */
Character constants
Character constants hold a single character enclosed in single quotations marks
m = 'a'; // ASCII value 0x61
m = 0x01;
Character can hold an integer value as well (maximum value character constants can hold in 127 and 255 for unsigned character constants). Also, different characters have associated integer values (like 'A' is 65, 'a' is 97). These values are standard and known as ASCII.
Recommended by LinkedIn
String constants/Literals
String constants consist of any number of consecutive characters in enclosed quotation marks (").
String (array) of characters:
char my_string[] = "My String";
// Compiler will interpret the above statement as
char my_string[10] = {'M', 'y', ' ', 'S', 't', 'r', 'i', 'n', 'g', '\0'};
In C programming language, system internally stores the string as a character array with a null character (\0) as the terminator. null character marks the end of a string.
Data types
Basic data types in C51 compiler
Data types simply refers to the type and size of data associated with variables.
Most types are signed by default (short, int, long long), char is unsigned by default.
Basic data types in ARM C compiler
Because the natural data-size for an ARM processor is 32 bits, its is much more preferable to use int as a variable than short, the processor may actually have to use more instructions to do a calculation on a short than an int.
In code ported from other platforms, especially 8-bit or 16-bit platforms, the data types may have had different sizes. For example, int may have been represented as 16 bits.
Arithmatic Operations in Embedded C
int i, j, k; // 32-bit signed integers
uint8_t m, n, p; // 8-bit unsigned numbers
i = j + k; // add 32-bit integers
m = n - 5; // subtract 8-bit numbers
j = i * k; // multiply 32-bit integers
m = n / p; // quotient of 8-bit divide
m = n % p; // remainder of 8-bit divide
i = (j + k) * (i - 2); // arithmetic expression
/*
*, /, % are higher in precedence than +, - (higher precedence applied 1st)
Example: j * k + m / n = (j * k) + (m / n)
*/
Bitwise operations in Embedded C
Bit level Operations in C
unsigned char A, B, C; // we can declare an 8-bit number as a char
A = 0x66; // binary A = 01100110;
B = 0xB3; // binary B = 10110011;
C = A & B; // binary C = 00100010; i.e., 0x22;
unsigned int A, B, C;
A = 0x64; // binary A = 01100100
B = 0x10; // binary B = 00010000
C = A | B; // C = 0x74 which is binary 01110100
unsigned int A, B, C;
A = 0x64; // binary A = 01100100
B = 0xB3; // binary B = 10110011
C = A ^ B; // C = 0xD7 which is binary 11010111
unsigned int A, B;
A = 0x64; // binary A = 0b01100100
B = ~A; // B = 0x9B which is binary 0b10011011
Shift operators
A >> B (right shift operand A by B bit positions) A << B (left shift operand A by B bit positions)
Vacated bits are filled with 0’s.
Shift right/left fast way to multiply/divide by power of 2
B= A<<2;
B= A>>4;
8051 is the 8-bit microcontroller originally developed by Intel in the mid-80s. A typical 8051 microcontroller also known as Intel MCS-51 and here are the configuration of that particular microcontroller
Since 8051 is 8-bit microcontroller it can read-write and process 8 bit of data. There are a bunch of manufacturers like Atmel, NXP, Texas Instruments who manufacturer their own versions of 8051 microcontrollers. Irrespective of manufacturers internal hardware design i.e internal architecture of 8051 microcontroller remains more or less the same. Here a diagram shows the architecture of 8051 in block diagram style.
Central Processing Unit is the heart of microcontroller mainly contains ALU and CU. ALU stands for the arithmetic logic unit as the name suggest it used to perform arithmetic and logical operations. CU nothing but a control unit responsible for all the timing of communication process between CPU and other peripherals.
Program memory is also known as code memory is a read-only memory used to store the CPU instructions. A program written into the memory will retain even if the power is down or the system is reset. The data memory is also known as Random Access Memory or RAM is responsible for storing the value of variable temporary data and immediate result for the proper operation of the microcontroller. RAM is a volatile memory and generally organized as a register and user accessible memory locations.
Input-output ports provide microcontroller a physical connection with the outside world. These ports can be configured as an input port or output port. Input provides a gateway for passing data from the outside world to the microcontroller with the help of sensors and output port allows the microcontroller to control external devices like motor, LED etc.
The oscillator is used to generate a clock signal. Clock signal allows the operation inside the microcontroller and other parts to be synchronous. The clock generator is an integral part of microcontroller architecture and the user has to provide additional timing circuitry in the form of a crystal.
Timer hardware is used to generate delay and the same hardware can be used to count external event on T0 and T1 pin of the microcontroller.
serial port used for serial communication between the microcontroller and other serial devices Interrupt control block, this block is used to control external and internal interrupt in 8051 microcontrollers.
Program memory, data memory, timer, serial port, input-output ports, interrupt control block and CPU all interface together through the system bus.
A microcontroller programmer or microcontroller burner is a hardware device accompanied with software which is used to transfer the machine language code to the microcontroller ROM from the PC.
The compiler converts the code written in languages like assembly, C, etc., to machine language code and stores it in a hex file.
The API/software of the programmer reads data from the hex file stored on the PC and feeds it into the controller’s memory.
The software transfers the data from the PC to the hardware using serial, parallel, or USB port.
Depending on the way it interacts with PC, there are 3 types of microcontroller programmers:
The conventional method to burn a controller is to take it out the circuit, place it on burner and then dump the hex file into the controller using the API.
In order to remove this problem of removing the controller from the circuit every time it needs to be programmed, the controllers have now been upgraded with In System Programmer (ISP) feature.
The latest controllers are coming with the feature like bootloader, which allows self burning capabilities, such microcontroller controller does not need any additional programmer hardware.
What is BootLoader?
A bootloader is a program present in flash memory of microcontroller which enables download of hex-files directly into the flash-memory of a microcontroller.
Generally the bootloader are written to empower a controller with self burning capabilities.
The bootloader program can access any of inbuilt peripherals like USB, USART, CAN, SPI, etc. to exchange the data.
Conclusion
In this article, we explored the basics of Embedded C programming, a crucial foundation for working with embedded systems. We began by reviewing the key factors for selecting a programming language and highlighted why C is a preferred choice in this field. By differentiating between standard C and Embedded C, we gained a clearer understanding of the unique constraints faced when developing software for embedded hardware.
We also covered essential concepts such as variables, functions, constants, data types, and bitwise operations. These fundamental elements are critical for efficient embedded programming. Additionally, we introduced the 8051 architecture and explained the role of the bootloader in initializing an embedded system.
In the next article, Embedded Systems Programming on ARM Cortex-M3/M4 Processor, we will delve deeper into embedded systems development by focusing on programming ARM Cortex-M3 and M4 microcontrollers. We will explore the specific features of these advanced architectures and discuss techniques to fully leverage their capabilities.
ECE 24 || Verilog || System Verilog || Digital Electronics || Analog Electronics || Static Timing Analysis || Digital IC Design || UVM || LINUX
3moGreat article and informative. It provides a great overview about Embedded C and 8051 microcontroller..