File/Function Headers

Every file/function must have a consistent comment header block!

People have to read, understand and interact with your code. Writing clear and concise code goes a long way here, but you should also include at least one sentence about every function in your file to say what it does.

I never use Doxygen, but I've gotten in the habit of using Doxygen style comments as good practice since it includes everything you need to properly document a function right next to your source code, ensuring it's more likely to get updated as the code itself changes.

File Headers: The Bare Minimum

You must include at least a one or two line description of this file, ideally a full description, the author(s), and the license terms in every file. If relevant, a link to the associated product or datasheet should also be included.

The format doesn't need to use DOxygen style tags, but the above information must be included. An example of this is shown in the file header below for the TSL2561 light sensor:
Download: file
/**************************************************************************/
/*!
    @file     Adafruit_TSL2561.cpp
    @author   K.Townsend (Adafruit Industries)
    @license  BSD (see license.txt)

    Driver for the TSL2561 digital luminosity (light) sensors.

    Pick one up at http://www.adafruit.com/products/439

    Adafruit invests time and resources providing this open source code,
    please support Adafruit and open-source hardware by purchasing
    products from Adafruit!

    @section  HISTORY

    v2.0 - Rewrote driver for Adafruit_Sensor and Auto-Gain support, and
           added lux clipping check (returns 0 lux on sensor saturation)
    v1.0 - First release (previously TSL2561)
*/
/**************************************************************************/

Functions: The Bare Minimum

As an absolute minimum, you must include at least a few words describing every single function in your module. This applies to both public and private functions.
Download: file
/**************************************************************************/
/*!
    Writes the specified number of bytes over I2C
*/
/**************************************************************************/
error_t pcf2129WriteBytes(uint8_t reg, uint8_t *p_buffer, size_t length)
{
  // ...
}

Public Functions: The Full Monty!

Comment every param on public functions, include an example if possible.

DOxygen style tags are not necessary, but the minimum amount of information should be included.

Why?
Because it stink to try to decipher exactly what the range on a parameter is, what that obscure looking pointer thingy actually does or wants, etc.!

Bonus Points: Adding a 2-3 line example of how to use this function takes two minutes when you're knee-deep writing the code, but it's a huge favour to the future you as well as anyone who has to deal with your code in the future. A simple code sample allows you to quickly digest how a function is meant to work, and goes a long way to getting started with the code quickly.
Download: file
/**************************************************************************/
/*!
    @brief  Sets the time on the RTC to the supplied value

    @param[in] time  The rtcTime_t variable containing the time to set

    @section EXAMPLE

    @code

    // Try to initialise the PCF2129 RTC
    if (pcf2129Init())
    {
      printf("PCF2129 failed to initialise");
    }
    else
    {
      // Set time to 10:04:00, 4 September 2012 (24-hour time)
      rtcTime_t time;
      rtcCreateTime(2012, RTC_MONTHS_SEPTEMBER, 4, 10, 4, 0, 0, &time);
      pcf2129SetTime(time);
    }

    @endcode
*/
/**************************************************************************/
error_t pcf2129SetTime(rtcTime_t time)
{
  // ...
}

Comment Blocks

Be consistent, and document key information in the code.

While some safety standards like MISRA state that you must use full opening and closing comments even for single line comments ... /* one line of commenty stuff */ ... two forward-slashes ... // ... is fine and doesn't matter on any modern C compiler.

For large, complex comment blocks, I've personally ended up with the following styles, though these are just suggestions.

Register Tables

This comment block describes individual bits for a config register. You generally have to read the documentation thoroughly once writing the first draft of the driver, but you'll quickly forget those details, so a bit of extra effort here pays off when future you needs to come back to the code, or when someone else needs to pick it up and debug.
Download: file
/* Set CONTROL1 register (0x00)
     ====================================================================
     BIT  Symbol    Description                                   Default
     ---  ------    --------------------------------------------- -------
       7  EXT_TEST  0 = Normal mode, 1 = External clock test mode       0
       6  --        RESERVED
       5  STOP      0 = RTC clock runs, 1 = RTC clock stopped           0
       4  TSF1      0 = No timestamp interrupt,                         0
                    1 = Flag set when TS input is driven to an
                        intermediate level between power supply
                        and ground. (Flag must be cleared to
                        clear interrupt.)
       3  POR_OVRD  0 = Power on reset override disabled                0
                    1 = Power on reset override enabled
       2  12_24     0 = 24 hour mode, 1 = 12 hour mode                  0
       1  MI        0 = Minute interrupt disabled, 1 = enabled          0
       0  SI        0 = Second interrupt disabled, 1 = enabled          0 */

  ASSERT_STATUS(pcf2129Write8(PCF2129_REG_CONTROL1, 0x00));

