我正在为 Cortex-M4 编写一些汇编代码,特别是 STM32F4DISCOVERY 套件中的 STM32F407VG。
该代码对性能极其敏感,因此我希望从中挤出最后一个周期。我对其进行了基准测试(使用 Cortex-M4 中提供的 DWT 周期计数器),对于特定大小的输入,它以 1494 个周期运行。代码从闪存运行,CPU 降频至 24 MHz,以确保对闪存进行真正的零等待状态访问(禁用 ART 加速器)。对 DWT 周期计数器的两次连续读取进行基准测试会产生一个周期,因此这是与基准测试相关的唯一开销。
该代码仅从闪存读取 5 个常量 32 位字(如果从闪存读取指令和数据,可能会导致总线矩阵争用);所有其他数据存储器访问都是从 RAM 进行或到 RAM 进行的。我确保所有分支目标都是 32 位对齐的,并手动.W向某些指令添加后缀以消除所有指令,除了两个 16 位但不是 32 位对齐的 32 位指令——其中之一没有即使运行这个输入大小,第二条是POP函数的最终指令,它显然不是在循环中运行。请注意,大多数指令使用 32 位编码:实际上,平均指令长度为 3.74 字节。
我还制作了一个电子表格,记录了代码中的每一条指令,它们在循环内运行了多少次,甚至还记录了每个分支是否被采用,因为这会影响给定指令需要的周期数。我阅读了Cortex-M4 技术参考手册(TRM) 来获取每条指令的周期计数,并始终使用最保守的估计:当一条指令取决于管道刷新的成本时,我假设它最多需要 3 个周期;此外,我假设了所有加载和存储的最坏情况,尽管 TRM 第 3.3.2 节中讨论的许多特殊情况实际上可能会减少这些计数。我的电子表格包含 DWT 周期计数器两次读取之间每条指令的成本。
因此,我非常惊讶地发现我的电子表格预测代码应该在 1268 个周期内运行(回想一下实际性能是 1494 个周期)。我无法解释为什么代码的运行速度比根据指令时序假定的最坏情况慢 18%。即使完全展开代码的主循环(应负责大约 3/4 的执行时间)也只能将其减少到 1429 个周期,并且快速调整电子表格表明此展开的版本应在 1186 个周期内运行。
有趣的是,同一算法的完全展开、仔细调整的 C 版本运行了 1309 个周期。它总共有 1013 条指令,而我的汇编代码的完全展开版本有 930 条指令。在这两种情况下,都有一些代码处理未由用于基准测试的特定输入执行的情况,但就这些未使用的代码而言,C 版本和汇编版本之间应该没有显着差异。最后,C …
我正在尝试使用arm-none-eabi-gcc和Makefile编译STM32Cube项目.我已经指定:
CFLAGS = -mthumb\
-march=armv6-m\
-mlittle-endian\
-mcpu=cortex-m0\
-ffunction-sections\
-fdata-sections\
-MMD\
-std=c99\
-Wall\
-g\
-D$(PART)\
-c
Run Code Online (Sandbox Code Playgroud)
和:
LDFLAGS = -Wl,--gc-sections\
-Wl,-T$(LDFILE)\
-Wl,-v
Run Code Online (Sandbox Code Playgroud)
FW构建没有问题.但是当我启动MCU时,我陷入了Hard Fault.堆栈跟踪是:
#0 HardFault_Handler () at ./Src/main.c:156
#1 <signal handler called>
#2 0x0800221c in ____libc_init_array_from_thumb ()
#3 0x080021be in LoopFillZerobss () at Src/startup_stm32f030x8.s:103
#4 0x080021be in LoopFillZerobss () at Src/startup_stm32f030x8.s:103
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
Run Code Online (Sandbox Code Playgroud)
当我踩到bl __libc_init_array启动文件时,我会直接进入Hard Fault .
/* Zero fill the bss segment. */
FillZerobss:
movs r3, #0
str r3, …Run Code Online (Sandbox Code Playgroud) 我是ARM架构的新手,我正试图围绕唤醒机制.
首先,我发现很难找到关于此的好消息.ARM的文档似乎非常简洁.
我想要了解的是,当Cortex(尤其是我正在使用的M0)将被唤醒时.
作为参考,我还咨询了以下内容:
WFE指令的文档是:
3.7.11. WFE
Wait For Event.
Syntax
WFE
Operation
If the event register is 0, WFE suspends execution until
one of the following events occurs:
an exception, unless masked by the exception mask registers or the current
priority level
an exception enters the Pending state, if SEVONPEND in the
System Control Register is set
a Debug Entry request, if debug is enabled
an event signaled by a peripheral or another processor in a
multiprocessor …Run Code Online (Sandbox Code Playgroud) 我在网上找到了几个地方,其中指出每当进入中断例程时“必须”调用 CLREX,我不明白。CLREX状态的文档(添加编号以便于参考):
(1) 清除执行处理器的本地记录,该记录表明地址已请求独占访问。
(2) 使用该
CLREX指令将一个紧密耦合的独占访问监视器返回到其开放访问状态。这消除了对内存的虚拟存储的要求。(3) 是否
CLREX也清除执行处理器的全局记录,即某个地址已请求独占访问,则由实现定义。
我在这里几乎什么都不懂。
MOV r1, #0x1 ; load the ‘lock taken’ value
try: <---\
LDREX r0, [LockAddr] ; load the lock value |
CMP r0, #0 ; is the lock free? |
STREXEQ r0, r1, [LockAddr] ; try and claim the lock |
CMPEQ r0, #0 ; did this succeed? |
BNE try ; no - try again ------------/
.... ; yes - …Run Code Online (Sandbox Code Playgroud) 我从德州仪器购买了Tiva C系列LaunchPad TM4C123G评估套件.该套件包含一个带有ARM Cortex M4F微控制器的小型PCB.现在我想开始为这个微控制器编写软件.我习惯使用Windows上的AVR Studio对AVR 8位微控制器进行编程.我听说在Linux上编写基于ARM的微控制器很容易,而且由于Linux是我的主要平台,我想要一个简单的IDE,它或多或少会像我以前从AVR那样工作.
几天来,我一直在寻找一个好的IDE和工具来完成这项工作.令我惊讶的是,只有少数将在Linux上运行,没有一个是开源或免费软件.这真的可以吗?我不想花几百美元来尝试一些Cortex M4F的编程.我现在也不想学习一个IDE,然后在我发现它不够好或太贵的时候再学习另一个IDE.我已经习惯了Linux和开源的做事方式,我很震惊,似乎没有人在Linux上使用开源工具进行任何严肃的嵌入式ARM编程.如果我错了,请纠正我.
我没有计划在Cortex M4F上运行Linux - 我只是想像普通的微控制器一样编程.
德州仪器(TI)建议在评估套件的封底上使用以下工具链之一:
我也从code_red推荐了Red Studio.
既不是开源的也不是免费的,都有局限性.在我看来,只有Code Composer Studio和Red Studio兼容Linux.
我偶然发现了另一种产品Rowley CrossWorks,它也兼容Linux,但仍然非常商业化和昂贵.
没有开源替代品真的是真的吗?大多数产品似乎都使用Eclipse和GCC,没有这些商业软件包应该可以做到,对吧?我找不到任何教程或指南,解释如何为嵌入式ARM编程设置它.另外,我需要知道如何在编译后对器件进行编程.
我真的很想早点开始.任何建议和想法都非常感激:-)
我有一个对象,其地址不是4字节对齐的.当存在STR指令保存2个寄存器时,这会在cpu中导致HardFault错误.
这是生成的代码:
00000000 <_ZN8BaseAreaC1EPcmm>:
0: b510 push {r4, lr}
2: 4604 mov r4, r0
4: 6042 str r2, [r0, #4]
6: e9c4 3102 strd r3, r1, [r4, #8]
a: 2001 movs r0, #1
c: 7420 strb r0, [r4, #16]
e: b921 cbnz r1, 1a <_ZN8BaseAreaC1EPcmm+0x1a>
Run Code Online (Sandbox Code Playgroud)
这些是在"4:6042 ......"行的寄存器
R0 08738B82 R8 0
R1 08738BAE R9 0
R2 0 R10 082723E0
R3 2FCC R11 0
R4 08738B82 R12 0
R5 20007630 R13 2000CB38
Run Code Online (Sandbox Code Playgroud)
如图所示,STR指令的目标寄存器未在4字节上对齐.该指令STR r2, [r0, #4]执行正常.但它就是HardFaults的下一个STRD r3, r1, …
我在我的项目中使用了一个头文件,其中包含以下定义:
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
#define __I volatile /*!< Defines 'read only' permissions*/
#else
#define __I volatile const /*!< Defines 'read only' permissions*/
#endif
Run Code Online (Sandbox Code Playgroud)
将__I被用作在另一头文件如下:
typedef struct {
// more members before
__I uint32_t CR; /*!< GPIO Commit*/
// more members after
} GPIOA_Type;
#define GPIOF_BASE 0x40025000UL
#define GPIOF ((GPIOA_Type *) GPIOF_BASE)
Run Code Online (Sandbox Code Playgroud)
我的问题是为什么__I在C中使用const而不是在C++中?您仍然可以修改CR指向的值,因为您有地址,但我只是好奇为什么定义__I不同.
对于任何感兴趣的人来说,这些__I定义来自IAR Embedded Workbench ARM for Cortex-M4,结构来自德州仪器LM4F120H5QR CMSIS文件.
我正在尝试为Cortex-M4F构建一个项目.芯片有一个FPU,所以我正在构建,-mfpu=fpv4-sp-d16 -mfloat-abi=hard我没有使用任何库来节省空间,所以我这样做-nostdlib -fno-builtin.
现在我想使用浮点运算,但是这样做时我得到一个链接器错误:
led1642gw_gain.c:(.text.led_calculateGain+0xc): undefined reference to `__aeabi_f2d'
led1642gw_gain.c:(.text.led_calculateGain+0x24): undefined reference to `__aeabi_ddiv'
led1642gw_gain.c:(.text.led_calculateGain+0x36): undefined reference to `__aeabi_dsub'
led1642gw_gain.c:(.text.led_calculateGain+0x48): undefined reference to `__aeabi_ddiv'
led1642gw_gain.c:(.text.led_calculateGain+0x54): undefined reference to `__aeabi_d2f'
led1642gw_gain.c:(.text.led_calculateGain+0x9e): undefined reference to `__aeabi_f2d'
led1642gw_gain.c:(.text.led_calculateGain+0xb6): undefined reference to `__aeabi_ddiv'
led1642gw_gain.c:(.text.led_calculateGain+0xc8): undefined reference to `__aeabi_dsub'
led1642gw_gain.c:(.text.led_calculateGain+0xda): undefined reference to `__aeabi_ddiv'
led1642gw_gain.c:(.text.led_calculateGain+0xe6): undefined reference to `__aeabi_d2f'
led1642gw_gain.c:(.text.led_calculateGain+0x10c): undefined reference to `__aeabi_f2d'
Run Code Online (Sandbox Code Playgroud)
这是为什么?如果我理解正确,它不应该依赖库函数,而是使用ARM本机FPU指令.
我正在尝试从Raspberry Pi 3计算模块GPIO中闪存基于皮质m0的SoC,但它仍然会出现相同的错误.
错误:无法初始化调试端口
我正在关注这个https://learn.adafruit.com/programming-microcontrollers-using-openocd-on-raspberry-pi?view=all和本教程https://movr0.com/2016/09/02/use -raspberry-pi-23-as-a-jtagswd-adapter /.编译和安装没有问题.
cortex m0 SoC是一款采用ISP1302模块封装的Nordic Semiconductor nRF51822蓝牙芯片.
模块GND和3.3V直接连接到Compute模块dev-kit,SWDCLK和SWDIO按照教程在GPIO 25,24上连接.SRST或TRST没有连接.
配置文件如下:
source [find interface/raspberrypi2-native.cfg]
bcm2835gpio_swd_nums 25 24
transport select swd
# target
source [find target/nrf51.cfg]
init
targets
Run Code Online (Sandbox Code Playgroud)
(我bcm2835gpio_srst_num 18从raspberrypi2-native.cfg中删除了)
执行 sudo openocd -f config.cfg
树莓派CM3在选项core_freq=250打开的情况下运行,/boot/config.txt我需要此选项才能可靠地访问UART1.我认为它可能与时钟有关,但不确定如何更改/修复它.
我尝试了几种reset_config没有改变错误的组合.完整初始化堆栈如下:
Open On-Chip Debugger 0.10.0+dev-00111-gca9dcc8 (2017-04-24-15:30)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
BCM2835 GPIO nums: swclk = 25, swdio = 24
cortex_m reset_config sysresetreq
adapter …Run Code Online (Sandbox Code Playgroud) 在ARM 文档中,它提到
Cortex-M4 处理器支持 ARMv7 未对齐访问,并将所有访问作为单个未对齐访问执行。它们通过 DCode 和系统总线接口转换为两个或多个对齐的访问。
我不清楚这是否意味着数据访问对程序员来说是原子的。然后我发现了一个 StackOverflow注释,将文档解释为:
实际上,一些 ARM 处理器(例如 Cortex-M3)支持硬件中的未对齐访问,因此即使是未对齐的读/写也是原子的。访问可能跨越多个总线周期到内存,但没有机会让另一条指令在其间跳转,因此对程序员来说是原子的。
不过,我看了看周围多一些,发现索赔违背了先前的要求:
另一个事实是,在 ARMv6 及更高版本的内核上,为了让硬件“修复”未对齐的访问,它会将其拆分为多个较小的字节负载。但是,这些不是原子的!。
那么,我相信谁呢?对于某些情况,我的项目中的打包结构中的每个元素都有 setter/getter 。换句话说,某些结构元素可能未对齐。我想知道在 Cortex-M4 上访问结构元素是否总是保证是原子的。如果不是,我想我将不得不手动启用/禁用中断或添加一些互斥锁,但如果 ARM Cortex M4 可以保证数据访问是原子的,我宁愿不这样做。