【问题标题】:Enable GPIO on AM335x in C在 C 中启用 AM335x 上的 GPIO
【发布时间】:2023-04-04 04:13:01
【问题描述】:

我有以下函数initGPIO。目标是使用 am335x 在 beaglebone 上启用 GPIO 0、1 和 2。如何启用相应的 GPIO 设置为头文件中给出的 reg_GPIO?我有头文件 GPIO.h,其中包含 GPIO 的编号、寄存器编号和寄存器结构。我试图在函数 initGPIO 中设置 GPIO。有意义吗?

gpio.h

#include <stdint.h>
#include <stdbool.h>

#define GPIO0 0  /*!< GPIO 0 number */
#define GPIO1 1 /*!< GPIO 1 number */
#define GPIO2 2 /*!< GPIO 2 number */
#define GPIO3 3 /*!< GPIO 3 number */

// Base address for each gpio hardware module.
#define GPIO0_REG  0x44E07000  //<! gpio0 hardware module address.
#define GPIO1_REG  0x4804C000  //<! gpio1 hardware module address.
#define GPIO2_REG  0x481AC000  //<! gpio2 hardware module address.
#define GPIO3_REG  0x481AE000  //<! gpio3 hardware module address.

// Register Structure
typedef struct
{
    volatile uint32_t irqstatus_set_0;   // Offset 0x34 - Enables specific interrupt event to trigger.
    volatile uint32_t irqstatus_set_1;   // Offset 0x38 - Enables specific interrupt event to trigger.
    volatile uint32_t irqwaken_0;        // Offset 0x44 - Enables wakeup events on an interrupt.
    volatile uint32_t irqwaken_1;        // Offset 0x48 - Enables wakeup events on an interrupt.
    volatile uint32_t ctrl;  // Offset 0x130 - Controls clock gating functionality, i.e. enables module.
    volatile uint32_t oe; // Offset 0x134 – Output Enable pin (clear bit to 0) output capability.
    volatile uint32_t datain;            // Offset 0x138 - Registers data read from the GPIO pins.
    volatile uint32_t dataout;           // Offset 0x13c - Sets value of GPIO output pins.
    volatile uint32_t cleardataout;      // Offset 0x190 - Clears to 0 bits in dataout
    volatile uint32_t setdataout;        // Offset 0x194 - Sets to 1 bits in dataout
} GPIO_REGS;


void initGPIO();

gpio.c

/*!
 * \brief Initialize GPIOs.
 *
 * Enables GPIO0, GPIO1, and GPIO2 (GPIO3 not used in IDP. Also configures the output pins
 * used in the IDP to control relays and address the ADC's on relays.
 *
 *****************************************************************************************/
void initGPIO()
{

    //enable GPIOs
    GPIO_REGS gpio_regs;
    //might need to change ctrl

    gpio_regs.datain |= (GPIO0 << GPIO0_REG  );
    gpio_regs.datain |= (GPIO1 << GPIO1_REG  );
    gpio_regs.datain |= (GPIO2 << GPIO2_REG  );
}

【问题讨论】:

  • 是关于裸机还是假定操作系统?如果后者是真的,那是哪个操作系统?更新标签!

标签: c gpio beagleboneblack


【解决方案1】:

默认情况下,Beaglebones 与 Debian Linux 一起提供。除非您决定放弃它,否则内核有一个 GPIO 驱动程序,它假定控制所有 GPIO。您不应尝试直接访问原始 GPIO 寄存器,而应与内核驱动程序对话。最简单的方法是安装libgpiod(可能在最近的 Beagles 上默认安装)并调用其 API。

【讨论】:

    【解决方案2】:

    对于裸机平台,您可能习惯于执行以下操作来访问硬件地址:

    volatile GPIO_REGS* gpio1_regs = (GPIO_REGS*)0x44E07000;
    volatile GPIO_REGS* gpio2_regs = (GPIO_REGS*)0x4804C000;
    

    现在您的代码也没有这样做,但我会假设这就是您的意思。 除了在操作系统内部,用户空间应用程序中的内存偏移量不会一对一地映射到硬件地址偏移量,这根本行不通。

    如果你想直接寄存器访问这样的东西,你必须使用/dev/mem 或者如果你的平台支持它,/dev/gpiomem 做一些类似内存映射的事情(我知道 Raspberry Pi 支持这个,我不是确定BBB)。这将检查是否允许您访问所需的硬件地址范围,并确保地址范围在您的用户空间中正确映射。

    例如:

    /* open /dev/mem */
    int fd = open("/dev/mem", O_RDWR|O_SYNC);
    if (fd >= 0) {
        /* mmap GPIO */
        volatile GPIO_REGS* gpio1_regs = mmap(NULL, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0x44E07000);
        close(fd); /* No need to keep fd open after mmap */
    
        /* Check for MAP_FAILED error */
        if (gpio1_regs != (GPIO_REGS*)-1) {
            /* Do whatever */
    

    (mmap 的最后一个参数是您放置硬件地址的位置,在此示例中我使用的是 0x44E07000。)

    如需进一步阅读,另请参阅:

    【讨论】:

    • windows对应的dev/mem是什么?
    • 对于 Windows,这是内存映射 IO 访问的良好起点:docs.microsoft.com/en-us/windows-hardware/drivers/wdf/…
    • 对你的问题很感兴趣,我尽可能地搜索,但我没有找到任何人在 Beaglebone Black 上成功运行 Windows(我假设是 Windows IoT?!),那么你为什么要/dev/mem Windows 的替代品?
    最近更新 更多