У меня есть простой код, над которым я хочу работать. Я пытаюсь как можно быстрее включать и выключать контакт 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 МГц»
Так что это должно быть возможно, но мне нужна помощь.
volatile int* odr = GPIOA->regs->ODR; *odr = (1<<8); *odr = ~(1<<8);
должно помочь (в зависимости от того, что такоеODR
). - person Jester   schedule 09.01.2020%
в%[odr]
. Расширения операндов в шаблоне asm обозначаются знаком%
, вроде того, как%stuff
является специальным для строк формата printf. - person Peter Cordes   schedule 09.01.2020~(1<<8)
в r3, тогда выполнениеstr r2, = %[odr]\n str r3, =%[odr]
будет (немного) быстрее? - person David Wohlferd   schedule 09.01.2020volatile int*
. Посмотрите на вывод asmgcc -O3
, чтобы увидеть, что вы получите от компилятора. ОчевидноGPIOA->regs->ODR
- это сам регистр ввода-вывода, а не адрес, поэтому очевидно, что вам нужно&GPIOA->regs->ODR
для инициализации указателя. - person Peter Cordes   schedule 09.01.2020