Need Help Manipulating Registers in Inline Assembly (STM32F103 “BluePill”)

时间秒杀一切 提交于 2020-03-03 12:21:18

问题


I have some simple code I want to get working. What I'm trying to do is to switch Pin PA8 ON and OFF as fast as possible on the STM32F103 "BluePill" using Assembly. I'm having trouble with the correct syntax.

__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)
);

The compiler throws this error:

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 normally allows me to use GPIOA->regs->ODR to manipulate registers using bitwise operations, but in practice I couldn't get switching speeds higher than 2MHz. I'm also very new to inline assembly.

EDIT:

So I tried what Jester suggested:

volatile uint32* odr = (GPIOA->regs->ODR); *odr = (1<<8); *odr = 0;

But PlatformIO is complaining that "a value of type "uint32" cannot be used to initialize an entity of type "volatile uint32 *" and the compiler too:

invalid conversion from 'uint32 {aka long unsigned int}' to 'uint32* {aka long unsigned int*}' [-fpermissive]

However, I tried improving the original assembly code:

asm volatile (

"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)

);

and this compiles just fine but it doesn't do what I would expect. PA8 reads 3.3v but it doesn't oscillate at all. If I change (GPIOA_BASE->ODR) to (GPIOA->regs->ODR) then I get not voltage signal on PA8 nor oscillation. What could be the problem here? To answer both David and old_timer, I want to basically recreate what this guy did:

http://cliffle.com/blog/pushing-pixels/#continue-reading

In that blog post you'll see he used store and load commands to quickly test out the maximum switching speed of a GPIO peripheral, while there are obviously other things that can limit the switching speed all I'm really looking for is to get at least 36MHz from a GPIO pin. I know this is absolutely possible because I've configured TIMER1 on the stm32 to oscillate this fast, but the timers are limiting for this VGA bitbanging project I want to do, I was hoping Inline Assembly would be a little more flexible. Another thing that brought me to using Assembly is something I read:

'The theoretical maximum for toggling a pin is two assembly store instructions, which must be at least 2 cycles at 72MHz, or 36MHz'

So this should be possible, but I need some help getting there.

来源:https://stackoverflow.com/questions/59656274/need-help-manipulating-registers-in-inline-assembly-stm32f103-bluepill

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!