c - 函数调用不适用于使用 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
解决方案
您在此代码中有几个较小的错误。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
.
推荐阅读
- azure - 在 Azure 门户应用注册中公开 Azure DevOps API
- javascript - 验证密码强度的 Javascript 函数(带有特殊字符)
- r - R中的条件统计(首选dplyr解决方案)
- amazon-web-services - AWS STS Endpoints 仅适用于一个区域的一个子网。STS 连接在其他区域不起作用
- python - 有没有办法将 url 更改为 python 中的下一个 url
- r - 创建一个以美国州名作为输入并返回文本的函数
- r - 如何在 R 中迭代地过滤列表中的列表,或者如何同时使用两个条件过滤 data.table,在运行时创建对象
- websphere - WebSphere 配置文件存储
- python-3.x - 如何将乘法 asyncio start_server 包含到运行循环中?
- javascript - 在父组件中将子组件作为道具发送,并在父方法中将道具添加到子组件