• STM32L476vg ARM Cortex M4F Architecture

    It uses ARM v7E-M architecture.

    It a Harvard based architecture with two distinct buses for data and memory.

    It has all the instruction set of M0, M1 and M3 .

    It also has an additional feature set to support Floating-point Arithmetic. IEEE754 standard in single precision and double precision.

    The following points are from the programming model.

    There are three modes of operations:

    1. Thumb State
      1. Thread mode: Privileged
      2. Thread mode: Unprivileged
    2. Debug mode

    Two thread mode are given to support a operating system. Kernel software run in priviledged mode and the user application software runs in unprivledged mode.

    Unprivileged mode has some restriction on memory access.

    Privileged mode has full access to system resources.

    If an operating system is running and a user application needs to access the Privileged resources it has to generate an exception/interrupt and then the interrupt will be taken by the handler and put the system in privilege mode.

    You can switch from privilege mode to unprivileged mode by setting nPRIV and SPSEL bit in the CONTROL register.

    Just like all the other processors ARM Cotex M4 has registers and pointer registers.

    The major difference is the use of two different stack pointer registers.

    1. Main Stack Pointer (MSP)
    2. Process Stack Pointer (PSP)

    If application is running in privileged mode than main stack pointer will be used. And if the application is working in unprivileged the process stack pointer will be used.

    General Purpose Registers:

    R0 – R12 – General Purpose Register

    R13 – Stack Pointer (SP) {MSP and PSP}

    R14 – Link Register (LR)

    R15 – program counter (PC)

    Special registers:

    • xPSR – {APSR, EPSR, IPSR}
    • FAULTMASK
    • BASEPERI
    • PRIMASK
    • CONTROL
    floating point registers of arm cortex m4f

    There are 32 FPU registers from s0 to s31.

    They group together to form a single 64-bit register. which are from D0 to D15

    There is a Floating Point Status and Control Register (FPSCR).

  • ARM Processor Based Microcontrollers from ST

    There are lot of ARM based microcontroller offered by ST.

    They use ARM Cortex M processor with ST peripheral such as GPIO, ADC etc.

    They mostly fall into these following groups:

    1. ARM Cortex M0
    2. ARM Cortex M3
    3. ARM Cortex M4
    4. ARM Cortex M33
    5. ARM Cortex M7
      which is also known as M4F as it has an FPU unit.

    Then there is ST classification :

    • High performance
      Higher clock speed, Has almost everything included from that segment.
    • Mainstream
      Balanced between Low Power and High Performance.
    • Low Power
      Clock speed reduced to a limit, Has additional hardware for switching off individual peripherals.
    • Wireless
      Has cortex M0+, Peripherals support for radio

    The widely available stm32f1 microcontroller also known as the blue pill has ARM cortex M3.

    STM32L4 has an ARM Cortex M4F.

  • The command-line argument in C

    Lets say if we want our program to work with other programs and other program call our program. Then just like how we provide arguments in function call; we can call our program and the arguments can be given using the command line.

    #include <stdio.h>
    #include <string.h>
    
    int main(int argc, char* argv[]){
    	int arr[5] = {1,2,3,4,5};
    
    	printf("the argument number of of main argc : %d\n",argc);
    	printf("The first argument : %s\n",argv[1]);
    	
    	return 0;
    }
    
    
    

    argc contains the number of argument passed to the main function.

    argv is the argument vector. Contains the argument given from index 1 and above.

    index 0 of argv is the file name of the function.

  • Union

    Union is another user defined data type.

    The difference between union and struct is that; struct uses a contagious memory allocation for each individual item inside it; whereas union uses the size of biggest element for allocation of memory.

    union segment1 {
    int x1;
    char y2;
    };
    
    // sizeof segement1 union is 4 bytes 
    
    struct segment2{
    int x1;
    char y2;
    };
    
    // sizeof segement1 union is 8 bytes 

  • Convert program written in C into assembly

    Sometimes to understand code , you need to look into assembly language. I write mostly using C. So sometimes to better understand the program i converte the program into assembly. The syntax changes from machine to machine.

    Here is the program that i will use to convert to assembly using two different machine. One is ARM based and the other is x86_64.

    #include <stdio.h>
    
    struct CarDetail{
    int CarNumber;
    char CarOptions;
    };
    
    int main() {
    struct CarDetail maruti_alto;
    
    maruti_alto.CarNumber = 123;
    maruti_alto.CarOptions = 'L';
    
    printf("Maruti Alto Details\nNumber = \t%d\nOptions = \t%c",maruti_alto.CarNumber,maruti_alto.CarOptions);
    return 0;
    }

    ARM

    If i convert the above program using ARM based machine using command

    gcc main.c -S -o main.s
            .arch armv6
    	.file	"main.c"
    	.text
    	.section	.rodata
    	.align	2
    .LC0:
    	.ascii	"Maruti Alto Details\012Number = \011%d\012Options ="
    	.ascii	" \011%c\000"
    	.text
    	.align	2
    	.global	main
    	.arch armv6
    	.syntax unified
    	.arm
    	.fpu vfp
    	.type	main, %function
    main:
    	@ args = 0, pretend = 0, frame = 8
    	@ frame_needed = 1, uses_anonymous_args = 0
    	push	{fp, lr}
    	add	fp, sp, #4
    	sub	sp, sp, #8
    	mov	r3, #123
    	str	r3, [fp, #-12]
    	mov	r3, #76
    	strb	r3, [fp, #-8]
    	ldr	r3, [fp, #-12]
    	ldrb	r2, [fp, #-8]	@ zero_extendqisi2
    	mov	r1, r3
    	ldr	r0, .L3
    	bl	printf
    	mov	r3, #0
    	mov	r0, r3
    	sub	sp, fp, #4
    	@ sp needed
    	pop	{fp, pc}
    .L4:
    	.align	2
    .L3:
    	.word	.LC0
    	.size	main, .-main
    	.ident	"GCC: (Raspbian 8.3.0-6+rpi1) 8.3.0"
    	.section	.note.GNU-stack,"",%progbits
    

    If we want to remove relative addressing modes and make it very simple you can use -fomit-frame-pointer option

    gcc main.c -S -fomit-frame-pointer -o main-omit-fp.s
            .arch armv6
    	.file	"main.c"
    	.text
    	.section	.rodata
    	.align	2
    .LC0:
    	.ascii	"Maruti Alto Details\012Number = \011%d\012Options ="
    	.ascii	" \011%c\000"
    	.text
    	.align	2
    	.global	main
    	.arch armv6
    	.syntax unified
    	.arm
    	.fpu vfp
    	.type	main, %function
    main:
    	@ args = 0, pretend = 0, frame = 8
    	@ frame_needed = 0, uses_anonymous_args = 0
    	str	lr, [sp, #-4]!
    	sub	sp, sp, #12
    	mov	r3, #123
    	str	r3, [sp]
    	mov	r3, #76
    	strb	r3, [sp, #4]
    	ldr	r3, [sp]
    	ldrb	r2, [sp, #4]	@ zero_extendqisi2
    	mov	r1, r3
    	ldr	r0, .L3
    	bl	printf
    	mov	r3, #0
    	mov	r0, r3
    	add	sp, sp, #12
    	@ sp needed
    	ldr	pc, [sp], #4
    .L4:
    	.align	2
    .L3:
    	.word	.LC0
    	.size	main, .-main
    	.ident	"GCC: (Raspbian 8.3.0-6+rpi1) 8.3.0"
    	.section	.note.GNU-stack,"",%progbits
    

    X86_64

    gcc main.c -S -o main.s
    	.file	"main.c"
    	.text
    	.section	.rodata
    	.align 8
    .LC0:
    	.string	"Maruti Alto Details\nNumber = \t%d\nOptions = \t%c"
    	.text
    	.globl	main
    	.type	main, @function
    main:
    .LFB0:
    	.cfi_startproc
    	pushq	%rbp
    	.cfi_def_cfa_offset 16
    	.cfi_offset 6, -16
    	movq	%rsp, %rbp
    	.cfi_def_cfa_register 6
    	subq	$16, %rsp
    	movl	$123, -8(%rbp)
    	movb	$76, -4(%rbp)
    	movzbl	-4(%rbp), %eax
    	movsbl	%al, %edx
    	movl	-8(%rbp), %eax
    	movl	%eax, %esi
    	leaq	.LC0(%rip), %rdi
    	movl	$0, %eax
    	call	printf@PLT
    	movl	$0, %eax
    	leave
    	.cfi_def_cfa 7, 8
    	ret
    	.cfi_endproc
    .LFE0:
    	.size	main, .-main
    	.ident	"GCC: (Debian 8.3.0-6) 8.3.0"
    	.section	.note.GNU-stack,"",@progbits
    
    gcc main.c -S -fomit-frame-pointer -o main-omit-fp.s
    	.file	"main.c"
    	.text
    	.section	.rodata
    	.align 8
    .LC0:
    	.string	"Maruti Alto Details\nNumber = \t%d\nOptions = \t%c"
    	.text
    	.globl	main
    	.type	main, @function
    main:
    .LFB0:
    	.cfi_startproc
    	subq	$24, %rsp
    	.cfi_def_cfa_offset 32
    	movl	$123, 8(%rsp)
    	movb	$76, 12(%rsp)
    	movzbl	12(%rsp), %eax
    	movsbl	%al, %edx
    	movl	8(%rsp), %eax
    	movl	%eax, %esi
    	leaq	.LC0(%rip), %rdi
    	movl	$0, %eax
    	call	printf@PLT
    	movl	$0, %eax
    	addq	$24, %rsp
    	.cfi_def_cfa_offset 8
    	ret
    	.cfi_endproc
    .LFE0:
    	.size	main, .-main
    	.ident	"GCC: (Debian 8.3.0-6) 8.3.0"
    	.section	.note.GNU-stack,"",@progbits
    
  • Struct

    Variables are used for storage of individual data elements. But what if we want to group different data element and use them as a individual element.

    //Example 1
    #include <stdio.h>
    struct tag_name {
    int x;
    char y;
    float z;
    }element1;
    
    int main() {
    struct tag_name element2;
    
    element1.x = 1;
    element1.y = 'a';
    element1.z = 3.14;
    
    element2.x = eletment1.x;
    element2.y = eletment1.y;
    element2.z = eletment1.z;
    
    printf("element 1\nx = %d \ty = %c \tz= %f\nelement 2\nx = %d \ty = %c \tz= %f\n", element1.x,element1.y,element1.z,element2.x,element2.y,element2.z);
    return 0;
    }
    Struct example 1 Code Output
    Struct example 1 Code Output

    Nesting Struct is a way of creating more complex data structure.

    // Example 2
    #include <stdio.h>
    
    typedef struct {
    int x;
    char y;
    } point;
    
    int main() {
    point p1, *ptPtr;
    
    p1.x = 9;
    p1.y = 'x';
    
    printf("p1.x = %d\n",p1.x);
    printf("p1.y = %c\n",p1.y);
    
    struct line {
    point pt1;
    point pt2;
    };
    
    struct line l1, *l1Ptr;
    
    l1Ptr = &l1;
    ptPtr = &l1.pt1;
    
    l1.pt1.x = 44;
    l1.pt1.y = 'r';
    
    printf("l1.pt1.x = %d\n",l1.pt1.x);
    printf("l1.pt1.y = %c\n",l1.pt1.y);
    
    printf("l1.pt1.x = %d\n",l1Ptr->pt1.x);
    printf("l1.pt1.y = %c\n",ptPtr->y);
    
    
    return 0;
    }
    
    
    
    Example 2 output

  • First Program in C language

    The very first program in every language is “Hello World”. You can compile this program very easily.

    // a single line comment
    
    /*
    * A multi line comment
    */
    
    #include <stdio.h> // Header File
    
    int main()         // Marks the start of program 
    { 
        printf("Hello World!\n"); // Prints the "hello world" statement onto the
                                  // serial output device such as monitor.
    return 0;
    }
  • Operating System and Embedded System

    An operating system is a software that runs directly on the hardware.

    It comes in between user software and hardware. The operating system is a combination of different software’s. Every software that operating system has to perform functions to manage the memory, processing time and complete utilization of resources without any deadlock situations.

    At the very core of an operating system is a scheduler, which is guided by a Timer. The timer provides the regular interval for the scheduler to run. The job of the scheduler is to run various user program. It also monitors and controls the allocation of memory space to each user program.

    An operating system can be classified as

    • real-time
    • single user
    • multi-user
    • multitasking
    • multiprocessing
    • general-purpose

    Real-Time OS:
    These are operating which respond to an event( internal or external) in a specified unit of time. If the system does not respond to the event in a specified unit of time; it corresponds to the failure of the system.

    There are two major classifications of real-time os:
    1. Hard Real-Time OS
    2. Soft Real-Time OS

    Hard Real-Time OS: These are the system which absolutely must respond to an event within a specified unit of time with the appropriate action. And that action is strictly governed and monitored. Failure of the OS in response time results in total system loss. Example: Network communication operating system running in mainframes to provide backbone infrastructure of voice-based communication such as PBX, POTS, Wireless Mobile Communication etc.

    Soft Real-Time OS: These are also real-time operating but they are not so strict at hard real-time operating system. A missed event will not lead to a catastrophic loss. Example: General-pupose mobile devices operating system is soft real time operating system; in the event of incoming call the operating system may not respond to the user input and give priority to the incoming call notification from the modem.

    Majorly embedded system have small memory and processing footprint. So to accommodate a ready made solution is very much out of the equation. You have to either heavily customize the operating system or make your own scheduler.

    There are different real-time operating system provider
    1. FreeRTOS
    2. uC RTOS
    3. mbed RTOS
    4. CMSIS-RTOS

  • Data Structure and Algorithm

    Data is acquired by the embedded system. That data may be numbers, voice data, image data etc.. This data needs to be stored. The problem comes when you have multiple streams of data coming in and you have to store them.

    Algorithms helps us in doing just. They helps us in managing the Storage, Retrieval and data manipulation. There are many ways to data the said things. But the selection of different algorithms depends on the circumstances. So before implementing any algorithms we have to carefully study the present and some future circumstances( Based on past trends).

    It is likely that any system designed for today’s circumstances will grow in future. So to accommodate the scalability, the designer should select the system which can incorporate all these in future.

    For example: Let me consider a APU. An APU is nothing but a combination of different logic circuit that can manipulate the data. The APU can be designed around using only one full adder and all the higher functionality can be implemented in software algorithms. Or we can implement the different logical implementation such as subtractor, multiplier, integrator and differentiator etc.
    You can use adder to implement multiplication.
    You can use adder to implement division. As subtraction can be done by using addition. and then it can be used to implement division.

    The right selection of algorithms is crucial in the initial stages of system design.
    For a static system which will not be revised further it becomes even more difficult as you have to consider a lot of things.
    For a dynamic update based system you can start with the algorithm which is based on the current requirement and in future you can always alter the system. But the system must update the algorithm so that had to be done prior to any modification.

  • Memory Management

    The memory is limited. And since it is limited it becomes a precious resource. So you have to manage the memory from the beginning of the embedded system.

    Most of the code written for embedded system will be in c or in c++ using an IDE. The code will then built by the compiler in the IDE. Compiler will take your code and translate the code into the machine language or the language which your system understands.

    Compilers does a decent amount of memory management. But they have limitations. As the size and complexity of your code increase the struggle of the compiler to manage the memory also increase.

    So knowing about memory optimization’s from the beginning is good.

    In a very basic memory managed model of programming, never make your complete code execute from the main() function. Instead call the sub-functions from the main() and allocate memory at the beginning and do the data processing. After the data processing save the elements in their corresponding memory locations. Deallocate the memory when the data processing is over and return the main function.