|
When I write a low-level driver for a microcontroller, I always use a configuration table to initialization the driver. For example, I might create a structure like the following:
typedef struct {
DioChannel_t Channel; /**< The I/O pin */
DioResistor_t Resistor; /**< ENABLED or DISABLED */
DioDirection_t Direction; /**< OUTPUT or INPUT */
DioPinState_t Data; /**<HIGH or LOW */
DioMode_t Function; /**< Mux Function – Dio_Peri_Select*/
}DioConfig_t;
An example configuration table might look something like the following:
const DioConfig_t DioConfig[] =
{
/* Resistor Initial */
/* Channel Enabled Direction Pin Function */
/* */
{ PORT1_0, DISABLED, OUTPUT, HIGH, FCN_GPIO },
{ PORT1_1, DISABLED, OUTPUT, HIGH, FCN_GPIO },
{ PORT1_2, DISABLED, OUTPUT, HIGH, FCN_GPIO },
{ PORT1_3, DISABLED, OUTPUT, HIGH, FCN_GPIO },
{ PORT1_4, DISABLED, OUTPUT, HIGH, FCN_GPIO },
{ PORT1_5, DISABLED, OUTPUT, HIGH, FCN_GPIO },
{ PORT1_6, DISABLED, OUTPUT, HIGH, FCN_GPIO },
{ PORT1_7, DISABLED, OUTPUT, HIGH, FCN_GPIO },
};
There are at least a dozen advantages to writing your code this way, but the top 5 advantages are:
-
Code Readability: Having all the configuration parameters organized within a single structure makes the code more readable. This aids in understanding the purpose and function of each parameter quickly.
-
Modularity: The use of a structure allows for easy modification and expansion. If a new feature or setting needs to be added to the driver in the future, a new member can be added to the structure without significantly altering the rest of the driver code.
-
Centralized Configuration: All the necessary configurations are in one place, making it easier to understand the peripheral’s setup at a glance. This also reduces the chances of missing a configuration or making configuration mistakes.
-
Ease of Initialization: With such a structure, initialization of the peripheral can be done by simply passing an instance of this configuration structure to an initialization function. This keeps the initialization code cleaner and more organized.
-
Automateable: This probably isn’t a word, but the idea is that if you have a nice configuration structure like this, you can leverage the use of configuration files like YAML and TOML to generate custom configuration files for different projects. Keeping one driver that is configured based on its need.
If you ever write a low-level driver, don’t just bit bang the value of registers. Carefully think through the reuse case. Very few companies today are writing code for a single product. It’s all about writing configurable code that builds a platform of products.
|