STM32 советы по программированию и вопросы - PullRequest
2 голосов
/ 12 ноября 2011

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

  1. Я заметил, что во всех примерах программ, которые предоставляет STM, локальные переменные для main () всегда определяются вне функции main () (со случайным использованием статического ключевого слова). Есть ли причина для этого? Должен ли я следовать аналогичной практике? Должен ли я избегать использования локальных переменных внутри основного?

  2. У меня есть глобальная переменная, которая обновляется в дескрипторе прерывания часов. Я использую ту же переменную внутри другой функции в качестве условия цикла. Разве мне не нужно обращаться к этой переменной, используя некоторую форму атомарного чтения? Как я могу узнать, что прерывание часов не меняет своего значения в середине выполнения функции? Должен ли я отменить прерывание часов каждый раз, когда мне нужно использовать эту переменную внутри функции? (Однако, мне это кажется крайне неэффективным, поскольку я использую его как условие цикла. Я считаю, что должны быть более эффективные способы сделать это).

  3. Keil автоматически вставляет код запуска, который написан на ассемблере (т.е. startup_stm32f4xx.s). Этот код запуска имеет следующие операторы импорта: ИМПОРТ SystemInit ИМПОРТ __основная .В "С" это имеет смысл. Однако в C ++ и main, и system_init имеют разные имена (например, _ int _main__void). Как этот код запуска все еще может работать в C ++, даже не используя "extern" C "" (я пытался, и это сработало). Как компоновщик c ++ (armcc --cpp) может связать эти операторы с правильными функциями?

Ответы [ 3 ]

4 голосов
/ 13 ноября 2011

Вопрос 1: Локальные переменные

Пример кода, предоставленного ST, не особенно эффективен или элегантен. Он выполняет свою работу, но иногда нет веских причин для того, что они делают.

Как правило, вы всегда хотите, чтобы ваши переменные имели наименьшую возможную область видимости. Если вы используете переменную только в одной функции, определите ее внутри этой функции. Добавляйте ключевое слово «static» в локальные переменные тогда и только тогда, когда вам нужно, чтобы они сохранили свое значение после завершения функции.

В некоторых встроенных средах, таких как архитектура PIC18 с компилятором C18, локальные переменные намного дороже (больше места в программе, медленнее время выполнения), чем глобальные. На Cortex M3 это не так, поэтому вы можете свободно использовать локальные переменные. Проверьте список сборки и убедитесь сами.

Вопрос 2: Совместное использование переменных между прерываниями и главным циклом

Люди написали целые главы, объясняющие ответы на эту группу вопросов. Всякий раз, когда вы разделяете переменную между основным циклом и прерыванием, вы должны обязательно использовать ключевые слова volatile. Переменные из 32 или менее битов могут быть доступны атомарно (если они не выровнены).

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

Вопрос 3: основная функция в C ++

Я не уверен. Вы можете использовать arm-none-eabi-nm (или как называется nm в вашей цепочке инструментов) в вашем объектном файле, чтобы увидеть, какое имя символа компилятор C ++ назначает main(). Могу поспорить, что компиляторы C ++ воздерживаются от искажения основной функции именно по этой причине, но я не уверен.

4 голосов
/ 13 ноября 2011

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

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

unsigned int myglobal;

void fun ( void )
{
   unsigned int myg;

   myg=myglobal;

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

Кейл знает, что они делают, если они поддерживают C ++, то с системного уровня ониэто сработало.Я не использую Keil. Я использую gcc и llvm для таких микроконтроллеров.

Редактировать:

Вот пример того, о чем я говорю

https://github.com/dwelch67/stm32vld/tree/master/stm32f4d/blinker05

stm32, используя прерывания на основе таймера, обработчик прерываний изменяет переменную, используемую совместно с задачей переднего плана.Задача переднего плана делает один снимок общей переменной (на цикл) и при необходимости использует снимок в цикле более одного раза, а не общую переменную, которая может измениться.Это C не C ++, я понимаю это, и я использую gcc и llvm, а не Keil.(заметьте, у llvm есть известные проблемы с оптимизацией циклов while, очень старая ошибка, не знаю, почему они не заинтересованы в ее исправлении, llvm работает в этом примере).

2 голосов
/ 15 ноября 2011

Пример кода STM не является примером хорошей практики кодирования, он просто предназначен для демонстрации использования их стандартной периферийной библиотеки (предположим, что это примеры, о которых вы говорите). В некоторых случаях может случиться так, что переменные объявлены внешними по отношению к main(), потому что к ним обращаются из контекста прерывания (разделяемая память). Также, возможно, существует вероятность того, что это было сделано просто для того, чтобы переменные можно было наблюдать в отладчике из любого контекста; но это не повод копировать технику. Мое мнение о примере кода STM заключается в том, что он, как правило, довольно плохой, даже если пример кода, не говоря уже с точки зрения разработки программного обеспечения.

В этом случае ваша переменная прерывания часов является атомарной, если она 32-битная или менее, если вы не используете семантику чтение-изменение-запись с несколькими записывающими устройствами. Вы можете безопасно иметь одного писателя и нескольких читателей независимо. Это верно для этой конкретной платформы, но не обязательно универсально; Ответ может быть разным для 8 или 16-битных систем или, например, для многоядерных систем. Переменная должна быть объявлена ​​volatile в любом случае.

Я использую C ++ на STM32 с Keil, и проблем нет. Я не уверен, почему вы думаете, что точки входа в C ++ разные, их здесь нет (Keil ARM-MDK v4.22a). Код запуска вызывает SystemInit(), который, например, инициализирует PLL и синхронизацию памяти, затем вызывает __main(), который выполняет глобальную статическую инициализацию, затем вызывает конструкторы C ++ для глобальных статических объектов перед вызовом main(). Если сомневаетесь, пошагово пройдитесь по коду в отладчике. Важно отметить, что __main() - это не функция main(), которую вы пишете для своего приложения, это оболочка с различным поведением для C и C ++, но в конечном итоге вызывающая вашу функцию main().

...