首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用于嵌入式开发的Pin掩码协议

用于嵌入式开发的Pin掩码协议
EN

Stack Overflow用户
提问于 2014-02-23 04:23:53
回答 3查看 2.4K关注 0票数 1

对于嵌入式C应用程序,我一直使用以下约定来定义GPIO引脚掩码:

‘传统’示例:32位CPU与32位GPIO端口

在GPIO输出寄存器中断言bit5以打开led。

代码语言:javascript
复制
#define BIT5 (1u << 5)      //or maybe even just hardcode as 0x20
...
#define PIN_LED_CTRL (BIT5) //LED_CTRL is Pin #5
...
void gpio_set(uint16_t pin_mask) {
    GPIO_OUT |= pin_mask;
}
...
//turn the led on
gpio_set(PIN_LED_CTRL);

在最近的一个多开发人员嵌入式项目中,一个开发人员选择了以下语法

的替代示例:32位CPU和32位GPIO端口

代码语言:javascript
复制
#define PIN(x) (1u << (x##_PIN_NUM))
...
#define LED_CTRL_PIN_NUM (5)
...
void gpio_set(uint16_t pin_mask) {
    GPIO_OUT |= pin_mask;
}
...
//turn the led on
gpio_set(PIN(LED_CTRL));

没有真正清楚地解释为什么选择这一办法。与所有文档化的代码一样,它看起来很神秘,以至于“cleary”可以保证它的实现。当然,开发人员知道一些我不知道的事情。在这种情况下,这家伙是一个聪明的饼干来自CPU驱动世界。

反对

我一点也不喜欢“alt”的方法。它看起来太可爱了,为了自己的利益。但我能提出的唯一理由是:

  • 'LED_CTRL‘不是编译时常数
    • 此外,您还不能在IDE中下降/检查它。

  • 'LED_CTRL_PIN_NUM‘与uri命名模式完全相反。
    • 例如PIN_NUM_abc是首选

  • 没有其他人这么做*
  • 看上去很奇怪

但在我看来,这似乎是一种抱怨;所有这些都不是反对使用“alt”方法的真正理由。

问题

为什么有人会使用'alt‘方法呢?这可能是桌面驱动程序中注册表使用中的一种方式吗?

是否有任何常见的嵌入式MCU库、替代目标或编程语言使用这种“alt”方法?

谢谢!

*在一天结束时,我可能会坚持“它看起来很奇怪”:)。

EN

回答 3

Stack Overflow用户

发布于 2014-02-23 10:01:59

这两种方法几乎是一样的,只是风格不同,但问题是相同的。

通常,引脚不是由位数定义的,您还需要知道端口。

因此,在更改端口时,不仅需要修改定义,还需要修改代码。

代码语言:javascript
复制
#define PIN_LED_CTRL (BIT5) //LED_CTRL is Pin #5
...
void gpio_set_port2(uint16_t pin_mask) {
    GPIO2_OUT |= pin_mask;
}
...
//turn the led on
gpio_set_port2(PIN_LED_CTRL);

我只需要定义一次引脚,所有不同的依赖项都是由宏或函数构建的。

代码语言:javascript
复制
#define HW_SPI_CLOCK    2,5    // uses port2,bit5
#define HW_RESET_EXT    4,3    // uses port4,bit3

然后,我使用一些宏来定义获取端口方向、pushPull和其他寄存器。

这些宏几乎不依赖于平台和工具链。

代码语言:javascript
复制
/**
 * Generic GH-Macros
 */
#define PASTE2(a,b)       a##b
#define PASTE3(a,b,c)     a##b##c
#define __PASTE3(a,b,c)     PASTE3(a,b,c)
#define PASTE4(a,b,c,d)   a##b##c##d
#define PASTE6(a,b,c,d,e,f)     a##b##c##d##e##f
#define __PASTE6(a,b,c,d,e,f)     PASTE6(a,b,c,d,e,f)

#define GH_PORT(port,pin)       port
#define GH_PIN(port,pin)       pin
#define GPIO_PIN(gh)      __PASTE6(FIO,GH_PORT(gh),PIN_bit.P,GH_PORT(gh),_,GH_PIN(gh))
#define GPIO_DIR(gh)      __PASTE6(FIO,GH_PORT(gh),DIR_bit.P,GH_PORT(gh),_,GH_PIN(gh))
票数 1
EN

Stack Overflow用户

发布于 2014-02-23 06:02:08

假设"Alternative“示例中有一个错误(在最后一行中,您指定了"LED_CTRL",它没有定义).我假设您的意思是"LED_CTRL_PIN_NUM"),那么我相信这两个示例将产生相同的机器代码。所以,在这两种选择之间。这只是一个风格偏好的问题。(第二个示例中的##只是一个嵌入的注释。)

就我个人而言,我会使用一种完全不同的方法。我会使用内置的位字段构造来修改一个按位排列的字段,这样编译器就可以决定什么是最有效的方法。例子如下:

代码语言:javascript
复制
struct {
    unsigned int :4, LED_CTRL:1, :27;
} GPIO_OUT;
...
GPIO_OUT.LED_CTRL = 1;

注意,":4“和":27”指的是寄存器中的其他位.您可能希望映射整个I/O寄存器,而不仅仅是其中的一部分。

票数 0
EN

Stack Overflow用户

发布于 2014-02-23 08:12:50

Bitfield: SGeorgiades在上面给出了一个有风险的问题的答案*

如果您正在使用C Bitfield来定义您的引脚,请非常小心。

  • 位字段'type‘与实现相关(需要引用;int/uint)
  • 字段在默认情况下并不是连续的按位排列,并且被提升到与驱动相关的大小。
  • 跨越int-位大小边界的位字段在位域映射中不会是连续的!(需要报价)

对于GCC/C11,我将使用以下位域语法(如果我使用它)

代码语言:javascript
复制
struct gpio_out {
    int b0        : 1;
    int led_ctrl  : 1;
    ....
    int b30       : 1;
    int b31       : 1;
} __attribute__((packed));

Notes

  • 通过将引脚位置的概念合并到结构中,您不能与gpio中的其他寄存器共享它(例如,DIR、IN、INT_EN、IFG等)。
  • 我将提供这里提出的要点的x86反汇编示例。它们非常依赖于实现和编译器配置!

*如果我弄错了,请纠正我。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21964192

复制
相关文章

相似问题

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