微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

了解 ARM Cortex-M 中断向量表定义的 C 语法

如何解决了解 ARM Cortex-M 中断向量表定义的 C 语法

我目前正在查看其他人编写的 ARM Cortex-M 微控制器的一些启动代码。可以在此 Github repo 中找到整个文件

它可以使用一些简单的 for 循环来设置堆栈指针并适当地初始化 .data.bss 部分。

我正在努力理解用于定义中断向量表的语法:

#define DUMMY __attribute__ ((weak,alias ("irq_handler_dummy")))

//-----------------------------------------------------------------------------
void irq_handler_reset(void);
DUMMY void irq_handler_nmi(void);
DUMMY void irq_handler_hard_fault(void);
// etc. 

extern int main(void);

extern void _stack_top(void);
// etc.

//-----------------------------------------------------------------------------
__attribute__ ((used,section(".vectors")))
void (* const vectors[])(void) =
{
  &_stack_top,// 0 - Initial Stack Pointer Value

  // Cortex-M0+ handlers
  irq_handler_reset,// 1 - Reset
  irq_handler_nmi,// 2 - NMI
  irq_handler_hard_fault,// 3 - Hard Fault
  // etc.
};

GCC 的 __attribute__ 定义很明确,我在官方文档中找到了它的答案:GCC Function attributes

我仍然不知道如何解析和表达这种语法的含义

void (* const vectors[])(void)

有人能帮我理解所有这些语法解包或代表什么吗?

解决方法

vectors 是一个 const 函数指针数组,它们接受并返回 void

_stack_top 不是函数指针,它是栈顶的地址,但对于皮层 m,它始终是向量表中的第一个元素。

Cortex M 架构以及您正在使用的它的实现定义了向量表的顺序和位置。这段代码是一些语法糖,用于生成表格并将其放置在正确的位置。

,

向量表本质上只是一个 ISR 地址数组。其中翻译成C可以看作是一个函数指针数组。将向量表创建为函数指针数组是很常见的。

使 Cortex M 成为特殊雪花的原因是它通过硬件从闪存加载堆栈指针,而不是程序员在运行时手动设置它。向量表的第一项包含初始堆栈指针的值——它实际上不是一个函数地址。因此,某种方式的 hack 是必要的。 _stack_top 可能会归结为链接描述文件中设置的某个堆栈地址。您的代码永远不会直接使用这个项目,它只是在那里,以便在启动时正确设置堆栈。

除此之外,其余的只是指向 ISR 的普通函数指针。由于 ISR 不带参数并返回值,因此 ISR 函数指针的语法为:

void (*name) (void)

这样的函数指针数组声明为:

void (*name [n]) (void)

其中 n 可选择性地用于表示数组大小。

__attribute__ ((used,section(".vectors"))) 只是将数组放置在特定地址,在这种情况下,从 0 开始。您可以检查链接器脚本,您会在那里找到 .vectors

我们希望这个向量表作为只读数据加载到闪存中。因此我们希望指针是只读的,而不是它们所指向的。这是通过将 const 放在 * 的右侧来实现的(同样的规则也适用于普通对象指针):

void (*const vectors[])(void)

如果使用了 typedef,我们本可以写得更易读:

typedef void isr_vector_t (void);
...

isr_vector_t* const vectors[] = { ... };
,
              vectors             -- vectors
              vectors[]           -- is an array of
      * const vectors[]           --   const pointer to
     (* const vectors[])(    )    --   function taking
     (* const vectors[])(void)    --     no parameters
void (* const vectors[])(void)    --   returning void

IOW,每个vectors[i]都是一个函数指针;所指向的函数在初始化程序中指定:

vectors[1] == irq_handler_reset,// 1 - Reset
vectors[2] == irq_handler_nmi,// 2 - NMI
vectprs[3] == irq_handler_hard_fault,// 3 - Hard Fault

const 后面的 * 表示 vector[i] 初始化后无法更新; IOW,您不能将 vectors[1] 设置为指向 irq_handler_reset 以外的函数。

const T *p;  // you can update p to point to different objects,but
             // you cannot write to the pointed-to objects

T const *p;  // same as above

T * const p = some_addr; // you can write a new value to the object at
                         // some_addr,but you can't write a new value
                         // to p.
,

void (* const vectors[])(void)

它是函数指针的const数组的定义和声明,引用了不带参数且不返回任何值的函数。

它通过对源代码中定义的中断处理程序(函数)的引用进行初始化。第一个值采用链接描述文件中定义的符号 _stack_top 的地址。该值将在微启动时设置初始堆栈指针。

具有 weak 链接的函数可以被其他函数替换,而不会产生链接器错误。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。