Перейти к содержанию
    

STM32 Ассемблер. Идеи и приёмы написания

По ассемблеру для арм документации и разного рода примеров гораздо меньше для С. Начал осваивать и возникли сомнения, правильный ли подход частого использования макросов и где та грань, свыше которой не стоит заморачиваться с написанием кода. В ассемблера я не силён, в основном по-любительски пишу на С. Но вот раз начал осваивать асм, сделал несколько элементарных макросов для битовых операций, настройки и использования портов. Вопрос в том правильно ли это делать и использовать таким образом (когда в коде используются много макросов), или может быть есть более рациональный способ, как лучше писать на асме для арм. Вот примерчик:

STM32F100RB.

И что конкретно делает команда bfi R1,R2,#$Pin,#4 ?

Определение макросов:

;--------------------------------------
;Start_GPIO_Conf $Port,$PinRange - начало настройки порта, где $Port - имя порта (GPIOA,..), $PinRange - верхняя/нижняя тетрада порта (GPIO_CR_H/GPIO_CR_L)
        macro
        Start_GPIO_Conf $Port,$PinRange
        mov32            R0,#$Port        ;загружаем в регистр "R0" имя порта (его код) из памяти
        ldr             R1,[R0,#$PinRange];загружаем в регистр "R1" значение по адресу из памяти "R0 + #GPIO_CR_H(0x00)" или "R0 + #GPIO_CR_H(0x04)"
        mend
;--------------------------------------
;GPIO_Conf          $Pin,$Mode - настройка ножек выбраного порта, где $Pin - номер ножки (CNF_Pin_0,..), $Mode - режим ножки (GPIO_OUT_50_PP,..)
        macro
        PinConfig         $Pin,$Mode
        movs             R2,#$Mode
        bfi             R1,R2,#$Pin,#4
        mend
;--------------------------------------
;End_GPIO_Conf      $Port,$PinRange - конец настройки порта, где $Port - имя порта (GPIOA,..), $PinRange - верхняя/нижняя тетрада порта (GPIO_CR_H/GPIO_CR_L)
        macro
        End_GPIO_Conf     $Port,$PinRange
        str             R1,[R0,#$PinRange];загружаем в память по адресу "R0 + #GPIO_CR_H(0x00)" или "R0 + #GPIO_CR_H(0x04)" значение "R1"
        mend
;--------------------------------------
;SetBit_GPIO    $Port,$Pin
        macro
        SetBit_GPIO        $Port,$Pin
        mov32            R0,#($Port + GPIO_BSRR)
        mov32            R1,#$Pin
        str                R1,[R0]
        mend
;--------------------------------------
;ResetBit_GPIO    $Port,$Pin
        macro
        ResetBit_GPIO    $Port,$Pin
        mov32            R0,#($Port + GPIO_BRR)
        mov32            R1,#$Pin
        str                R1,[R0]
        mend
;--------------------------------------

Использование в программе:

;--------------------------------------
            Start_GPIO_Conf GPIOC,GPIO_CR_H
        PinConfig         CNF_Pin_9,GPIO_OUT_50_PP
        PinConfig         CNF_Pin_8,GPIO_OUT_50_PP
        End_GPIO_Conf     GPIOC,GPIO_CR_H
;--------------------------------------
        SetBit_GPIO        GPIOC,PIN9
        SetBit_GPIO        GPIOC,PIN8
;--------------------------------------

 

Пробный проект в Keil 5 прикреплен:

test11_ASM.7z

Изменено пользователем allsettingsdone

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Все зависит от того чего вы хотите в итоге.

 

Если вы упражняетесь смысл имеет. Если это коммерческий продукт убежден что не имеет.

 

С темпами развития процессоров сейчас на первый план выход не отдельная производительность одной функции, а удобство поддержки, модификации и расширения программного решения. В том числе и перенос его на другие процессоры и платформы. А для этого чем более абстрактно написан код и чем более читаемо и понятно он написан тем лучше.

 

код из раздела

a = (!temp) ? 2 : 0;

 

гораздо хуже чем код

if(temp != 0)
  a = 2;
else 
  a = 0;

 

и второй момент,

 

SetBit_GPIO    $Port,$Pin
        macro
        SetBit_GPIO        $Port,$Pin
        mov32            R0,#($Port + GPIO_BSRR)
        mov32            R1,#$Pin
        str                R1,[R0]
        mend

 

каким образом вы будете гарантировать что в ходе выполнения вашей программы к моменту вызова этого макроса у вас свободны R0 и R1? То есть просто по ходу программы написанной на С этот макрос вызывать нельзя. А если вы будете следить за этими регистрами всю программу, то это как раз ярчайший пример АБСОЛЮТНО не поддерживаемого кода. Любое шевеление в будущем чревато багами.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Встраивать асемблеровский код в проект на С я не планирую, идея в написании всего проекта на асм, так что я условился приблизительно регистры R0-R3 использовать с оглядкой на то что они будут постоянно меняться, так как задействованы почти во всех макросах. А уже по ходу выполнения программы буду держать в поле зрения другие регистры с ключевой информацией.

Вот ещё что интересно: одно и то же действие можно сделать разными командами и бывает не понятно как лучше поступить. Вот например загрузка в регистр адреса из памяти: (кусочек кода из макроса)

mov32        R0,#$Port

или

ldr          R0,=$Port

В итоге эти две строчки равнозначны и вот какую из них лучше применять совсем непонятно.

 

Хотелось бы узнать как бы идею и философию подхода к программированию на ассемблере для мк. (может есть годные примеры такого?)

 

Встраивать асемблеровский код в проект на С я не планирую, идея в написании всего проекта на асм, так что я условился приблизительно регистры R0-R3 использовать с оглядкой на то что они будут постоянно меняться, так как задействованы почти во всех макросах. А уже по ходу выполнения программы буду держать в поле зрения другие регистры с ключевой информацией.

Вот ещё что интересно: одно и то же действие можно сделать разными командами и бывает не понятно как лучше поступить. Вот например загрузка в регистр адреса памяти: (кусочек кода из макроса)

mov32        R0,#$Port

или

ldr          R0,=$Port

В итоге эти две строчки равнозначны и вот какую из них лучше применять совсем непонятно.

 

Или вот ещё

mov32            R0,#($Port + GPIO_BSRR)

Тоже интересно где именно происходит это сложение? Как я понимаю в на эту строчку уйдет далеко не два такта микроконтроллера?

 

Хотелось бы узнать как бы идею и философию подхода к программированию на ассемблере для мк. (может есть годные примеры такого?)

 

PS: с BFI разобрался

Изменено пользователем allsettingsdone

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Встраивать асемблеровский код в проект на С я не планирую, идея в написании всего проекта на асм

Ну и зря. Это просто борьба с ветряными мельницами какая-то. Она имеет право на жизнь, конечно, но лучше потратьте своё время на что-нибудь более полезное и интересное.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Поддерживаю.

Весь проект на ассемблере - это долго, опасно, и не эффективно, если конечно вы делаете не новогоднюю гирлянду с 2 режимами мигания.

 

Убейте книгой того кто вам сказал что крутые железячники все пишут на ассемблере, это было верно для готов 80. Сейчас уже давно и С++ практикуют, потому что стоимость машинного такта неуклонно падает. А требования к скорости и качеству разработки очень быстро растут.

 

Поглядите новым продуктам ставят сроки жизни и актуальности 4-5 лет. И если вы на ассемблере год будите писать программу, и год ее отлаживать, то через 2-3 оставшихся года при переходе на новый проц, вы что опять 2 года жизни прибора отъедите? Кому нужна такая разработка?

 

Максимум где допустим ассемблер - это вставки в особо критических местах кода, да и то в 95% случаев оптимизаторы современных языков делают эту работу лучше.

 

Не ходите валить лес с топором как делали наши деды, уже давно есть бензопилы!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Использование в программе:

;--------------------------------------
        SetBit_GPIO        GPIOC,PIN9
        SetBit_GPIO        GPIOC,PIN8
;--------------------------------------

Разворачиваем, получаем

        mov32            R0,#(GPIOC + GPIO_BSRR)
        mov32            R1,#PIN9
        str            R1,[R0]
        mov32            R0,#(GPIOC + GPIO_BSRR)
        mov32            R1,#PIN8
        str            R1,[R0]

Дважды грузится R0 одинаковым значением. И где хваленый выигрыш от Ассемблера? Такого даже самый плохой Си-компилятор себе не позволяет. Не морочьте себе и нам голову, лучше потратьте это время и эти усилия на более глубокое изучение Си или Си с плюсами. Поверьте, это будет гораздо продуктивнее и полезнее. Ассемблер на уровне, достатотчном для анализа листингов и пошаговой отладки вы уже знаете.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Топикстартер задал конкретный вопрос в надежде получить от господ ПРОФЕССИОНАЛОВ конкретный ответ и если вы не можете его дать, то наверно лучше помолчать (наболело).

Я для ARMов не программирую, но посоветовал бы глянуть книги на эту тему:

1. Joseph Yiu "The Definitive Guide to the ARM Cortex-M0"

2. Joseph Yiu "The Definitive Guide to the ARM Cortex-M3"

3. Vincent Mahout "Assembly Language Programming: ARM Cortex-M3"

4. Muhammad Ali Mazidi "ARM Assembly Language Programming & Architecture"

5. Jonathan Valvano "Embedded Systems: Introduction to Arm® Cortex-M Microcontrollers" Сайт автора книги

Все эти книги содержат достаточно примеров на асме.

Вот ссылка на реальный проект для Cortex-M0, я думаю если поискать, то можно много информации найти.

Желаю удачи :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как раз читаю одну из этих книг. Что касается С, то на нем я как раз и пишу, но есть мнение что качественно и без извращений, писать на асм может дать выигрыш в прозрачности кода и более логически правильному её написанию и именно к микроконтроллерам это очень даже применимо.

Я думаю что современный компилятор таки может гораздо лучше человека составить асм код, но когда пишешь на С, то не всегда очевидно какое огромное кол-во операций может повлечь за собой та или иная простенькая строчка на С.

Изменено пользователем allsettingsdone

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я думаю что современный компилятор таки может гораздо лучше человека составить асм код, но когда пишешь на С, то не всегда очевидно какое огромное кол-во операций может повлечь за собой та или иная простенькая строчка на С.

На самом деле всё-таки почти всегда очевидно, что он там нагенерит. А если не очевидно, то заглянуть в дизассемблер совсем не сложно.

Ну и погоня за тактами - это ложная и вредная цель. Реально такая задача возникает крайне редко, и решается она небольшой ассемблерной вставкой.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Гость MALLOY2
но когда пишешь на С, то не всегда очевидно какое огромное кол-во операций может повлечь за собой та или иная простенькая строчка на С.

 

Вы всегда можете открыть листинги и посмотреть что сделал компилятор и подправить.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ассемблер очевиднее С, только для ОЧЕНЬ маленьких программок из раздела мигаем лампочкой. Да и то С тут очевиднее...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ладно, а что по поводу таких вещей:

mov32            R0,#($Port + GPIO_BSRR)

Интересно, где именно происходит сложение "$Port + GPIO_BSRR" в данном случае $Port = 0x40001800, а GPIO_BSRR = 0x10. Для такой операции тоже ведь нужно использовать регистры, я пытался проследить этот момент, но именного таких чисел не увидел. И где вообще хранится константы когда мы используем их в виде "mov R0,#4" - вот число 4 здесь, процессор же должен от куда нибудь его взять? Откуда именно (если из ПЗУ, то как узнать по какому адресу компилятор что,где ложит)?

 

ассемблер очевиднее С, только для ОЧЕНЬ маленьких программок из раздела мигаем лампочкой. Да и то С тут очевиднее...

Любую программу же можно разбить на отдельные блоки/функции/файлы отвечающие за что-то одно. И можно будет во всем разобраться.

Изменено пользователем allsettingsdone

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Любую программу же можно разбить на отдельные блоки/функции/файлы отвечающие за что-то одно. И можно будет во всем разобраться.

Настоящие мущщины кодят прямо в хексе :-)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как раз читаю одну из этих книг. Что касается С, то на нем я как раз и пишу, но есть мнение что качественно и без извращений, писать на асм может дать выигрыш в прозрачности кода и более логически правильному её написанию и именно к микроконтроллерам это очень даже применимо.

Как правило, наоборот - чем код объёмнее - тем он менее прозрачен, а на асме код всяко будет ОБЪЁМНЕЕ :)

 

