Універсальний gcc-avr.mak

У зв’язку з описаною раніше помилкою avr-ld та методом боротьби з нею мене спитали про той «універсальний» файл gcc-avr.mak, яким я користуюся у всіх проектах. «Нічого воєнного», це просто файл, у який зібрано команди, які без змін переходили б з проекту в проект шляхом копіювання (і наступного редагування) Makefile від попереднього проекту 😉

Тепер файл gcc-avr.mak підключається до Makefile проекту командою include. Так само, як і подібний мейк-файл для роботи з програматором avreal — avreal.mak. Файл для проекту тепер короткий, містить лише головні налаштування. Легше знайти потрібне, важче поламати те, що вже перевірене.

Повернімося тепер до цього універсального мейк-файлу для avr-gcc і до згаданої помилки в avr-ld.

Окрім іншого, на початку gcc-avr.mak здійснюється налаштування шляхів до програм, використовуваних при компіляції. Виглядає це так (нумерація рядків відповідає файлу, доданому у прикріплений архів).

40
41
42
43
44
45
46
47
48
49
# Set default toolchain prefix if it does not defind in environment or project makefile
TOOL ?= avr-

# Set tool names
CC  := $(TOOL)gcc
AS  := $(TOOL)gcc -x assembler-with-cpp
BIN := $(TOOL)objcopy
OBJCOPY := $(TOOL)objcopy
OBJDUMP := $(TOOL)objdump
SIZE    := $(TOOL)size

Зроблено це було ще у часи, коли я багато працював паралельно з різними версіями avr-gcc з різних джерел. Частково тому, що все «дихало», нові версії мали кращу оптимізацію, але могли «глюкнути» і потрібно було мати можливість швидко відкотитися на перевірену версію. Частково тому, що я активно розвивав і супроводжував AVR-порти scmRTOS і треба було перевіряти всі зміни у різних версіях компіляторів, вишукувати «інтерференцію» помилок і «особливостей» ;-). Тоді найперевіреніша і найстабільніша версія avr-gcc була встановлена основною за допомогою команди junction (див. допис Різні версії WinAVR поруч). У файлі gcc-avr.mak підключалася ця основна версія — але лише тоді, коли змінна TOOL не була встановлена у Makefile проекту. У проекті ж цей рядок або був відсутнім, або міг мати вигляд:

1
TOOL = c:/avr-gcc/kgp/20080530/bin/avr-

Ще у цьому gcc-avr.mak, у його варіанті для Windows, були рядки, які приводили до єдиного вигляду шляхи у змінній PATH і експортували її для процесів, викликаних make. Це було пов’язане з необхідністю змусити працювати на одному комп’ютері avr-gcc з різних джерел. Якщо коротко, то ті, що спиралися на MSYS, і ті, що були зібрані геть автономно, використовували шляхи вигляду /c/directory і c:\directory відповідно. Це теж окрема пісня, яка тепер для мене цікава лише в історичному плані. Якщо комусь цікаво почути — проспіваю окремо.

Ну так от, оця змінна TOOL виявилася найкращим місцем для додавання заміни значення змінної оточення LANG (дивись вже згаданий допис щодо виправлення помилки переповнення буфера в avr-ld):

40
41
# Set default toolchain prefix if it does not defind in environment or project makefile
TOOL ?= LANG=en avr-

Позаяк змінна є префіксом для всіх інструментів, вона ж превентивно перемикає мову і для інших програм пакету. Файл цей у мене лежить один на всі проекти, тому вони всі відразу виправилися. Добре, на всі проекти з однієї групи, тому все ж таки по внесенні змін мені довелося його розкопіювати у декілька місць. І я так і не зробив собі репозиторію для загально-загальних файлів.

Додаю архів із дуже-демо-проектом, який має використовувану мною структуру каталогів.
Там є спільниі для всіх проектів «бібліотеки» (каталог common, що може містити як підкаталоги незалежних від архітектури мікроконтролера модулів, так і залежні, наприклад, common/avr, що може своєю чергою містити підкаталоги з контролеро-залежними модулями). На цьому ж рівні знаходиться спільний для всіх каталог tools, де живуть спільні (для групи проектів) скрипти і підкаталог tools/makefiles зі згаданими «універсальними» файлами. Всі проекти (представлені одним-однісіньким project1) мають схожу структуру. На верхньому рівні проекту живе його Makefile а також файли середовища програмування (у мене це Code::Blocks) і, при необхідності, деякі додаткові персональні скрипти. У підкаталозі src для простих проектів лежсть всі їхні тексти, у складніших — ще підкаталоги з модулями.

«Модуль» (мають бути перелічені у змінній MODULES у Makefile проекту) у контексті цього підходу є каталог, який може бути підключеним до проекту як одне ціле. Окремі файли ніде не перелічуються, gcc-avr.mak автоматично включає у компіляцію і лінкування всі асемблерні, C-шні і C++-ні файли, які у цих каталогах знаходить. Таким чином, «модуль» у цьому розумінні може містити декілька модулів у термінах програмування, які можуть бути використані у проекті лише разом. Так само «модулем» може бути каталог із лише h-файлами, які пов’язані між собою лише тим, що стосуються однієї сім’ї мікроконтролерів і ніяк більше не пов’язані між собою. Весь каталог буде підключено до проекту, а які конкретно файли будуть використані — залежить від директив #include у файлах проекту.

