我有一些我想开始工作的简单代码。我想要做的是使用Assembly 在STM32F103“BluePill”上尽快打开和关闭引脚PA8。我在使用正确的语法时遇到问题。
__asm__ volatile (
"ldr r2, = (1<<8) \n\t"
"str r2, = [odr] \n\t"
"ldr r2, = ~(1<<8) \n\t"
"str r2, = [odr] \n\t"
: [odr] "=r" (GPIOA->regs->ODR)
);
编译器抛出此错误:
Compiling .pio/build/genericSTM32F103C8/src/main.ino.cpp.o
/tmp/ccLofo6i.s: Assembler messages:
/tmp/ccLofo6i.s:46: Error: invalid pseudo operation -- `str r2,=[odr]'
/tmp/ccLofo6i.s:48: Error: invalid pseudo operation -- `str r2,=[odr]'
*** [.pio/build/genericSTM32F103C8/src/main.ino.cpp.o] Error 1
Libmaple 通常允许我使用 GPIOA->regs->ODR 来使用按位操作来操作寄存器,但实际上我无法获得高于 2MHz 的切换速度。我对内联汇编也很陌生。
编辑:
所以我尝试了 Jester 的建议:
volatile uint32* odr = (GPIOA->regs->ODR); *odr = (1<<8); *odr = 0;
但是 PlatformIO 抱怨“类型为“uint32”的值不能用于初始化类型为“volatile uint32 *”的实体以及编译器:
从 'uint32 {aka long unsigned int}' 到 'uint32* {aka long unsigned int*}' 的无效转换 [-fpermissive]
但是,我尝试改进原始汇编代码:
asm易失性(
"ldr r2, = (1<<8) \n\t"
"str r2, [%[odr]] \n\t"
"ldr r2, = 0 \n\t"
"str r2, [%[odr]] \n\t"
: [odr] "=r" (GPIOA_BASE->ODR)
);
这编译得很好,但它没有达到我的预期。PA8 读数为 3.3v,但它根本不振荡。如果我将 (GPIOA_BASE->ODR) 更改为 (GPIOA->regs->ODR),那么我不会在 PA8 上获得电压信号,也不会出现振荡。这里可能是什么问题?为了回答 David 和 old_timer,我想基本上重现这个人所做的事情:
http://cliffle.com/blog/pushing-pixels/#continue-reading
在该博客文章中,您将看到他使用存储和加载命令来快速测试 GPIO 外设的最大开关速度,而显然还有其他可以限制开关速度的东西,我真正想要的是至少 36MHz 来自 GPIO 引脚。我知道这是绝对可能的,因为我已经在 stm32 上配置了 TIMER1 来快速振荡,但是对于我想做的这个 VGA bitbanging 项目来说,定时器是有限的,我希望 Inline Assembly 会更灵活一些。让我开始使用 Assembly 的另一件事是我读到的一些东西:
“切换引脚的理论最大值是两个汇编存储指令,在 72MHz 或 36MHz 下必须至少有 2 个周期”
所以这应该是可能的,但我需要一些帮助才能到达那里。