Нужна помощь в управлении регистрами во встроенной сборке (STM32F103 BluePill)

У меня есть простой код, над которым я хочу работать. Я пытаюсь как можно быстрее включать и выключать контакт PA8 на STM32F103 «BluePill», используя Assembly. У меня проблемы с правильным синтаксисом.

__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 для управления регистрами с помощью побитовых операций, но на практике я не мог получить скорость переключения выше 2 МГц. Я также очень новичок в встроенной сборке.

РЕДАКТИРОВАТЬ:

Итак, я попробовал то, что предложил Шут:

изменчивый 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 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)

);

и это прекрасно компилируется, но не делает того, чего я ожидал. PA8 читает 3,3 В, но не колеблется. Если я изменю (GPIOA_BASE-> ODR) на (GPIOA-> regs-> ODR), то я не получу ни сигнала напряжения на PA8, ни колебаний. В чем может быть проблема? Чтобы ответить как Дэвиду, так и old_timer, я хочу в основном воссоздать то, что сделал этот парень:

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

В этом сообщении в блоге вы увидите, что он использовал команды store и load, чтобы быстро проверить максимальную скорость переключения периферийного устройства GPIO, в то время как, очевидно, есть другие вещи, которые могут ограничить скорость переключения, все, что я действительно ищу, - это получить минимум 36 МГц от вывода GPIO. Я знаю, что это абсолютно возможно, потому что я настроил TIMER1 на stm32 для такой быстрой генерации, но таймеры ограничивают этот проект VGA bitbanging, который я хочу сделать, я надеялся, что Inline Assembly будет немного более гибким. Еще одна вещь, которая подтолкнула меня к использованию Assembly, - это то, что я прочитал:

«Теоретический максимум для переключения вывода - это две инструкции хранилища сборки, которые должны составлять не менее 2 циклов при 72 МГц или 36 МГц»

Так что это должно быть возможно, но мне нужна помощь.


person SirSpunk    schedule 09.01.2020    source источник
comment
Компилятор должен уметь генерировать для этого хороший код (на самом деле лучше, чем ваша версия). Убедитесь, что вы включили оптимизацию, и проверьте, что вы получите, если у вас возникнут проблемы с эффективностью. Просто volatile int* odr = GPIOA->regs->ODR; *odr = (1<<8); *odr = ~(1<<8); должно помочь (в зависимости от того, что такое ODR).   -  person Jester    schedule 09.01.2020
comment
Для записи, похоже, вы упустили % в %[odr]. Расширения операндов в шаблоне asm обозначаются знаком %, вроде того, как %stuff является специальным для строк формата printf.   -  person Peter Cordes    schedule 09.01.2020
comment
Хотя я не говорю на STM32F103, топтание на r2 как это законно? Разве не должно быть шлепка? Кроме того, если цель - как можно быстрее, возможно, загрузка ~(1<<8) в r3, тогда выполнение str r2, = %[odr]\n str r3, =%[odr] будет (немного) быстрее?   -  person David Wohlferd    schedule 09.01.2020
comment
почему бы тебе не использовать настоящую сборку и избавить от головной боли? и вы можете сделать это с меньшим количеством инструкций, по крайней мере, для части включения / выключения. И вы хотите запускать его из sram, если хотите быстрее и т. Д. И т. Д., Или просто позволить оборудованию делать работу за вас и иметь пульс еще быстрее / короче.   -  person old_timer    schedule 09.01.2020
comment
используя программное обеспечение, вы, вероятно, будете ограничены / ограничены вводом-выводом.   -  person old_timer    schedule 09.01.2020
comment
что вы пытаетесь сделать и почему вы думаете, что это правильный способ?   -  person old_timer    schedule 09.01.2020
comment
«Теоретический максимум для переключения вывода - это две инструкции хранилища сборки, которые должны составлять не менее 2 циклов на 72 МГц или 36 МГц» Это то, что компилятор выдаст за вас, если вы правильно используете volatile int*. Посмотрите на вывод asm gcc -O3, чтобы увидеть, что вы получите от компилятора. Очевидно GPIOA->regs->ODR - это сам регистр ввода-вывода, а не адрес, поэтому очевидно, что вам нужно &GPIOA->regs->ODR для инициализации указателя.   -  person Peter Cordes    schedule 09.01.2020