首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >最佳通用实践I2C寄存器映射

最佳通用实践I2C寄存器映射
EN

Stack Overflow用户
提问于 2012-11-20 14:54:58
回答 2查看 3.8K关注 0票数 5

只是想知道关于I 2 C寄存器地图的最佳做法是什么,或者更确切地说,其他人经常/喜欢使用什么。

到目前为止,我通常已经做了很多定义,一个针对每个寄存器,一个针对所有比特、掩码、移位等。然而,最近我看到一些驱动程序使用(可能是打包)结构而不是定义的。我认为这些是Linux内核模块。

不管怎样,他们会

代码语言:javascript
运行
复制
struct i2c_sensor_fuu_registers {

    uint8_t  id;
    uint16_t big_register;
    uint8_t  another_register;
    ...

} __attribute__((packed));

然后,他们将使用偏移(或宏)来获取i2c寄存器,并对要读取的字节数使用大号。

我认为这两种方法都有其优点:

结构方法:

  • (+)寄存器偏移量在逻辑上都包含在结构中,而不必在定义中拼写每个寄存器。
  • (+)条目大小使用适当大小的数据类型显式说明。
  • (-)这不包括广泛使用的位字段
  • (-)这不包括未映射字节的寄存器映射(例如LM75),其中一个从偏移量n+0x00读取2个字节,而n+0x01是另一个寄存器,而不是寄存器n+0x00的高/低字节
  • (-)这并不能解释地址空间的巨大差距(例如,寄存器在0x00,0x01,0x80,0xAA,无中间.)还有(我想呢?)依赖于编译器优化来消除结构。

界定方法:

  • (+)每个寄存器及其位通常是在一个块中定义的,这样很容易找到正确的符号,并且依赖于命名约定。
  • (+)透明/不了解解决空间差距的问题。
  • (-)每个登记册必须单独定义,即使没有空白
  • (-)因为定义往往是全局的,所以名称通常很长,在源代码中乱扔几十个长符号名。
  • (-)要读取的数据大小通常是硬编码魔术数字或(end + 1)样式的计算,可能有长的符号名。
  • (o)透明/不了解地图中的数据大小与地址。

基本上,我在寻找一种更明智的方法来处理这些案件。我经常发现自己为每个寄存器和每个位输入了很多令人痛苦的长符号名,可能还有掩码和移位(后两个取决于数据类型),最后只使用其中的几个符号(但讨厌稍后重新定义丢失的符号,这就是为什么我在一个会话中输入所有符号)。不过,我注意到读/写字节的大小大多是神奇的数字,通常需要并行读取数据表和源代码才能理解甚至最基本的交互。

我想知道其他人是如何处理这种情况的?我在网上找到了一些例子,人们也在一个大标题中艰难地输入了每一个寄存器、位等等,但是没有什么非常明确的.然而,上述两种选择在这一点上似乎都不太明智:

EN

Stack Overflow用户

回答已采纳

发布于 2012-11-20 16:22:48

警告:这里描述的方法使用位字段,其在内存中的排列是特定于实现的。如果这样做,请确保您知道编译器在这方面的工作方式。

正如您所指出的,每种方法都有其优点和缺点。我喜欢混合的方法。您可以定义寄存器偏移量,但随后使用结构表示内容,并使用联合指定位或整个寄存器。在联合内部,使用正确的大小变量来表示寄存器的大小(正如您所提到的,有时它们不是字节可寻址的)。你不需要那么多的定义,你不太可能搞砸位转移,也不需要面具。例如:

代码语言:javascript
运行
复制
#define unsigned char u8;
#define unsigned short u16;

#define CTL_REG_ADDR  0x1234
typedef union {
  struct { 
    u16 not_used:10; //top 10 bits ununsed
    u16 foo_bits:3;  //a multibit register
    u16 bar_bit:1;   //just one bit
    u16 baz_bits:2;  //2 more bits
  } fields;
  u16 raw;
} CTL_REG_DATA;

#define STATUS_REG_ADDR 0x58
typedef union {
  struct { 
    u8 bar_bits:4;  //upper nibble
    u8 baz_bits:4;  //lower nibble
  } fields;
  u8 raw;
} STATUS_REG_DATA;

//use them like the following
u16 readregister(u16);
void writeregister(u16,u16);

CTL_REG_DATA reg;
STATUS_REG_DATA rd;
rd = readregister(STATUS_REG_ADDR);
if (rd.fields.bar_bit) {
   reg.raw = 0xffff;        //set every bit
   reg.fields.bar_bit = 0;  //but clear this one bit
   writeregister(CTL_REG_ADDR, reg);
}
票数 2
EN
查看全部 2 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13475828

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档