首页 > 解决方案 > 函数调用不适用于使用 gnu 工具链的 cortex m0 的裸机 c 代码

问题描述

我正在构建基于 arm cortex m0 设计开始的自定义 soc。SOC 现在有一个连接到 AHB lite 总线的 cortex mo 内核,上面有一些 ram 和一个 gpio 模块。我目前正在努力使用 gnu 工具链为其编写和编译代码。函数调用不起作用。我尝试了很多东西,但似乎没有任何效果。有趣的是,如果我用 keil 编译相同的代码,它就可以工作。我想问题出在我如何设置堆栈和/或 liker 脚本的某个地方,或者我缺少一些编译器/链接器选项。

这有效

#include<stdint.h>

volatile uint8_t* led_reg;

int main() {
   led_reg=(uint8_t*)0x50000000;
    while (1) {
        *led_reg=0x8;
        for(int i=0;i<=0x2FFFFF;i++);
        *led_reg=0x4;
        for(int i=0;i<=0x2FFFFF;i++);
        *led_reg=0x2;
        for(int i=0;i<=0x2FFFFF;i++);
        *led_reg=0x1;
        for(int i=0;i<=0x2FFFFF;i++);
    }
 }

但这并不

#include<stdint.h>

volatile uint8_t* led_reg;

void wait(void){
    for(int i=0;i<=0x2FFFFF;i++);

}

void on(uint8_t pat){
    *led_reg=pat;
}

int main() {
    led_reg=(uint8_t*)0x50000000;
    while (1){
        on(0x8);
        wait();
        on(0x4);
        wait();
        on(0x2);
        wait();
        on(0x1);
        wait();
    }
}

这是链接描述文件

ENTRY(Reset_Handler)

STACK_SIZE = 0x1000;

SECTIONS
{
  . = 0x00000000;

  .ram :
    {
        . = ALIGN(4);
        _stext = .;
        KEEP(*(.vectors .vectors.*))
        *(.text .text.*)
        *(.rodata .rodata*)
    
        . = ALIGN(4);
         _sbss = . ;
        *(.bss .bss.*)
        *(COMMON)
        . = ALIGN(4);
        _ebss = . ;

        . = ALIGN(4);
        _sdata = .;
        *(.data .data.*);
        . = ALIGN(4);
        _edata = .;

        . = ALIGN(8);
        _sstack = .;
        . = . + STACK_SIZE;
        . = ALIGN(8);
        _estack = .;
        . = ALIGN(4);
        _end = . ;
    }

}

启动代码的相关部分

/* Exception Table */
__attribute__ ((section(".vectors")))
const DeviceVectors exception_table = {

        /* Configure Initial Stack Pointer, using linker-generated symbols */
        .pvStack                = (void*) (&_estack),

        .pfnReset_Handler       = (void*) Reset_Handler,
        .pfnNMI_Handler         = (void*) NMI_Handler,
        .pfnHardFault_Handler   = (void*) HardFault_Handler,

这是编译和链接命令示例

arm-none-eabi-gcc -Wall -Werror -g -O0 -std=c99 -ffreestanding -ffunction-sections -fdata-sections  -mcpu=cortex-m0 -mfloat-abi=soft -march=armv6-m   -mthumb  -Wall -Iinclude/headers   -o build/main.o -c src/main.c
arm-none-eabi-gcc -Wall -Werror -g -O0 -std=c99 -ffreestanding -ffunction-sections -fdata-sections  -mcpu=cortex-m0 -mfloat-abi=soft -march=armv6-m   -mthumb  -Wall -Iinclude/headers   -Wl,-Map=build/firmware.map,--gc-sections -T vcoresoc.lds --specs=nano.specs build/main.o build/startup_vcoresoc.o build/syscall.o -o build/firmware.elf 

标签: cgccarmembeddedgnu-toolchain

解决方案


您在此代码中有几个较小的错误。gcc 可能比 Keil 更好地优化代码,因此可以简单地删除该函数。在某些情况下,您缺少volatile可能会破坏代码:

  • led_reg=(uint8_t*)0x50000000;应该是led_reg=(volatile uint8_t*)0x50000000u;,请参阅如何从固件访问硬件寄存器?
  • void wait(void){ for(int i=0;i<=0x2FFFFF;i++); }也应该如此volatile,否则循环将被删除。

此外,我不知道您是否编写了启动代码或工具供应商是否编写了,但它有错误。即.pvStack = (void*) (&_estack)调用未定义的行为,因为 C 不允许从函数指针到对象指针的转换。而不是void*您需要使用无符号整数或函数指针类型。正如评论中提到的,在 Cortex M 向量表上放置一些对齐关键字是有问题的——它应该在地址 0 处,那么它怎么可能不对齐呢?看看 的定义会很有趣DeviceVectors

此外,裸机微控制器系统不会从main(). 您不应该使用int main(),因为这可能会导致一些不必要的堆栈开销。使用实现定义的形式,例如void main (void)为嵌入式(“独立”)系统编译。使用 gcc 就是-ffreestanding.


推荐阅读