Я думаю что современный компилятор таки может гораздо лучше человека составить асм код,

Что-то очень часто приходится слышать это заблуждение.... По-моему пошло из рекламных буклетов си-компиляторов и к реалиям не имеет никакого отношения.

Не встречал ещё ни одного компилятора, способного написать на асме лучше меня :)

Причём бывает что это соотношение в разы. Даже со всеми оптимизациями.

Даже не очень хорошего знания ассемблера достаточно чтобы написать оптимальнее си-компилёра.

Хотя я совсем не агитирую писать на чистом асм - сейчас это затея отдаёт мазохизмом. Сейчас асм только для отдельных функций.

 

но когда пишешь на С, то не всегда очевидно какое огромное кол-во операций может повлечь за собой та или иная простенькая строчка на С.

Достаточно периодически заглядывать в листинги. И через некоторое время вам достаточно будет только бросить взгляд на эту строчку, чтобы примерно прикинуть, что получится на асме :)

 

Настоящие мущщины кодят прямо в хексе :-)

:biggrin:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1. Для некоторых процессоров ассемблер достаточно простой и наглядный. ARM ассемблер этими свойствами очевидно не обладает. Это мнение разработчиков компиляторов, ссылаясь на слова Тревора.

2. Написать несложную программу на простом ассемблере, с использованием макросов действительно несложно. Но Вам сказали об переносимости и поддерживаемости (сопровождении). А здесь ассемблер даже не мина а огромная бомба.

Для того, чтобы Вы сами приняли правильное решение предлагаю Вам несложный эксперимент. Напишите проект на ASM. Сделайте выдержку 1-2 месяца. Внесите в него изменения. Только изменения не сразу продумайте, а попросите кого-нибудь со стороны, чтобы он придумал Вам изменения. Ну и отладьте.

Я думаю, больше у Вас вопросов к форуму не будет.

PS: Я писал значительные проекты на ASM.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...