如何解决如何使用llvm生成的汇编语言打开stm32板上的LED?
我的英语能力很差,因为我不会说英语。请理解。
我编译了一些测试代码,这些代码可以在LLVM下文的IAR中正常运行,但是生成的代码未在我的测试板上运行。 详细信息如下。
测试目标
测试环境
- MCU:stm32l152VD(Cortex M3)
- IDE:IAR 8.2
- 调试器:Segger JLink
- LLVM站点:http://ellcc.org/demo/index.cgi
测试步骤(摘要)
- 创建可以在IAR中正常运行的测试代码。
- 将测试代码移至http://ellcc.org/demo/index.cgi并在选择Target后进行编译。
- 使用生成的汇编代码创建test.s文件。
- 创建makefile来生成bin文件并使用make程序执行makefile。
- 使用JLink程序将bin文件加载到目标板上。
步骤1
volatile int* _RCC = (int*)(0x40023800);
volatile int* _RCC_AHBENR = (int*)(0x4002381c);
volatile int* _GPIOE = (int*)0x40021000;
volatile int* _GPIOE_BSRR = (int*)(0x40021000 + 0x18);
void InitPort()
{
const int _RCC_AHBENR_GPIOEEN = (0x00000010);
int Setoutput = 0x00000600;
*_RCC_AHBENR = _RCC_AHBENR_GPIOEEN;
*_GPIOE = Setoutput; // set mode to output
*_GPIOE_BSRR = 0x00000020; // set
}
int main()
{
InitPort();
*_GPIOE_BSRR = 0x00200000; // reset
while(1);
}
上面的代码直接在IAR中运行。
步骤2
我将创建的测试代码移至http://ellcc.org/demo/index.cgi,并在选择以下选项后按下了编译按钮。
步骤3
.text
.Syntax unified
.eabi_attribute 67,"2.09"
.cpu cortex-m3
.eabi_attribute 6,10
.eabi_attribute 7,77
.eabi_attribute 8,0
.eabi_attribute 9,2
.eabi_attribute 34,1
.eabi_attribute 17,1
.eabi_attribute 20,1
.eabi_attribute 21,1
.eabi_attribute 23,3
.eabi_attribute 24,1
.eabi_attribute 25,1
.eabi_attribute 38,1
.eabi_attribute 18,4
.eabi_attribute 26,2
.eabi_attribute 14,0
.file "_2376_0.c"
.globl InitPort
.p2align 1
.type InitPort,%function
.code 16
.thumb_func
InitPort:
.fnstart
sub sp,#8
movs r0,#16
str r0,[sp,#4]
mov.w r1,#1536
str r1,[sp]
movw r1,:lower16:_RCC_AHBENR
movt r1,:upper16:_RCC_AHBENR
ldr r1,[r1]
str r0,[r1]
ldr r0,:lower16:_GPIOE
movt r1,:upper16:_GPIOE
ldr r1,[r1]
movw r0,:lower16:_GPIOE_BSRR
movt r0,:upper16:_GPIOE_BSRR
ldr r0,[r0]
movs r1,#32
str r1,[r0]
add sp,#8
bx lr
.Lfunc_end0:
.size InitPort,.Lfunc_end0-InitPort
.cantunwind
.fnend
.globl main
.p2align 1
.type main,%function
.code 16
.thumb_func
main:
.fnstart
push {r7,lr}
mov r7,sp
sub sp,#0
str r0,#4]
bl InitPort
movw r0,[r0]
mov.w lr,#2097152
str.w lr,[r0]
b .LBB1_1
.LBB1_1:
b .LBB1_1
.Lfunc_end1:
.size main,.Lfunc_end1-main
.cantunwind
.fnend
.type _RCC,%object
.data
.globl _RCC
.p2align 2
_RCC:
.long 1073887232
.size _RCC,4
.type _RCC_AHBENR,%object
.globl _RCC_AHBENR
.p2align 2
_RCC_AHBENR:
.long 1073887260
.size _RCC_AHBENR,4
.type _GPIOE,%object
.globl _GPIOE
.p2align 2
_GPIOE:
.long 1073876992
.size _GPIOE,4
.type _GPIOE_BSRR,%object
.globl _GPIOE_BSRR
.p2align 2
_GPIOE_BSRR:
.long 1073877016
.size _GPIOE_BSRR,4
.ident "ecc version 2017-08-23 (http://ellcc.org) based on clang version 6.0.0 (trunk 311547)"
.section ".note.GNU-stack","",%progbits
步骤4
我创建了makefile来生成bin文件,如下所示。 这是makefile的内容。
bin: test.s
@echo "Running target all"
arm-none-eabi-as c:/backend/files/test.s -o c:/backend/files/test.o
arm-none-eabi-ld -Ttext=0x08000000 c:/backend/files/test.o -o c:/backend/files/test.elf
arm-none-eabi-objdump -D c:/backend/files/test.elf
arm-none-eabi-objcopy c:/backend/files/test.elf -O binary c:/backend/files/test.bin
clean:
@echo "Running target clean"
rm -f *.o
rm -f *.elf
rm -f *.bin
我用make程序执行了上述makefile文件,并得到了test.o,test.elf,test.bin文件。
步骤5
我用JLink.exe(seggar)加载了bin文件,并使用go命令执行了该文件,但注意在板上发生了。 (将bin文件加载到板上时,我使用的命令是“ loadbin C:\ backend \ files \ test.bin,0x08000000”)
结论
这就是我所做的一切。 我按照上面的方法进行操作,但是与IAR生成的代码不同,LLVM下文生成的汇编代码未运行。 我想知道我做错了什么以及如何解决才能实现目标。 任何帮助将不胜感激。
谢谢。
附加信息
板上没有像RTOS这样的软件。 下图是我用来测试的整个结构。 只有main.cpp文件是源代码。其他文件是由EWARM IDE生成的。
###############################################################################
#
# IAR ELF Linker V8.22.2.15995/W32 for ARM 24/Oct/2020 19:22:32
# copyright 2007-2018 IAR Systems AB.
#
# Output file = C:\Users\jjw\Desktop\hobby\Test\Debug\Exe\Test.out
# Map file = C:\Users\jjw\Desktop\hobby\Test\Debug\List\Test.map
# Command line =
# -f C:\Users\jjw\AppData\Local\Temp\EW7E50.tmp
# (C:\Users\jjw\Desktop\hobby\Test\Debug\Obj\main.o -o
# C:\Users\jjw\Desktop\hobby\Test\Debug\Exe\Test.out --redirect
# _Printf=_PrintfFullNoMb --redirect _Scanf=_ScanfFullNoMb --map
# C:\Users\jjw\Desktop\hobby\Test\Debug\List\Test.map --config
# "C:\Program Files (x86)\IAR Systems\Embedded Workbench
# 8.0\arm\CONfig\generic_cortex.icf" --semihosting --entry
# __iar_program_start --redirect __iar_sh_stdout=__iar_sh_stdout_swo
# --vfe --text_out locale)
#
###############################################################################
*******************************************************************************
*** RUNTIME MODEL ATTRIBUTES
***
CppFlavor = *
__CPP_Exceptions = disabled
__CPP_Language = C++14
__SystemLibrary = DLib
__dlib_version = 6
*******************************************************************************
*** HEAP SELECTION
***
The basic heap was selected because no calls to memory allocation
functions were found in the application outside of system library
functions,and there are calls to deallocation functions in the
application.
*******************************************************************************
*** PLACEMENT SUMMARY
***
"A0": place at 0x00000000 { ro section .intvec };
"P1": place in [from 0x00000000 to 0x0007ffff] { ro };
define block CSTACK with size = 1K,alignment = 8 { };
define block PROC_STACK with size = 0M,alignment = 8 { };
define block HEAP with size = 2K,alignment = 8 { };
"P2": place in [from 0x20000000 to 0x2000ffff] {
rw,block CSTACK,block PROC_STACK,block HEAP };
initialize by copy { rw };
Section Kind Address Size Object
------- ---- ------- ---- ------
"A0": 0x40
.intvec ro code 0x00000000 0x40 vector_table_M.o [4]
- 0x00000040 0x40
"P1": 0x104
.text ro code 0x00000040 0x3c main.o [1]
.text ro code 0x0000007c 0x2c copy_init3.o [4]
.text ro code 0x000000a8 0x28 data_init.o [4]
.iar.init_table const 0x000000d0 0x14 - Linker created -
.text ro code 0x000000e4 0x1e cmain.o [4]
.text ro code 0x00000102 0x4 low_level_init.o [3]
.text ro code 0x00000106 0x4 exit.o [3]
.text ro code 0x0000010a 0x2 vector_table_M.o [4]
.text ro code 0x0000010c 0xa cexit.o [4]
.rodata const 0x00000116 0x1 unwind_debug.o [5]
.text ro code 0x00000118 0x14 exit.o [5]
.text ro code 0x0000012c 0xc cstartup_M.o [4]
Initializer bytes const 0x00000138 0xc <for P2-1>
.rodata const 0x00000144 0x0 copy_init3.o [4]
- 0x00000144 0x104
"P2",part 1 of 2: 0xc
P2-1 0x20000000 0xc <Init block>
.data inited 0x20000000 0x4 main.o [1]
.data inited 0x20000004 0x4 main.o [1]
.data inited 0x20000008 0x4 main.o [1]
- 0x2000000c 0xc
"P2",part 2 of 2: 0x400
CSTACK 0x20000010 0x400 <Block>
CSTACK uninit 0x20000010 0x400 <Block tail>
- 0x20000410 0x400
*******************************************************************************
*** INIT TABLE
***
Address Size
------- ----
copy (__iar_copy_init3)
1 source range,total size 0xc:
0x00000138 0xc
1 destination range,total size 0xc:
0x20000000 0xc
*******************************************************************************
*** MODULE SUMMARY
***
Module ro code ro data rw data
------ ------- ------- -------
C:\Users\jjw\Desktop\hobby\Test\Debug\Obj: [1]
main.o 60 12 12
-------------------------------------------
Total: 60 12 12
command line: [2]
-------------------------------------------
Total:
dl7M_tln.a: [3]
exit.o 4
low_level_init.o 4
-------------------------------------------
Total: 8
rt7M_tl.a: [4]
cexit.o 10
cmain.o 30
copy_init3.o 44
cstartup_M.o 12
data_init.o 40
vector_table_M.o 66
-------------------------------------------
Total: 202
shb_l.a: [5]
exit.o 20
unwind_debug.o 1
-------------------------------------------
Total: 20 1
Gaps 1
Linker created 20 1 024
-----------------------------------------------
Grand Total: 291 33 1 036
*******************************************************************************
*** ENTRY LIST
***
Entry Address Size Type Object
----- ------- ---- ---- ------
.iar.init_table$$Base 0x000000d0 -- Gb - Linker created -
.iar.init_table$$Limit 0x000000e4 -- Gb - Linker created -
?main 0x000000e5 Code Gb cmain.o [4]
CSTACK$$Base 0x20000010 -- Gb - Linker created -
CSTACK$$Limit 0x20000410 -- Gb - Linker created -
InitPort() 0x00000041 0x1e Code Gb main.o [1]
Region$$Table$$Base 0x000000d0 -- Gb - Linker created -
Region$$Table$$Limit 0x000000e4 -- Gb - Linker created -
_GPIOE 0x20000004 0x4 Data Gb main.o [1]
_GPIOE_BSRR 0x20000008 0x4 Data Gb main.o [1]
_RCC_AHBENR 0x20000000 0x4 Data Gb main.o [1]
__cmain 0x000000e5 Code Gb cmain.o [4]
__exit 0x00000119 0x14 Code Gb exit.o [5]
__iar_copy_init3 0x0000007d 0x2c Code Gb copy_init3.o [4]
__iar_data_init3 0x000000a9 0x28 Code Gb data_init.o [4]
__iar_debug_exceptions 0x00000116 0x1 Data Gb unwind_debug.o [5]
__iar_program_start 0x0000012d Code Gb cstartup_M.o [4]
__iar_systems$$module {Abs}
0x00000001 Data Gb command line/config [2]
__low_level_init 0x00000103 0x4 Code Gb low_level_init.o [3]
__vector_table 0x00000000 Data Gb vector_table_M.o [4]
_call_main 0x000000f1 Code Gb cmain.o [4]
_exit 0x0000010d Code Gb cexit.o [4]
_main 0x000000ff Code Gb cmain.o [4]
exit 0x00000107 0x4 Code Gb exit.o [3]
main 0x0000005f 0x12 Code Gb main.o [1]
[1] = C:\Users\jjw\Desktop\hobby\Test\Debug\Obj
[2] = command line
[3] = dl7M_tln.a
[4] = rt7M_tl.a
[5] = shb_l.a
291 bytes of readonly code memory
33 bytes of readonly data memory
1 036 bytes of readwrite data memory
Errors: none
Warnings: none
/*###ICF### Section handled by ICF editor,don't touch! ****/
/*-Editor annotation file-*/
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_4.xml" */
/*-Specials-*/
define symbol __ICFEDIT_intvec_start__ = 0x00000000;
/*-Memory Regions-*/
define symbol __ICFEDIT_region_IROM1_start__ = 0x00000000;
define symbol __ICFEDIT_region_IROM1_end__ = 0x0007FFFF;
define symbol __ICFEDIT_region_IROM2_start__ = 0x0;
define symbol __ICFEDIT_region_IROM2_end__ = 0x0;
define symbol __ICFEDIT_region_EROM1_start__ = 0x0;
define symbol __ICFEDIT_region_EROM1_end__ = 0x0;
define symbol __ICFEDIT_region_EROM2_start__ = 0x0;
define symbol __ICFEDIT_region_EROM2_end__ = 0x0;
define symbol __ICFEDIT_region_EROM3_start__ = 0x0;
define symbol __ICFEDIT_region_EROM3_end__ = 0x0;
define symbol __ICFEDIT_region_IRAM1_start__ = 0x20000000;
define symbol __ICFEDIT_region_IRAM1_end__ = 0x2000FFFF;
define symbol __ICFEDIT_region_IRAM2_start__ = 0x0;
define symbol __ICFEDIT_region_IRAM2_end__ = 0x0;
define symbol __ICFEDIT_region_ERAM1_start__ = 0x0;
define symbol __ICFEDIT_region_ERAM1_end__ = 0x0;
define symbol __ICFEDIT_region_ERAM2_start__ = 0x0;
define symbol __ICFEDIT_region_ERAM2_end__ = 0x0;
define symbol __ICFEDIT_region_ERAM3_start__ = 0x0;
define symbol __ICFEDIT_region_ERAM3_end__ = 0x0;
/*-Sizes-*/
define symbol __ICFEDIT_size_cstack__ = 0x400;
define symbol __ICFEDIT_size_proc_stack__ = 0x0;
define symbol __ICFEDIT_size_heap__ = 0x800;
/**** End of ICF editor section. ###ICF###*/
define memory mem with size = 4G;
define symbol use_IROM1 = (__ICFEDIT_region_IROM1_start__ != 0x0 || __ICFEDIT_region_IROM1_end__ != 0x0);
define symbol use_IROM2 = (__ICFEDIT_region_IROM2_start__ != 0x0 || __ICFEDIT_region_IROM2_end__ != 0x0);
define symbol use_EROM1 = (__ICFEDIT_region_EROM1_start__ != 0x0 || __ICFEDIT_region_EROM1_end__ != 0x0);
define symbol use_EROM2 = (__ICFEDIT_region_EROM2_start__ != 0x0 || __ICFEDIT_region_EROM2_end__ != 0x0);
define symbol use_EROM3 = (__ICFEDIT_region_EROM3_start__ != 0x0 || __ICFEDIT_region_EROM3_end__ != 0x0);
define symbol use_IRAM1 = (__ICFEDIT_region_IRAM1_start__ != 0x0 || __ICFEDIT_region_IRAM1_end__ != 0x0);
define symbol use_IRAM2 = (__ICFEDIT_region_IRAM2_start__ != 0x0 || __ICFEDIT_region_IRAM2_end__ != 0x0);
define symbol use_ERAM1 = (__ICFEDIT_region_ERAM1_start__ != 0x0 || __ICFEDIT_region_ERAM1_end__ != 0x0);
define symbol use_ERAM2 = (__ICFEDIT_region_ERAM2_start__ != 0x0 || __ICFEDIT_region_ERAM2_end__ != 0x0);
define symbol use_ERAM3 = (__ICFEDIT_region_ERAM3_start__ != 0x0 || __ICFEDIT_region_ERAM3_end__ != 0x0);
if (use_IROM1)
{
define region IROM1_region = mem:[from __ICFEDIT_region_IROM1_start__ to __ICFEDIT_region_IROM1_end__];
}
else
{
define region IROM1_region = [];
}
if (use_IROM2)
{
define region IROM2_region = mem:[from __ICFEDIT_region_IROM2_start__ to __ICFEDIT_region_IROM2_end__];
}
else
{
define region IROM2_region = [];
}
define region IROM_region = IROM1_region | IROM2_region;
if (use_EROM1)
{
define region EROM1_region = mem:[from __ICFEDIT_region_EROM1_start__ to __ICFEDIT_region_EROM1_end__];
}
else
{
define region EROM1_region = [];
}
if (use_EROM2)
{
define region EROM2_region = mem:[from __ICFEDIT_region_EROM2_start__ to __ICFEDIT_region_EROM2_end__];
}
else
{
define region EROM2_region = [];
}
if (use_EROM3)
{
define region EROM3_region = mem:[from __ICFEDIT_region_EROM3_start__ to __ICFEDIT_region_EROM3_end__];
}
else
{
define region EROM3_region = [];
}
define region EROM_region = EROM1_region | EROM2_region | EROM3_region;
if (use_IRAM1)
{
define region IRAM1_region = mem:[from __ICFEDIT_region_IRAM1_start__ to __ICFEDIT_region_IRAM1_end__];
}
else
{
define region IRAM1_region = [];
}
if (use_IRAM2)
{
define region IRAM2_region = mem:[from __ICFEDIT_region_IRAM2_start__ to __ICFEDIT_region_IRAM2_end__];
}
else
{
define region IRAM2_region = [];
}
define region IRAM_region = IRAM1_region | IRAM2_region;
if (use_ERAM1)
{
define region ERAM1_region = mem:[from __ICFEDIT_region_ERAM1_start__ to __ICFEDIT_region_ERAM1_end__];
}
else
{
define region ERAM1_region = [];
}
if (use_ERAM2)
{
define region ERAM2_region = mem:[from __ICFEDIT_region_ERAM2_start__ to __ICFEDIT_region_ERAM2_end__];
}
else
{
define region ERAM2_region = [];
}
if (use_ERAM3)
{
define region ERAM3_region = mem:[from __ICFEDIT_region_ERAM3_start__ to __ICFEDIT_region_ERAM3_end__];
}
else
{
define region ERAM3_region = [];
}
define region ERAM_region = ERAM1_region | ERAM2_region | ERAM3_region;
do not initialize { section .noinit };
initialize by copy { readwrite };
if (isdefinedsymbol(__USE_DLIB_PERTHREAD))
{
// required in a multi-threaded application
initialize by copy with packing = none { section __DLIB_PERTHREAD };
}
place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };
if (!isempty(IROM_region))
{
place in IROM_region { readonly };
}
if (!isempty(EROM_region))
{
place in EROM_region { readonly section application_specific_ro };
}
if (!isempty(IRAM_region))
{
define block CSTACK with alignment = 8,size = __ICFEDIT_size_cstack__ { };
define block PROC_STACK with alignment = 8,size = __ICFEDIT_size_proc_stack__ { };
define block HEAP with alignment = 8,size = __ICFEDIT_size_heap__ { };
place in IRAM_region { readwrite,block HEAP };
}
if (!isempty(ERAM_region))
{
place in ERAM_region { readwrite section application_specific_rw };
}
在EWARM工具中,我使用JLink调试器上传了以上源代码。 JLink调试器和我的板的连接如图。
我也尝试手动上传EWARM工具生成的bin文件(不使用EWARM功能),如下所示。
以下方法与LLVM生成的通过bin上传bin文件的方法相同。 结果,EWARM bin文件是LED亮起的但llvm文件不是。
在上载EWARM bin文件和上载LLVM bin文件时,我检查了不同的寄存器值。 (PC,SP,MSP)
以下是上载EWARM bin文件后起点处的寄存器值。 (已操作)
以下是上载LLVM bin文件后起点处的寄存器值。 (未操作)
我认为导致此问题的原因是程序计数器(主)堆栈指针的值不正确。如果此推断正确,那么如何首次配置寄存器值?
如果需要其他信息,请告诉我。我想认真解决这个问题。
解决方法
需要更多信息才能正确回答此问题。
- 板上还有其他软件(引导加载程序,操作系统)吗?
- 大多数臂目标上的地址0x08000000映射到连接到bootflash的硬件总线。 Jlink在闪烁芯片吗?
- 您的IAR工作台是否在模拟器中运行?
听起来像您在没有任何引导程序或操作系统的情况下运行。在这种情况下,您需要按照Cortex M3芯片手册中的启动程序进行操作。
例如
- 启用电源域
- 设置时钟
- 初始化堆栈
一条更简单的方法可能是查看目标是否支持uboot。如果是devboard,则大多数devbords都可以使用一些默认软件加载。设置核心硬件后,即可开始运行代码。
,因此,除了几件事情之外,您还在正确的道路上。您正在使用bsrr进行复位然后置位,然后立即复位输出引脚。首先,要打开LED,您的电路板设计需要将引脚设为低电平还是低电平?如果为低电平,则main.c代码很好;如果为高,则它应该闪烁得如此之快,以至于您需要一个示波器或类似的东西,您的眼睛将看不到它。
我有许多带有许多不同芯片的stm32板。我没有这个家族的一个或一个,但这很好,将逐步查找一些内容,展示如何完全控制所有代码,然后可以向后使用工具并检查输出并查看问题是否出在二进制文件上,或者如何将其加载到零件中。有人会假设,如果您可以构建一个方法并使用相同的工具/命令加载,并且它“起作用”但构建另一种方法却不起作用,则不是加载二进制文件而是构建/软件。>
我正在使用NUCLEO-F446RE板。 PA5上有一个指示灯。您有gnu工具,我有gnu工具,因此您将能够使用这些工具来构建该项目(并选择修改您的需求)。
flash.ld
MEMORY
{
rom : ORIGIN = 0x08000000,LENGTH = 0x1000
ram : ORIGIN = 0x20000000,LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > rom
}
flash.s
.cpu cortex-m3
.thumb
.thumb_func
.global _start
_start:
.word 0x20001000
.word reset
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.thumb_func
reset:
bl main
b hang
.thumb_func
hang: b .
.thumb_func
.globl PUT32
PUT32:
str r1,[r0]
bx lr
.thumb_func
.globl GET32
GET32:
ldr r0,[r0]
bx lr
.thumb_func
.globl bounce
bounce:
bx lr
main.c
void PUT32 ( unsigned int,unsigned int );
unsigned int GET32 ( unsigned int );
void bounce ( unsigned int );
#define RCCBASE 0x40023800
#define RCC_AHB1ENR (RCCBASE+0x30)
#define RCC_APB1ENR (RCCBASE+0x40)
#define GPIOABASE 0x40020000
#define GPIOA_MODER (GPIOABASE+0x00)
#define GPIOA_BSRR (GPIOABASE+0x18)
static void led_init ( void )
{
unsigned int ra;
ra=GET32(RCC_AHB1ENR);
ra|=1<<0; //enable GPIOA
PUT32(RCC_AHB1ENR,ra);
ra=GET32(GPIOA_MODER);
ra&=~(3<<(5<<1)); //PA5
ra|= (1<<(5<<1)); //PA5
PUT32(GPIOA_MODER,ra);
}
static void led_on ( void )
{
PUT32(GPIOA_BSRR,((1<<5)<< 0));
}
static void led_off ( void )
{
PUT32(GPIOA_BSRR,((1<<5)<<16));
}
int main ( void )
{
unsigned int rx;
led_init();
while(1)
{
led_on();
for(rx=0;rx<400000;rx++) bounce(rx);
led_off();
for(rx=0;rx<400000;rx++) bounce(rx);
}
return(0);
}
构建
arm-linux-gnueabi-as --warn --fatal-warnings -mcpu=cortex-m3 flash.s -o flash.o
arm-linux-gnueabi-gcc -Wall -O2 -ffreestanding -mcpu=cortex-m3 -mthumb -S main.c -o main.s
arm-linux-gnueabi-as --warn --fatal-warnings -mcpu=cortex-m3 main.s -o main.o
arm-linux-gnueabi-ld -nostdlib -nostartfiles -T flash.ld flash.o main.o -o blinker.elf
arm-linux-gnueabi-objdump -D blinker.elf > blinker.list
arm-linux-gnueabi-objcopy -O binary blinker.elf blinker.bin
您不必一定要使用所有这些命令行选项进行实验(但要检查输出)。
在使用二进制文件之前,先对其进行检查
Disassembly of section .text:
08000000 <_start>:
8000000: 20001000 andcs r1,r0,r0
8000004: 08000041 stmdaeq r0,{r0,r6}
8000008: 08000047 stmdaeq r0,r1,r2,r6}
800000c: 08000047 stmdaeq r0,r6}
8000010: 08000047 stmdaeq r0,r6}
8000014: 08000047 stmdaeq r0,r6}
8000018: 08000047 stmdaeq r0,r6}
800001c: 08000047 stmdaeq r0,r6}
8000020: 08000047 stmdaeq r0,r6}
8000024: 08000047 stmdaeq r0,r6}
8000028: 08000047 stmdaeq r0,r6}
800002c: 08000047 stmdaeq r0,r6}
8000030: 08000047 stmdaeq r0,r6}
8000034: 08000047 stmdaeq r0,r6}
8000038: 08000047 stmdaeq r0,r6}
800003c: 08000047 stmdaeq r0,r6}
08000040 <reset>:
8000040: f000 f808 bl 8000054 <main>
8000044: e7ff b.n 8000046 <hang>
08000046 <hang>:
8000046: e7fe b.n 8000046 <hang>
第一部分是向量表,它必须位于0x08000000
08000000 <_start>:
8000000: 20001000 andcs r1,r6}
我使用objdump生成了此文件,因此无论如何它都会尝试反汇编这些字节。因此,当您看到上面的内容时,这很重要
08000000 <_start>:
8000000: 20001000
8000004: 08000041
8000008: 08000047
800000c: 08000047
第一项是堆栈指针的初始值,您可能拥有更多的内存,并且简单地将堆栈指针设置为最大地址加上一个或0x20000000 + ram的数量并不少见。这个小例子几乎不使用堆栈,而且应用程序很小,因此0x1000字节绰绰有余。
接下来的很多向量本身就是它们,它们必须是与1对应的处理程序地址ORRED。
08000040 <reset>:
08000046 <hang>:
如果您没有看到该内容将无法启动,并且已经结束游戏,则不要尝试使用二进制文件,直到向量表链接到正确的地址并且至少包含前两个单词的堆栈指针为止初始化和重置处理程序。
我包括了许多其他可以捕获故障的媒介,如果您的代码没有错误并且可以正确构建,那么您不需要像这样的东西。
08000054 <main>:
8000054: b570 push {r4,r5,r6,lr}
8000056: 4816 ldr r0,[pc,#88] ; (80000b0 <main+0x5c>)
8000058: f7ff fff8 bl 800004c <GET32>
800005c: f040 0101 orr.w r1,#1
8000060: 4813 ldr r0,#76] ; (80000b0 <main+0x5c>)
orr.w指令指示这是为thumb2 armv7-m构建的。这对我的电路板(cortex-m4)和您的电路板(cortex-m3)都很好,但是如果这是cortex-m0或cortex-m0 +,则此代码将失败并导致出现错误,即使要无限循环(而不是向量入口会进一步破坏内核,并使其更难尝试使用调试器进行调试)。手臂如何做包括统一语法在内的事情的不幸副作用是,您无法从汇编语言中确切地知道要通过实践获得的结果,但是查看它的最佳方法是反汇编。
因此该代码有可能会起作用。此核子板为mbed样式,因此可将其呈现为可移动驱动器,您只需复制.bin文件即可。
PUT32 / GET32是基于经验的,抽象层有很多好处。您可以使用volatile指针,我将在稍后展示。
同样,最好习惯将这些寄存器读-修改-写,这部分和这些寄存器都有据可查,这是复位后的代码,前面没有其他代码(rtos,库等),因此可以安全地假定您可以将值简单地塞入寄存器中(不是时钟使能寄存器部分复位为0x00008000且您正在禁用GPIOG,为什么启用了GPIOG?谁知道)
0x00000020与(1
for(rx=0;rx<400000;rx++) bounce(rx);
这是一个简单的延迟,不需要volatile,在这种情况下编译器无法在文件外部进行优化,因此必须实现循环。该值是手动调整的,不要指望它能产生任何可靠的速率,只需使其足够小即可看到led闪烁不是太快就不会太慢。一旦看到它起作用,则将其值更改为两倍,一半,重新构建,重新加载,并查看LED闪烁速率的变化,这是一个粗略的测试,以了解闪烁代码是您刚刚生成的代码,而不是剩下的东西从您或其他人那里得到的结果,我们不想以错误的假设来结束,即当工具使您无法使用并且它们没有将新程序加载到Flash中时,您编写的某些代码可以工作。
可变指针方法,这可能与您的问题有关。
void bounce ( unsigned int );
#define RCCBASE 0x40023800
#define RCC_AHB1ENR (*((volatile unsigned int *)(RCCBASE+0x30)))
#define GPIOABASE 0x40020000
#define GPIOA_MODER (*((volatile unsigned int *)(GPIOABASE+0x00)))
#define GPIOA_BSRR (*((volatile unsigned int *)(GPIOABASE+0x18)))
static void led_init ( void )
{
RCC_AHB1ENR = 0x00100001;
bounce(0);
GPIOA_MODER = 0xA8000400;
}
static void led_on ( void )
{
GPIOA_BSRR = 0x00000020;
}
static void led_off ( void )
{
GPIOA_BSRR = 0x00200000;
}
int main ( void )
{
unsigned int rx;
led_init();
while(1)
{
led_on();
for(rx=0;rx<400000;rx++) bounce(rx);
led_off();
for(rx=0;rx<400000;rx++) bounce(rx);
}
return(0);
}
这是怎么回事:
RCC_AHB1ENR = 0x00100001;
bounce(0);
GPIOA_MODER = 0xA8000400;
我在文档中找不到该语句,但是问题是,仅将值塞入这两个寄存器中,在使能外设与我们开始尝试写入之间存在少量时钟对此。读-修改-写方法,特别是使用抽象函数,提供了很多延迟。因此,在这种情况下,我实验性地添加了一个虚拟调用来刻录一些时间。这在我的芯片上就足够了。
使用易失性的read-modify-write也足够。
RCC_AHB1ENR = 0x00100001;
GPIOA_MODER |= 0x400;
在其他STM32部件上进行研究时,无论出于何种原因,您都可以在启用时钟之前读取调制解调器寄存器或调制解调器寄存器的复位值,而无需完全启用外设,因此读取通过该解决方案进行操作,然后修改写入会在处理器和总线之间消耗一些时钟,从而导致允许写入工作所需的延迟。您的代码可能存在此问题,并且两个编译器生成的代码可能不同。从研究中我知道llvm / clang和gnu对volatile的含义有不同的看法。我们一分钟就能看到。
我有意进行了此构建,以便为gnu情况生成main.s,即使这是不必要的步骤。
RCC_AHB1ENR = 0x00100001;
8000060: 4b0d ldr r3,#52] ; (8000098 <main+0x44>)
8000062: 490e ldr r1,#56] ; (800009c <main+0x48>)
8000064: 4a0e ldr r2,#56] ; (80000a0 <main+0x4c>)
8000066: 6019 str r1,[r3,#0]
GPIOA_MODER |= 0x400;
8000068: 6813 ldr r3,[r2,#0]
800006a: 4e0e ldr r6,#56] ; (80000a4 <main+0x50>)
800006c: f443 6380 orr.w r3,r3,#1024 ; 0x400
8000070: 4d0d ldr r5,#52] ; (80000a8 <main+0x54>)
8000072: 6013 str r3,#0]
8000098: 40023830
800009c: 00100001
80000a0: 40020000
80000a4: 40020018
以下是比赛条件:
8000060: 490c ldr r1,#48] ; (8000094 <main+0x40>)
8000062: 480d ldr r0,#52] ; (8000098 <main+0x44>)
8000064: 4b0d ldr r3,#52] ; (800009c <main+0x48>)
8000066: 4a0e ldr r2,#56] ; (80000a0 <main+0x4c>)
8000068: 4e0e ldr r6,#56] ; (80000a4 <main+0x50>)
800006a: 4d0f ldr r5,#60] ; (80000a8 <main+0x54>)
RCC_AHB1ENR = 0x00100001;
800006c: 6008 str r0,[r1,#0]
GPIOA_MODER = 0xA8000400;
800006e: 601a str r2,#0]
8000094: 40023830 andmi r3,lsr r8
8000098: 00100001 andseq r0,r1
800009c: 40020000 andmi r0,r0
80000a0: a8000400 stmdage r0,{sl}
80000a4: 40020018 andmi r0,r8,lsl r0
编译器在前面准备了两个存储,然后将它们做得背靠背,有一些与ahb总线相关的时钟,但显然不够。
我没有看到您正在使用的网页内容,我“简单地”(即使在快速的计算机上也需要花很长时间)为这些目标构建llvm / clang的交叉编译器(这是我唯一的方法)使其正常工作,三合一的apt不适用于版本10或11,无论我最后尝试了什么。我也从源头发布了自己的gnu工具,但无论如何。
llvm
8000062: f641 2680 movw r6,#6784 ; 0x1a80
8000066: f04f 0820 mov.w r8,#32
800006a: f44f 1900 mov.w r9,#2097152 ; 0x200000
800006e: f2c4 0002 movt r0,#16386 ; 0x4002
8000072: f2c0 0110 movt r1,#16
8000076: f2c4 0502 movt r5,#16386 ; 0x4002
800007a: f2c0 0606 movt r6,#6
800007e: 6001 str r1,[r0,#0]
8000080: f240 4000 movw r0,#1024 ; 0x400
8000084: f6ca 0000 movt r0,#43008 ; 0xa800
8000088: f845 0c18 str.w r0,[r5,#-24]
所以对于llvm
RCC_AHB1ENR = 0x00100001;
GPIOA_MODER = 0xA8000400;
可以无延迟地背对背,这不是因为一定要不稳定,而是因为编译器如何选择排列指令以及选择使用哪些指令。
也可以理解这是gcc版本10.2.0,没有理由假设先前版本/不同版本会产生相同的代码。如果不使用IAR不使用gnu或其他工具链,也没有任何理由会假设它会生成相同的代码。您需要检查反汇编,了解可能出现问题的地方,等等。您可以轻松地看到不喜欢我的PUT32 / GET32的人会进行读取-修改-写入操作,而只是将那几行代码更改为易失性指针,可能会导致该程序打破。凭经验,由于那些寄存器修改的执行速度已经改变,时序确实很重要,因此人们应该将高级代码的差异视为可能导致竞争的条件。在这种情况下,顺序当然很重要,因此重新安排它们将失败,而且还会计时,试图使您的代码更快,删除用于调试的printf,然后一切都中断了,首先想到的是我是否将代码更改为某种东西在功能上是等效的,如果这是真的,那么下一个想法就是计时,请添加大量延迟,然后开始删除它们。
您现在可以使用我的flash.ld和flash.s轻松地重复所有这些操作,并将您的main.c变成main.s,或者将我的main.c变成其中之一,然后用地址替换这三个寄存器从您的数据表中。
所以我们可以假设,由于理想情况下只更改main.c / main.s,所以向量表不是问题,否则二进制文件就可以了。
*_RCC_AHBENR = _RCC_AHBENR_GPIOEEN;
*_GPIOE = SetOutput; // set mode to output
至少让主持人注册为“读-修改-写”,或者延迟一下看看您是否也遇到了竞争情况。
int SetOutput = 0x00000600;
*_RCC_AHBENR = _RCC_AHBENR_GPIOEEN;
*_GPIOE = SetOutput; // set mode to output
*_GPIOE_BSRR = 0x00000020; // set
bsrr值表明您的led位于(端口E的)引脚5上,这是在现代模式中设置的第10位,您将第10位和第11位设置为0x600,这是有原因的,尝试获取它不会有伤害带领。
然后基本上就是
*_GPIOE_BSRR = 0x00000020; // set
很快跟进了
*_GPIOE_BSRR = 0x00200000; // reset
然后进入无限循环,不再改变PE5永远为低的状态,或者直到您重置后才出现短暂/几十个时钟的短脉冲。
您可能在llvm网页代码中没有竞争条件:
movw r1,:lower16:_RCC_AHBENR
movt r1,:upper16:_RCC_AHBENR
ldr r1,[r1]
str r0,[r1]
ldr r0,[sp]
movw r1,:lower16:_GPIOE
movt r1,:upper16:_GPIOE
ldr r1,[r1]
有可能仍然是工具。
arm-none-eabi-as c:/backend/files/test.s -o c:/backend/files/test.o
arm-none-eabi-ld -Ttext=0x08000000 c:/backend/files/test.o -o c:/backend/files/test.elf
对我来说是您生成的汇编语言
arm-none-eabi-as main.s -o main.o
arm-none-eabi-ld -Ttext=0x08000000 main.o -o main.elf
arm-none-eabi-ld: warning: cannot find entry symbol _start; defaulting to 0000000008000000
arm-none-eabi-objdump -D main.elf
main.elf: file format elf32-littlearm
Disassembly of section .text:
08000000 <InitPort>:
8000000: b082 sub sp,#8
8000002: 2010 movs r0,#16
8000004: 9001 str r0,[sp,#4]
8000006: f44f 61c0 mov.w r1,#1536 ; 0x600
800000a: 9100 str r1,#0]
800000c: f240 0168 movw r1,#104 ; 0x68
8000010: f6c0 0101 movt r1,#2049 ; 0x801
所以最初的问题就在屏幕上。
8000000: b082 sub sp,#1536 ; 0x600
arm-none-eabi-objcopy main.elf -O binary main.bin
hexdump -C main.bin
00000000 82 b0 10 20 01 90 4f f4 c0 61 00 91 40 f2 68 01 |... ..O..a..@.h.|
00000010 c0 f6 01 01 09 68 08 60 00 98 40 f2 6c 01 c0 f6 |.....h.`..@.l...|
00000020 01 01 09 68 08 60 40 f2 70 00 c0 f6 01 00 00 68 |...h.`@.p......h|
向量表如下:
0x08000000: 0x2010b082
0x08000004: 0xF44F9001
这根本行不通,它甚至可能尝试在该地址处获取,但这很快就结束了。
因此,最简短的答案是您没有提供向量表或引导程序。
现在就我而言,这是我的引导程序:
bl main
通常,对于要从Flash复制.data到ram和零.bss的MCU,您需要更复杂的链接描述文件来识别这些区域,并且链接描述文件和引导程序代码密切相关(并且特定于工具链,不假定移植到其他工具链)。我不使用.data也不使用也不关心.bss项是否为零,因此我的链接脚本是如此简单,并且我的引导程序设置了堆栈指针并输入C代码,因为cortex-m负责堆栈指针我要做的就是调用C入口点。由于cortex-m的工作原理,您实际上可以执行以下操作:
flash.s
.cpu cortex-m3
.thumb
.thumb_func
.global _start
_start:
.word 0x20001000
.word main
.thumb_func
.globl bounce
bounce:
bx lr
但这仅在不依赖.data或.bss或上帝禁止的情况下有效,您认为可以用C代码而不是引导程序(当然是用asm编写)来初始化它们。
通用C支持的正确答案是借用/修改/创建一个复杂的链接描述文件,您可以使用该链接描述文件来获取工具,以帮助您创建用于标识.data的开头和结尾或开头和大小的变量(均在flash中)和ram)和.bss(在ram中),然后复制并为零,以防万一用户感到有需要时,会生成一个int argc(为1)和argv [0]。
C库的实现通常包括更多的链接描述文件,尽管这不一定是某些人倾向于这样做的方式,同样,更多的引导文件也可以,这当然是其中某些内容的正确地方。如果可以避免,我不会使用C库,因为它会使项目立即变大,因此许多库都需要伪造的系统,您必须实施伪造的系统才能使它们正常工作。
很明显,我的例子很简单,它对您可以执行的操作有严格的限制,但是它展示了成功,将您与可能干扰成功的任何库代码完全隔离(通过尝试做绕过的事情)库代码或库代码及其引导项,可能会干扰您直接访问寄存器的成功。
还请注意,在我的实现中,我依靠命令行将向量表放在前面,很多人会:
.cpu cortex-m3
.thumb
.section .vectors
.thumb_func
.global _start
_start:
.word 0x20001000
.word reset
.text
.thumb_func
reset:
bl main
b hang
.thumb_func
hang: b .
然后类似
MEMORY
{
rom : ORIGIN = 0x08000000,LENGTH = 0x1000
}
SECTIONS
{
.romx : {
*(.vectors*)
*(.text*)
} > rom
}
请注意
MEMORY
{
rom : ORIGIN = 0x08000000,LENGTH = 0x1000
}
SECTIONS
{
.bob : { *(.vectors*) } > rom
.ted : { *(.text*) } > rom
}
是各种各样的坏事
Disassembly of section .bob:
08000000 <_start>:
8000000: 20001000 andcs r1,r0
8000004: 08000001 stmdaeq r0,{r0}
Disassembly of section .ted:
08000000 <reset>:
8000000: f000 f808 bl 8000014 <main>
8000004: e7ff b.n 8000006 <hang>
08000006 <hang>:
8000006: e7fe b.n 8000006 <hang>
并且不会启动。尝试对零件进行编程之前,请始终在cortex-m构建上检查向量表。不是在您的情况下,也不在我的情况下,但是在某些/许多解决方案中,重新编程部件的能力在很大程度上依赖于其中所有加载程序代码都在其中且没有任何挂起或损坏的部件上的二进制文件。像这样的木板洗衣清单,我不会在此提及任何名字。
许多在Arduino环境下工作的人都会陷入这种情况,如果您像这样滚动自己的方向指示灯,则会首先出现这种情况,这将破坏您再次通过沙箱加载零件的能力。但是,如果您打算将其所有代码都嵌入其中,并且发生了这种情况,您仍然会感到困惑(仍然可以通过boot0和serial或usb等进入sw32部件,或者使用swd,某些供应商的部件可以轻松实现砖砌而无法用swd恢复)。 (您正在使用的jlink东西是使用swd(串行线调试)进入零件并对闪存进行编程的。)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。