Описувати це довше, ніж читати самі файли. Беріть як є.
Прикрутити таку систему можна до будь-якого інтегрованого середовища, яке дозволяє зробити проект «із зовнішнім Makefile». При цьому, напевне, будуть втрачені якісь зручні можливості середовища по налаштуванню проекту, але можна нашвидкоруч щось підправити у vim чи gedit, а тоді з консолі набрати make program :-).

p.s. Раніше я писав про те, що можна зробити в gcc (avr-gcc) з використанням секцій (дописи «Використання секцій в GCC» і «Секції .init в avr-gcc»). Робота з Makefile і gcc-avr.mak згадані там лише побіжно, але у прикріплених архівах є реалістичніші проекти з використанням такої техніки роботи з мейк-файлами «модулями».

Attached Files:

OpenOCD, LPC17xx та srec_cat

Boot-loader в мікроконтролерах LPC17xx очікує 32-бітну контрольну суму перших семи слів прошивки (вміст вказівника стеку, та перших шести векторів) на місці не використовуваного вектора по адресі 0x1C. В це слово записується мінус-сума перших семи слів. Схожим чином перевіряє наявність програми і бутлоадер LPC2000.
OpenOCD вміє «на льоту» генерувати таку контрольну суму при програмуванні мікроконтролера, потрібно лишень в команді flash вказати аргумент calc_checksum (ця команда є у файлі target/lpc17xx.cfg пакету).
Але чомусь він не генерує її для звірки вмісту (верифікації). Причому сам він знає, що мені буде незручно, раніше навіть писав щось таке:

Warn : Verification will fail since checksum in image (0x00000000) to be written
    to flash is different from calculated vector checksum (0xeffee33a).
Warn : To remove this warning modify build tools on developer PC to inject
    correct LPC vector checksum.

Тобто якщо йому дати для верифікації той же файл, що йому було дано для прошивки, то він видасть помилку в тих чотирьох байтах. Ось нещодавно я в черговий раз підятягнув з репозиторію оновлення, зібрав та встановив свіжісіньку версію, однак маю:
»»» Подивитися повідомлення про помилку верифікації та боротьбу з нею

Двійкові дані та програма мікроконтролера

Досить часто виникає потреба додати двійкові дані до «прошивки» мікроконтролера. Це може бути знакогенератор для графічного дисплея чи принтера, закодована певним чином музика чи якась інша інформація, отримана у «двійковому» (тобто не-текстовому) вигляді від якоїсь «сторонньої» відносно компілятора для мікроконтролера програми.

У моєму випадку це теж прошивка, але для програмованої логіки (FPGA). Цю прошивку можна отримати у вигляді файлу .ttf (tabular text file, а не true type font :-)), у якому знаходяться десяткові числа, розділені комами.
Колись давно, ще «десь між i87c51FA та AT89C55» я з такого файлу для EPF8282 генерував asm-файл. Програмою sed додавав до та після масиву чисел потрібні заголовки з мітками, на початку кожного рядка директиву .DB і тому подібне. Асемблерний файл згодом компілювався в об’єктний та прилінковувався до програми.
Для ATmega162 та EP1K10 користувався власноруч написаною програмою — основна її робота була стиснути прошивку для альтерини простим, але ефективним алгоритмом, а вже видати назовні C-масив то була проста робота.
Тепер у мене LPC1766 та EP1C3. Циклони вже мають в собі декомпресор і квартус може стискати прошивки. Він це робить гірше, ніж алгоритм від Ivan Mak, але він це робить сам і розпаковує теж без мене. Тому я, принаймні зараз, повертаюся до простого перетворення стороннього файлу прошивки в об’єктний файл з масивом.

Зараз для таких робіт зазвичай пропонують вже готові програми на зразок bin2c для генерації C-шного масиву. До речі, на мою думку, однією з найкращих програм на тему все2всюди є пакет srecord.
Але при роботі з компіляторами gcc (точніше, з набором програм GNU binutils, яким користується і gcc) можна обійтися без додаткових програм, »»» прочитати — яким саме штатним інструментом з пакету та як…

Використання секцій в GCC

Нехай перед нами стоїть наступна задача. Програма може складатися з набору модулів, які комбінуються в залежності від потреб. Кожен модуль має функцію, яка викликається при його виборі в простому меню на терміналі. Також є текстовий рядок та літера для меню. Ми хочемо автоматизувати процес збирання програми таким чином, що при підключення модуля в проект він «сам» ініціалізується і «реєструється» в програмі до початку роботи main(). В C++ це робиться за допомогою конструкторів, але при цьому розмір програми росте. В C можна в окремому файлі створити масив структур опису модулів і ініціалізувати його статично. Щоправда, при цьому доведеться ініціалізувати модулі окремим циклом на початку функції main() (теж трохи додаткового коду) та для формування масиву залежно від потреб використовувати #ifdef / #endif.

Зрозуміло, якщо «з першого акту на стіні висить рушниця» моделі «використання секцій», то тут стрілятиме саме вона.
Читати далі — автоматизація реєстрації модулів за допомогою секцій… » » »

Attached Files:

  • zip GCC sections usage demo

    avr-gcc, atmega168. Code::Blocks project with external makefile (can be used with any IDE or without IDE)

[flagcounter image]