只是想知道在 C 中关于 I²C 寄存器映射的最佳实践是什么,或者更确切地说是其他人经常使用/喜欢什么。
到目前为止,我通常已经做了很多定义,一个用于每个寄存器,一个用于所有位、掩码、移位等。但是,最近我看到一些驱动程序使用(可能是打包的)结构而不是定义。我认为这些是 Linux 内核模块。
无论如何,他们会
struct i2c_sensor_fuu_registers {
uint8_t id;
uint16_t big_register;
uint8_t another_register;
...
} __attribute__((packed));
然后他们将使用 offsetof(或宏)来获取 i2c 寄存器并使用 sizeof 来读取要读取的字节数。
我发现这两种方法都有其优点:
结构方法:
- (+) 寄存器偏移在逻辑上都包含在结构中,而不必在定义中拼出每个寄存器。
- (+) 条目大小使用适当大小的数据类型明确说明。
- (-) 这不考虑广泛使用的位字段
- (-) 这不考虑不是字节映射的寄存器映射(例如 LM75),其中一个从偏移量 n+0x00 读取 2 个字节,但 n+0x01 是另一个寄存器,而不是寄存器 n 的高/低字节+0x00
- (-) 这并没有考虑地址空间中的大间隙(例如,0x00、0x01、0x80、0xAA 处的寄存器,没有中间...)并且(我认为?)依赖于编译器优化来摆脱结构.
定义方法:
- (+) 每个寄存器及其位通常在一个块中定义,这使得查找正确的符号变得容易并依赖于命名约定。
- (+) 透明/不知道地址空间间隙。
- (-) 每个寄存器都必须单独定义,即使没有间隙
- (-) 因为定义往往是全局的,所以名称通常很长,在源代码中有些乱七八糟的长符号名称。
- (-) 要读取的数据大小通常是硬编码的幻数或 (end - start + 1) 样式的计算,符号名称可能很长。
- (o) 透明/不知道数据大小与地图中的地址。
基本上,我正在寻找一种更聪明的方法来处理这些情况。我经常发现自己为每个寄存器和每个位以及可能的掩码和移位(后两个取决于数据类型)键入了很多令人痛苦的长符号名称,只是最终只使用了其中的几个(但讨厌稍后重新定义缺少的符号,这就是我在一个会话中输入所有符号的原因)。尽管如此,我注意到要读取/写入的字节大小主要是幻数,通常需要并排读取数据表和源代码才能理解最基本的交互。
我想知道其他人如何处理这些情况?我在网上找到了一些示例,其中人们还费力地在一个大标题中输入了每个寄存器、位等,但没有什么非常确定的……但是,在这一点上,上面的两个选项似乎都不太聪明:(