【问题标题】:Array of pointers like (*(volatile unsigned long *)0x40004000)指针数组,如 (*(volatile unsigned long *)0x40004000)
【发布时间】:2011-11-20 20:19:15
【问题描述】:

我很难弄清楚如何解决以下问题。我在一个内存很少的嵌入式系统上,并希望最大限度地减少内存使用量。 指针总是让我很困惑,而且永远都会这样做。

我有一大堆寄存器地址的定义:

#define GPIO_PORTA_BASE      (*((volatile unsigned long *)0x40004000))
#define GPIO_PORTB_BASE      (*((volatile unsigned long *)0x40005000))
//etc..

这些寄存器可以直接访问。例如:

GPIO_PORT_BASE &= 0x01;

我需要的是一个包含上述寄存器的数组,以便我可以轻松地将它们映射到索引。例如:

not_sure_what_to_declare_the array_as port_base_array[] {
   GPIO_PORTA_BASE,
   GPIO_PORTB_BASE,
   //etc
}

我最终需要做的是这样的事情:

volatile unsigned long *reg;
*reg_a = port_base_array[0];
reg_a &=0x1;

我正在使用 gcc 为 arm cortex m3 编译代码。

任何见解将不胜感激。

【问题讨论】:

  • 到底是什么问题?
  • ...问题很清楚。他试图将(*((volatile unsigned long *)0x40004000)) 放入一个数组中。有什么难理解的?
  • 附注:在开始使用volatile 之前,请阅读this,这表明编译器优化器无法正确处理 volatile 并且存在潜在危险。即使在 linux 内核中也是frowned upon。还有丹尼斯·里奇本人didn't like it

标签: c++ c gcc


【解决方案1】:

我不知道为什么@Etienne 删除了他的答案,但它包含了基本信息:地址被转换为volatile unsigned long *。这就是你需要的数组。

typedef volatile unsigned long* reg_addr;

reg_addr registers[] = {
  &GPIO_PORTA_BASE,
  &GPIO_PORTB_BASE,
  // ...
};

我们需要再次获取地址 (&GPIO_PORTA_BASE),因为宏会自动取消引用它们。访问方式:

*registers[i] &= your_value;

【讨论】:

  • @Xeo Eh,我不确定这是一个合适的答案。
  • Xeo,这正是我想要的!非常感谢你帮我解决这个问题!刚刚做了一个快速测试,它就像一个魅力!我并不完全清楚到底发生了什么,但正如我所说,指针对我来说是黑魔法,而且可能永远都是。知道任何关于这个指针魔术的好网站吗?尚不清楚该数组将占用多少内存,但我将为此发布另一个问题,因为它超出了此处的范围。无论如何,非常感谢您帮助我解决这个问题。在试图弄清楚这一点时,我花了很多时间。
【解决方案2】:

通常的方式是声明一个结构体,例如:

struct RegsAtAddrA
{
  unsigned int array1[10];
  char val1;
  // etc
};

然后访问它:

volatile RegsAtAddrA *pRegsA = (volatile RegsAtAddrA *) 0x40004000;
pRegsA->val1= 'a';
//etc

编辑:我刚刚意识到我还没有回答这个问题。所以,这里是:

#include <iostream>
unsigned long a=1;
unsigned long b=2;
volatile unsigned long *port_base_array[] = {
   &a,
   &b,
   //etc
};
int main()
{
    std::cout<<"a="<<*port_base_array[0]<<std::endl;
    std::cout<<"b="<<*port_base_array[1]<<std::endl;
}

【讨论】:

  • 您的编辑是错误的,因为宏是引用,并且已经转换为正确的类型。再取它的地址,看看我的回答。或者以我猜的另一种方式定义它们。 :)
  • @Xeo 没错。无论如何,这是一个完全可编译的示例,它以最高警告级别编译。
【解决方案3】:

我认为您正在尝试做的是这样的事情:

volatile unsigned long * gpio_porta = &GPIO_PORTA_BASE;

如果您使用的是 C++,您还可以执行以下操作:

volatile unsigned long & reg_foo = (&GPIO_PORTA_BASE)[3];
volatile unsigned long & reg_foo = gpio_porta[3];

并将其用作:

reg_foo &= 0x1;

但是,大多数时候我希望基地址寄存器实际上存储为指针,而不是指针的取消引用。因此,我可能希望将您的宏定义为:

#define GPIO_PORTA_BASE      ((volatile unsigned long *) 0x40004000)
#define GPIO_PORTB_BASE      ((volatile unsigned long *) 0x40005000)

然后你可以简单地访问它们

GPIO_PORTA_BASE[3] &= 0x1

【讨论】:

    【解决方案4】:

    如果我没听错的话,这就足够了:

    volatile unsigned long* GPIO_PORTA = (volatile unsigned long*) 0x40004000;
    

    你可以把它当作

    volatile unsigned long regxx = GPIO_PORTA[0x17];
    
    // even
    
    GPIO_PORTA[10] &= 0xF000;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-06-23
      • 2016-04-19
      • 1970-01-01
      • 2016-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多