У минулих публікаціях я показав від чого можна відштовхнутися при написанні програм для STM32F4, налаштували середу компіляції, визначили файл компоновщика, отримали шаблонний файл програми на мові асемблера, спробували налаштувати GPIO мікроконтролера і моргнути світлодіодом.
Тепер прийшов час розібратися в компіляції програм складаються з декількох файлів, розібрати спосіб написання програм для декількох налагоджувальних плат, навчитися виносити настройки програми для зручного їх зміни
Почнемо з самого простого: механізм умовної компіляції
- до висновку 15 GPIO_D для STM32F4 Discovery
- до висновку 2 GPIO_H для Open407I-C
В асемблері GNU AS є механізм умовної компіляції.
Знайшов команду .def - згідно з документацією вона повинна створювати значення, однак змусити її працювати не вдалося, тому я використав директиву ".set".
Спочатку ми присвоюємо змінної компілятор (не програми!) Деяке значення, я вибрав ім'я змінної DEVBOARD:
Налаштування цих параметрів при умовної компіляції виглядає наступним чином:
У тексті самої програми все «прямі» згадки GPIOD (GPIOH) тепер змінюємо на GPIO_LED. значення для RCC_AHB1ENR замінимо на RCC_GPIO_EN і так далі.
Отримаємо наступну програму:
Тепер замислимося про відносно великих за розміром програмах, які навряд чи буде зручно писати в одному файлі, і які будуть складатися з декількох (можливо навіть декількох десятків) файлів.
розглянемо це на прикладі нашої програми «мигалка»: в ній є підпрограма яка реалізує паузу між включенням / виключенням світлодіода, зараз це просто цикл з фіксованим числом циклічного очікування, але в майбутньому підпрограму можна буде переписати на використання системного таймера - і цю підпрограму буде правильніше розмістити в іншому файлі.
Включати файли можна директивою ".include" асемблера:
це рішення дуже просте і досить ефективне, але у нього є один, по початку здається незначним, недолік - спільний простір імен міток.
Поки Програма не перевалить за 150-300 інструкцій - у вас не буде особливих проблем в «вигадуванні» імен міток, наприклад, наступну підпрограму затримки можна буде почати з мітки "DELYA1:", а наступну з ще який-небудь комбінацією, але все не так просто: як тільки ви почнете створювати власну бібліотеку підпрограм і почнете їх використовувати в різних поєднаннях - то обов'язково почнуться перетину в іменах міток.
Один із способів вирішення - введення в ім'я мітки префікса імені файлу исходника, наприклад для нашої підпрограми затримки можна задати наступне ім'я мітки "DELAY_ASM_DELAY:", я випробував такий шлях, правда знову не без застережень - адже в процесі розробки деякі модулі можуть знаходитися в підкаталогах проекту, і щоб не було перетинів ім'я мітки повинно включати в себе не тільки ім'я файлу, але і ім'я каталогу "DIRECTORY_DELAY_ASM_DELAY:" (приклад для каталогу з ім'ям "DIRECTORY", в результаті, якщо нам ще знадобляться мітки ім'я яких складається з 2 3 слів для зрозумілості - ми отримаємо зовсім вже монстроідальние імена міток: "DIRECTORY_DELAY_ASM_DELAY_LOOP_0x10000:" ...
Ще один спосіб це роздільна компіляція вихідних файлів програми.
Фактично асемблер може компілювати окремо файл main.asm і delay.asm. і потім на етапі компонування - ці дві відкомпільованих частини будуть об'єднуватися в підсумковій прошивці.
Оскільки кожен .asm файл компілюватиметься окремо - на початку кожного потрібно включати вказівки налаштувань компіляції і, якщо є необхідність, включати файл констант.
Для того щоб повідомити компілятору яку мітку з цього файлу можна використовувати ззовні - використовується директива ".global".
Розглянемо текст підпрограми при розміщенні в окремому файлі для роздільної компіляції:
Відповідно, мітка DELAY оголошена як .global буде доступна для виклику з інших файлів початкових кодів програми, а ось мітка DELAY_loop доступна тільки всередині файлу delay.asm і фактично ім'я такої мітки може без будь-яких наслідків використовуватися в будь-яких інших частинах програми - перехрещення не буде!
в текст основної програми згідно де-факто сформованих правил потрібно включати директиву ".extern" яка вказує на мітку яка визначена в іншому файлі і буде пов'язана на етапі компонування, але в документації на GNU AS вказано що дана директива пропускається для забезпечення сумісності, і будь-які невіднайденій в вихідному файлі компіляції мітки і константи вважаються глобальними. Підхід на мій погляд спірне, все таки зовнішні значення міток і констант краще позначати явно.
як видно з наведеного лістингу - ніяких додаткових ".include" для файлу, що включається робити не потрібно! включення буде обробляти компоновщик.
процес компіляції і збірки проекту повинен виглядати наступним чином:
Тепер явно видно незручність такої схеми для конкретного програміста: необхідно проводити компіляцію окремих файлів і потім так само при складанні вказувати отримані відкомпілювалися файли. Робити це в ручному режимі, постійно редагуючи файл make_project.bat, досить рутинне заняття, тому даний процес потрібно перекласти на чиїсь інші «могутні плечі»
Трохи по експерементувати «в суботу», я написав новий .bat файл збирає проект в автоматичному режимі.
Довелося внести деякі зміни в структуру каталогів проекту і в «угоду» про іменування файлів:
- вихідний текст програми розміщується в підкаталозі src / проекту:
- в підкаталозі compile / розміщуються готові файли для прошивки, в підкаталозі compile / temp / розміщуються довідкові файли відкомпільованих файлів, файл значень і т.д.
- компілюватиметься будуть всі файли знаходяться починаючи з підкаталогу / src і мають розширення .asm. При цьому, ті файли які будуть включатися директивою .include не повинні мати розширення .asm - оскільки в цьому випадку вони будуть відкомпільовані двічі - перший раз в тексті програми в яку вони включалися директивою .include. і окремо по розширенню.
- шлях всіх файлів які включаються до проекту командою .include повинен починатися з вказівки каталогу src /. наприклад, для файлу констант який лежить в каталозі src / директива повинна бути написана таким чином .include «src / const_file.inc»
Компіляцію робить наступний скрипт розміщений в
Папку проекту потрібно розміщувати в папці в якій і в її шляху немає прогалин в іменах. Російські літери в іменах каталогів допускаються.
Таким чином шлях запуску: D: / МойПроект / gnuas / Перший / - припустимо, а ось D: / Мій Проект / gnus / Перший / - не допустимо (Ім'я папки «Мій Проект» містить пробіл)
За секції прошивки .text зроблю пояснення:
Такий запис вказує компонувальнику що секції повинні бути розміщені саме в тому порядку в якому описані.
Для векторів переривань я ввів секцію .vectors, це секція повинна зустрічатися в програмі тільки один раз (що логічно, так як таблиця векторів в наших програмах поки тільки одна).
Далі я оголошую секції в яких буде розміщуватися текст програми: це .text і .asmcode - по «задумом» секція .text буде гарантовано розміщена після таблиці векторів - в цій секції я розміщую різні службові підпрограми (наприклад, «заглушки» переривань), а ось в секції .asmcode я пишу сам текст програми.
Таким чином відзначивши в програмі секцію .vectors я гарантую її розміщення на початку програми незалежно від того яким за рахунком файлом буде вказано при компонуванні main.o
Порядок розміщення декількох секцій .asmcode. відносно один одного, як правило вже ролі не грає (ну якщо бути зовсім чесним - то звичайно грає, але це тільки для дуже високих програм, але про це поки замислюватися рано)
Секція .rodata - це секція констант у flash, окремо виділив для зручності, пояснити навіщо вона потрібна простіше на прикладі:
а константа розміщена в окремій секції .rodata після секцій .asmcode
Дрібниця. - Так! Але іноді дуже зручно!
Сподіваюся основні ідеї які рухали мною при формуванні секцій стали зрозумілі, і тепер залишилося внести зміни в наш проект «мигалка», з двома файлами вихідної програми, що стосуються іменування секцій
Тепер, в якому б ми порядку не віддавали файли на компоновку - секція .vectors завжди буде на початку вихідного файлу, а секція .asmcode після неї ... А ось яка частина програми буде йти відразу після таблиці покажчиків переривань (main.asm або delay.asm ) - буде залежати від порядку їх компонування (хто раніше встав - того і тапки раніше і розмістили)
Що ще потрібно для повного щастя? написання програм на асемблері для STM32F4?
p.s. мало не забув архів прикріпити blink4.zip