我有这个简单的内联汇编代码:
__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"
);
PA8只振荡2.4MHz,我想要36MHz的速度。我之前尝试过使用计时器并达到 36MHz 的速度,但由于一些限制,我想避免使用它们。
我不明白为什么 TIMER1 channel 1 (PA8) 可以配置为 36MHz 的开关速度,但是当我尝试在组装中做同样的事情时,我只能在同一引脚上达到 2.4MHz 的速度。
我也在使用
PinMode(PA8, OUTPUT);
设置 pin我已经尝试过这个汇编代码的其他变体,但在 PA8 上只达到了 2.8MHz 的最大值。我的问题是:STM32f103C8 上的 GPIO 引脚上的开关速度是否不可能高于 2.4-2.8MHz?
(这是 Need Help Manipulating Registers in Inline Assembly (STM32F103 "BluePill") 之后的后续问题)
最佳答案
STM32F103C8 以 72 MHz 的最大时钟速度运行。因此 36 MHz 是可以在 GPIO 上生成的最大频率,因为需要一个单独的时钟周期来设置和清除引脚。这个频率只能通过定时器来实现。
如果你用代码尝试同样的方法,你至少需要三个指令:两个商店和一个分支。这些指令需要大约 6 个时钟周期才能执行,因此最大频率约为 12 Mhz。
为了在软件中实现这一点,您的代码应如下所示:
while (1) {
GPIOA->ODR = 1 << 8;
GPIOA->ODR = 0;
}
不需要汇编代码,因为编译器会提供最佳代码。它看起来像这样: ldr r3, .L3
movs r1, #128
movs r2, #0
.L2:
str r1, [r3]
str r2, [r3]
b .L2
.L3:
.word 1207959572
更新 我已经在真实世界的设备上对其进行了测试,频率为 8 MHz。我估计这三个指令需要 6 个时钟周期,但似乎需要 9 个周期。
生成的代码或多或少符合预期:
7a: 60d9 str r1, [r3, #12]
7c: 60da str r2, [r3, #12]
7e: e7fc b.n 7a <main+0x7a>
范围清楚地显示所有三个指令花费相同的时间。
关于assembly - STM32f103c8 gpio限速,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59708656/