UDS Write Memory By Address (0x3D) Service: Format, Use Cases, and Implementation
Hello, automotive protocol learners! In this blog post, I’m excited to walk you through UDS Write Memory By Address (0x3D) – one of the powerful services in the UDS proto
col – the Write Memory By Address (0x3D) service. This service allows you to write data directly into a specified memory location within a control unit, making it an essential tool for tasks like flashing and calibration. Understanding how this service works is crucial for diagnostic communication and memory handling in ECUs. In this post, we’ll explore the format of the request and response messages, when and why you should use it, and practical use cases in the field. You’ll also learn about important considerations, such as memory addressing and security. By the end of this guide, you’ll be confident in using 0x3D in real diagnostic workflows. Let’s dive into the world of memory access with UDS!Table of contents
- UDS Write Memory By Address (0x3D) Service: Format, Use Cases, and Implementation
- Introduction to Write Memory By Address (0x3D) Service in UDS Protocol
- Why do we need Write Memory By Address (0x3D) Service in UDS Protocol?
- 1. Direct Memory Access
- 2. Essential for Flash Programming
- 3. Supports Calibration and Configuration
- 4. Enables Bootloader-Level Operations
- 5. Facilitates Secure and Controlled Updates
- 6. Improves Development and Testing Efficiency
- 7. Enables Partial Updates in ECU Memory
- 8. Useful for Custom Diagnostic Applications
- Syntax of 0x3D SID Request Message Frame Format
- Syntax of 0x3D SID Positive Response Message
- Syntax of 0x3D SID Negative Response Message
- Example of Write Memory By Address (0x3D) Service in UDS Protocol
- Advantages of Write Memory By Address (0x3D) Service in UDS Protocol
- Disadvantages of Write Memory By Address (0x3D) Service in UDS Protocol
- Future Development and Enhancement of Write Memory By Address (0x3D) Service in UDS Protocol
Introduction to Write Memory By Address (0x3D) Service in UDS Protocol
The Write Memory By Address (0x3D) service is a vital function within the Unified Diagnostic Services (UDS) protocol, widely used in automotive electronic control unit (ECU) diagnostics. This service enables users to write data directly to a specific memory location within the ECU, making it a key feature during software flashing, parameter updates, and calibration tasks. By specifying a memory address and the corresponding data to be written, technicians and developers can directly manipulate memory contents in a controlled and secure way. This level of access is particularly useful during development, testing, and in-field ECU reprogramming. In this section, we’ll explore the purpose, structure, and significance of the 0x3D service in automotive diagnostics.
What is Write Memory By Address (0x3D) Service in UDS Protocol?
The Write Memory By Address (Service ID: 0x3D) in the UDS (Unified Diagnostic Services) protocol is used to write data directly to a specified memory address in an ECU (Electronic Control Unit). This service provides a way for diagnostic tools to program or update memory areas such as RAM, Flash, or EEPROM. The memory location is defined using a MemoryAddress and MemorySize parameter, followed by the actual data to be written.
This service is crucial during ECU flashing, software updates, and calibration processes. Since it allows direct memory manipulation, it is typically protected by security access levels to prevent unauthorized access. Proper use of the 0x3D service ensures reliable updates and configuration of vehicle systems during development, manufacturing, or maintenance.
- This service can be used to
- Clear non-volatile memory
- Change calibration values.
Note: This service does not use a sub-function
Why do we need Write Memory By Address (0x3D) Service in UDS Protocol?
Here’s a detailed explanation of why we need the Write Memory By Address (0x3D) service in UDS:
1. Direct Memory Access
The 0x3D service allows direct access to specific memory addresses in an ECU, enabling targeted data writing. This is useful for updating only a particular section of memory without affecting the rest of the system. For example, you can update a configuration table or a block of calibration data directly. This targeted approach saves time and reduces the risk of corrupting unrelated memory areas. It is especially helpful during development and testing phases where frequent changes are needed.
2. Essential for Flash Programming
During ECU firmware updates, the 0x3D service is used to write chunks of binary data into the Flash memory. It plays a crucial role in reprogramming ECUs with updated software or security patches. Instead of using high-level tools, technicians and developers can control exactly where and how the update is written. This service forms the backbone of many OEM and aftermarket flashing tools. Its precision ensures the correct data is stored in the correct memory segment.
3. Supports Calibration and Configuration
The service is ideal for writing calibration data such as engine parameters, sensor thresholds, and operational settings. These values are often stored in EEPROM or Flash and need periodic updates based on vehicle performance or diagnostics. With 0x3D, these changes can be made dynamically, without requiring a full software update. This supports adaptive systems that evolve with usage or environmental factors.
4. Enables Bootloader-Level Operations
In many ECUs, the bootloader uses 0x3D to receive new software from external tools before handing control over to the application. This service is especially valuable in manufacturing plants and service centers where multiple vehicles are programmed daily. Since the bootloader is often minimal and lightweight, the 0x3D service simplifies implementation while maintaining security and reliability. It helps establish a stable programming interface for different vehicle variants.
5. Facilitates Secure and Controlled Updates
Due to its powerful nature, this service is protected by UDS security access mechanisms. Only authorized tools with the correct security keys can use it, ensuring that critical memory is not modified accidentally or maliciously. This controlled access is vital in maintaining the integrity and safety of vehicle ECUs. By combining 0x3D with secure diagnostic sessions, automakers can enable OTA (Over-the-Air) or remote diagnostics safely.
6. Improves Development and Testing Efficiency
During ECU development, frequent memory modifications are common. The 0x3D service allows engineers to patch memory quickly without going through full build and flashing cycles. It also supports debugging, where test values or mock data can be written into memory on-the-fly. This saves time, reduces rework, and enhances productivity for development teams. Its flexibility is especially helpful in lab environments and prototype testing.
7. Enables Partial Updates in ECU Memory
The 0x3D service allows developers to update only the required section of memory instead of rewriting the entire memory space. This is particularly useful when fixing bugs or making minor improvements in large firmware systems. Partial updates save time, reduce data transfer overhead, and minimize the risk of errors during the flashing process. It also conserves flash memory life by reducing unnecessary write cycles. This feature is highly beneficial in both production and field service environments.
8. Useful for Custom Diagnostic Applications
Custom diagnostic tools often need to interact with ECU memory in flexible ways. The Write Memory By Address service empowers tool developers to implement advanced features such as real-time data logging, custom data injection, or test mode activation. It offers a low-level interface that can be adapted to specific OEM or supplier requirements. With proper security and session handling, it becomes a powerful asset for building robust, custom diagnostic solutions.
Syntax of 0x3D SID Request Message Frame Format
Data Byte | Parameter Name | Byte Value |
#1 | Write Memory By Address Request SID | 0x3D |
#2 | Address And Length Format Identifier | 0x00 – 0xFF |
#3 : #m+2 | Memory Address[] = [ byte#1 (MSB) : byte#m ] | 0x00 – 0xFF : 0x00 – 0xFF |
#n-r-2-(k-1) : #n-r-2 | Memory Size[] = [ byte#1 (MSB) : byte#k ] | 0x00 – 0xFF : 0x00 – 0xFF |
#n-(r-1) : #n | Data Record[] = [ data#1 : data#r ] | 0x00 – 0xFF : 0x00 – 0xFF |
C1: The inclusion of this parameter depends on the address length information parameter of the address And Length Format Identifier. C2: The presence of this parameter depends on the memory size length information of the address And Length Format Identifier. |
Request Message Data-Parameter
addressAndLengthFormatIdentifier
This parameter is a one-byte value with each nibble encoded separately:
- Bits 7-4: Length (in bytes) of the memorySize parameter
- Bits 3-0: Length (in bytes) of the memoryAddress parameter
memoryAddress
The memoryAddress parameter specifies the starting address in server memory where data will be written. The number of bytes for this address is defined by the low nibble (bits 3-0) of the addressAndLengthFormatIdentifier. Byte #m is the least significant byte, with the most significant byte(s) serving as a memory identifier. For example, in a dual-processor server with 16-bit addressing and overlapping memory, an unused byte can specify the desired memory device. This usage is defined by the vehicle manufacturer or system supplier.
memorySize
The memorySize parameter in the WriteMemoryByAddress request message specifies the number of bytes to be written, starting at the address specified by memoryAddress in the server’s memory. The number of bytes for this size is defined by the high nibble (bits 7-4) of the addressAndLengthFormatIdentifier.
dataRecord
This parameter provides the data that the client is attempting to write into the server memory addresses within the range {0xMA to (0xMA + 0xMS – 0x01)}.
Syntax of 0x3D SID Positive Response Message
Data Byte | Parameter Name | Byte Value |
#1 | Write Memory By Address +Ve Response SID | 0x7D |
#2 | Address And Length Format Identifier | 0x00 – 0xFF |
#3 : #m+2 | Memory Address[] = [ byte#1 (MSB) : byte#m ] | 0x00 – 0xFF : 0x00 – 0xFF |
#n-r-2-(k-1) : #n-r-2 | Memory Size[] = [ byte#1 (MSB) : byte#k ] | 0x00 – 0xFF : 0x00 – 0xFF |
C1: The inclusion of this parameter depends on the address length information parameter of the address And Length Format Identifier. C2: The presence of this parameter depends on the memory size length information of the address And Length Format Identifier. |
Response Message Data-Parameter
addressAndLengthFormatIdentifier
This parameter echoes the addressAndLengthFormatIdentifier from the request message.
memoryAddress
This parameter echoes the memoryAddress from the request message.
memorySize
This parameter echoes the memorySize from the request message.
Syntax of 0x3D SID Negative Response Message
Data Byte | Parameter Name | Byte Value |
#1 | Write Memory By Address –Ve Response SID [ byte#1 ] | 0x7F |
#2 | Requested SID [ byte#1 ] | 0x3D |
#3 | Negative Response Code [ byte#1 ] | NRC |
Supported Negative Response Codes (NRCs) of 0x3D in UDS Protocol
NRC | Parameter Name | Description |
0x13 | Incorrect Message Length Or Invalid Format | This Negative Response Code (NRC) shall be sent if the length of the message is incorrect. |
0x22 | Conditions Not Correct | This Negative Response Code (NRC) shall be sent if the operating conditions of the server do not meet the requirements to perform the required action. |
0x31 | Request Out Of Range | This Negative Response Code (NRC) shall be sent if: • Any memory address within the interval [0xMA, (0xMA + 0xMS – 0x1)] is invalid. • Any memory address within the interval [0xMA, (0xMA + 0xMS – 0x1)] is restricted. • The memory Size parameter value in the request message is not supported by the server. • The specified address And Length Format Identifier is not valid. • The memory Size parameter value in the request message is zero. |
0x33 | Security Access Denied | This Negative Response Code (NRC) shall be sent if any memory address within the interval [0xMA, (0xMA + 0xMS – 0x1)] is secured and the server is locked. |
0x72 | General Programming Failure | This Negative Response Code (NRC) shall be returned if the server detects an error when writing to a memory location. |
Example of Write Memory By Address (0x3D) Service in UDS Protocol
Here are the Examples of Write Memory By Address (0x3D) Service in UDS Protocol:
Example #1: Write Memory By Address, 2-Byte (16-bit) Addressing
Write Memory By Address Request Message Flow Example #1
Message direction | Client → Server | |
Message Type | Request | |
Data Byte | Description (all values are in hexadecimal) | Byte Value |
#1 | Write Memory By Address Request SID | 0x3D |
#2 | Address And Length Format Identifier | 0x12 |
#3 #4 | Memory Address [ byte#1 ] (MSB) Memory Address [ byte#2 ] (LSB) | 0x20 0x48 |
#5 | Memory Size [ byte#1 ] | 0x02 |
#6 #7 | Data Record [ data#1 ] Data Record [ data#2 ] | 0x00 0x8C |
Write Memory By Address Positive Response Message Flow Example #1
Message direction | Server → Client | |
Message Type | Response | |
Data Byte | Description (all values are in hexadecimal) | Byte Value |
#1 | Write Memory By Address +Ve Response SID | 0x7D |
#2 | Address And Length Format Identifier | 0x12 |
#3 #4 | Memory Address [ byte#1 ] (MSB) Memory Address [ byte#2 ] (LSB) | 0x20 0x48 |
#5 | Memory Size [ byte#1 ] | 0x02 |
Write Memory By Address Negative Response Message Flow Example #1
Message direction | Server → Client | |
Message Type | Response | |
Data Byte | Description (all values are in hexadecimal) | Byte Value |
#1 | Write Memory By Address –Ve Response SID [ byte#1 ] | 0x7F |
#2 | Requested SID [ byte#1 ] | 0x3D |
#3 | Negative Response Code [ byte#1 ] | NRC |
Example #2: Write Memory By Address, 3-Byte (24-bit) Addressing
Write Memory By Address Request Message Flow Example #2
Message direction | Client → Server | |
Message Type | Request | |
Data Byte | Description (all values are in hexadecimal) | Byte Value |
#1 | Write Memory By Address Request SID | 0x3D |
#2 | Address And Length Format Identifier | 0x13 |
#3 #4 #5 | Memory Address [ byte#1 ] Memory Address [ byte#2 ] Memory Address [ byte#3 ] | 0x20 0x48 0x13 |
#6 | Memory Size [ byte#1 ] | 0x03 |
#7 #8 #9 | Data Record [ data#1 ] Data Record [ data#2 ] Data Record [ data#3 ] | 0x00 0x01 0x8C |
Write Memory By Address Positive Response Message Flow Example #2
Message direction | Server → Client | |
Message Type | Response | |
Data Byte | Description (all values are in hexadecimal) | Byte Value |
#1 | Write Memory By Address +Ve Response SID | 0x7D |
#2 | Address And Length Format Identifier | 0x13 |
#3 #4 #5 | Memory Address [ byte#1 ] Memory Address [ byte#2 ] Memory Address [ byte#3 ] | 0x20 0x48 0x13 |
#6 | Memory Size [ byte#1 ] | 0x03 |
Write Memory By Address Negative Response Message Flow Example #2
Message direction | Server → Client | |
Message Type | Response | |
Data Byte | Description (all values are in hexadecimal) | Byte Value |
#1 | Write Memory By Address –Ve Response SID [ byte#1 ] | 0x7F |
#2 | Requested SID [ byte#1 ] | 0x3D |
#3 | Negative Response Code [ byte#1 ] | NRC |
Example of Request Upload (0x3D) SID Request and Positive Response Frame Format
Request Frame Format:
PCI Length | SID | Data by Identifier | Memory Size | Memory Address | Data Parameter | |||
0x08 | 0x3D | 0xF1 | 0x8C | 0x02 | 0xA0 | 0x00 | 0xFE | 0x0C |
Positive Response Frame Format:
PCI Length | SID | Data by Identifier | Memory Size | Memory Address | ||
0x06 | 0x7D | 0xF1 | 0x8C | 0x02 | 0xA0 | 0x00 |
Example of Request Upload (0x3D) SID Request and Negative Response Frame Format
Request Frame Format:
PCI Length | SID | Sub-Function | Data by Identifier | Memory Size | Memory Address | Data Parameter | |||
0x08 | 0x3D | 0x01 | 0xF1 | 0x8C | 0x02 | 0xA0 | 0x00 | 0xFE | 0x0C |
Negative Response Frame Format:
PCI Length | Negative Response | SID | NRC |
0x03 | 0x7F | 0x3D | 13 |
Advantages of Write Memory By Address (0x3D) Service in UDS Protocol
Below are the Advantages of Write Memory By Address (0x3D) Service in UDS Protocol:
- Precise Control Over Memory Operations: It allows engineers to write data directly to specific memory addresses, which is essential for targeted updates. This precision helps avoid unintentional data corruption in unrelated memory areas. Developers can change only what’s needed instead of performing full memory writes. It’s especially useful during debugging or calibration. This feature saves time and enhances safety during development.
- Speeds Up ECU Programming and Updates: Instead of flashing the entire firmware, developers can write only the updated blocks. This significantly reduces data transfer time and update duration. It is especially beneficial in over-the-air updates and factory programming lines. Technicians can apply quick fixes or changes without full reprogramming. This increases the efficiency of both development and field service.
- Enables Modular Firmware Design: The 0x3D service supports memory operations on separate firmware modules, such as bootloader, application, and calibration. This modular approach improves maintainability and flexibility. It allows independent updates of different software parts without impacting the rest. It also helps in version control and easier rollback if needed. Overall, it enhances firmware lifecycle management.
- Supports Flash, EEPROM, and RAM Writes: This service is compatible with various memory types used in automotive ECUs. Whether it’s persistent memory like Flash or temporary memory like RAM, the service can handle it. This allows a wide range of applications, from runtime parameter updates to permanent calibration storage. Developers can adjust values or settings as needed without restrictions. This makes it versatile and powerful.
- Integrates Seamlessly With Security Mechanisms: The service operates within the UDS security framework, which restricts access to authorized users. Security levels and key exchange ensure that sensitive memory operations are protected. This helps prevent unauthorized modifications that could affect vehicle safety or behavior. The system stays secure while still allowing controlled access. It balances usability with cybersecurity.
- Crucial for Bootloader and Reprogramming Tasks: Most ECUs rely on the 0x3D service during initial flashing or firmware updates. The bootloader uses it to accept software updates before switching to the main application. It allows reprogramming ECUs in the factory, during servicing, or over-the-air. The service supports robust update workflows and is standardized across many OEMs. It is a fundamental building block of secure ECU updates.
- Reduces Downtime During Vehicle Servicing: The ability to patch or update an ECU quickly using 0x3D reduces vehicle repair and maintenance time. Instead of removing and replacing hardware, technicians can fix issues through software. This reduces costs, minimizes vehicle downtime, and increases service center efficiency. It’s especially useful for calibration updates or bug fixes. The faster turnaround improves customer satisfaction.
- Enhances Testing and Debugging Capabilities: During development, engineers can write test values or simulate behaviors by altering memory directly. This real-time memory editing speeds up debugging and validation. It enables quick testing of different conditions without recompiling or reflashing. It also aids in identifying memory-related bugs or issues. It is a must-have for rapid prototyping and diagnostics.
- Enables Flexible Memory Management: Engineers can divide memory into blocks and manage them independently using this service. This helps in allocating memory efficiently and updating specific areas without full rewrites. It supports advanced memory usage strategies, especially in complex ECU systems. Developers gain better control over memory layout. It contributes to more robust and scalable software design.
- Ideal for Custom Diagnostic Tools: Diagnostic tool developers can use this service to create advanced features like writing configuration data or triggering test modes. It provides a low-level access interface that can be adapted for OEM-specific requirements. The service supports custom workflows while remaining compliant with UDS standards. This makes tool development more flexible and effective. It’s a key component for professional automotive tools.
Disadvantages of Write Memory By Address (0x3D) Service in UDS Protocol
Below are the Disadvantages of Write Memory By Address (0x3D) Service in UDS Protocol:
- Risk of Writing to Wrong Memory Location: If the address or size is incorrectly specified, it can overwrite critical memory areas. This may corrupt the ECU firmware or affect normal operation. Unlike high-level services, 0x3D offers low-level access that doesn’t protect against such mistakes. Developers need to be extremely cautious. One wrong address could brick the ECU.
- Requires Elevated Security Access: The service demands a security level unlock, typically requiring a seed-key exchange. This adds complexity to implementation and delays during runtime. Without proper handling, the service will be denied. In some cases, security restrictions may block legitimate operations. It adds an additional layer of challenge for tool developers.
- Not Supported in All Diagnostic Sessions: This service is usually available only in specific sessions like programming or extended diagnostic. If not switched to the correct session, the ECU will reject the request. This can confuse developers or technicians unfamiliar with UDS session control. It limits flexibility for on-the-fly changes or real-time testing. Session handling must be carefully managed.
- Limited Error Feedback in Basic Implementations: Some ECUs provide minimal error information if the service fails. This makes debugging issues like incorrect memory size, address, or permissions difficult. Developers may struggle to identify what went wrong without detailed negative response codes. It slows down the development and troubleshooting process. Enhanced feedback requires more sophisticated implementations.
- Potential Security Vulnerabilities: If poorly implemented, this service could be exploited by attackers to write malicious code. It may lead to system compromise, unauthorized access, or malware injection. Therefore, strict access controls, input validation, and monitoring must be applied. Neglecting security aspects could pose serious risks. It is a sensitive service that must be protected.
- Requires Deep Knowledge of Memory Layout: Developers must know exact memory addresses, ranges, and types to use this service safely. Mistakes can lead to system instability or data loss. This increases development complexity and limits who can use the service. It is not suitable for casual diagnostics or general-purpose tools. Memory documentation must be thorough and accurate.
- Not Ideal for Large File Transfers: While possible, transferring large binary files using this service is inefficient. The payload size is limited per message, requiring multiple transfers and flow control. This increases the time and complexity for firmware updates. More specialized services like Request Download and Transfer Data are better suited for large operations. 0x3D is best for small blocks.
- No Built-In Data Verification: The service doesn’t automatically verify that the written data is correct or valid. If the user doesn’t read back and check, corrupted writes may go unnoticed. This could lead to runtime errors or failure to boot. Additional verification steps must be implemented separately. It adds to the workflow complexity and risk.
- ECU May Reject Writes During Runtime: Some memory regions may be locked or inaccessible during normal ECU operation. Attempting to write to such areas will result in service rejection. Developers must coordinate with the ECU’s state and conditions. Write permissions may also depend on internal flags or conditions. This limits flexibility in some scenarios.
- Increased Flash Wear if Misused: Repeatedly writing to the same Flash memory area can reduce its lifespan. Unlike RAM, Flash has a limited number of write-erase cycles. Excessive or unnecessary usage of 0x3D can degrade memory over time. This is critical in production or service environments where multiple updates may occur. Proper memory usage planning is essential.
Future Development and Enhancement of Write Memory By Address (0x3D) Service in UDS Protocol
These are the Future Development and Enhancement of Write Memory By Address (0x3D) Service in UDS Protocol:
- Enhanced Security Models for Memory Access: Future versions of the service may integrate with more advanced cybersecurity models such as Secure Boot and Hardware Security Modules (HSM). This will help restrict memory writes to verified software only. With increasing threats to connected vehicles, securing low-level services like 0x3D becomes essential. Dynamic encryption and runtime authentication may also be included. These enhancements will reduce unauthorized access risks.
- Integration with Over-the-Air (OTA) Update Frameworks: To support modern OTA systems, 0x3D may evolve to include optimized transfer and memory verification mechanisms. This would allow more reliable and efficient field updates. The service could be aligned with update strategies that minimize downtime and data consumption. It may also integrate with differential update systems. This makes updates faster and more seamless in real-world use.
- Automatic Memory Verification Post-Write: Future versions might incorporate automatic checksum or hash verification after memory writes. This would ensure that the written data is accurate and complete without requiring manual verification. It adds an extra layer of reliability. ECUs could return a status indicating successful memory validation. This improvement will reduce post-write errors significantly.
- Support for Compressed Data Writing: As memory footprints grow, writing compressed data blocks could save space and bandwidth. Future enhancements may allow writing data in compressed form, with the ECU handling decompression. This would reduce transmission time during programming or updates. It also aligns with modern software optimization practices. Developers can send more data in fewer packets.
- Improved Flow Control for Large Data Blocks: Enhanced flow control mechanisms may be introduced for better handling of large memory operations. This includes smarter segmentation, buffer management, and dynamic block size negotiation. It will reduce errors and increase speed during bulk memory writes. Particularly useful for programming high-capacity ECUs. The process becomes smoother and more robust.
- Cloud-Based Diagnostic Tool Integration: As cloud diagnostics become more common, 0x3D services may be supported remotely through secure, encrypted channels. Cloud-based interfaces could allow manufacturers to write or update ECU memory without local tools. Real-time sync with back-end servers could also be added. This facilitates centralized management of memory updates across fleets.
- Context-Aware Write Operations: Future ECUs may allow memory writes based on context like ignition state, speed, or operational mode. This means write access will be dynamically granted based on safety conditions. It helps prevent dangerous or unintended writes during driving. Context-aware access adds an intelligent layer to ECU diagnostics. It makes the service more adaptive and safer.
- Better Error Handling and Logging: Enhanced diagnostics will include detailed error logs when 0x3D requests fail. Logs could include memory address, size, cause, and user credentials involved. This helps trace faults and improve debugging efficiency. It supports audit trails for safety and security compliance. Such visibility is essential in safety-critical systems.
- Integration with AI-Based Update Planning: With AI integration, update tools could automatically decide when and how to write memory for best efficiency and safety. AI could optimize the address range, block size, and even schedule based on vehicle usage. It enables predictive maintenance and smarter diagnostics. This can prevent issues before they occur.
- Backward-Compatible Evolution: Future versions of the 0x3D service are likely to remain backward-compatible with legacy UDS implementations. This ensures smooth migration in mixed-vehicle environments. Enhancements may be layered on top via new sub-functions or metadata. This approach protects investment in existing tools and infrastructure. Compatibility ensures industry-wide adoption.
Discover more from PiEmbSysTech
Subscribe to get the latest posts sent to your email.