Embedded devices need to set parameters during operation, which is often accomplished by a PC. A communication protocol must be designed for both parties, with three representative protocols as follows:

As can be seen from the table above, embedded devices generally have limited memory and computational performance, so fixed binary
is the preferred communication protocol.
1. Simplicity
Ensure that the protocol is a simple solution; obscurity often means difficulty in implementation and a high chance of errors. The protocol structure should be flat, with each field having a clear purpose. Data fields should be designed with fixed lengths and positions as much as possible, with detailed comments, clear documentation, and rich examples to help users quickly understand and get started.
Protocols generally require the following fields: frame header, length, frame type, destination address, source address, data, checksum, frame tail.
2. Extensibility
It is essential to ensure that the protocol can still function after future feature additions and hardware changes, often achieved by reserving space. Changes to the protocol should only involve quantitative increases and not structural changes.
3. Low Coupling
Ideally, each protocol packet is atomic information, meaning this protocol packet is not linked to other protocol packets to prevent communication packet loss and errors caused by interdependencies.
4. Stability
The length of the protocol packet should be appropriate: too small contains too little information, and a wide variety of packet types can easily cause communication confusion and interdependent errors; too large contains too much information, reducing readability and complicating framing and deframing, which can also make communication susceptible to interference. Generally, the protocol length should be measured by the smallest atomic information.
The protocol must include a checksum mechanism to help the receiver determine whether the protocol packet is correctly and completely received. If errors occur, a good mechanism should ensure successful communication (e.g., retransmission).
5. High Efficiency
Differentiate protocol packet types by information type, such as setting network information parameters and current operational parameters, which can be separated for easier program handling.
Coding the same operation into a subset is an efficient method, such as coding Read operations as 0x0010 and Write operations as 0x0020.
Data should be designed in a homogenous pattern as much as possible; if there are differences, at least place the same type of data together so that the program can fully utilize pointers and linear addressing to speed up processing.
6. Ease of Implementation
Minimize the use of complex algorithms. For example, if the communication link is stable, the checksum for data frames can be replaced with CheckSum instead of CRC. Unless resources are extremely tight, do not squeeze too much information into one data packet, as it will reduce readability and complicate implementation.
7. Software Development
Try to let the hardware ISR complete the driver work, and do not let the “process” participate in complex timing logic, or the processor will be sluggish and the logic will become complicated! For example:
To receive fixed-length data frames, DMA can be used, and after receiving each frame, DMA_ISR sends a message to the process. Be cautious in handling DMA segmentation exceptions (where the received data frame length is normal but the data is incorrect, being the second half of the previous frame plus the first half of the current frame).
For receiving variable-length data frames, a state machine can be used, and when the “frame tail data” is received, a message is sent to the process.
Related articles: How to Efficiently Parse Variable-Length Protocol Frames?
Be cautious of data disorder and timeout exceptions (when data disorder occurs, the state machine needs to be reset in a timely manner, and timeouts are generally monitored using timers).
8. Consider Hardware
If the communication link is a high-speed bus (such as SPORT reaching 100Mbps), generally design it to produce an interrupt once per frame, implemented through DMA triggered by length, requiring the protocol to be designed as a fixed length, as shown in Appendix A. This has high efficiency but lower flexibility.
If the communication link is a low-speed bus (such as UART generally 100kbps), usually one byte generates an interrupt, and the protocol can be designed as variable-length frames, as shown in Appendix B. This has high flexibility but lower efficiency.
Appendix A: An Example of a Fixed-Length Protocol Based on DMA Transmission

As shown in the figure, the format of the data frame sent by the PC has a total length of 64 bytes, which is a multiple of 4 bytes, conforming to the alignment characteristics of most 32-bit processor structures.
-
0x3C: INT8U, frame header, visible character ‘<’
-
Len: INT8U, total data length of this frame, which in Figure 4 is 64
-
Dst: INT8U, identifies the ID number of the target device
-
Src: INT8U, identifies the ID number of the source device
-
Data: 56-byte storage area, content depends on the specific communication frame (see Table 2)
-
Cmd: INT16U, category of the data frame
-
CS: INT8U, performs an 8-bit cumulative checksum validation on all preceding data (62 bytes)
-
0x7D: INT8U, frame tail, visible character ‘}’
Data field data structure example:

Appendix B: An Example of a Variable-Length UART Communication Protocol
The communication frame between the PC and iWL880A (a wireless communication product, see www.rimelink.com) adopts a variable-length format, as shown in the figure below. Most devices (commonly PCs) handle receiving very well with the “carriage return” mechanism, where the Tail in the protocol equals 0x0D (newline).

Original text: https://blog.csdn.net/jiangjunjie_2005/article/details/50273105
Previous Recommendations
Hello Series | Basics of Multithreaded Programming!
Sharing Examples of LittlevGL + Framebuffer Adaptation!