Open PranabNandy opened 3 months ago
Static vs. Dynamic Linking and Loading
Whether youโre just starting out or youโre a seasoned pro, itโs always good to refresh our knowledge on these fundamental concepts. So, letโs break it down!
Static Linking: ๐ Imagine youโre baking a cake, and you mix all your ingredients (code libraries) directly into the batter (your program). Once baked, everything is a single, solid cake. This is what static linking does โ it combines all the necessary libraries with your code into one executable file at compile time. The result? Fast execution because everythingโs already in place, but it comes at the cost of a larger file size. ๐ฆ
Dynamic Linking: ๐ Now, picture making a cake but keeping the frosting (code libraries) separate until you serve it. This is dynamic linking โ your program and its libraries remain separate entities. The linking happens at runtime, meaning the program will call the necessary libraries when needed. This keeps your executable smaller and allows updates to libraries without recompiling the entire program, but it can be a bit slower due to the additional steps during execution. โก
Loading: ๐ Both static and dynamic linking involve loading. For static, the loading happens once when the program is started. For dynamic, loading can happen multiple times during the programโs execution, whenever a library is needed.
Adding Sugar to the Frosting: ๐ฐ Think about dynamic linking like deciding to add more sugar to the frosting just before serving the cake. If you realize your frosting (code library) needs a tweak or an update, you can easily mix in the extra sugar (update the library) without having to rebake the entire cake (recompile the program). This flexibility is a huge advantage in environments where updates and changes are frequent.
When to Use What? ๐ ๏ธ Use static linking when you need speed and donโt mind the larger file size, like in embedded systems where you want everything tightly packed and optimized for performance.
๐ ๏ธ Use dynamic linking when you want flexibility and ease of updates, perfect for applications where libraries might change or get updated frequently.
In the end, the choice between static and dynamic linking and loading depends on your specific needs and constraints. Understanding these concepts helps us make informed decisions in our software projects.
Happy coding ๐ฅธ
๐ค DMA and๐จโ๐ณ Cooking at Home ๐
๐คWhat is DMA?
Direct Memory Access (DMA) is a feature that allows certain hardware subsystems to access main system memory (RAM) independently of the central processing unit (CPU). In simpler terms, DMA can transfer data between memory and peripherals without burdening the CPU.
Imagine you are cooking a meal๐คค with your spouse. You are busy at the stove, managing multiple dishes, while your spouse๐ helps by fetching ingredients from the fridge and the pantry. If you had to stop cooking every time to get ingredients yourself, it would slow down the whole process๐ข.
In this analogy, imgine you are the CPU, the kitchen is the memory, and your spouse is the DMA controller. Your spouse handles the task of bringing ingredients, allowing you to focus on cooking without interruptions. So you need not to pull out onions potatos and wash hands and go back and start cooking again. Similar is with DMA, cpu need not to worry about waiting for the data and doing data read writes and data flushing itself while executing something more important๐ฅธ
So what does DMA offers ๐ง :
Efficiency and Speed: DMA significantly speeds up data transfers. By offloading the data transfer tasks to the DMA controller, the CPU is free to execute other instructions, leading to more efficient system performance.
Reduced CPU Load: In embedded systems, the CPU often has to manage multiple tasks simultaneously. DMA reduces the CPU's workload by handling the bulk of data movement, allowing the CPU to focus on critical real-time tasks.
Low Power Consumption: Embedded systems, especially those in battery-powered devices, benefit from DMA's ability to perform data transfers with minimal CPU intervention. This helps in conserving power and extending battery life.
Improved Data Handling: DMA is particularly useful for handling large blocks of data, such as streaming audio or video, where timely and efficient data transfer is crucial. It ensures data integrity and smooth operation of multimedia applications.
In summary, DMA is like having a dedicated helper in the kitchen who brings you ingredients while you cook. It enhances efficiency, performance, and power management in embedded systems. Understanding and utilizing DMA can make a significant difference in the design and functionality of embedded applications.
๐ง๐๐ง๐ญ๐๐ซ๐ฏ๐ข๐๐ฐ๐๐ซ: Ok and have you ever worked on ARM Cortex-M0 processors before?
๐๐๐: Yes, I'm familiar with M0 processor. I have worked on it under various projects that i have worked on.
๐ง๐๐ง๐ญ๐๐ซ๐ฏ๐ข๐๐ฐ๐๐ซ: I see, so have you heard about the NVIC in ARM Cortex-M0 processors?
๐๐๐: Yes Its an interrupt controller
๐ง๐๐ง๐ญ๐๐ซ๐ฏ๐ข๐๐ฐ๐๐ซ: Do you know what it stands for ?
๐ฅฒ๐๐: Well the last part "IC" stands for Interrupt controller๐ฌ
๐ซก๐๐ง๐ญ๐๐ซ๐ฏ๐ข๐๐ฐ๐๐ซ: I see ๐, so what its used for in M0 ?
๐คYou: NVIC is a crucial component in ARM Cortex-M0 processors. It serves as the traffic manager for interrupts, ensuring efficient handling of various events.
๐ง๐๐ง๐ญ๐๐ซ๐ฏ๐ข๐๐ฐ๐๐ซ: Can you elaborate more on its role in M0 processor?
๐ค๐๐: NVIC's nested and prioritized structure allows for the seamless handling of multiple interrupt sources. It ensures that critical tasks are addressed promptly, contributing to the overall efficiency of the system.
๐ง๐๐ง๐ญ๐๐ซ๐ฏ๐ข๐๐ฐ๐๐ซ: And how does the NVIC contribute to energy efficiency in embedded systems?
๐ฅธ๐๐: The NVIC helps in energy efficiency by allowing the processor to enter low-power states when not actively processing interrupts. This dynamic power management ensures that the system conserves energy without compromising responsiveness.
๐ง๐๐ง๐ญ๐๐ซ๐ฏ๐ข๐๐ฐ๐๐ซ: Correct and how about real-time responsiveness? How does the NVIC handle high-priority interrupts?
๐ค๐๐: Umm.. NVIC's nested structure enables immediate handling of high-priority interrupts, minimizing latency and ensuring that time-sensitive tasks are executed with precision. This makes it ideal for applications requiring real-time responsiveness, such as sensor networks and motor control systems.
๐ง๐๐ง๐ญ๐๐ซ๐ฏ๐ข๐๐ฐ๐๐ซ: Can we say it has good scalability? or... umm how the NVIC adapts to different project sizes?
๐ค๐๐: NVIC is has good scalability. Whether you're working on a small-scale project or a complex embedded system, the NVIC adapts seamlessly, allowing developers to allocate priorities based on the criticality of each interrupt source. This flexibility empowers developers to fine-tune system behavior to meet the unique demands of their applications.
๐๐๐ง๐ญ๐๐ซ๐ฏ๐ข๐๐ฐ๐๐ซ: Can you name some more Interrupt controllers ?
๐ง๐๐ป๐๐ฒ๐ฟ๐๐ถ๐ฒ๐๐ฒ๐ฟ: "Which paging technique is used in RTOS?"
๐ฅธ๐ ๐ฒ: "In RTOS, demand paging is commonly used."
๐ง๐๐ป๐๐ฒ๐ฟ๐๐ถ๐ฒ๐๐ฒ๐ฟ: "Could you explain what demand paging is?"
๐๐ ๐ฒ: "Certainly! Demand paging is a memory management technique where pages are loaded into memory only when they are required by the executing program. It helps optimize memory usage by bringing in only the necessary pages, reducing overhead and improving overall system performance."
๐ง๐๐ป๐๐ฒ๐ฟ๐๐ถ๐ฒ๐๐ฒ๐ฟ: "Interesting! What is the primary motive of RTOS then?"
๐๐ ๐ฒ: "The primary goal of RTOS is to ensure quick response times and deterministic behavior for real-time applications."
๐๐๐ป๐๐ฒ๐ฟ๐๐ถ๐ฒ๐๐ฒ๐ฟ: "Considering that, can demand paging be used in RTOS?"
๐ฅฒ๐ ๐ฒ: "You're absolutely correct. Given that the primary objective of RTOS is rapid response times, demand paging, with its dynamic loading of pages from disk to memory, might not be suitable."
๐๐๐ป๐๐ฒ๐ฟ๐๐ถ๐ฒ๐๐ฒ๐ฟ: So what do we use in RTOS?
๐ ๐ฒ: ๐ถ
๐คPreparing for a telephonic Interview ? Here are some trivial yet crucial questions you might encounter:
โ๏ธ Difference between a hard link and a soft link in Linux? โ ๏ธ A hard link points directly to the file's inode, while a soft link points to the file's path.
โ๏ธWhat is a shell in Linux? โ ๏ธ The shell is a command-line interpreter facilitating user-OS interaction and command execution.
โ๏ธHow to check the memory usage of a Linux system? โ ๏ธUse the "free" command to display memory usage, including total, used, free memory, and swap usage.
โ๏ธHow to find the IP address of a Linux system? โ ๏ธUtilize the "ifconfig" command to display network interface information, including IP addresses.
โ๏ธHow to find the list of running processes in Linux? โ ๏ธEmploy the "ps" command with options like "-ef" or "-aux" to display running processes.
โ๏ธHow to kill a process in Linux? โ ๏ธTerminate a process using the "kill" command, requiring the process ID obtained from "ps.
โ๏ธ"Purpose of the "chmod" command in Linux? โ ๏ธ"chmod" changes file and directory permissions, granting or revoking read, write, and execute permissions.
โ๏ธHow to search for a file in Linux? โ ๏ธUse the "find" command to search for files based on various criteria like name, size, or modification time.
โ๏ธWhat is the purpose of the "cron" daemon in Linux? โ ๏ธThe "cron" daemon is a time-based job scheduler in Linux, allowing users to automate command execution at specified intervals.
โ๏ธHow do you schedule a cron job in Linux? โ ๏ธTo schedule a cron job, use the "crontab" command. Running "crontab -e" opens the user's crontab file to specify the command or script and schedule.
โ๏ธDifference between SSH and SSL? โ ๏ธSSH (Secure Shell) is for secure remote access and system management, while SSL (Secure Sockets Layer) establishes encrypted connections for secure web communication (HTTPS).
โ๏ธHow to check network connectivity in Linux? โ ๏ธUse the "ping" command to check connectivity between your machine and a remote host by sending ICMP echo requests and displaying response time.
๐คDo share your experience for telephonic interview questions and answers that you might have stumbled upon.
๐คImagine your computer is like a house๐ , and the BIOS (Basic Input/Output System) is like the lock๐on the front door.
Just as the lock controls access to your house, the BIOS controls access๐ซ to your computer's hardware when it starts up.
Now, think of Coreboot as a customizable, open-source security system for your house. Instead of relying on a standard lock, Coreboot allows you to design your own security measures ๐โจ๏ธ tailored to your specific needs. You can choose the types of locks, alarms, and access controls you want to implement, giving you more control and transparency over your home's security๐๐.
So you have a traditional house with a standard lock on the front door (BIOS). However, you're concerned about security vulnerabilities and limitations with the standard lock. So, you decide to install Coreboot, which allows you to customize your home's security system.
๐ฎโ๐จWith BIOS (Standard Lock):
You have limited control over the lock's features and settings.If there's a security flaw in the lock, you have to wait for the manufacturer to release a fix. You can't easily modify or upgrade the lock to better suit your needs.
๐คWith Coreboot (Custom Security System):You have full control over the security features of your home.If there's a security issue, you can directly address it or rely on the active community to provide solutions. You can customize and upgrade your security system at any time, adding new features or improving existing ones.
So, Coreboot empowers๐ you to take control of your computer's firmware, just like a customizable security system gives you more control over your home's security. It's all about flexibility, transparency, and putting the power back in your hands.
๐คค Imagine you're a head chef (representing a process) in a bustling kitchen, tasked with creating a masterpiece dish. You have a limited number of ingredients (resources) at your disposal, and if you attempt to whip up the entire dish from start to finish solo, you'll end up spending a lot of time juggling tasks๐ฐ.
But fear not! ๐ You've hired a team of eager intern chefs๐งโ๐ณ๐งโ๐ณ๐งโ๐ณ (representing threads) who may not know the recipe from start to finish, but they excel at handling individual tasks like frying, seasoning, or marinating. Just like threads in an operating system, these interns can work simultaneously and independently, each focusing on a specific aspect of the dish.
Now, here's where the magic happens! ๐ฉโจ Instead of hoarding all the ingredients to yourself, you share them with your intern chefs, allowing them to prepare their assigned tasks in parallel. While one intern is sautรฉing onions, another can be grilling the protein, and yet another can be prepping the garnishes.
By delegating tasks to your team of intern chefs (threads), you optimize efficiency and minimize downtime. Plus, if one task requires a bit more time or resources, it doesn't stall the entire cooking process. Just like in operating systems, where threads can be managed and executed concurrently, this culinary analogy illustrates the power of parallelism and resource sharing.
So, embrace the kitchen chaos and let your intern chefs (threads) work their culinary magic, all under the guidance of the head chef (process). Bon appรฉtit! ๐ฝ๏ธ
๐ฅน๐๐ฎ๐๐ฎ ๐๐ฒ๐ป๐ ๐ฎ๐ป๐ฑ ๐ฒ๐ ๐ฝ๐ฒ๐ฐ๐๐ฒ๐ฑ ๐ป๐ผ๐ ๐บ๐ฎ๐๐ฐ๐ต๐ถ๐ป๐ด ? Have you ever encountered memory alignment issues or wanted to reduce the memory footprint of your C/C++ structs? ๐ง The ๐๐ญ๐ญ๐ซ๐ข๐๐ฎ๐ญ๐((๐ฉ๐๐๐ค๐๐)) attribute might just be the tool you need! In C and C++, structures are typically padded with extra bytes to ensure proper alignment, which can lead to wasted memory space, especially in embedded systems or when working with network protocols. But fear not! The ๐๐ญ๐ญ๐ซ๐ข๐๐ฎ๐ญ๐((๐ฉ๐๐๐ค๐๐)) attribute comes to the rescue by instructing the compiler to pack structure members without any padding. Here's a quick example: hashtag#๐ข๐ง๐๐ฅ๐ฎ๐๐ <๐ฌ๐ญ๐๐ข๐จ.๐ก> ๐ฌ๐ญ๐ซ๐ฎ๐๐ญ ๐๐ฑ๐๐ฆ๐ฉ๐ฅ๐ { ๐๐ก๐๐ซ ๐; ๐ข๐ง๐ญ ๐; ๐๐ก๐๐ซ ๐; } ๐๐ญ๐ญ๐ซ๐ข๐๐ฎ๐ญ๐((๐ฉ๐๐๐ค๐๐)); ๐ข๐ง๐ญ ๐ฆ๐๐ข๐ง() { ๐ฉ๐ซ๐ข๐ง๐ญ๐("๐๐ข๐ณ๐ ๐จ๐ ๐ฌ๐ญ๐ซ๐ฎ๐๐ญ ๐๐ฑ๐๐ฆ๐ฉ๐ฅ๐: %๐ณ๐ฎ ๐๐ฒ๐ญ๐๐ฌ\๐ง", ๐ฌ๐ข๐ณ๐๐จ๐(๐ฌ๐ญ๐ซ๐ฎ๐๐ญ ๐๐ฑ๐๐ฆ๐ฉ๐ฅ๐)); ๐ซ๐๐ญ๐ฎ๐ซ๐ง ๐; } ๐คBy applying attribute((packed)) to the Example struct, we eliminate any padding between its members, resulting in a more compact memory layout. However, it's crucial to note that using this attribute may affect performance due to potential alignment issues, so it's best suited for specific use cases where memory optimization is paramount. ๐Next time you're optimizing memory usage or working on a project with strict memory constraints, consider harnessing the power of attribute((packed)) to streamline your data structures and enhance efficiency!
Ever heard about IP addresses and MAC addresses in networking systems ? what are these two terms ?
๐We can say mac_addr is pet name or ghar ka naam e.g. munna and ip_addr is your social media tag/username e.g princess_angel
So the social media would know you by your social media name or IP_ADDR. And in your home everybody knows you via your pet name or mac_addr.
So in terms of networking let's say you have a home network with multiple devices connected to a Wi-Fi router.
Say your smartphone has an IP address of 192.xxx.x.xxx assigned to it by the router.
And Your laptop has an IP address of 192.xxx.x.xxx assigned to it by the router.
And these IP addresses are used for devices to communicate with each other over the network and to access the internet.
And when we talk about MAC Address
Your smartphone has a MAC address like 00:1A:xx:xx:xx:xx. Your laptop has a MAC address like 11:22:xx:xx:xx:xx.
MAC addresses are used by the router to direct data specifically to each device within the local network(ghar).When data packets are sent between devices on the local network, the router uses the MAC address to determine which device to send the data to.
So, while IP addresses help devices communicate across networks and the internet, MAC addresses are used within a local network to ensure that data is sent to the correct device.
Both IP addresses and MAC addresses work together to facilitate communication and data transmission in computer networks.
As C developers, we heavily rely on this function, and it's often a hot topic in interviews.
One of the most commonly asked questions is: "Can you describe and demonstrate the use of malloc()
?"๐ง
So, let's dive into a few important points about ๐๐ปโโ๏ธmalloc()
:
๐๐๐ป๐ฎ๐บ๐ถ๐ฐ ๐ ๐ฒ๐บ๐ผ๐ฟ๐ ๐๐น๐น๐ผ๐ฐ๐ฎ๐๐ถ๐ผ๐ป: malloc()
in C allows dynamic allocation of memory during runtime, enabling programs to adapt to varying memory needs.
๐๐ฒ๐ฎ๐ฝ ๐ ๐ฒ๐บ๐ผ๐ฟ๐: Memory allocated by malloc()
comes from the heap, a region of the process's virtual memory space, providing flexibility in memory management.
๐ฆ๐๐ป๐๐ฎ๐
: The syntax of malloc()
is void* malloc(size_t size)
, where size
specifies the number of bytes to allocate.
๐ฅ๐ฒ๐๐๐ฟ๐ป ๐ฉ๐ฎ๐น๐๐ฒ: It returns a pointer to the beginning of the allocated memory block or NULL if the allocation fails.
๐จ๐๐ฎ๐ด๐ฒ: malloc()
is commonly used for allocating memory for arrays, structs, and other data structures whose size may vary at runtime.
๐ ๐ฒ๐บ๐ผ๐ฟ๐ ๐๐ฒ๐ฎ๐ธ ๐ฃ๐ฟ๐ฒ๐๐ฒ๐ป๐๐ถ๐ผ๐ป: Proper use of malloc()
helps prevent memory leaks by allocating memory dynamically and freeing it when no longer needed using free()
.
๐๐ฟ๐ฟ๐ผ๐ฟ ๐๐ฎ๐ป๐ฑ๐น๐ถ๐ป๐ด: It's essential to check if malloc()
returns NULL to handle failed memory allocation gracefully.
๐ง๐๐ฝ๐ฒ๐ฐ๐ฎ๐๐๐ถ๐ป๐ด: Although not required in C, it's a good practice to typecast the returned pointer from malloc()
to the appropriate type.
๐ฆ๐ถ๐๐ฒ ๐๐ฎ๐น๐ฐ๐๐น๐ฎ๐๐ถ๐ผ๐ป: The size argument in malloc()
should be calculated based on the size of the data type being allocated and the number of elements required.
๐ ๐ฒ๐บ๐ผ๐ฟ๐ ๐ข๐ฝ๐๐ถ๐บ๐ถ๐๐ฎ๐๐ถ๐ผ๐ป: By dynamically allocating memory only when needed, malloc()
optimizes memory usage and improves program efficiency.
Understanding and mastering malloc()
is crucial for efficient memory management in C programming, enabling developers to build robust and scalable applications.
1) What is a Makefile, and what role does it play in software development?๐ง
-> Makefiles automate the build process in software development by specifying rules for compiling, linking, and executing code files.
๐คSo say if we have very huge number of files and directories that need to be compiled and they all have dependencies on certain header files and other files๐ฅธ, so compiling them one by one will be next to impossible that's when makefile comes into action.
2) How are rules defined in a Makefile, and what are their components?๐คจ
-> Rules consist of targets, dependencies, and commands. For example:
target: dependency1 dependency2 { your command }
3) Why is dependency management important in Makefiles, and how does it optimize the build process?
-> Dependency management minimizes unnecessary recompilation by tracking file relationships.
Example: target: dependency {command}
4) What are implicit rules in Makefiles, and when would you use them?๐ง Provide an example.
->Implicit rules are pre-defined templates for common tasks, simplifying Makefile maintenance.
Example: %.o: %.c $(CC) -c $< -o $@
5) How can variables be utilized in Makefiles, and what advantages do they offer?๐ฅธ
Variables enhance flexibility, consistency, and readability.
Example:
CC = gcc CFLAGS = -Wall -O2 SRC = main.c utils.c OBJ = $(SRC:.c=.o) TARGET = my_program
๐Mastering these Makefile interview questions will not only showcase your expertise but also set you apart as a skilled software developer ready to tackle complex build processes with ease.
๐ชSo, are you prepared to tackle Makefile questions in your next interview?
๐ฅณ ๐ฆ๐ถ๐บ๐ฝ๐น๐ฒ ๐ฆ๐๐๐๐ฒ๐บ ๐ฑ๐ฒ๐๐ถ๐ด๐ป ๐ถ๐ป ๐๐บ๐ฏ๐ฒ๐ฑ๐ฑ๐ฒ๐ฑ ๐ฆ๐ผ๐ณ๐๐๐ฎ๐ฟ๐ฒ ๐๐ป๐๐ฒ๐ฟ๐๐ถ๐ฒ๐๐ค๐ฐ
๐ฅธ๐๐ป๐๐ฒ๐ฟ๐๐ถ๐ฒ๐๐ฒ๐ฟ (๐ ธ): Shashank, Can you explain the use of interrupts? Why do we need interrupts? how do they work?
๐ค๐ ผ๐ ด: Sure! Interrupt mechanism allows processor to respond to ext. events without constantly polling status. When interrupt occurs, processor stops executing current code, saves context, and jumps to ISR to handle the event. After ISR is complete, processor resumes its previous operation.
๐ฅธ๐ ธ: Hmmm.. correct. Now, let's say you're working on an embedded system with button presses and sensor readings as interrupt sources. What exactly you need to do to prioritize and manage these interrupts?
๐ค๐ ผ๐ ด: Okay let me explain step wise what I need to do:
๐ญ.๐๐ผ๐ป๐ณ๐ถ๐ด๐๐ฟ๐ฒ ๐๐ป๐๐ฒ๐ฟ๐ฟ๐๐ฝ๐ ๐ฆ๐ผ๐๐ฟ๐ฐ๐ฒ๐: I can set up INT0 to trigger on a falling edge (for button presses) and INT1 to trigger on a rising edge (for sensor readings).
๐ฎ.๐๐ป๐ฎ๐ฏ๐น๐ฒ ๐๐ป๐๐ฒ๐ฟ๐ฟ๐๐ฝ๐๐: I would enable the respective interrupts using EIMSK (External Interrupt Mask Register).
๐ฏ. ๐๐ฒ๐ณ๐ถ๐ป๐ฒ ๐๐ฆ๐ฅ๐: I'd write separate ISRs for each interrupt source. In the ISRs, I'd handle the specific tasks related to the interrupt source.
In the main loop, I continuously check the interrupt flags associated with each interrupt source. If an interrupt flag is set, I'd execute the corresponding ISR to handle the event and reset the flag afterwards.
๐ฅธ๐ ธ: Cool! Please write a sample code?
๐ฅน๐ ผ๐ ด: Ok! Here's an ex. code in C:
// ๐๐๐๐ข๐ง๐ ๐๐ฅ๐๐ ๐ฌ ๐ญ๐จ ๐ญ๐ซ๐๐๐ค ๐ข๐ง๐ญ๐๐ซ๐ซ๐ฎ๐ฉ๐ญ ๐ฌ๐ญ๐๐ญ๐ฎ๐ฌ ๐ฏ๐จ๐ฅ๐๐ญ๐ข๐ฅ๐ ๐ฎ๐ข๐ง๐ญ8_๐ญ ๐๐ฎ๐ญ๐ญ๐จ๐ง๐๐ง๐ญ๐๐ซ๐ซ๐ฎ๐ฉ๐ญ๐ ๐ฅ๐๐ = 0; ๐ฏ๐จ๐ฅ๐๐ญ๐ข๐ฅ๐ ๐ฎ๐ข๐ง๐ญ8_๐ญ ๐ฌ๐๐ง๐ฌ๐จ๐ซ๐๐ง๐ญ๐๐ซ๐ซ๐ฎ๐ฉ๐ญ๐ ๐ฅ๐๐ = 0;
๐ฏ๐จ๐ข๐ ๐๐ง๐๐๐ฅ๐๐๐ฅ๐จ๐๐๐ฅ๐๐ง๐ญ๐๐ซ๐ซ๐ฎ๐ฉ๐ญ๐ฌ() { ๐ฌ๐๐ข(); }
// ๐๐๐ ๐๐จ๐ซ ๐๐ฎ๐ญ๐ญ๐จ๐ง ๐ฉ๐ซ๐๐ฌ๐ฌ๐๐ฌ ๐๐๐(๐๐๐0_๐ฏ๐๐๐ญ) { ๐๐ฎ๐ญ๐ญ๐จ๐ง๐๐ง๐ญ๐๐ซ๐ซ๐ฎ๐ฉ๐ญ๐ ๐ฅ๐๐ = 1; } // ISR for sensor ๐๐๐(๐๐๐1_๐ฏ๐๐๐ญ) { ๐ฌ๐๐ง๐ฌ๐จ๐ซ๐๐ง๐ญ๐๐ซ๐ซ๐ฎ๐ฉ๐ญ๐ ๐ฅ๐๐ = 1; } ๐ข๐ง๐ญ ๐ฆ๐๐ข๐ง(๐ฏ๐จ๐ข๐) { // ๐๐ง๐ข๐ญ๐ข๐๐ฅ๐ข๐ณ๐ ๐๐๐๐ ๐๐ง๐ ๐๐จ๐ง๐๐ข๐ ๐ฎ๐ซ๐ ๐ข๐ง๐ญ๐๐ซ๐ซ๐ฎ๐ฉ๐ญ๐ฌ // (๐๐จ๐ง๐๐ข๐ ๐ฎ๐ซ๐ ๐๐๐0 ๐๐ง๐ ๐๐๐1 ๐๐ฌ ๐ฆ๐๐ง๐ญ๐ข๐จ๐ง๐๐ ๐๐๐ซ๐ฅ๐ข๐๐ซ)
๐๐๐๐๐ |= (1 << ๐๐๐01); // Set falling edge trigger for INT0
๐๐๐๐๐ |= (1 << ๐๐๐11) | (1 << ๐๐๐10); // Set Rising edge trigger for INT1
๐๐๐๐๐ |= (1 << ๐๐๐0) | (1 << ๐๐๐1); // Enabling INT1 & INT2
๐๐ง๐๐๐ฅ๐๐๐ฅ๐จ๐๐๐ฅ๐๐ง๐ญ๐๐ซ๐ซ๐ฎ๐ฉ๐ญ๐ฌ();
๐ฐ๐ก๐ข๐ฅ๐ (1) // GIC handles this { ๐ข๐ (๐๐ฎ๐ญ๐ญ๐จ๐ง๐๐ง๐ญ๐๐ซ๐ซ๐ฎ๐ฉ๐ญ๐ ๐ฅ๐๐ ) { //สแดษดแด สแด button press interrupt & clear it ๐๐ฎ๐ญ๐ญ๐จ๐ง๐๐ง๐ญ๐๐ซ๐ซ๐ฎ๐ฉ๐ญ๐ ๐ฅ๐๐ = 0; } ๐ข๐ (๐ฌ๐๐ง๐ฌ๐จ๐ซ๐๐ง๐ญ๐๐ซ๐ซ๐ฎ๐ฉ๐ญ๐ ๐ฅ๐๐ ) { //สแดษดแด สแด ๊ฑแดษด๊ฑแดส สแดแดแด ษชษดษข ษชษดแดแดสส. & clear it ๐ฌ๐๐ง๐ฌ๐จ๐ซ๐๐ง๐ญ๐๐ซ๐ซ๐ฎ๐ฉ๐ญ๐ ๐ฅ๐๐ = 0; } } ๐ซ๐๐ญ๐ฎ๐ซ๐ง 0; }
๐ ธ: Can you explain why using "volatile" ?
๐ฅธ๐๐ง๐ญ๐๐ซ๐ฏ๐ข๐๐ฐ๐๐ซ: What Linux flavour you are most used to ?
๐ค๐๐: Ubuntu ๐ง mostly
๐ฅธ๐๐ง๐ญ๐๐ซ๐ฏ๐ข๐๐ฐ๐๐ซ: So you use Ubuntu ? Do you know about its boot flow ? Can you explain ?
๐ค๐๐: Sure (grabs Marker and hops ๐ infront of white board)
๐. ๐๐๐๐/๐๐๐ ๐: It all starts with the Basic Input/Output System (BIOS) or Unified Extensible Firmware Interface (UEFI) initializing hardware and loading the bootloader.
๐. ๐๐จ๐จ๐ญ๐ฅ๐จ๐๐๐๐ซ (๐๐๐๐): GRand Unified Bootloader (GRUB) is a common choice. It allows you to choose your Linux kernel and initial RAM disk (initrd) if needed.
๐. ๐๐๐ซ๐ง๐๐ฅ ๐๐ง๐ข๐ญ๐ข๐๐ฅ๐ข๐ณ๐๐ญ๐ข๐จ๐ง: ...
๐ง๐๐ง๐ญ๐๐ซ๐ฏ๐ข๐๐ฐ๐๐ซ: Wait, can you elaborate more about Bootloader ? may be about its stages?
๐ ๐๐: ok sure..
๐.๐ ๐๐จ๐จ๐ญ๐ฅ๐จ๐๐๐๐ซ ๐๐ญ๐๐ ๐๐ฌ:
Stage 1 (MBR/PBR): The first stage of GRUB is usually found in the Master Boot Record (MBR) or the Partition Boot Record (PBR) of the boot device. It's responsible for locating the next stage.
Stage 1.5 (Optional): In complex storage setups, a Stage 1.5 may come into play, understanding file systems and facilitating the loading of Stage 2
Stage 2 (core.img): The critical second stage of GRUB, stored in /boot/grub/, takes over. It presents the GRUB menu, loads the Linux kernel, and initializes the boot process.
๐. ๐๐๐ซ๐ง๐๐ฅ ๐๐ง๐ข๐ญ๐ข๐๐ฅ๐ข๐ณ๐๐ญ๐ข๐จ๐ง: Post-GRUB, the Linux kernel (vmlinuz) and possibly the initial RAM disk (initrd.img) are loaded into memory. The kernel's start_kernel() function is executed, beginning the kernel's internal initialization process.
๐. ๐๐ง๐ข๐ญ-๐ซ๐๐ฆ-๐๐ฌ, ๐๐ง๐ข๐ญ ๐๐ซ๐จ๐๐๐ฌ๐ฌ, ๐๐ง๐ ๐๐๐ฒ๐จ๐ง๐: The process continues as we discussed earlier, with initramfs, the init process (often systemd in modern Ubuntu), and user-space services.
๐ฉโ๐ป๐๐๐ฌ๐ญ ๐๐ง๐ญ๐๐ซ๐ฏ๐ข๐๐ฐ ๐๐ฑ๐ฉ๐๐ซ๐ข๐๐ง๐๐: The interview started with a discussion on my previous projects and experience with embedded systems. We delved into some technical questions and problem-solving scenarios.
One question that stood out was related to optimizing code for an embedded system with limited resources(Always limited ๐ ).
๐ก ๐๐ง๐ญ๐๐ซ๐ฏ๐ข๐๐ฐ ๐๐ฎ๐๐ฌ๐ญ๐ข๐จ๐ง:
Question: "So How would you optimize following C code snippet for an embedded system with limited RAM and Flash memory?" I shared the following approach:
hashtag#๐๐ฃ๐๐ก๐ช๐๐ <๐จ๐ฉ๐๐๐ค.๐>
/ ๐ฟ๐๐๐๐ฃ๐ ๐ ๐๐ช๐จ๐ฉ๐ค๐ข ๐๐๐ฉ๐ ๐จ๐ฉ๐ง๐ช๐๐ฉ๐ช๐ง๐ ๐ฉ๐ค ๐ค๐ฅ๐ฉ๐๐ข๐๐ฏ๐ ๐ข๐๐ข๐ค๐ง๐ฎ ๐ช๐จ๐๐๐ / ๐ฉ๐ฎ๐ฅ๐๐๐๐ ๐จ๐ฉ๐ง๐ช๐๐ฉ { ๐๐ฃ๐ฉ ๐ญ; ๐๐ก๐ค๐๐ฉ ๐ฎ; ๐๐๐๐ง ๐ฏ; } ๐พ๐ค๐ข๐ฅ๐๐๐ฉ๐ฟ๐๐ฉ๐;
๐๐ฃ๐ฉ ๐ข๐๐๐ฃ() { // ๐พ๐ง๐๐๐ฉ๐ ๐๐ฃ ๐๐ง๐ง๐๐ฎ ๐ค๐ ๐พ๐ค๐ข๐ฅ๐๐๐ฉ๐ฟ๐๐ฉ๐ ๐พ๐ค๐ข๐ฅ๐๐๐ฉ๐ฟ๐๐ฉ๐ ๐๐๐ฉ๐_๐๐ง๐ง๐๐ฎ[100];
// ๐๐ฃ๐๐ฉ๐๐๐ก๐๐ฏ๐ ๐๐๐ฉ๐_๐๐ง๐ง๐๐ฎ ๐๐ก๐๐ข๐๐ฃ๐ฉ๐จ ๐๐ค๐ง (๐๐ฃ๐ฉ ๐ = 0; ๐ < 100; ++๐) { ๐๐๐ฉ๐_๐๐ง๐ง๐๐ฎ[๐].๐ญ = ๐; ๐๐๐ฉ๐_๐๐ง๐ง๐๐ฎ[๐].๐ฎ = 2.5 * ๐; ๐๐๐ฉ๐_๐๐ง๐ง๐๐ฎ[๐].๐ฏ = '๐ผ' + (๐ % 26); }
// ๐ผ๐๐๐๐จ๐จ ๐๐ฃ๐ ๐ข๐๐ฃ๐๐ฅ๐ช๐ก๐๐ฉ๐ ๐๐๐ฉ๐_๐๐ง๐ง๐๐ฎ ๐๐จ ๐ฃ๐๐๐๐๐
๐ง๐๐ฉ๐ช๐ง๐ฃ 0; }
โ๐ฆ๐๐๐ ๐ข๐ฆ๐๐ค๐ฅ๐๐ ๐ ~ โ๐ ๐จ ๐จ๐ ๐ฆ๐๐ ๐ช๐ ๐ฆ ๐๐๐ง๐ ๐ ๐ก๐ฅ๐๐๐๐ซ๐๐ ๐ฅ๐๐ ๐๐ ๐๐?
๐ค In the code, I emphasized the importance of data structure design for memory optimization. By grouping related data fields into a custom structure (CompactData), we minimize padding and reduce memory overhead. This approach helps maximize the efficient use of RAM and Flash memory, a crucial consideration in embedded systems.
The interviewer appreciated the solution and we discussed further optimizations like using bitfields, minimizing global variables, and avoiding dynamic memory allocation.
Remember, interview questions like these often focus on your problem-solving skills and understanding of embedded systems constraints. Tailoring your solution to the specific requirements of the system is key. Hope this helps fellow embedded enthusiasts! Good luck with your interviews! ๐ช
๐ช๐ต๐ฎ๐ ๐ถ๐ ๐จ๐ฆ๐ ๐๐ผ ๐ง๐ง๐?
USB to TTL is a small device that allows your computerโs USB port to communicate with other devices using a simpler communication method called TTL (Transistor-Transistor Logic). This is essential when working with devices like microcontrollers, which use serial communication instead of USB.
๐๐ผ๐ ๐๐ผ๐ฒ๐ ๐๐ ๐ช๐ผ๐ฟ๐ธ? ๐ฆ๐ฒ๐ฟ๐ถ๐ฎ๐น ๐๐ผ๐บ๐บ๐๐ป๐ถ๐ฐ๐ฎ๐๐ถ๐ผ๐ป: Many small electronic devices communicate using a method called serial communication. In serial communication, data is sent one bit at a time over a single wire, which is simple but effective for many applications. ๐ง๐ฟ๐ฎ๐ป๐๐น๐ฎ๐๐ถ๐ผ๐ป ๐ผ๐ณ ๐ฆ๐ถ๐ด๐ป๐ฎ๐น๐: Your computer sends data using USB, but most microcontrollers and sensors speak โserial.โ The USB to TTL converter translates the USB signals from your computer into TTL-level serial signals. This allows your computer to send and receive data to and from the microcontroller. ๐ฉ๐ผ๐น๐๐ฎ๐ด๐ฒ ๐๐ฒ๐๐ฒ๐น๐: TTL signals usually operate at 3.3V or 5V, which are safe for small electronic components. The converter ensures that the voltage levels are correct so that your devices donโt get damaged.
๐๐ ๐ฎ๐บ๐ฝ๐น๐ฒ: Imagine youโre working on a project where your microcontroller needs to send sensor data to your computer. Hereโs how USB to TTL makes it happen: ๐ฆ๐ฒ๐ป๐๐ผ๐ฟ ๐๐ฎ๐๐ฎ: The microcontroller collects data from a temperature sensor. This data is in the form of serial dataโbits of information sent one after the other. ๐๐ฎ๐๐ฎ ๐ง๐ฟ๐ฎ๐ป๐๐บ๐ถ๐๐๐ถ๐ผ๐ป: The microcontroller sends this serial data out through its serial port, which operates at TTL voltage levels. ๐จ๐ฆ๐ ๐๐ผ ๐ง๐ง๐ ๐๐ผ๐ป๐๐ฒ๐ฟ๐๐ฒ๐ฟ: You connect the microcontroller to your computer using a USB to TTL converter. The converter translates the serial data into a form that your computer can understand through its USB port. ๐๐ฎ๐๐ฎ ๐ผ๐ป ๐ฌ๐ผ๐๐ฟ ๐๐ผ๐บ๐ฝ๐๐๐ฒ๐ฟ: Your computer receives the sensor data, which you can then process, log, or display in real-time.
๐ช๐ต๐ ๐๐โ๐ ๐๐บ๐ฝ๐ผ๐ฟ๐๐ฎ๐ป๐ USB to TTL converters are essential tools for anyone working with embedded systems, IoT devices, or DIY electronics. They provide a reliable way to connect your computer to various devices, enabling you to seamlessly program, debug, and interact with your projects.
SPI Communication โ
SPI (Serial Peripheral Interface) is a key protocol in embedded systems, allowing microcontrollers to communicate with devices like sensors and displays. Hereโs a quick overview: Master-Slave Setup: One master device controls the communication, and the others are slaves. Four Main Lines: โก MOSI: Master Out, Slave In โก MISO: Master In, Slave Out โก SCLK: Serial Clock โก SS: Slave Select Full-Duplex: Data can be sent and received at the same time. Flexible Clock Settings: SPI can be configured for different devices with clock polarity and phase settings. SPI is fast and efficient, making it essential for many IoT and embedded applications. Learn more at https://media.licdn.com/dms/image/v2/D4D22AQHkCt1rGSDFwA/feedshare-shrink_2048_1536/feedshare-shrink_2048_1536/0/1722947307172?e=1727308800&v=beta&t=WSV76hCmJCq-5LeWj8kFTJN-jfqoRFFcJlPepEObiy8
UART Communication UART (Universal Asynchronous Receiver/Transmitter) is a fundamental serial communication protocol widely used in embedded systems. It enables devices to exchange data without a shared clock, making it simple and efficient for short-distance communication.
๐น Key Features: Asynchronous: No shared clock needed. Data Packets: Start bit, data bits, optional parity bit, stop bits. Baud Rate: Common rates include 9600, 19200, 115200 bps.
๐น Pros: Easy to implement. Full-duplex capability. Optional error detection with parity bits.
๐น Cons: Best for short distances. Limited speed compared to protocols like SPI/I2C. Ideal for microcontroller communication, peripheral interfaces, and legacy serial devices. Understanding UART is crucial for designing and debugging embedded systems.
Understanding System Calls vs. Library Calls
System Call:
A system call is a function provided by the operating system (OS) that allows programs to request services from the kernel, such as accessing hardware or managing system resources. System calls are essential for performing tasks like reading from a file or handling network communication, as they provide a controlled interface to interact with hardware without needing to manage the details directly.
Library Function:
Library functions, on the other hand, are predefined functions that operate in user space. These functions are part of libraries (like the C Standard Library) and help with a wide range of tasks, from string manipulation to complex mathematical operations, making coding more efficient and modular.
Key Differences:
Library Call: Involves direct communication between the application and the library.
System Call: Involves three levels of communicationโfirst, the application calls a wrapper function, which then triggers a software interrupt to interact with the kernel, where the system call is executed.
Library Call: Arguments are typically passed via the stack.
System Call: Arguments are often passed through CPU registers, providing faster access for the kernel.
Library Call: Functions are invoked by their name or memory address.
System Call: Invoked using a unique ID and generally involves a software interrupt.
Library Call: Called directly without the need for a wrapper.
System Call: Usually involves a wrapper routine to switch from user mode to kernel mode.
Library Call: Abstracts system complexities, making them user-friendly.
System Call: Provides essential functions while abstracting hardware details, but involves more complexity due to the kernel interaction.
๐คMe: Okay..the first step is really getting to know the device we are dealing with. That means diving into the datasheets and making sure I understand the communication protocols, whether it is I2C, SPI, or UART. It is all about getting that solid understanding from the start.
๐ฅธInterviewer: That makes sense. What would you do next?
๐คMe: After that, I would focus on the kernel module itself.
In Linux, most drivers are kernel modules,
so I would start with the basicsโsetting up the moduleโs initialization and cleanup functions. It is kind of like doing a โHello, World!โ but for the kernel.๐ฅธInterviewer: And how would you handle the interaction with the device?
๐คMe: That is where the device file (
/dev/xyz_device
)system comes into play. Linux treats hardware devices like files, soI would create a device file to let user-space applications talk to the driver.
Implementing functions like open, read, write, and ioctl would be key here. Also, I will ensure that the necessary entries in the DTS are correctly configured to match the driver.๐คจInterviewer: How do you deal with hardware interrupts in your driver (The interrupt generated by hardware device)?
๐ตโ๐ซMe: Handling interrupts efficiently is really important. I would make sure the driver registers the right interrupt handlers and manages them so we do not end up with latency issues or miss any important events.
Here is 2 things:
๐งInterviewer: Sounds good. Anything tricky that you keep an eye on?
๐ตโ๐ซMe: Definitely. Memory management is a big one. Kernel memory is not like user space, so I would be really careful to allocate and free memory properly to avoid any leaks. Also, dealing with concurrency is super importantโusing spinlocks or semaphores to protect shared resources helps prevent race conditions.
๐Interviewer: And what about debugging?
๐ Me: Debugging in the kernel can be a bit tricky, but tools
like dmesg, printk, and gdb
are really helpful. I would make sure to test the driver under different conditions to catch any issues early on.Interviewer: Hmmm ...anything else ?
๐Me: Adding a new device is not just about making it workโit is about making sure it fits well with the Linux kernel and plays nicely with other drivers. Plus, I would make sure the code follows the open-source licensing rules since Linux uses the GPL license.
๐Interviewer: Yea right.. Good explanation, lets move forward.