Embedded Interview Questions
Embedded Interview Questions
The volatile keyword is a type qualifier that prevents the objects from the compiler
optimization. According to C standard, an object that has volatile-qualified type may be
modified in ways unknown to the implementation or have other unknown side effects.
You can also say that the value of the volatile-qualified object can be changed at any time
without any action being taken by the code. If an object is qualified by the volatile
qualifier, the compiler reloads the value from memory each time it is accessed by the
program that means it prevents from to cache a variable into a register. Reading the value
from the memory is the only way to check the unpredictable change of the value.
In another side volatile prevent from any compiler optimization and says that the value of
the object can be changed by something that is beyond the control of the program and so
that compiler will not make any assumption about the object.
e.g,
volatile int a;
When the compiler sees the above declaration then it avoids to make any assumption
regarding the “a” and in every iteration read the value from the address which is assigned
to the variable.
Can a variable be both constant and volatile in C?
Yes, we can use both constant and volatile together. One of the great use of volatile and
const keyword together is at the time of accessing the GPIO registers. In case of GPIO,
its value can be changed by the ‘external factors’ (if a switch or any output device is
attached with GPIO), if it is configured as an input. In that situation, volatile plays an
important role and ensures that the compiler always read the value from the GPIO
address and avoid to make any assumption.
After using the volatile keyword, you will get the proper value whenever you are
accessing the ports but still here is one more problem because the pointer is not const
type so it might be your program change the pointing address of the pointer. So we have
to create a constant pointer with volatile keyword.
Syntax of declaration,
In above line, we have already read that the ISR is not called by the code, so there is no
calling code to read the returned values of the ISR. It is the reason that an ISR is not
returned any value.
The Cortex-M processors have the very low interrupt latency. In below table, I have
mentioned, Interrupt latency of Cortex-M processors with zero wait state memory
systems.
Cortex-M0+ 15
Cortex-M3 12
Cortex-M4 12
Cortex-M7 12
The interval between the two signals (interrupt latency) may be easily read from the
instrument.
How to reduce the interrupt latency?
The interrupt latency depends on many factors, some factor I am mentioning in below
statements.
So using the proper selection of platform and processor we can easily reduce the interrupt
latency. We can also reduce the interrupt latency by making the ISR shorter and avoid to
calling a function within the ISR.
If you want to learn STM32 from scratch, you should follow this course “Mastering
Microcontroller with Embedded Driver Development“. The course contains video
lectures of 18.5-hours length covering all topics like, Microcontroller & Peripheral
Driver Development for STM32 GPIO, I2C, SPI, USART using Embedded C.
Enroll In Course
The Cortex-M3 and Cortex-M4 processors the NVIC supports up to 240 interrupt inputs,
with 8 up to 256 programmable priority levels
Can we use any function inside ISR?
Yes, you can call a function within the ISR but it is not recommended because it can
increase the interrupt latency and decrease the performance of the system. If you want to
call a nested function within the ISR, you need to read the datasheet of your
microcontroller because some vendors have a limit to how many calls can be nested.
One important point also needs to remember that function which is called from the ISR
should be re-entrant. If the called function is not re-entrant, it could create the issues.
For example,
If the function is not reentrant and supposes that it is called by another part of the code
beside the ISR. So the problem will be invoked when if the ISR calls the same function
which is already invoked outside of the ISR?
There are the different way to create an infinite loop, here I am mentioning some
methods.
Method 1:
while(1)
{
// task
}
Method 2:
for(;;)
{
// task
}
Method 3:
Loop:
goto Loop;
RISC CISC
Acronym It stands for ‘Reduced Instruction It stands for ‘Complex Instruction
Set Computer’. Set Computer’.
Definition The RISC processors have a The CISC processors have a larger
smaller set of instructions with few set of instructions with many
addressing nodes. addressing nodes.
Memory unit It has no memory unit and uses a It has a memory unit to implement
separate hardware to implement complex instructions.
instructions.
Calculations The calculations are faster and The calculations are slow and
precise. precise.
External memory It does not require external It requires external memory for
memory for calculations. calculations.
Code expansion Code expansion can be a problem. Code expansion is not a problem.
If stack overflow occurs, the program can crash or you can say that segmentation fault
that is the result of the stack overflow.
The important difference between the I2C and SPI communication protocol.
I2C support half duplex while SPI is the full duplex communication.
I2C requires only two wire for communication while SPI requires three or
four wire for communication (depends on requirement).
I2C is slower as compared to the SPI communication.
I2C draws more power than SPI.
I2C is less susceptible to noise than SPI.
I2C is cheaper to implement than the SPI communication protocol.
I2C work on wire and logic and it has a pull-up resistor while there is no
requirement of pull-up resistor in case of the SPI.
In I2C communication we get the acknowledgment bit after each byte, it is
not supported by the SPI communication protocol.
I2C ensures that data sent is received by the slave device while SPI does
not verify that data is received correctly.
I2C support the multi-master communication while multi-master
communication is not supported by the SPI.
One great difference between I2C and SPI is that I2C supports multiple
devices on the same bus without any additional select lines (work on the
basis of device address) while SPI requires additional signal (slave select
lines) lines to manage multiple devices on the same bus.
I2C supports arbitration while SPI does not support the arbitration.
I2C support the clock stretching while SPI does not support the clock
stretching.
I2C can be locked up by one device that fails to release the communication
bus.
I2C has some extra overhead due to start and stop bits.
I2C is better for long distance while SPI is better for the short distance.
In the last I2C developed by NXP while SPI by Motorola.
There is no common clock signal between the sender Communication is done by a shared clock.
and receivers.
Sends 1 byte or character at a time. Sends data in the form of blocks or frames.
A start and stop bit used for the data synchronization. A shared clock is used for the data synchronization.
Economical Costly
Bit rate is the number of bits per second. Baud rate is the number of signal units per second.
It determines the number of bits traveled per second. It determines how many times the state of a signal is
changing.
Cannot determine the bandwidth. It can determine how much bandwidth is required to
send the signal.
This term generally used to describe the processor This term generally used to describe the data
efficiency. transmission over the channel.
Bit rate = baud rate x the number of bits per signal Baud rate = bit rate / the number of bits per signal unit
unit
Generally, the segmentation fault occurs when a program tried to access a memory
location that it is not allowed to access or tried to access a memory location in a way that
is not allowed (tried to access read-only memory).
What are the common causes of segmentation
fault in C?
There are many reasons for the segmentation fault, here I am listing some common
causes of the segmentation fault.
Non-existent address.
Unaligned access.
Paging errors
Primarily size of integer depends on the type of the compiler which has written by
compiler writer for the underlying processor. You can see compilers merrily changing the
size of integer according to convenience and underlying architectures. So it is my
recommendation use the C99 integer data types ( uin8_t, uin16_t, uin32_t ..) in place of
standard int.
A signed integer can store the positive and negative value both but beside
it unsigned integer can only store the positive value.
The range of nonnegative values of a signed integer type is a sub-range of
the corresponding unsigned integer type.
For example,
Assuming size of the integer is 2 bytes.
signed int -32768 to +32767
unsigned int 0 to 65535
When computing the unsigned integer, it never gets overflow because if
the computation result is greater than the largest value of the unsigned
integer type, it is reduced modulo the number that is one greater than the
largest value that can be represented by the resulting type.
For example,
Computational Result % (Largest value of the unsigned integer+1)
The overflow of signed integer type is undefined.
If Data is signed type negative value, the right shifting operation of Data is
implementation dependent but for the unsigned type, it would be Data/
2pos.
If Data is signed type negative value, the left shifting operation of Data
show the undefined behavior but for the unsigned type, it would be Data x
2pos.
What is the difference between a macro and a
function?
typedef:
The C language provides a very important keyword typedef for defining a new name for
existing types. The typedef is the compiler directive mainly use with user-defined data
types (structure, union or enum) to reduce their complexity and increase the code
readability and portability.
Syntax,
typedef type NewTypeName;
Now UnsignedInt is a new type and using it, we can create a variable of unsigned int.
UnsignedInt Mydata;
In above example, Mydata is variable of unsigned int.
Note: A typedef creates synonyms or a new name for existing types it does not create new
types.
Macro:
A macro is a pre-processor directive and it replaces the value before compiling the
code.One of the major problem with the macro that there is no type checking. Generally,
the macro is used to create the alias, in C language macro is also used as a file guard.
Syntax,
#define Value 10
Now Value becomes 10, in your program, you can use the Value in place of the 10.
An enumeration increases the readability of the code and easy to debug in comparison of
symbolic constant (macro).
The most important thing about the enum is that it follows the scope rule and compiler
automatic assign the value to its member constant.
Note: A variable of enumeration type stores one of the values of the enumeration list
defined by that type.
Syntax of enum,
enum Enumeration_Tag { Enumeration_List };
Example,
enum FLASH_ERROR { DEFRAGMENT_ERROR, BUS_ERROR};.
Clearing a Bits
Bitwise AND operator (&) use to clear a bit of integral data type. “AND” of two bits is
always zero if any one of them is zero.To clear the nth bit, first, you need to invert the
string of bits then AND it with the number.
Checking a Bits
To check the nth bit, shift the ‘1’ nth position toward the left and then “AND” it with the
number.
Toggling a Bits
Bitwise XOR (^) operator use to toggle the bit of an integral data type. To toggle the nth
bit shift the ‘1’ nth position toward the left and “XOR” it.
1 #include <stdio.h>
2
3 int main()
4 {
5 int a = 10, b = 5;
6
7 // algo to swap 'a' and 'b'
8 a = a + b; // a becomes 15
9 b = a - b; // b becomes 10
10 a = a - b; // fonally a becomes 5
11
12 printf("After Swapping the value of: a = %d, b = %d\n\n", a, b);
13
14 return 0;
15 }
1 #include <stdio.h>
2
3 int main()
4 {
5 int a = 10, b = 5;
6
7 // algo to swap 'a' and 'b'
8 a = a ^ b; // a becomes (a ^ b)
9 b = a ^ b; // b = (a ^ b ^ b), b becomes a
10 a = a ^ b; // a = (a ^ b ^ a), a becomes b
11
12 printf("After Swapping the value of: a = %d, b = %d\n\n", a, b);
13
14 return 0;
15 }
Padding has increased the performance of the processor at the penalty of memory.In
structure or union data members aligned as per the size of the highest bytes member to
prevent from the penalty of performance.
Note: Alignment of data types mandated by the processor architecture, not by language.
What is the endianness?
The endianness is the order of bytes to store data in memory and it also describes the
order of byte transmission over a digital link. In memory data store in which order it
depends on the endianness of the system, if the system is big-endian then the MSB byte
store first (means at lower address) and if the system is little-endian then LSB byte store
first (means at lower address).
Big-endian
The most significant byte of data stored at the lowest memory address.
Little-endian
The least significant byte of data stored at the lowest memory address.
Note: Some processor has the ability to switch one endianness to other endianness using
the software means it can perform like both big endian or little endian at a time. This
processor is known as the Bi-endian, here are some architecture (ARM version 3 and
above, Alpha, SPARC) who provide the switchable endianness feature.
Write a c program to check the endianness of the
system.
Method 1:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <inttypes.h>
4
5 int main(void)
6 {
7 uint32_t u32RawData;
8 uint8_t *pu8CheckData;
9 u32RawData = 0x11223344; //Assign data
10
11 pu8CheckData = (uint8_t *)&u32RawData; //Type cast
12
13 if (*pu8CheckData == 0x44) //check the value of lower address
14 {
15 printf("little-endian");
16 }
17 else if (*pu8CheckData == 0x11) //check the value of lower address
18 {
19 printf("big-endian");
20 }
21
22
23 return 0;
24 }
Method 2:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <inttypes.h>
4
5 typedef union
6 {
7
8 uint32_t u32RawData; // integer variable
9 uint8_t au8DataBuff[4]; //array of character
10
11 }RawData;
12
13
14 int main(void)
15 {
16 RawData uCheckEndianess;
17 uCheckEndianess.u32RawData = 0x11223344; //assign the value
18
19 if (uCheckEndianess.au8DataBuff[0] == 0x44) //check the array first index value
20 {
21 printf("little-endian");
22 }
23 else if (uCheckEndianess.au8DataBuff[0] == 0x11) //check the array first index value
24 {
25 printf("big-endian");
26 }
27
28 return 0;
29 }
Method 1:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <inttypes.h>
4
5 //Function to change the endianess
6 uint32_t ChangeEndianness(uint32_t u32Value)
7 {
8 uint32_t u32Result = 0;
9 u32Result |= (u32Value & 0x000000FF) << 24;
10 u32Result |= (u32Value & 0x0000FF00) << 8;
11 u32Result |= (u32Value & 0x00FF0000) >> 8;
12 u32Result |= (u32Value & 0xFF000000) >> 24;
13 return u32Result;
14 }
15
16
17 int main()
18 {
19 uint32_t u32CheckData = 0x11223344;
20 uint32_t u32ResultData =0;
21 u32ResultData = ChangeEndianness(u32CheckData); //swap the data
22 printf("0x%x\n",u32ResultData);
23 u32CheckData = u32ResultData;
24 u32ResultData = ChangeEndianness(u32CheckData);//again swap the data
25 printf("0x%x\n",u32ResultData);
26 return 0;
27 }
When we allocate the memory using the memory management function, they return a
pointer to the allocated memory block and the returned pointer is pointing to the
beginning address of the memory block. If there is no space available, these functions
return a null pointer.
What is the memory leak in C?
A memory leak is a common and dangerous problem. It is a type of resource leak. In C
language, a memory leak occurs when you allocate a block of memory using the memory
management function and forget to release it.
1 int main ()
2{
3
4 char * pBuffer = malloc(sizeof(char) * 20);
5
6 /* Do some work */
7
8 return 0; /*Not freeing the allocated memory*/
9}
Note: once you allocate a memory than allocated memory does not allocate to another
program or process until it gets free.
In C language,calloc function initialize the all allocated space bits with zero but malloc
does not initialize the allocated memory. These both function also has a difference
regarding their number of arguments, malloc take one argument but calloc takes two.
The calloc function first deallocates the old object and allocates again with newly
specified size. If the new size is lesser to the old size, the contents of the newly allocated
memory will be same as prior but if any bytes in the newly created object goes beyond
the old size, the values of the exceeded size will be indeterminate.
Syntax:
void *realloc(void *ptr, size_t size);
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 int main ()
6 {
7 char *pcBuffer = NULL;
8 /* Initial memory allocation */
9 pcBuffer = malloc(8);
10
11 strcpy(pcBuffer, "aticle");
12 printf("pcBuffer = %s\n", pcBuffer);
13
14 /* Reallocating memory */
15 pcBuffer = realloc(pcBuffer, 15);
16
17 strcat(pcBuffer, "world");
18 printf("pcBuffer = %s\n", pcBuffer);
19
20 //free the allocated memory
21 free(pcBuffer);
22
23 return 0;
24 }
Output:
pcBuffer = aticle
pcBuffer = aticleworld
Note: It should be used for dynamically allocated memory but if a pointer is a null
pointer, realloc behaves like the malloc function.
What is the return value of malloc (0)?
If the size of the requested space is zero, the behavior will be implementation-defined.
The return value of the malloc could be a null pointer or it shows the behavior of that size
is some nonzero value.It is suggested by the standard to not use the pointer to access an
object that is returned by the malloc while size is zero.
The external fragmentation is due to the small free blocks of memory (small memory
hole) that is available on the free list but program not able to use it. There are different
types of free list allocation algorithms that used the free memory block efficiently.
Whenever we called the malloc function then it reserves some extra bytes (depend on
implementation and system) for bookkeeping. This extra byte is reserved for each call of
malloc and become a cause of the internal fragmentation.
For example,
See the below code, the programmer may think that system will be allocated 8 *100 (800)
bytes of memory but due to bookkeeping (if 8 bytes) system will be allocated 8*100 extra
bytes. This is an internal fragmentation, where 50% of the heap waste.
1 char *acBuffer[100];
2
3 int main()
4 {
5 int iLoop = 0;
6 while(iLoop < 100)
7 {
8 acBuffer[iLoop ] = malloc(8);
9 ++iLoop;
10
11 }
12
13 }
Whenever we call the free function and pass the pointer that is pointing to allocated
memory, the free function gets the bookkeeping information and release the allocated
memory. Anyhow if you or your program change the value of the pointer that is pointing
to the allocated address, the calling of free function give the undefined result.
In the other word, we can say, a function pointer is a type of pointer that store the address
of a function and these pointed function can be invoked by function pointer in a program
whenever required.
For the better understanding, let’s take an example to describe the declaration of a
function pointer in c.
e.g,
void ( *pfDisplayMessage) (const char *);
1 #include <stdio.h>
2
3 int main()
4 {
5 int x = -15;
6
7 x = x << 1;
8
9 printf("%d\n", x);
10 }
Output:
undefined behavior.
1 #include <stdio.h>
2
3 int main()
4 {
5 int x = -30;
6
7 x = x >> 1;
8
9 printf("%d\n", x);
10 }
Output:
implementation-defined.
According to C standard, the pointer to void shall have the same representation and
alignment requirements as a pointer to a character type.A void pointer declaration is
similar to the normal pointer, but the difference is that instead of data types we use the
void keyword.
Syntax:
void * Pointer_Name;
1 #include<stdio.h>
2 #include<stdlib.h>
3
4 int main()
5 {
6 int *piData = NULL;
7
8 piData = malloc(sizeof(int)* 10); //creating integer of size 10.
9
10 free(piData); //free the allocated memory
11
12 *piData = 10; //piData is dangling pointer
13
14 return 0;
15
16 }
In simple word, we can say that dangling pointer is a pointer that not pointing a valid
object of the appropriate type and it can be the cause of the undefined behavior.
In the other word, we can say every pointer in programming languages that are not
initialized either by the compiler or programmer begins as a wild pointer.
Syntax,
int *piData; //piData is wild pointer.
Syntax,
int *piData = NULL; // piData is a null pointer
If you are reading a flash memory byte by bytes through the character pointer then here
you have to use the post-increment, either you will skip the first byte of the data. Because
we already know that in case of pre-increment pointing address will be increment first
and after that, you will read the value.
1 #include <stdio.h>
2
3 int main(void)
4 {
5
6 char acData[5] ={'A','B','C','D','E'};
7 char *pcData = NULL;
8
9 pcData = acData;
10
11 printf("%c ",*++pcData);
12
13 return 0;
14 }
But in place of pre-increment if we use post-increment then the problem is getting solved
and you will get A as the output.
1 #include <stdio.h>
2
3 int main(void)
4 {
5
6 char acData[5] ={'A','B','C','D','E'};
7 char *pcData = NULL;
8
9 pcData = acData;
10
11 printf("%c ",*pcData++);
12
13 return 0;
14 }
Besides that, when we need a loop or just only need to increment the operand then pre-
increment is far better than post-increment because in case of post increment compiler
may have created a copy of old data which takes extra time. This is not 100% true
because nowadays compiler is so smart and they are optimizing the code in a way that
makes no difference between pre and post-increment. So it is my advice, if post-
increment is not necessary then you have to use the pre-increment.
Note: Generally post-increment is used with array subscript and pointers to read the data,
otherwise if not necessary then use pre in place of post-increment.Some compiler also
mentioned that to avoid to use post-increment in looping condition.
iLoop = 0.
Explanation:
In the above example, two operators are involved and both have the same precedence
with a right to left associativity. So the above expression ++*p is equivalent to ++ (*p).
In another word, we can say it is pre-increment of value and output is 101, 200, 101.
1 #include <stdio.h>
2
3 int main(void)
4 {
5 int aiData[5] = {100,200,30,40,50};
6
7 int *piData = aiData;
8
9 *++piData;
10
11 printf("aiData[0] = %d, aiData[1] = %d, *piData = %d", aiData[0], aiData[1], *piData);
12
13 return 0;
14 }
Output: 100, 200, 200
Explanation:
In the above example, two operators are involved and both have the same precedence
with the right to left associativity. So the above expression *++p is equivalent to *(++p).
In another word you can say it is pre-increment of address and output is 100, 200,200.
What does the keyword const mean?
A const is only a qualifier, it changes the behavior of a variable and makes it read-only
type. When we want to make an object read-only type, then we have to declare it as
const.
Syntax
const DataType Identifier = Value;
e.g.
const int iData = 0
At the time of declaration, const qualifier only gives the direction to the compiler that
the value of declaring object could not be changed. In simple word, const means not
modifiable (cannot assign any value to the object at the runtime).
Let’s see the below example code when you will compile the below code get the
compiler error.
1 #include<stdio.h>
2
3 int main(void)
4 {
5 int var1 = 10, var2 = 20;
6
7 //Initialize the pointer
8 int *const ptr = &var1;
9
10 //Try to modify the pointer value
11 ptr = &var2;
12
13 printf("%d\n", *ptr);
14
15 return 0;
16 }
Pointer to a constant:
In this scenario the value of pointed address is constant that means we can not change the
value of the address that is pointed by the pointer.
So global variable can be accessed outside of the file but the static global variable only
accesses within the file in which it is declared.
Declaration of variable in c
A variable declaration only provides sureness to the compiler at the compile time
that variable exists with the given type and name, so that compiler proceeds for further
compilation without needing all detail of this variable. In C language, when we declare a
variable, then we only give the information to the compiler, but there is no memory
reserve for it. It is only a reference, through which we only assure to the compiler that
this variable may be defined within the function or outside of the function.
Note: We can declare a variable multiple time but defined only once.
eg,
extern int data;
extern int foo(int, int);
int fun(int, char); // extern can be omitted for function declarations
Definition of variable in c
The definition is action to allocate storage to the variable. In another word, we can say
that variable definition is the way to say the compiler where and how much to create the
storage for the variable generally definition and declaration occur at the same time but
not almost.
eg,
int data;
int foo(int, int) { }
Note: When you define a variable then there is no need to declare it but vice versa is not
applicable.
In this method value of the variable is passed. Changes made to formal will
not affect the actual parameters.
Different memory locations will be created for both variables.
Here there will be temporary variable created in the function stack which
does not affect the original variable.
Pass By Reference :
Aticleworld invites you to try skillshare (Unlimited Access to over 20,000 classes)
Premium free for 2 months.
for example,
Advantages:-
1) It saves the function calling overhead.
2) It also saves the overhead of variables push/pop on the stack, while function calling.
3) It also saves the overhead of return call from a function.
4) It increases locality of reference by utilizing instruction cache.
5) After inlining compiler can also apply intraprocedural optimization if specified. This is
the most important one, in this way compiler can now focus on dead code elimination,
can give more stress on branch prediction, induction variable elimination etc..
Disadvantages:-
1) May increase function size so that it may not fit in the cache, causing lots of cache
miss.
2) After inlining function, if variables number which are going to use register increases
than they may create overhead on register variable resource utilization.
3) It may cause compilation overhead as if somebody changes code inside an inline
function then all calling location will also be compiled.
4) If used in the header file, it will make your header file size large and may also make it
unreadable.
5) If somebody used too many inline functions resultant in a larger code size than it may
cause thrashing in memory. More and number of page fault bringing down your program
performance.
6) It’s not useful for an embedded system where large binary size is not preferred at all
due to memory size constraints.
1 struct sStudentInfo {
2
3 char Name[12];
4 int Age;
5 float Weight;
6 int RollNumber;
7
8 };
9
10
11 #define STUDENT_INFO struct sStudentInfo*
12
13 typedef struct sStudentInfo* studentInfo;
14
15 statement 1
16 STUDENT_INFO p1, p2;
17
18 statement 2
19 studentInfo q1, q2;
Both statements looking same but actually, both are different to each other.
Statement 1 will be expanded to struct sStudentInfo * p1, p2. It means that p1 is a pointer
to struct sStudentInfo but p2 is a variable of struct sStudentInfo.
Here, I have mentioned some questions for you. If you know, please write in comment
box. Might be your comment helpful for other.
EPROM is a nonvolatile memory that retains data even after the power is
switched off. The EPROM contains the computer BIOS used during the boot
up of the computer. It is a read-only memory whose content can be erased
by exposing the EPROM chip to ultraviolet light.
EPROM is read and written electrically; before a write operation, all the storage cells
must be erased to the same initial state by exposure of the packaged chip to ultraviolet
radiation. Erasure is performed by shining an intense ultraviolet light through a window
that is designed into the memory chip.
EEPROM is a read- mostly memory that can be written into at any time without erasing
prior contents; only the byte or bytes addressed are updated.
Flash memory is intermediate between EPROM and EEPROM in both cost and
functionality. Like EEPROM, flash memory uses an electrical erasing technology. An
entire flash memory can be erased in one or a few seconds, which is much faster than
EPROM. In addition, it is possible to erase just blocks of memory rather than an entire
chip. However, flash memory does not provide byte-level erasure. Like EPROM, flash
memory uses only one transistor per bit, and so achieves the high density (compared
with EEPROM) of EPROM
What is the difference between Volatile & Non Volatile Memory?
Volatile Memory :
A device which holds the data as long as it has power supply connected to it and cannot
hold the memory when there is no power supply connected to it is called Volatile
Memory. The best example for this can be Random Access Memory ( RAM ), which will
hold memory only as long as it is connected to power source and everything in it will be
cleared if it gets disconnected from power source. Volatile memory is also called as
temporary memory as it will hold memory temporarily.
A device which can hold data in it even if it is not connected to any power source is
called Non Volatile Memory. The typical examples for Non Volatile Memory are your
Hard drives and flash drives. Even if you turn off your PC the data in your hard drive or
flash drive stays intact.
The watchdog timer is an important device in the embedded system , which is used to
develop reliable products. Most of the embedded systems need to be self-reliant in order
to restart and restore the system if any software bug disturbs the system. It is not always
possible for human operators to wait for rebooting the system for every software
problem. The watchdog timer is a piece of hardware that provides ultimate solutions for
the real-time industries, which used to detect system abnormalities automatically and to
reset the processor.
The watchdog timer is a simple electronic device that is responsible to resetting the
microcontroller or microprocessor for invalid software status. Generally
a microcontroller is programmed with software that contains several loops and number
of subroutines that direct variety of activities. If any reason, if the loop isfail to execute,
then it finds and resets the device at starting or top of the loop.
T-ON
Duty Cycle % = x 100
T-ON + T-OFF
Example :
T-ON = 3.5ms
T-OFF = 6.5ms
Hence , DutyCyle = 35%
PWM Edges
A PWM signal contains 2 types of Edges which are called Leading Edge and Trailing Edge. The
Diagram shown below explains this:
Types of PWM
PWM Signal can be Classified in Different ways. However , I would like to classify PWM as :
1) Single Edge PWM
2) Double Edge PWM
In Leading Edge PWM the Trailing Edge is fixed at the End of a Period and the Leading Edge is
Modulated i.e. Varied. Diagram for Leading Edge(Right Aligned) PWM:
In case the Low State Represents a Negative Voltage then the above equation can be generalized
as follows :
Vaverage = (DutyCycle x VH) + ((1-D) x VL)
Where , VH = Voltage for High State & VL = Voltage for Low State
This can be converted into an Analog Voltage by Using a Simple R-C filter.
Note : This Tutorial is a supplementary material for tutorials on PWM generation using MCUs like
LPC176x , LPC214x , etc..