为了好玩,我深入研究了 IDA 和 eagle_soc.h,看看哪些寄存器用于访问 GPIO 引脚。事实证明,有几种方法可以处理引脚,在这里我想分享我目前的结果。请注意,这确实包括选择引脚的实际功能,我稍后会看到。此外,到目前为止,这仅适用于 GPIO0 和 GPIO2,因为我只有一个模块将这两个公开为 GPIO。但这应该足以给你一个想法。
有几个寄存器允许设置/清除作为输出的引脚,使引脚成为输入或输出,以及读取输入引脚。首先,我将这些 PROVIDE 添加到主链接器脚本 eagle.app.v6.ld 中,以使这些寄存器可用:
代码:
全选PROVIDE(PIN_OUT = 0x60000300);
PROVIDE(PIN_OUT_SET = 0x60000304);
PROVIDE(PIN_OUT_CLEAR = 0x60000308);
PROVIDE(PIN_DIR = 0x6000030C);
PROVIDE(PIN_DIR_OUTPUT = 0x60000310);
PROVIDE(PIN_DIR_INPUT = 0x60000314);
PROVIDE(PIN_IN = 0x60000318);
PROVIDE(PIN_0 = 0x60000328);
PROVIDE(PIN_2 = 0x60000330);
在您的 C 代码或包含文件中,您可以将它们定义为外部变量以访问它们:
代码:
全选extern uint32_t PIN_OUT;
extern uint32_t PIN_OUT_SET;
extern uint32_t PIN_OUT_CLEAR;
extern uint32_t PIN_DIR;
extern uint32_t PIN_DIR_OUTPUT;
extern uint32_t PIN_DIR_INPUT;
extern uint32_t PIN_IN;
extern uint32_t PIN_0;
extern uint32_t PIN_2;
PIN_OUT 是一个寄存器,它同时保存所有引脚的输出。位 0 = GPIO0,位 2 = GPIO2。那里写的任何内容都会立即影响所有引脚。例如,写入 0x01 会将 GPIO0 设置为高电平,将 GPIO2 设置为低电平。写入 0x04 会将 GPIO2 设置为高电平,将 GPIO0 设置为低电平。0x05 将两者都设置为高,0x00 将两者都设置为低。这意味着如果您使用多个引脚作为输出,您必须准备好写入该寄存器的内容,以免意外更改您不想更改的任何其他引脚。
PIN_OUT_SET 是一个只将一个引脚设置为高电平的寄存器。设置的任何位都会将该引脚设置为高电平,任何未设置的引脚都将完全无效。例如,假设 GPIO0 和 GPIO2 均为低电平。将 0x01 写入该寄存器会将 GPIO0 设置为高电平。现在向它写入 0x04 会将 GPIO2 设置为高电平,而 GPIO 保持不变,即仍然为高电平。这对于快速设置特定引脚很有用,而无需屏蔽其他引脚,芯片将自行完成。
PIN_OUT_CLEAR 就像_SET,只是任何“1”位都会将相应的引脚设置为低电平。因此,继续上面的内容,向该寄存器写入 0x01 不会将 GPIO0 设置为低电平,而 GPIO2 仍然保持高电平,然后写入 0x04 会将 GPIO2 设置为低电平。
PIN_DIR 的组织方式与 PIN_OUT 类似,即它同时影响所有引脚。设置的任何位都会使该引脚成为输出。例如,写入 0x05 将使 GPIO0 和 GPIO2 输出,写入 0x01 将使 GPIO0 成为输出,GPIO2 成为输入,等等。PIN_DIR_OUTPUT 类似于
PIN_OUT_SET,只是这会将引脚方向更改为输出而不是输出电平。随后,PIN_DIR_INPUT 将引脚设置为输入。同样,仅写入“1”位会导致更改。
PIN_IN 保存引脚的输入状态。任何“1”位表示相关引脚为逻辑高电平,任何“0”位表示逻辑 0。无论引脚配置为输出还是输入,这些位都会发生变化。将一个引脚设置为输出然后将其设置为高电平也会将该寄存器中该引脚的位设置为高电平,
现在,上面我还给出了 PIN_0 和 PIN_2 的地址。到目前为止,我还不知道这些是做什么的。我猜这些是为了以某种方式配置特定的引脚。并非所有位都可以设置,例如 PIN_2。根据输出状态,我可以通过在那里切换位 0 来切换引脚,但我不确定这是否会硬驱动引脚或者是否有一些上拉/下拉的东西在那里愚弄我。
无论如何,_OUT_SET 和 _OUT_CLEAR 寄存器非常有用,_DIR_OUTPUT 和 _DIR_INPUT 寄存器也是如此,如果想要快速设置/清除引脚或改变它们的方向,而不通过提供的 API,它总是需要 4 个参数,这些参数被移交给一个在 ROM 中的功能,然后在那里使用。直接访问它们将减少开销。
哦,当然 PIN_OUT 和 PIN_DIR 寄存器也可以读回(但不是设置/清除和输入/输出寄存器,它们在读取时总是返回 0)
0