标签: cortex-m

了解 Cortex M4 上的周期计数

我正在使用带有 Cortex M4 的 STM32F407,并且通过在DWT_CYCCNT调用我在汇编中实现的函数(C 语言)之前和之后直接读取来测量函数的周期计数。我想了解我得到的结果。

08000610 <my_function>:
 8000610:       f04f 20ff       mov.w   r0, #4278255360 ; 0xff00ff00
 8000614:       f04f 11ff       mov.w   r1, #16711935   ; 0xff00ff
 8000618:       ea81 0100       eor.w   r1, r1, r0
 800061c:       ea81 0100       eor.w   r1, r1, r0
 8000620:       ea81 0100       eor.w   r1, r1, r0
 8000624:       ea81 0100       eor.w   r1, r1, r0
 8000628:       4770            bx      lr
 800062a:       bf00            nop
Run Code Online (Sandbox Code Playgroud)

执行上述(包括函数调用)需要21个周期。当我添加一条eor指令时:

08000610 <my_function>:
 8000610:       f04f 20ff       mov.w   r0, #4278255360 ; 0xff00ff00
 8000614:       f04f 11ff       mov.w   r1, #16711935 …
Run Code Online (Sandbox Code Playgroud)

assembly arm stm32f4discovery cortex-m

3
推荐指数
1
解决办法
2072
查看次数

PUSH 和 POP 括号中的寄存器顺序

ARM 文档对 PUSH 和 POP 做了以下说明

PUSH 将寄存器存储在堆栈上,编号最低的寄存器使用最低的内存地址,编号最高的寄存器使用最高的内存地址。

POP 从堆栈中加载寄存器,编号最低的寄存器使用最低的内存地址,编号最高的寄存器使用最高的内存地址。

我发现的一个教程是这么说的

...{} 中的寄存器可以按任意顺序指定,但它们在堆栈中出现的顺序是固定的...

因此,根据上述解释,一个 PUSH 括号中的寄存器顺序并不重要。即PUSH {R0,R1,R2}PUSH {R2,R1,R0}, 和PUSH {R1,R2,R0}所有都会导致堆栈中的某种排序,因为“...最低/最高编号的寄存器(R0/R2)使用最低/最高(堆栈)内存地址...”

  • 这是否意味着如果单个 PUSH 指令在括号中具有多个寄存器,汇编器会自动在目标代码中对推送操作进行排序,其中PUSH R2首先进入堆栈以获取最高地址,然后以PUSH R1获取PUSH R0最低地址结束?

  • 因此,如果我想保证 R2 在 LIFO 堆栈中最后压入并首先弹出(即 SP 指向 R2 或让 R2 获取最低堆栈地址),我不能在一个 PUSH 括号语句中执行此操作,而只能单独使用PUSH R0; PUSH R1; PUSH R2?

stack arm thumb cortex-m

3
推荐指数
1
解决办法
1949
查看次数

用于嵌入式编程的微控制器

我住在一个流行的微控制器不易获得的国家.我能找到的唯一基于arm的是STM32F4 Discovery和STM32VL Discovery.后者更便宜,因此这是优选的.

所以问题是,我正朝着正确的方向前进吗?这些微控制器是否专门用于嵌入式编程?(我是初学者)如果有人能让我朝着正确的方向前进,那将会非常有帮助.

谢谢!

embedded microcontroller arm cortex-m

2
推荐指数
1
解决办法
389
查看次数

Cortex M3上的非Thumb ARM代码

我有一些ARM代码,我试图在Cortex M3上运行.我用Thumb编写的大部分代码都是用C语言编写的 - 但对于某些函数,我希望能够运行普通的ARM代码(据我所知,这在M3上是可行的吗?).

所以...

原始C代码和汇编:

int donothing(int a) {
  return a;
}