Config Setting/Macro Groups

I'm in the habit of creating a projectconfig.h file for every complex project I work on, and place all config settings and macros in this file.

To keeps things organized, I've come up with the following format for these config values:
Download: file
/*=========================================================================
    UART
    -----------------------------------------------------------------------

    CFG_UART_BAUDRATE         The default UART speed.  This value is used
                              when initialising UART, and should be a
                              standard value like 57600, 9600, etc.
                              NOTE: This value may be overridden if
                              another value is stored in EEPROM!
    CFG_UART_BUFSIZE          The length in bytes of the UART RX FIFO. This
                              will determine the maximum number of received
                              characters to store in memory.

    -----------------------------------------------------------------------*/
    #define CFG_UART_BAUDRATE           (115200)
    #define CFG_UART_BUFSIZE            (256)
/*=========================================================================*/

Documenting Resource Allocation

You can use these types of table to keep track of available pins or finite resources like EEPROM memory as follows, which is not only good practice for you but can help avoid problems later when other people interact with your code:
Download: file
/*=========================================================================
    EEPROM
    -----------------------------------------------------------------------
    EEPROM is used to persist certain user modifiable values to make
    sure that these changes remain in effect after a reset or hard
    power-down.  The addresses in EEPROM for these various system
    settings/values are defined below.  The first 256 bytes of EEPROM
    are reserved for this (0x0000..0x00FF).

    CFG_EEPROM_SIZE           The number of bytes available on the EEPROM
    CFG_EEPROM_RESERVED       The last byte of reserved EEPROM memory

          EEPROM Address (0x0000..0x00FF)
          ===============================
          0 1 2 3 4 5 6 7 8 9 A B C D E F
    000x  x x . . x x x x x x x x . . . .   Chibi Node Addresses
    001x  . . . . . . . . . . . . . . . .
    002x  . . . . . . . . . . . . . . . .
    003x  . . . . . . . . . . . . . . . .
    004x  x x x x . . . . x x x x x x x x   Accelerometer Cal Settings
    005x  x x x x x x x x x x x x x x x x
    006x  x x x x . . . . x x x x x x x x   Magnetometer Cal Settings
    007x  x x x x x x x x x x x x x x x x
    008x  x x x x . . . . x x x x x x x x   Gyroscope Cal Settings
    009x  x x x x x x x x x x x x x x x x
    00Ax  . . . . . . . . . . . . . . . .
    00Bx  . . . . . . . . . . . . . . . .
    00Cx  . . . . . . . . . . . . . . . .
    00Dx  . . . . . . . . . . . . . . . .
    00Ex  . . . . . . . . . . . . . . . .
    00Fx  . . . . . . . . . . . . . . . .

    -----------------------------------------------------------------------*/
    #define CFG_EEPROM_SIZE                         (4032)
    #define CFG_EEPROM_RESERVED                     (0x00FF) // Protect the first 256 bytes of memory

    #define CFG_EEPROM_CHIBI_NODEADDR               (uint16_t)(0x0000)  // 2
    #define CFG_EEPROM_CHIBI_IEEEADDR               (uint16_t)(0x0004)  // 8

    #define CFG_EEPROM_SENSORS_CAL_ACCEL_CONFIG     (uint16_t)(0x0040)  // 2
    #define CFG_EEPROM_SENSORS_CAL_ACCEL_SENSORID   (uint16_t)(0x0042)  // 2
    #define CFG_EEPROM_SENSORS_CAL_ACCEL_X_SCALE    (uint16_t)(0x0048)  // 4
    #define CFG_EEPROM_SENSORS_CAL_ACCEL_X_OFFSET   (uint16_t)(0x004C)  // 4
    #define CFG_EEPROM_SENSORS_CAL_ACCEL_Y_SCALE    (uint16_t)(0x0050)  // 4
    #define CFG_EEPROM_SENSORS_CAL_ACCEL_Y_OFFSET   (uint16_t)(0x0054)  // 4
    #define CFG_EEPROM_SENSORS_CAL_ACCEL_Z_SCALE    (uint16_t)(0x0058)  // 4
    #define CFG_EEPROM_SENSORS_CAL_ACCEL_Z_OFFSET   (uint16_t)(0x005C)  // 4

    #define CFG_EEPROM_SENSORS_CAL_MAG_CONFIG       (uint16_t)(0x0060)  // 2
    #define CFG_EEPROM_SENSORS_CAL_MAG_SENSORID     (uint16_t)(0x0062)  // 2
    #define CFG_EEPROM_SENSORS_CAL_MAG_X_SCALE      (uint16_t)(0x0068)  // 4
    #define CFG_EEPROM_SENSORS_CAL_MAG_X_OFFSET     (uint16_t)(0x006C)  // 4
    #define CFG_EEPROM_SENSORS_CAL_MAG_Y_SCALE      (uint16_t)(0x0070)  // 4
    #define CFG_EEPROM_SENSORS_CAL_MAG_Y_OFFSET     (uint16_t)(0x0074)  // 4
    #define CFG_EEPROM_SENSORS_CAL_MAG_Z_SCALE      (uint16_t)(0x0078)  // 4
    #define CFG_EEPROM_SENSORS_CAL_MAG_Z_OFFSET     (uint16_t)(0x007C)  // 4

    #define CFG_EEPROM_SENSORS_CAL_GYRO_CONFIG      (uint16_t)(0x0080)  // 2
    #define CFG_EEPROM_SENSORS_CAL_GYRO_SENSORID    (uint16_t)(0x0082)  // 2
    #define CFG_EEPROM_SENSORS_CAL_GYRO_X_SCALE     (uint16_t)(0x0088)  // 4
    #define CFG_EEPROM_SENSORS_CAL_GYRO_X_OFFSET    (uint16_t)(0x008C)  // 4
    #define CFG_EEPROM_SENSORS_CAL_GYRO_Y_SCALE     (uint16_t)(0x0090)  // 4
    #define CFG_EEPROM_SENSORS_CAL_GYRO_Y_OFFSET    (uint16_t)(0x0094)  // 4
    #define CFG_EEPROM_SENSORS_CAL_GYRO_Z_SCALE     (uint16_t)(0x0098)  // 4
    #define CFG_EEPROM_SENSORS_CAL_GYRO_Z_OFFSET    (uint16_t)(0x009C)  // 4
