STM32f103c8 gpio限速

Sir*_*unk 3 assembly stm32 inline-assembly gpio

我有这个简单的内联汇编代码:

__asm__ volatile (

    ".equ GPIOA_ODR, 0x4001080C \n\t" //GPIOA base address is 0x40010800 and ODR offset is 0x0C


    //turns on PA8
    "ldr r1, =(1 << 8)     \n\t"        
    "ldr r2, =#GPIOA_ODR   \n\t"     
    "str r1, [r2]          \n\t"   

    //turn off PA8
    "ldr r1, =0            \n\t"        
    "ldr r2, =#GPIOA_ODR   \n\t"     
    "str r1, [r2]          \n\t"          

);
Run Code Online (Sandbox Code Playgroud)

PA8只振荡2.4MHz,我想要36MHz的速度。我之前尝试过使用计时器并达到 36MHz 的速度,但由于一些限制,我想避免使用它们。

我不明白为什么 TIMER1 通道 1 (PA8) 可以配置为 36MHz 开关速度,但是当我尝试在组装中执行相同操作时,我在同一引脚上只能达到 2.4MHz 的速度。

我也在使用 PinMode(PA8, OUTPUT);

我尝试了这个汇编代码的其他变体,但在 PA8 上只达到了 2.8MHz 的最大值。我的问题是:STM32f103C8 上的 GPIO 引脚上的开关速度是否不可能高于 2.4-2.8MHz?

(这是Need Help Manipulating Registers in Inline Assembly(STM32F103“BluePill”)之后的后续问题)

Cod*_*odo 6

STM32F103C8 以 72 MHz 的最大时钟速度运行。因此 36 MHz 是可以在 GPIO 上生成的最大频率,因为需要一个单独的时钟周期来设置和清除引脚。这个频率只能通过定时器来实现。

如果你用代码尝试同样的方法,你至少需要三个指令:两个商店和一个分支。这些指令需要大约 6 个时钟周期才能执行,因此最大频率约为 12 Mhz。

为了在软件中实现这一点,您的代码应如下所示:

while (1) {
    GPIOA->ODR = 1 << 8;
    GPIOA->ODR = 0;
}
Run Code Online (Sandbox Code Playgroud)

不需要汇编代码,因为编译器会给出最佳代码。它看起来像这样:

        ldr     r3, .L3
        movs    r1, #128
        movs    r2, #0
.L2:
        str     r1, [r3]
        str     r2, [r3]
        b       .L2
.L3:
        .word   1207959572
Run Code Online (Sandbox Code Playgroud)

更新

我已经在真实世界的设备上对其进行了测试,频率为 8 MHz。我估计这三个指令需要 6 个时钟周期,但似乎需要 9 个周期。

生成的代码或多或少符合预期:

7a:   60d9            str     r1, [r3, #12]
7c:   60da            str     r2, [r3, #12]
7e:   e7fc            b.n     7a <main+0x7a>
Run Code Online (Sandbox Code Playgroud)

范围清楚地显示所有三个指令花费的时间相同。