00000068 <donothing>:
  68:   e52db004    push    {fp}        ; (str fp, [sp, #-4]!)
  6c:   e28db000    add fp, sp, #0
  70:   e24dd00c    sub sp, sp, #12
  74:   e50b0008    str r0, [fp, #-8]
  78:   e51b3008    ldr r3, [fp, #-8]
  7c:   e1a00003    mov r0, r3
  80:   e28bd000    add sp, fp, #0
  84:   e8bd0800    ldmfd   sp!, {fp}
  88:   e12fff1e    bx  lr
Run Code Online (Sandbox Code Playgroud)

编译使用 arm-none-eabi-gcc -mfloat-abi=soft -nostdinc -nostdlib

我转而使用blx r4- 如果基地址&3为0,它应该交换.

在GDB中逐步执行此操作,即使地址包含正确的数据,它也会一旦到达显示的行,就会进入HardFaults.

(gdb) …
Run Code Online (Sandbox Code Playgroud)

assembly arm thumb cortex-m

2
推荐指数
1
解决办法
584
查看次数

当我使用这种RAII风格的模式时,对象本身是否已经过优化?

有一种RAII风格的C++模式,它通过创建一个没有成员并依赖于类的构造函数和析构函数的类来实现基于作用域的所有权(以及在函数返回时自动调用析构函数的事实).例如,标准std::lock_guard实现了这种模式.

我正在编程一个EFM32 ARM Cortex-M微控制器,并提出了这个使用类似风格的类:

#include <em_int.h>

class InterruptGuard final {

public:

    explicit inline InterruptGuard() {
        INT_Disable();
    }

    InterruptGuard(const InterruptGuard &other) = delete;

    InterruptGuard(const InterruptGuard &&other) = delete;

    inline ~InterruptGuard() {
        INT_Enable();
    }

    InterruptGuard &operator=(const InterruptGuard &other) = delete;

    InterruptGuard &operator=(const InterruptGuard &&other) = delete;

};
Run Code Online (Sandbox Code Playgroud)

因此,如果我想在具有多个return语句的函数内禁用中断,我可以确保它们将重新启用,而不必担心在每个return语句中显式重新启用它们.

注意:INT_EnableINT_Disable函数实现一个计数器,因此它INT_Enable会做正确的事情,只有在真正需要启用时才启用中断.所以这个类应该是可以正确嵌套的.

void func() {
    InterruptGuard guard;

    // ...
}
Run Code Online (Sandbox Code Playgroud)

我的问题是:

当我使用这个模式,是编译器会做"正确的事"在这里,优化了对象(所以没有内存实际上是由这个类消费),只是内联INT_EnableINT_Disable调用到使用功能InterruptGuard类?

c++ microcontroller arm raii cortex-m

2
推荐指数
1
解决办法
191
查看次数

为什么用这个简单的代码生成了如此多的LDR和STR指令?

我有一个简单的C程序:

int main(){    
    unsigned int counter = 0;
    ++counter;
    ++counter;
    ++counter;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我使用以下编译标志:

arm-none-eabi-gcc -c -mcpu=cortex-m4 -march=armv7e-m -mthumb 
-mfloat-abi=hard -mfpu=fpv4-sp-d16 -DPART_TM4C123GH6PM -O0 
-ffunction-sections -fdata-sections -g -gdwarf-3 -gstrict-dwarf 
-Wall -MD -std=c99 -c -MMD -MP -MF"main.d" -MT"main.o" -o"main.o"  "../main.c"
Run Code Online (Sandbox Code Playgroud)

(为简洁起见,删除了一些-I指令)

请注意,我故意使用-O0禁用优化,因为我有兴趣了解编译器要优化的内容.

这将编译为ARM Cortex-M4的以下程序集:

6           unsigned int counter = 0;
00000396:   2300                movs       r3, #0
00000398:   607B                str        r3, [r7, #4]
7           ++counter;
0000039a:   687B                ldr        r3, [r7, #4]
0000039c:   3301                adds       r3, #1
0000039e:   607B                str        r3, [r7, …
Run Code Online (Sandbox Code Playgroud)

assembly gcc arm compiler-optimization cortex-m

2
推荐指数
1
解决办法
297
查看次数

LDMIA指令在皮质M4中的外部SRAM上无法正常工作

我在拇指模式下使用STM32L486ZG板.我正在运行一个没有任何RTOS的简单裸机应用程序.我使用FSM将外部SRAM连接到电路板.外部SRAM位于地址0x60000000.系统初始化并以72MHz运行(我已尝试过这个问题,频率从18-80 MHz)现在在我的主要功能中,我有以下代码:

int main(){
    asm volatile (
            "push {r0}\n"
            "mov r0, #0x60000000\n"
            "add r0, #0x400\n"
            "stmdb r0!, {r1-r12}\n"
            "ldmia r0!, {r1-r12}\n"
            "pop {r0}\n"
            );
}
Run Code Online (Sandbox Code Playgroud)

根据此代码,在执行此main函数后不应更改寄存器,但在以下指令之后不是这种情况

ldmia r0!, {r1-r12}
Run Code Online (Sandbox Code Playgroud)

r9执行后不正确.stmdb指令工作正常但未正确ldmia加载数据.我通过查看内存中的内容来验证这一点.

这个问题在ldmia指令中的任何参数都是持久的:第9个寄存器总是受到影响.

说明: 假设我正在调试此代码,下一条要执行的指令是:

stmdb r0!, {r1-r12}
Run Code Online (Sandbox Code Playgroud)

加强所有这些寄存器后,已保存在内存和价值r00x600003d0

记忆的内容:

0x600003D0  00000000 40021008 0000000C  .......@....
0x600003DC  40000000 00000000 00000000  ...@........
0x600003E8  20017FEC 00000000 00000000  ì.. ........
0x600003F4  00000000 00000000 00000000  ............
Run Code Online (Sandbox Code Playgroud)

登记册内容:

r0  0x600003d0
r1  0x00000000
r2  0x40021008
r3  0x0000000c
r4 …
Run Code Online (Sandbox Code Playgroud)

memory ram gcc arm cortex-m

2
推荐指数
1
解决办法
267
查看次数

在M0 +设备上除以零例外

在M0 +设备上是否存在除零除外?

我知道Cortex M3和M4设备有此功能.

embedded arm integer-division cortex-m

2
推荐指数
1
解决办法
809
查看次数

16位int机器(MSP430)和32位int机器(ARM CORTEX)的减法结果不同

当下面的代码针对像MSP430微控制器这样的16位整数机运行时,s32得到65446.

#include <stdint.h>

uint16_t   u16c;
int32_t    s32;

int main()
{
    u16c = 100U;
    s32  = 10 - u16c;
}
Run Code Online (Sandbox Code Playgroud)

我的理解是10 - u16c获取unsigned int的隐式类型提升.数学上10 - u16c等于-90.但是如何将负数表示为unsigned int呢?当-90被提升为unsigned int时,是否意味着忽略了数字的符号?

让我们假设,数字的符号被忽略.
90的二进制表示是00000000 01011010.当这被分配给s3232位宽的有符号整数变量时,转换是如何发生的?

为了s32等于65446,90必须采用2的补码.那就是00000000 10100110.

我不了解s32成为65446 的过程.

在像ARM这样的32位宽整数机器中,s32是-90,这是正确的.

要修复在16位整型机这种情况下,需要的类型转换(int16_t)u16c.这是如何解决这个问题的?

添加s32了IAR Workbench(右下角)所示的hexa数据表示.它显示s32成为0x0000FFA6.因此,对于MSP430,从无符号16位转换为带符号32位的机器实现,它只是预先设置16 0位.

在此输入图像描述

c embedded arm msp430 cortex-m

2
推荐指数
1
解决办法
492
查看次数

Gcc裸属性留下一些尾随函数序言asm指令

我在cortex-m0上有一个svc异常处理程序的以下实现:

int  __attribute__((naked))  
sv_call_handler(uint32_t n, uint32_t arg1, uint32_t arg2, uint32_t arg3,  
                uint32_t arg4, uint32_t arg5)
 {
      irq_off();
Run Code Online (Sandbox Code Playgroud)

当我为cortex-m0构建它时,它看起来像这样:

   0x7a50 <sv_call_handler>        movs   r4, r0                                                                    
   0x7a52 <sv_call_handler+2>      str    r1, [r7, #12]                                                             
   0x7a54 <sv_call_handler+4>      str    r2, [r7, #8]                                                              
   0x7a56 <sv_call_handler+6>      str    r3, [r7, #4]                                                              
   0x7a58 <sv_call_handler+8>      bl     0x3194 <irq_off> 
Run Code Online (Sandbox Code Playgroud)

当然,导致硬故障,R7中的值是"未定义的",并且它很可能包含不在地址范围内的值.

当我删除裸属性时,程序集更有意义:

   0x7a50 <sv_call_handler>        push   {r4, r5, r7, lr}                                                          
   0x7a52 <sv_call_handler+2>      sub    sp, #32                                                                   
   0x7a54 <sv_call_handler+4>      add    r7, sp, #8                                                                
   0x7a56 <sv_call_handler+6>      str    r0, [r7, #12]
Run Code Online (Sandbox Code Playgroud)

我之前没有使用过裸属性,为什么现在会发生这种情况呢?与svc异常处理程序是一个特殊情况这一事实有什么关系吗?

gcc arm system-calls armv6 cortex-m

2
推荐指数
1
解决办法
273
查看次数