/*=========================================================================*/
Another example of documenting resource allocation might be displaying which pins or interrupts are used by which driver to avoid conflicts on complex systems:
Download: file
/*=========================================================================
    GPIO INTERRUPTS
    -----------------------------------------------------------------------
    This table shows where GPIO interrupts are mapped in this project
    (Note that the LPC11U and LPC13U use different names for the
    IRQ Handlers in the standard headers)

    Interrupt                                     Location
    ------------------------------------------    -------------------------
    PIN_INT0_IRQHandler - FLEX_INT0_IRQHandler    chb_drvr.c
    PIN_INT1_IRQHandler - FLEX_INT1_IRQHandler    pcf2129.c
    PIN_INT2_IRQHandler - FLEX_INT2_IRQHandler    spi.c (cc3000)
    PIN_INT3_IRQHandler - FLEX_INT3_IRQHandler
    PIN_INT4_IRQHandler - FLEX_INT4_IRQHandler
    PIN_INT5_IRQHandler - FLEX_INT5_IRQHandler
    PIN_INT6_IRQHandler - FLEX_INT6_IRQHandler
    PIN_INT7_IRQHandler - FLEX_INT7_IRQHandler
    GINT0_IRQHandler
    GINT0_IRQHandler
    -----------------------------------------------------------------------*/
/*=========================================================================*/
This guide was first published on May 01, 2014. It was last updated on May 01, 2014.
This page (Comments) was last updated on Jul 04, 2020.