【问题标题】:Unable to get 2 LEDs working. [Raspberry pi, bare metal]无法让 2 个 LED 工作。 [树莓派,裸机]
【发布时间】:2014-05-18 09:10:14
【问题描述】:

我在让 2 个 LED 一个接一个或同时发光时遇到问题。但是,它们一次只能单独工作一个。当我尝试在同一个程序中实现这一点时,问题就来了。只有第一个 LED 开始闪烁而不是另一个。 以下是我的代码:

#define GPFSEL1 0x20200004
#define GPFSEL2 0x20200008

#define GPSET0  0x2020001C
#define GPCLR0  0x20200028

#define SET_PIN18_OUTPUT (0x01 << 24) // GPFSEL1
#define SET_PIN23_OUTPUT (0x01 << 9)  // GPFSEL2
#define SET_PIN24_OUTPUT (0x01 << 12) // GPFSEL2

#define SET_GPION(x)   (0x01 << x)
#define CLEAR_GPION(x) (0x01 << x)

#define NUM_OF_LEDS 3

//-------------------------------------------------------------------------
typedef unsigned int* UINT32_P;

void dummy(volatile unsigned int val)
{
  val++;
}

void setBit(unsigned int regAdd, unsigned char bit)
{
  unsigned int temp;
  temp  = *(UINT32_P)(regAdd);
  temp  |= (0x1 << bit);
  *(UINT32_P)(regAdd) = temp;
}

void clearBit(unsigned int regAdd, unsigned char bit)
{
  unsigned int temp;
  temp = *(UINT32_P)(regAdd);
  temp &= ~(1 << bit);
  *(UINT32_P)(regAdd) = temp;
}

int notmain ( void )
{
    unsigned int ra;

    setBit(GPFSEL1, 24);  // Configure PIN 18 to output
    setBit(GPFSEL2, 12);  // Configure PIN 24 to output
    while(1)
    {
    // L1 - -
    setBit(GPSET0, 18);
    setBit(GPSET0, 24);
    for(ra=0;ra<0x100000;ra++) dummy(ra);


    // - L2 -
    setBit(GPCLR0, 18);
    setBit(GPCLR0, 24);
    for(ra=0;ra<0x100000;ra++) dummy(ra);

    for(ra=0;ra<0x100000;ra++) dummy(ra);



    }
    return(0);
}

【问题讨论】:

  • 您最好从这段代码中删除未使用的冗余宏 - 这只会分散任何可能帮助您的人的注意力。
  • 样式修复:使用 stdint.h (C99) 中的 uint32_t,#define SET_GPION(x) (0x01

标签: c embedded raspberry-pi bare-metal


【解决方案1】:

GPIO 外设具有用于设置 (GPSET0) 和清除 (GPCLR0) 输出引脚的单独寄存器,因此您不必执行读取-修改-写入操作。写入 GPSET 寄存器仅设置为 1 的位,而为 0 的位保持不变。并且写入 GPCLR 寄存器只会清除为 1 的位,而为 0 的位保持不变。

您不应使用 setBit()clearBit() 例程来设置和清除 GPIO 输出。这些例程可能适用于其他没有用于设置和清除位的单独寄存器的外围设备。但是读取-修改-写入操作不适用于GPSET0GPCLR0。事实上,read-modify-write 操作实际上可能是您的问题的根源。可能GPSET0GPCLR0 在您阅读它们时总是返回 0x00000000,因为永远不需要阅读它们。 (我不确定,我只是推测。)

您应该直接写入GPSET0GPCLR0,而不是调用setBit()clearBit() 来设置GPIO 输出。在写信给他们之前,您不需要阅读GPSET0GPCLR0。因为当你写它们时,只有你设置为 1 的位会改变,你写到 0 的位会保持不变。

试试这样的:

// Set bits
*(UINT32_P)GPSET0 = (1 << 18);
*(UINT32_P)GPSET0 = (1 << 24);

// Clear bits
*(UINT32_P)GPCLR0 = (1 << 18);
*(UINT32_P)GPCLR0 = (1 << 24);

【讨论】:

  • 好地方,虽然实际上他只是调用了不同地址的setBit,GSET0和GPCLR0,所以读读-修改-写操作是不必要的。到目前为止,我建议他删除未使用的代码以澄清问题的建议已被忽略。
【解决方案2】:

notmain() 中,您永远不会调用clearBit(),只会调用setBit()

类型:

typedef unsigned int* UINT32_P;

应该声明:

typedef volatile unsigned int* UINT32_P;

我建议将您的地址定义为指针而不是整数:

#define GPFSEL1 ((UINT32_P)0x20200004)
#define GPFSEL2 ((UINT32_P)0x20200008)

#define GPSET0  ((UINT32_P)0x2020001C)
#define GPCLR0  ((UINT32_P)0x20200028)

使用 set/clearBit 采用 UINT32_P 而不是无符号整数。那么你就不需要大量的演员表了。

BCM2835 包含比“忙循环”更好地利用的计时器硬件。

【讨论】:

    【解决方案3】:

    每个 GPIO 引脚都有 3 个位来选择功能。您只设置三位中的一位,即最低位,而单独保留高位两位。所以我的猜测是,在启动时,引脚 18 具有功能 0,而引脚 24 具有功能 2(左右)。然后,您将引脚 18 配置为功能 1,因此它可以工作,但将引脚 24 配置为功能 3,它不起作用。

    您应该编写一个函数“void setFunction(uint32_t pin, uint32_t fn)”,根据引脚,加载 GPFSEL0/GPFSEL1/GPFSEL2 之一,屏蔽指定引脚的 3 位,或者指定 3 位在 fn 中,最后将其写回寄存器。

    我发现的另一件事(上面已经提到)是 GPSET0/GPCLR0 不需要读取-修改-写入。只需将要设置/清除的位直接写入它们即可。它不会影响任何其他位。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-20
      • 2014-01-13
      • 1970-01-01
      • 2018-08-17
      • 1970-01-01
      • 2015-08-09
      相关资源
      最近更新 更多