Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Info

This is not where syntax/style standards are discussed. For that, visit this page

Info

Any code snippets below are probably closer to pseudocode, they are meant to depict a concept not to be copy and pasted

...

These standards were developed with the following goals and realities in mind:

  1. Replicability

We want these standards to work for all applications, regardless of purpose, hardware, or other specifics.

  1. User-Friendly

Given the high turnover within the club, standards should be easy to follow and maintain a logical flow

  1. Memory-Consciousness

Running into memory issues sucks, and our standards will ensure efficiency in that regard

  1. Industry-Standardization

We want users to gain technical skills applicable to industry, these rules should be common methods. The Linux Kernel is always a good starting point, and will be the foundation of most practices (though we can veer away as needed)

  1. Being Realistic

Whether in support of or as an exception to anything above, we want to keep in mind that our hardware peripherals and high-level architecture are not changing too much on a year-to-year basis, and we will take advantage of that fact to promote simplicity

...

This choice is definitely one that you will see both ways in embedded, and is arguable the most debatable one here. In the end, we this choice was made because:

...

Also, this rule is almost a direct contradiction to the rule described in “Movement of Objects”, but since these are not being treated as objects, I’m allowing it.

All embedded base drivers should be made independent of any HAL or hardware layerother driver. Instead of relying on hard set driversa specific HAL, function pointers should be used to maintain this. to allow any HAL to work with the driver

Instead of this:

Code Block
int lsmdso_read_reg(uint8_t reg)
{
  return HAL_i2c_Mem_read(...); // THIS IS A FUNCTION FROM STM ONLY FOR CERTAIN STM32 DEVICES
}

Which relies on STM’s HAL i2c driver,

...

Code Block
typedef void (*I2C_WriteFuncPtr)(int device_addr, int reg_addr, int data);
typedef int (*I2C_ReadFuncPtr)(int device_addr, int reg_addr);

typedef struct static{
I2C_WriteFuncPtr local_I2C_Write = NULL;
static
I2C_ReadFuncPtr local_I2C_Read = NULL;
} lsm6dso_init(I2C_WriteFuncPtr write_func, I2C_ReadFuncPtr read_func)
{
    local_I2C_Write = write_func;
    local_I2C_Read = read_func;
}

t;

lsm6dso_t imu; //DEFINE OBJECT HERE

int lsmdso_read_reg(uint8_t reg)
{
  return local_I2C_Read(...);
}


(main.c)

lsm6dso_t imu;
imu = {.I2C_WriteFuncPtr = HAL_i2c_MemWrite, .I2C_ReadFuncPtr = HAL_i2c_MemRead};

While this is obviously more work, it means that these drivers should succeed for the foreseeable future and for all different chip sets in use right now, without having to change.

Also note the method of updating these values does utilize extern. For devices where more than one of these devices may be present on the bus, have the driver and its APIs have a device select parameter to dynamically update to a different device, do not make multiple instances of the device struct. In the above example, you may notice the first parameter is “device address”. This would allow you to have multiple lsm6dso’s on the bus (as they’d have the different i2c addresses), but they both use the same, local lsm6dso object, which works because this object only contains function pointers to i2c read and write, which will be the same no matter which instance of the hardware you are refencing.

Info

Note that this requires function signatures that match those of the function pointers defined in the driver. Make these as general as possible, and keep in mind wrappers may need to be made around the HAL in use to ensure their signature is the same