2.2.a. All comments shall be written in clear and complete sentences, with proper spelling and grammar and appropriate punctuation.
2.2.b. The most useful comments generally precede a block of code that performs one step of a larger algorithm. A blank line shall follow each such code block. The comments in front of the block should be at the same indentation level.
2.2.c. Avoid explaining the obvious. Assume the reader knows the C programming language. For example, end-of-line comments should only be used where the meaning of that one line of code may be unclear from the variable and function names and operations alone but where a short comment makes it clear. Specifically, avoid writing unhelpful and redundant comments, e.g.,
“numero <<= 2; // Shift numero left 2 bits.”.
2.2.d. The number and length of individual comment blocks shall be proportional to the complexity of the code they describe.
2.2.e. Whenever an algorithm or technical detail is defined in an external reference—e.g., a design specification, patent, or textbook—a comment shall include a sufficient reference to the original source to allow a reader of the code to locate the document.
2.2.f. Whenever a flow chart or other diagram is needed to sufficiently document the code, the drawing shall be maintained with the source code under version control and the comments should reference the diagram by file name or title.
2.2.g. All assumptions shall be spelled out in comments.5
2.2.h. Each module and function shall be commented in a manner suitable for automatic documentation generation, e.g., via Doxygen.
2.2.i. Use the following capitalized comment markers to highlight important issues:
i. “WARNING:” alerts a maintainer there is risk in changing this code. For example, that a delay loop counter’s terminal value was determined empirically and may need to change when the code is ported or the optimization level tweaked.
ii. “NOTE:” provides descriptive comments about the “why” of a chunk of code—as distinguished from the “how” usually placed in comments. For example, that a chunk of driver code deviates from the datasheet because there was an errata in the chip. Or that an assumption is being made by the original programmer.
iii. “TODO:” indicates an area of the code is still under construction and explains what remains to be done. When appropriate, an all-caps programmer name or set of initials may be included before the word TODO (e.g., “MJB TODO:”).
// Step 1: Batten down the hatches.
for (int hatch = 0; hatch < NUM_HATCHES; hatch++)
// Step 2: Raise the mizzenmast.
// TODO: Define mizzenmast driver API.
Reasoning: Following these rules results in good comments. And good comments correlate with good code. It is a best practice to write the comments before writing the code that implements the behaviors those comments outline.
Unfortunately, it is easy for source code and documentation to drift over time. The best way to prevent this is to keep the documentation as close to the code as possible. Likewise, anytime a question is asked about a section of the code that was previously thought to be clear, you should add a comment addressing that issue nearby.
Doxygen is a useful tool to generate documentation describing the modules, functions, and parameters of an API for its users. However, comments are also still necessary inside the function bodies to reduce the cost of code maintenance.
The quality of comments shall be evaluated during code reviews. Code reviewers should verify that comments accurately describe the code and are also clear, concise, and valuable. Automatically generated documentation should be rebuilt each time the software is built.
 Even better than comments is a set of design-by-contract tests or assertions. See, e.g., barrgroup.com/embedded-systems/how-to/design-by-contract-for-embedded-software.